Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import org.apache.commons.lang3.StringUtils;

Expand All @@ -27,6 +28,7 @@
import forge.screens.match.CMatchUI;
import forge.toolbox.special.CardZoomer;
import forge.util.Localizer;
import forge.view.KeyboardShortcutsDialog;

/**
* Consolidates keyboard shortcut assembly into one location
Expand All @@ -36,10 +38,16 @@
* and you're done.
*/
public class KeyboardShortcuts {
private static List<Shortcut> cachedShortcuts;

public static List<Shortcut> getKeyboardShortcuts() {
return attachKeyboardShortcuts(null);
}

public static List<Shortcut> getCachedShortcuts() {
return cachedShortcuts != null ? cachedShortcuts : getKeyboardShortcuts();
}

/**
* Attaches all keyboard shortcuts for match UI,
* and returns a list of shortcuts with necessary properties for later access.
Expand Down Expand Up @@ -200,6 +208,17 @@ public void actionPerformed(ActionEvent e) {
}
};

/** Show keyboard shortcuts dialog. */
final Action actShowHotkeys = new AbstractAction() {
@Override
public void actionPerformed(final ActionEvent e) {
if (!Singletons.getControl().getCurrentScreen().isMatchScreen()) { return; }
// Defer so the triggering key event is fully consumed before the dialog opens,
// preventing it from being captured by a KeyboardShortcutField.
SwingUtilities.invokeLater(() -> new KeyboardShortcutsDialog().setVisible(true));
}
};

final Localizer localizer = Localizer.getInstance();
//========== Instantiate shortcut objects and add to list.
list.add(new Shortcut(FPref.SHORTCUT_SHOWSTACK, localizer.getMessage("lblSHORTCUT_SHOWSTACK"), actShowStack, am, im));
Expand All @@ -215,6 +234,8 @@ public void actionPerformed(ActionEvent e) {
list.add(new Shortcut(FPref.SHORTCUT_MACRO_RECORD, localizer.getMessage("lblSHORTCUT_MACRO_RECORD"), actMacroRecord, am, im));
list.add(new Shortcut(FPref.SHORTCUT_MACRO_NEXT_ACTION, localizer.getMessage("lblSHORTCUT_MACRO_NEXT_ACTION"), actMacroNextAction, am, im));
list.add(new Shortcut(FPref.SHORTCUT_CARD_ZOOM, localizer.getMessage("lblSHORTCUT_CARD_ZOOM"), actZoomCard, am, im));
list.add(new Shortcut(FPref.SHORTCUT_SHOWHOTKEYS, localizer.getMessage("lblSHORTCUT_SHOWHOTKEYS"), actShowHotkeys, am, im));
cachedShortcuts = list;
return list;
} // End initMatchShortcuts()

Expand Down
9 changes: 9 additions & 0 deletions forge-gui-desktop/src/main/java/forge/menus/HelpMenu.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import forge.util.BuildInfo;
import forge.util.FileUtil;
import forge.util.Localizer;
import forge.view.KeyboardShortcutsDialog;

import static forge.localinstance.properties.ForgeConstants.GITHUB_FORGE_URL;

Expand All @@ -27,6 +28,7 @@ public static JMenu getMenu() {
menu.setMnemonic(KeyEvent.VK_H);
menu.add(getMenu_GettingStarted());
menu.add(getMenu_Troubleshooting());
menu.add(getMenuItem_KeyboardShortcuts());
menu.addSeparator();
menu.add(getMenuItem_ReleaseNotes());
menu.add(getMenuItem_License());
Expand Down Expand Up @@ -67,6 +69,13 @@ private static JMenu getMenu_GettingStarted() {
return mnu;
}

private static JMenuItem getMenuItem_KeyboardShortcuts() {
final Localizer localizer = Localizer.getInstance();
JMenuItem menuItem = new JMenuItem(localizer.getMessage("lblKeyboardShortcuts"));
menuItem.addActionListener(e -> new KeyboardShortcutsDialog().setVisible(true));
return menuItem;
}

private static JMenuItem getMenuItem_HowToPlayFile() {
final Localizer localizer = Localizer.getInstance();
JMenuItem menuItem = new JMenuItem(localizer.getMessage("lblHowtoPlay"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,7 +573,7 @@ private NoteLabel(final String txt0) {
* into characters and (dis)assembly of keycode stack.
*/
@SuppressWarnings("serial")
public class KeyboardShortcutField extends SkinnedTextField {
public static class KeyboardShortcutField extends SkinnedTextField {
private String codeString;

/**
Expand Down Expand Up @@ -648,7 +648,7 @@ public final void setCodeString(final String str0) {
}
}

this.setText(StringUtils.join(displayText, ' '));
this.setText(StringUtils.join(displayText, '+'));
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package forge.view;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Scrollable;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.UIManager;

import forge.control.KeyboardShortcuts;
import forge.control.KeyboardShortcuts.Shortcut;
import forge.screens.home.settings.VSubmenuPreferences.KeyboardShortcutField;
import forge.toolbox.FLabel;
import forge.toolbox.FScrollPane;
import forge.toolbox.FSkin;
import forge.util.Localizer;
import net.miginfocom.swing.MigLayout;

@SuppressWarnings("serial")
public class KeyboardShortcutsDialog extends FDialog {

public KeyboardShortcutsDialog() {
super(false, true, "10");
final Localizer localizer = Localizer.getInstance();
setTitle(localizer.getMessage("lblKeyboardShortcuts"));
setSize(500, 600);
setMinimumSize(new Dimension(350, 300));

// Scrollable panel that always matches viewport width, preventing horizontal scroll.
final JPanel content = new ScrollablePanel(new MigLayout("insets 10 15 20 15, gap 5, wrap 2, fillx", "[grow][120!]"));
content.setOpaque(false);

// Section 1: Configurable shortcuts
for (final Shortcut shortcut : KeyboardShortcuts.getCachedShortcuts()) {
final FLabel descLabel = new FLabel.Builder()
.text(shortcut.getDescription())
.fontAlign(SwingConstants.LEFT)
.fontSize(11).build();
content.add(descLabel, "growx");

final KeyboardShortcutField field = new KeyboardShortcutField(shortcut);
field.setFont(FSkin.getRelativeFont(11));
// Clear existing binding on click so a new key press replaces it.
field.addMouseListener(new java.awt.event.MouseAdapter() {
@Override
public void mousePressed(final java.awt.event.MouseEvent e) {
field.setCodeString("");
}
});
// Transfer focus away once a non-modifier key completes the binding.
field.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(final KeyEvent e) {
final int code = e.getKeyCode();
if (code != KeyEvent.VK_SHIFT && code != KeyEvent.VK_CONTROL
&& code != KeyEvent.VK_ALT && code != KeyEvent.VK_META) {
content.requestFocusInWindow();
}
}
});
content.add(field, "w 120!, h 22!");
}

// Section 2: Fixed menu accelerators
final FLabel headerFixed = new FLabel.Builder()
.text(localizer.getMessage("lblMenuShortcuts"))
.fontAlign(SwingConstants.LEFT)
.fontSize(14).fontStyle(Font.BOLD).build();
content.add(headerFixed, "span 2, gaptop 10, gapbottom 5, wrap");

final int menuMask = Toolkit.getDefaultToolkit().getMenuShortcutKeyMaskEx();
final String modPrefix = InputEvent.getModifiersExText(menuMask) + "+";

addFixedRow(content, "Forge Wiki", KeyEvent.getKeyText(KeyEvent.VK_F1));
addFixedRow(content, "Full Screen", KeyEvent.getKeyText(KeyEvent.VK_F11));
addFixedRow(content, "Undo", modPrefix + KeyEvent.getKeyText(KeyEvent.VK_Z));
addFixedRow(content, "Concede", modPrefix + KeyEvent.getKeyText(KeyEvent.VK_Q));
addFixedRow(content, "Alpha Strike", modPrefix + KeyEvent.getKeyText(KeyEvent.VK_A));
addFixedRow(content, "End Turn", modPrefix + KeyEvent.getKeyText(KeyEvent.VK_E));
addFixedRow(content, "Toggle Panel Tabs", modPrefix + KeyEvent.getKeyText(KeyEvent.VK_T));
addFixedRow(content, "Toggle Card Overlays", modPrefix + KeyEvent.getKeyText(KeyEvent.VK_O));

final FScrollPane scrollPane = new FScrollPane(content, false,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
add(scrollPane, "w 100%!, h 100%!");
setDefaultFocus(scrollPane);
}

private static void addFixedRow(final JPanel panel, final String description, final String keyText) {
final FLabel descLabel = new FLabel.Builder()
.text(description).fontAlign(SwingConstants.LEFT).fontSize(11).build();
panel.add(descLabel, "growx");

final JLabel field = new JLabel(keyText);
field.setOpaque(true);
field.setBackground(new Color(200, 200, 200));
field.setFont(FSkin.getRelativeFont(11).getBaseFont());
field.setBorder(BorderFactory.createCompoundBorder(
UIManager.getBorder("TextField.border"),
BorderFactory.createEmptyBorder(0, 2, 0, 2)));
panel.add(field, "w 120!, h 22!");
}

/** JPanel that implements Scrollable to track viewport width, preventing horizontal scrolling. */
private static class ScrollablePanel extends JPanel implements Scrollable {
ScrollablePanel(java.awt.LayoutManager layout) {
super(layout);
}

@Override
public Dimension getPreferredScrollableViewportSize() {
return getPreferredSize();
}

@Override
public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
return 16;
}

@Override
public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
return 64;
}

@Override
public boolean getScrollableTracksViewportWidth() {
return true;
}

@Override
public boolean getScrollableTracksViewportHeight() {
return false;
}
}
}
3 changes: 3 additions & 0 deletions forge-gui/res/languages/en-US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,9 @@ lblSHORTCUT_AUTOYIELD_ALWAYS_NO=Match: auto-yield ability on stack (Always No)
lblSHORTCUT_MACRO_RECORD=Match: record a macro sequence of actions
lblSHORTCUT_MACRO_NEXT_ACTION=Match: execute next action in a recorded macro
lblSHORTCUT_CARD_ZOOM=Match: zoom the currently selected card
lblSHORTCUT_SHOWHOTKEYS=Match: show keyboard shortcuts
lblKeyboardShortcuts=Keyboard Shortcuts
lblMenuShortcuts=Menu Shortcuts (Not Configurable)
#VSubmenuDraft.java
lblBoosterDraft=Booster Draft
lblHeaderBoosterDraft=Sanctioned Format: Booster Draft
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ public enum FPref implements PreferencesStore.IPref {
SHORTCUT_MACRO_RECORD ("16 82"),
SHORTCUT_MACRO_NEXT_ACTION ("16 50"),
SHORTCUT_CARD_ZOOM("90"),
SHORTCUT_SHOWHOTKEYS("72"),

LAST_IMPORTED_CUBE_ID("");

Expand Down