diff --git a/src/main/java/de/bwravencl/controllerbuddy/gui/EditActionsDialog.java b/src/main/java/de/bwravencl/controllerbuddy/gui/EditActionsDialog.java index e9180aa6..26884e61 100644 --- a/src/main/java/de/bwravencl/controllerbuddy/gui/EditActionsDialog.java +++ b/src/main/java/de/bwravencl/controllerbuddy/gui/EditActionsDialog.java @@ -79,10 +79,12 @@ public final class EditActionsDialog extends JDialog { private static final Logger log = Logger.getLogger(EditActionsDialog.class.getName()); - private static final int DIALOG_BOUNDS_WIDTH = 1000; - private static final int DIALOG_BOUNDS_HEIGHT = 600; + private static final int DIALOG_BOUNDS_WIDTH = 1015; + private static final int DIALOG_BOUNDS_HEIGHT = 665; private static final int DIALOG_BOUNDS_PARENT_OFFSET = 25; + private static final double ACTIONS_LIST_WEIGHT_X = .245d; + private static final List> axisActionClasses; private static final List> buttonActionClasses; private static final List> cycleActionClasses; @@ -434,8 +436,10 @@ private void init() { addButton.setEnabled(selectedAvailableAction != null); }); updateAvailableActions(); - actionsPanel.add(new JScrollPane(availableActionsList), new GridBagConstraints(0, 1, 1, 5, .1d, 1d, - GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + + actionsPanel.add(GuiUtils.wrapComponentInScrollPane(availableActionsList), + new GridBagConstraints(0, 1, 1, 5, ACTIONS_LIST_WEIGHT_X, 1d, GridBagConstraints.CENTER, + GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); actionsPanel.add(new JLabel(Main.strings.getString("ASSIGNED_ACTIONS_LABEL")), new GridBagConstraints(2, 0, 1, 1, 0d, 0d, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 25)); @@ -447,7 +451,7 @@ private void init() { final var propertiesScrollPane = new JScrollPane(); propertiesScrollPane.setVisible(false); - actionsPanel.add(propertiesScrollPane, new GridBagConstraints(3, 1, 1, 5, .8d, 1d, GridBagConstraints.CENTER, + actionsPanel.add(propertiesScrollPane, new GridBagConstraints(3, 1, 1, 5, 1d, 1d, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); assignedActionsList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); @@ -462,14 +466,14 @@ private void init() { if (selectedAssignedAction != null) { final var actionClass = selectedAssignedAction.action.getClass(); final var fieldToActionPropertyMap = getFieldToActionPropertiesMap(actionClass); - final var sortedEntires = fieldToActionPropertyMap.entrySet().stream().sorted((entry1, entry2) -> { + final var sortedEntries = fieldToActionPropertyMap.entrySet().stream().sorted((entry1, entry2) -> { final var action1 = entry1.getValue(); final var action2 = entry2.getValue(); return action1.order() - action2.order(); }).toList(); - for (final var entry : sortedEntires) { + for (final var entry : sortedEntries) { final var field = entry.getKey(); final var annotation = entry.getValue(); @@ -484,7 +488,7 @@ private void init() { new Insets(5, 5, 5, 5), 0, 10)); final var propertyNameLabel = new JLabel(Main.strings.getString(annotation.label())); - propertyNameLabel.setPreferredSize(new Dimension(175, 15)); + propertyNameLabel.setPreferredSize(new Dimension(155, 15)); propertyPanel.add(propertyNameLabel); try { @@ -522,9 +526,11 @@ private void init() { } propertiesLabel.setVisible(anyPropertiesFound); propertiesScrollPane.setVisible(anyPropertiesFound); + revalidate(); }); - actionsPanel.add(new JScrollPane(assignedActionsList), new GridBagConstraints(2, 1, 1, 5, .1d, 1d, - GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); + actionsPanel.add(GuiUtils.wrapComponentInScrollPane(assignedActionsList), + new GridBagConstraints(2, 1, 1, 5, ACTIONS_LIST_WEIGHT_X, 1d, GridBagConstraints.CENTER, + GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0)); final var okCancelButtonPanel = new JPanel(); okCancelButtonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT)); diff --git a/src/main/java/de/bwravencl/controllerbuddy/gui/GuiUtils.java b/src/main/java/de/bwravencl/controllerbuddy/gui/GuiUtils.java index 74f7e7fc..a09859a1 100644 --- a/src/main/java/de/bwravencl/controllerbuddy/gui/GuiUtils.java +++ b/src/main/java/de/bwravencl/controllerbuddy/gui/GuiUtils.java @@ -25,6 +25,7 @@ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; +import java.awt.Dimension; import java.awt.EventQueue; import java.awt.FlowLayout; import java.awt.Frame; @@ -46,6 +47,7 @@ import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.JScrollPane; @SuppressWarnings({ "exports", "missing-explicit-ctor" }) public final class GuiUtils { @@ -197,6 +199,21 @@ public static void showMessageDialog(final Main main, @SuppressWarnings("exports JOptionPane.showMessageDialog(parentComponent, message, title, messageType, icon); } + static JScrollPane wrapComponentInScrollPane(final java.awt.Component component) { + return wrapComponentInScrollPane(component, null); + } + + public static JScrollPane wrapComponentInScrollPane(final java.awt.Component component, + final Dimension preferredSize) { + final var scrollPane = new JScrollPane(component); + + if (preferredSize != null) { + scrollPane.setPreferredSize(preferredSize); + } + + return scrollPane; + } + static class FrameDragListener extends MouseAdapter { private final Main main; diff --git a/src/main/java/de/bwravencl/controllerbuddy/gui/Main.java b/src/main/java/de/bwravencl/controllerbuddy/gui/Main.java index f5316e9a..893e3b72 100644 --- a/src/main/java/de/bwravencl/controllerbuddy/gui/Main.java +++ b/src/main/java/de/bwravencl/controllerbuddy/gui/Main.java @@ -232,7 +232,7 @@ public final class Main { static final int DEFAULT_OVERLAY_SCALING = 1; static final int BUTTON_DIMENSION_HEIGHT = 25; @SuppressWarnings("exports") - public static final Dimension BUTTON_DIMENSION = new Dimension(120, BUTTON_DIMENSION_HEIGHT); + public static final Dimension BUTTON_DIMENSION = new Dimension(115, BUTTON_DIMENSION_HEIGHT); @SuppressWarnings({ "exports", "SuspiciousNameCombination" }) public static final Dimension SQUARE_BUTTON_DIMENSION = new Dimension(BUTTON_DIMENSION_HEIGHT, BUTTON_DIMENSION_HEIGHT); diff --git a/src/main/java/de/bwravencl/controllerbuddy/input/action/gui/KeystrokeEditorBuilder.java b/src/main/java/de/bwravencl/controllerbuddy/input/action/gui/KeystrokeEditorBuilder.java index cfdfd76a..bb1709fe 100644 --- a/src/main/java/de/bwravencl/controllerbuddy/input/action/gui/KeystrokeEditorBuilder.java +++ b/src/main/java/de/bwravencl/controllerbuddy/input/action/gui/KeystrokeEditorBuilder.java @@ -17,6 +17,7 @@ package de.bwravencl.controllerbuddy.input.action.gui; import de.bwravencl.controllerbuddy.gui.EditActionsDialog; +import de.bwravencl.controllerbuddy.gui.GuiUtils; import de.bwravencl.controllerbuddy.gui.Main; import de.bwravencl.controllerbuddy.input.KeyStroke; import de.bwravencl.controllerbuddy.input.ScanCode; @@ -24,12 +25,15 @@ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Insets; import java.io.Serial; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; -import java.util.LinkedHashSet; +import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; @@ -42,17 +46,25 @@ import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; -import javax.swing.JScrollPane; -import javax.swing.JTextArea; +import javax.swing.JTextPane; import javax.swing.ListCellRenderer; import javax.swing.ListModel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.StyleConstants; public final class KeystrokeEditorBuilder extends EditorBuilder { private static final Logger log = Logger.getLogger(KeystrokeEditorBuilder.class.getName()); - private final JTextArea keyStrokeTextArea = new JTextArea(); + + private static final Dimension KEY_LIST_SCROLL_PANE_DIMENSION = new Dimension(110, 200); + + private final KeyStrokeTextPane modifiersTextArea = new KeyStrokeTextPane(); + private final KeyStrokeTextPane keysTextArea = new KeyStrokeTextPane(); + private final JLabel plusLabel = new JLabel("+"); private CheckboxJList modifierList; private CheckboxJList keyList; @@ -93,58 +105,69 @@ public void buildEditor(final JPanel parentPanel) { final var modifiersPanel = new JPanel(); modifiersPanel.setLayout(new BoxLayout(modifiersPanel, BoxLayout.PAGE_AXIS)); final var modifiersLabel = new JLabel(Main.strings.getString("MODIFIERS_LABEL")); - modifiersLabel.setAlignmentX(java.awt.Component.CENTER_ALIGNMENT); + modifiersLabel.setAlignmentX(Component.CENTER_ALIGNMENT); modifiersPanel.add(modifiersLabel); modifiersPanel.add(Box.createVerticalStrut(5)); modifierList = new CheckboxJList<>(availableScanCodes.toArray(String[]::new)); modifierList.addListSelectionListener(new JListSetPropertyListSelectionListener(setterMethod, keyStroke, true)); - final var addedModifiers = new ArrayList(); - for (final var modifierCode : keyStroke.getModifierCodes()) { - addedModifiers.add(modifierCode.name()); - } - addedModifiers.forEach(s1 -> { - final var index1 = getListModelIndex(modifierList.getModel(), s1); - if (index1 >= 0) { - modifierList.addSelectionInterval(index1, index1); - } - }); + modifiersPanel.add(GuiUtils.wrapComponentInScrollPane(modifierList, KEY_LIST_SCROLL_PANE_DIMENSION)); + + modifiersPanel.add(Box.createVerticalStrut(5)); + modifiersPanel.add(modifiersTextArea); - final var modifiersScrollPane = new JScrollPane(modifierList); - modifiersScrollPane.setPreferredSize(new Dimension(130, 200)); - modifiersPanel.add(modifiersScrollPane); keystrokePanel.add(modifiersPanel, BorderLayout.WEST); final var keysPanel = new JPanel(); keysPanel.setLayout(new BoxLayout(keysPanel, BoxLayout.PAGE_AXIS)); final var keysLabel = new JLabel(Main.strings.getString("KEYS_LABEL")); - keysLabel.setAlignmentX(java.awt.Component.CENTER_ALIGNMENT); + keysLabel.setAlignmentX(Component.CENTER_ALIGNMENT); keysPanel.add(keysLabel); keysPanel.add(Box.createVerticalStrut(5)); keyList = new CheckboxJList<>(availableScanCodes.toArray(String[]::new)); keyList.addListSelectionListener(new JListSetPropertyListSelectionListener(setterMethod, keyStroke, false)); - final var addedKeys = new ArrayList(); - for (final var keyCode : keyStroke.getKeyCodes()) { - addedKeys.add(keyCode.name()); - } - addedKeys.forEach(s2 -> { - final var index2 = getListModelIndex(keyList.getModel(), s2); - if (index2 >= 0) { - keyList.addSelectionInterval(index2, index2); + keysPanel.add(GuiUtils.wrapComponentInScrollPane(keyList, KEY_LIST_SCROLL_PANE_DIMENSION)); + + keysPanel.add(Box.createVerticalStrut(5)); + keysPanel.add(keysTextArea); + + keystrokePanel.add(keysPanel, BorderLayout.EAST); + + final var plusPanel = new JPanel(); + plusPanel.setLayout(new BoxLayout(plusPanel, BoxLayout.PAGE_AXIS)); + plusPanel.setPreferredSize(new Dimension(10, plusPanel.getPreferredSize().height)); + plusPanel.add(Box.createVerticalStrut( + modifiersPanel.getPreferredSize().height - modifiersTextArea.getPreferredSize().height)); + plusLabel.setAlignmentX(Component.CENTER_ALIGNMENT); + plusLabel.setAlignmentY(Component.CENTER_ALIGNMENT); + plusPanel.add(plusLabel); + keystrokePanel.add(plusPanel, BorderLayout.CENTER); + + initListSelection(modifierList, keyStroke.getModifierCodes()); + initListSelection(keyList, keyStroke.getKeyCodes()); + + updateUpdateKeyStrokeVisualization(); + } + + private void initListSelection(final JList list, final ScanCode[] scanCodes) { + Arrays.stream(scanCodes).map(ScanCode::name).forEach(scanCodeName -> { + final var index = getListModelIndex(list.getModel(), scanCodeName); + if (index >= 0) { + list.addSelectionInterval(index, index); } }); + } - final var keysScrollPane = new JScrollPane(keyList); - keysScrollPane.setPreferredSize(new Dimension(130, 200)); - keysPanel.add(keysScrollPane); - keystrokePanel.add(keysPanel, BorderLayout.EAST); + private void updateUpdateKeyStrokeVisualization() { + final var selectedModifiersList = modifierList != null ? modifierList.getSelectedValuesList() + : Collections.emptyList(); + modifiersTextArea.setScanCodes(selectedModifiersList); + + final var selectedKeysList = keyList != null ? keyList.getSelectedValuesList() : Collections.emptyList(); + keysTextArea.setScanCodes(selectedKeysList); - keyStrokeTextArea.setLineWrap(true); - keyStrokeTextArea.setWrapStyleWord(true); - keyStrokeTextArea.setEditable(false); - keyStrokeTextArea.setFocusable(false); - keystrokePanel.add(keyStrokeTextArea, BorderLayout.SOUTH); + plusLabel.setVisible(!selectedModifiersList.isEmpty() && !selectedKeysList.isEmpty()); } private static final class CheckboxJList extends JList { @@ -176,6 +199,10 @@ public void setSelectionInterval(final int index0, final int index1) { addSelectionInterval(index0, index1); } } + + @Override + public void setValueIsAdjusting(final boolean isAdjusting) { + } }); } @@ -203,6 +230,55 @@ public Component getListCellRendererComponent(final JList list, fin } } + private static final class KeyStrokeTextPane extends JTextPane { + + @Serial + private static final long serialVersionUID = 4814218567890032503L; + + private KeyStrokeTextPane() { + setEditable(false); + setFocusable(false); + setMargin(new Insets(0, 5, 0, 5)); + setSize(Integer.MAX_VALUE, Integer.MAX_VALUE); + + final var styledDocument = getStyledDocument(); + final var attributeSet = new SimpleAttributeSet(); + StyleConstants.setAlignment(attributeSet, StyleConstants.ALIGN_CENTER); + styledDocument.setParagraphAttributes(0, styledDocument.getLength(), attributeSet, false); + + getDocument().addDocumentListener(new DocumentListener() { + + @Override + public void changedUpdate(final DocumentEvent e) { + updateSize(); + } + + @Override + public void insertUpdate(final DocumentEvent e) { + updateSize(); + } + + @Override + public void removeUpdate(final DocumentEvent e) { + updateSize(); + } + + private void updateSize() { + repaint(); + EventQueue.invokeLater(() -> { + setPreferredSize(new Dimension(getMinimumSize().width, getMinimumSize().height)); + revalidate(); + }); + } + }); + } + + private void setScanCodes(final List scanCodes) { + setText(scanCodes.stream().map(scanCode -> scanCode.toString().replaceAll(" ", "\u00A0")) + .collect(Collectors.joining(" + "))); + } + } + private final class JListSetPropertyListSelectionListener implements ListSelectionListener { private final Method setterMethod; @@ -235,16 +311,7 @@ public void valueChanged(final ListSelectionEvent e) { setterMethod.invoke(action, keyStroke); - final Set keyStrokeSet = new LinkedHashSet<>(); - if (modifierList != null) { - keyStrokeSet.addAll(modifierList.getSelectedValuesList()); - } - if (keyList != null) { - keyStrokeSet.addAll(keyList.getSelectedValuesList()); - } - - keyStrokeTextArea - .setText(keyStrokeSet.stream().map(Object::toString).collect(Collectors.joining(" + "))); + updateUpdateKeyStrokeVisualization(); } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) { log.log(Level.SEVERE, e1.getMessage(), e1); } diff --git a/src/main/java/de/bwravencl/controllerbuddy/input/action/gui/StringEditorBuilder.java b/src/main/java/de/bwravencl/controllerbuddy/input/action/gui/StringEditorBuilder.java index 59c8f096..35fb3e8e 100644 --- a/src/main/java/de/bwravencl/controllerbuddy/input/action/gui/StringEditorBuilder.java +++ b/src/main/java/de/bwravencl/controllerbuddy/input/action/gui/StringEditorBuilder.java @@ -44,7 +44,7 @@ public StringEditorBuilder(final EditActionsDialog editActionsDialog, final IAct @Override public void buildEditor(final JPanel parentPanel) { - final var textField = new JTextField(23); + final var textField = new JTextField(17); textField.setText((String) initialValue); textField.setCaretPosition(0);