diff options
Diffstat (limited to 'base/src/main/java/bjc/utils/gui/panels')
9 files changed, 723 insertions, 0 deletions
diff --git a/base/src/main/java/bjc/utils/gui/panels/DropdownListPanel.java b/base/src/main/java/bjc/utils/gui/panels/DropdownListPanel.java new file mode 100644 index 0000000..4f71d38 --- /dev/null +++ b/base/src/main/java/bjc/utils/gui/panels/DropdownListPanel.java @@ -0,0 +1,73 @@ +package bjc.utils.gui.panels; + +import java.awt.BorderLayout; + +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListSelectionModel; + +import bjc.utils.funcdata.IList; +import bjc.utils.gui.layout.AutosizeLayout; +import bjc.utils.gui.layout.HLayout; + +/** + * A panel that allows you to select choices from a dropdown list + * + * @author ben + * + */ +public class DropdownListPanel extends JPanel { + private static final long serialVersionUID = 2719963952350133541L; + + /** + * Create a new dropdown list panel + * + * @param <T> + * The type of items in the dropdown list + * @param type + * The label of the type of items in the list + * @param model + * The model to put items into + * @param choices + * The items to choose from + */ + public <T> DropdownListPanel(final String type, final DefaultListModel<T> model, final IList<T> choices) { + setLayout(new AutosizeLayout()); + + final JPanel itemInputPanel = new JPanel(); + itemInputPanel.setLayout(new BorderLayout()); + + final JPanel addItemPanel = new JPanel(); + addItemPanel.setLayout(new HLayout(2)); + + final JComboBox<T> addItemBox = new JComboBox<>(); + choices.forEach(addItemBox::addItem); + + final JButton addItemButton = new JButton("Add " + type); + + addItemPanel.add(addItemBox); + addItemPanel.add(addItemButton); + + final JList<T> itemList = new JList<>(model); + itemList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + final JButton removeItemButton = new JButton("Remove " + type); + + addItemButton.addActionListener((ev) -> { + model.addElement(addItemBox.getItemAt(addItemBox.getSelectedIndex())); + }); + + removeItemButton.addActionListener((ev) -> { + model.remove(itemList.getSelectedIndex()); + }); + + itemInputPanel.add(addItemPanel, BorderLayout.PAGE_START); + itemInputPanel.add(itemList, BorderLayout.CENTER); + itemInputPanel.add(removeItemButton, BorderLayout.PAGE_END); + + add(itemInputPanel); + } +} diff --git a/base/src/main/java/bjc/utils/gui/panels/FormattedInputPanel.java b/base/src/main/java/bjc/utils/gui/panels/FormattedInputPanel.java new file mode 100644 index 0000000..2cecf0c --- /dev/null +++ b/base/src/main/java/bjc/utils/gui/panels/FormattedInputPanel.java @@ -0,0 +1,66 @@ +package bjc.utils.gui.panels; + +import java.util.function.Consumer; + +import javax.swing.JFormattedTextField; +import javax.swing.JFormattedTextField.AbstractFormatter; +import javax.swing.JLabel; +import javax.swing.JPanel; + +import bjc.utils.gui.layout.HLayout; + +/** + * A simple panel allowing for input of a single formatted value + * + * @author ben + * + * @param <InputVal> + * The type of value being formatted + */ +public class FormattedInputPanel<InputVal> extends JPanel { + private static final long serialVersionUID = 5232016563558588031L; + + private final JFormattedTextField field; + + /** + * Create a new formatted input panel + * + * @param label + * The label for this panel + * @param length + * The length of this panel + * @param formatter + * The formatter to use for input + * @param reciever + * The action to call whenever the value changes + */ + @SuppressWarnings("unchecked") + public FormattedInputPanel(final String label, final int length, final AbstractFormatter formatter, + final Consumer<InputVal> reciever) { + setLayout(new HLayout(2)); + + final JLabel lab = new JLabel(label); + field = new JFormattedTextField(formatter); + + field.setColumns(length); + field.setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT); + field.addPropertyChangeListener("value", (event) -> { + // This is safe, because InputVal should be the type of + // whatever object the formatter is returning + reciever.accept((InputVal) field.getValue()); + }); + + add(lab); + add(field); + } + + /** + * Reset the value in this panel to a specified value + * + * @param value + * The value to set the panel to + */ + public void resetValues(final InputVal value) { + field.setValue(value); + } +} diff --git a/base/src/main/java/bjc/utils/gui/panels/HolderOutputPanel.java b/base/src/main/java/bjc/utils/gui/panels/HolderOutputPanel.java new file mode 100644 index 0000000..653dace --- /dev/null +++ b/base/src/main/java/bjc/utils/gui/panels/HolderOutputPanel.java @@ -0,0 +1,79 @@ +package bjc.utils.gui.panels; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.Timer; + +import bjc.utils.data.IHolder; +import bjc.utils.gui.layout.HLayout; + +/** + * A panel that outputs a value bound to a {@link IHolder} + * + * @author ben + * + */ +public class HolderOutputPanel extends JPanel { + private static final long serialVersionUID = 166573313903782080L; + + private Timer updater; + private final JLabel value; + private final int nDelay; + private final IHolder<String> val; + + /** + * Create a new display panel, backed by a holder + * + * @param lab + * The label to attach to this field + * @param valueHolder + * The holder to get the value from + * @param nDelay + * The delay in ms between value updates + */ + public HolderOutputPanel(final String lab, final IHolder<String> valueHolder, final int nDelay) { + this.val = valueHolder; + this.nDelay = nDelay; + + setLayout(new HLayout(2)); + + final JLabel label = new JLabel(lab); + value = new JLabel("(stopped)"); + + updater = new Timer(nDelay, (event) -> { + value.setText(valueHolder.getValue()); + }); + + add(label); + add(value); + } + + /** + * Set this panel back to its initial state + */ + public void reset() { + stopUpdating(); + + value.setText("(stopped)"); + + updater = new Timer(nDelay, (event) -> { + value.setText(val.getValue()); + }); + } + + /** + * Start updating the contents of the field from the holder + */ + public void startUpdating() { + updater.start(); + } + + /** + * Stop updating the contents of the field from the holder + */ + public void stopUpdating() { + updater.stop(); + + value.setText(value.getText() + " (stopped)"); + } +} diff --git a/base/src/main/java/bjc/utils/gui/panels/ListParameterPanel.java b/base/src/main/java/bjc/utils/gui/panels/ListParameterPanel.java new file mode 100644 index 0000000..cca73d5 --- /dev/null +++ b/base/src/main/java/bjc/utils/gui/panels/ListParameterPanel.java @@ -0,0 +1,133 @@ +package bjc.utils.gui.panels; + +import java.util.function.Consumer; +import java.util.function.Supplier; + +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.ListSelectionModel; + +import bjc.utils.funcdata.IList; +import bjc.utils.gui.SimpleJList; +import bjc.utils.gui.layout.HLayout; +import bjc.utils.gui.layout.VLayout; + +/** + * A panel that has a list of objects and ways of manipulating that list + * + * @author ben + * + * @param <E> + * The type of data stored in the list + */ +public class ListParameterPanel<E> extends JPanel { + // Version id for serialization + private static final long serialVersionUID = 3442971104975491571L; + + /** + * Create a new panel using the specified actions for doing things + * + * @param add + * The action that provides items + * @param edit + * The action that edits items + * @param remove + * The action that removes items + */ + public ListParameterPanel(final Supplier<E> add, final Consumer<E> edit, final Consumer<E> remove) { + this(add, edit, remove, null); + } + + /** + * Create a new panel using the specified actions for doing things + * + * @param add + * The action that provides items + * @param edit + * The action that edits items + * @param remove + * The action that removes items + * @param defaults + * The default values to put in the list + */ + public ListParameterPanel(final Supplier<E> add, final Consumer<E> edit, final Consumer<E> remove, + final IList<E> defaults) { + setLayout(new VLayout(2)); + + JList<E> list; + + if (defaults != null) { + list = SimpleJList.buildFromList(defaults.toIterable()); + } else { + list = new JList<>(new DefaultListModel<>()); + } + + list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + final JPanel buttonPanel = new JPanel(); + + int numButtons = 0; + + if (add != null) { + numButtons++; + } + + if (edit != null) { + numButtons++; + } + + if (remove != null) { + numButtons++; + } + + buttonPanel.setLayout(new HLayout(numButtons)); + + JButton addParam = null; + + if (add != null) { + addParam = new JButton("Add..."); + addParam.addActionListener((event) -> { + final DefaultListModel<E> model = (DefaultListModel<E>) list.getModel(); + + model.addElement(add.get()); + }); + } + + JButton editParam = null; + + if (edit != null) { + editParam = new JButton("Edit..."); + editParam.addActionListener((event) -> { + edit.accept(list.getSelectedValue()); + }); + } + + JButton removeParam = null; + + if (remove != null) { + removeParam = new JButton("Remove..."); + removeParam.addActionListener((event) -> { + final DefaultListModel<E> model = (DefaultListModel<E>) list.getModel(); + + remove.accept(model.remove(list.getSelectedIndex())); + }); + } + + if (add != null) { + buttonPanel.add(addParam); + } + + if (edit != null) { + buttonPanel.add(editParam); + } + + if (remove != null) { + buttonPanel.add(removeParam); + } + + add(list); + add(buttonPanel); + } +} diff --git a/base/src/main/java/bjc/utils/gui/panels/SimpleInputPanel.java b/base/src/main/java/bjc/utils/gui/panels/SimpleInputPanel.java new file mode 100644 index 0000000..65c533d --- /dev/null +++ b/base/src/main/java/bjc/utils/gui/panels/SimpleInputPanel.java @@ -0,0 +1,45 @@ +package bjc.utils.gui.panels; + +import java.awt.BorderLayout; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextField; + +/** + * A simple component for text input + * + * @author ben + * + */ +public class SimpleInputPanel extends JPanel { + private static final long serialVersionUID = -4734279623645236868L; + + /** + * The text field containing the input value + */ + public final JTextField inputValue; + + /** + * Create a new input panel + * + * @param label + * The label for the field + * @param columns + * The number of columns of text input to take + */ + public SimpleInputPanel(final String label, final int columns) { + setLayout(new BorderLayout()); + + final JLabel inputLabel = new JLabel(label); + + if (columns < 1) { + inputValue = new JTextField(); + } else { + inputValue = new JTextField(columns); + } + + add(inputLabel, BorderLayout.LINE_START); + add(inputValue, BorderLayout.CENTER); + } +} diff --git a/base/src/main/java/bjc/utils/gui/panels/SimpleListPanel.java b/base/src/main/java/bjc/utils/gui/panels/SimpleListPanel.java new file mode 100644 index 0000000..edc1797 --- /dev/null +++ b/base/src/main/java/bjc/utils/gui/panels/SimpleListPanel.java @@ -0,0 +1,93 @@ +package bjc.utils.gui.panels; + +import java.awt.BorderLayout; +import java.util.function.Consumer; +import java.util.function.Predicate; + +import javax.swing.DefaultListModel; +import javax.swing.JButton; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.ListSelectionModel; + +import bjc.utils.gui.layout.AutosizeLayout; +import bjc.utils.gui.layout.HLayout; + +/** + * A simple list of strings + * + * @author ben + * + */ +public class SimpleListPanel extends JPanel { + private static final long serialVersionUID = 2719963952350133541L; + + private static void addItem(final DefaultListModel<String> model, final Predicate<String> verifier, + final Consumer<String> onFailure, final JTextField addItemField) { + final String potentialItem = addItemField.getText(); + + if (verifier == null || verifier.test(potentialItem)) { + model.addElement(potentialItem); + } else { + onFailure.accept(potentialItem); + } + + addItemField.setText(""); + } + + /** + * Create a new list panel + * + * @param type + * The type of things in the list + * @param model + * The model to put items into + * @param verifier + * The predicate to use to verify items + * @param onFailure + * The function to call when an item doesn't verify + */ + public SimpleListPanel(final String type, final DefaultListModel<String> model, + final Predicate<String> verifier, final Consumer<String> onFailure) { + setLayout(new AutosizeLayout()); + + final JPanel itemInputPanel = new JPanel(); + itemInputPanel.setLayout(new BorderLayout()); + + final JPanel addItemPanel = new JPanel(); + addItemPanel.setLayout(new HLayout(2)); + + final JTextField addItemField = new JTextField(255); + final JButton addItemButton = new JButton("Add " + type); + + addItemPanel.add(addItemField); + addItemPanel.add(addItemButton); + + final JList<String> itemList = new JList<>(model); + itemList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + final JScrollPane listScroller = new JScrollPane(itemList); + + final JButton removeItemButton = new JButton("Remove " + type); + + addItemButton.addActionListener((ev) -> { + addItem(model, verifier, onFailure, addItemField); + }); + + addItemField.addActionListener((ev) -> { + addItem(model, verifier, onFailure, addItemField); + }); + + removeItemButton.addActionListener((ev) -> { + model.remove(itemList.getSelectedIndex()); + }); + + itemInputPanel.add(addItemPanel, BorderLayout.PAGE_START); + itemInputPanel.add(listScroller, BorderLayout.CENTER); + itemInputPanel.add(removeItemButton, BorderLayout.PAGE_END); + + add(itemInputPanel); + } +} diff --git a/base/src/main/java/bjc/utils/gui/panels/SimpleSpinnerPanel.java b/base/src/main/java/bjc/utils/gui/panels/SimpleSpinnerPanel.java new file mode 100644 index 0000000..6106182 --- /dev/null +++ b/base/src/main/java/bjc/utils/gui/panels/SimpleSpinnerPanel.java @@ -0,0 +1,42 @@ +package bjc.utils.gui.panels; + +import java.awt.BorderLayout; + +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSpinner; +import javax.swing.SpinnerModel; + +/** + * A simple spinner control + * + * @author ben + * + */ +public class SimpleSpinnerPanel extends JPanel { + private static final long serialVersionUID = -4734279623645236868L; + + /** + * The spinner being used + */ + public final JSpinner inputValue; + + /** + * Create a new spinner panel + * + * @param label + * The label for the spinner + * @param model + * The model to attach to the spinner + */ + public SimpleSpinnerPanel(final String label, final SpinnerModel model) { + setLayout(new BorderLayout()); + + final JLabel inputLabel = new JLabel(label); + + inputValue = new JSpinner(model); + + add(inputLabel, BorderLayout.LINE_START); + add(inputValue, BorderLayout.CENTER); + } +} diff --git a/base/src/main/java/bjc/utils/gui/panels/SliderInputPanel.java b/base/src/main/java/bjc/utils/gui/panels/SliderInputPanel.java new file mode 100644 index 0000000..e6a6da4 --- /dev/null +++ b/base/src/main/java/bjc/utils/gui/panels/SliderInputPanel.java @@ -0,0 +1,187 @@ +package bjc.utils.gui.panels; + +import java.text.ParseException; +import java.util.function.Consumer; + +import javax.swing.JFormattedTextField; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JSlider; + +import bjc.utils.gui.layout.HLayout; + +/** + * A simple input panel for a slider-controlled value and a manual-input field + * for setting the slider + * + * @author ben + * + */ +public class SliderInputPanel extends JPanel { + private final class NumberFormatter extends JFormattedTextField.AbstractFormatter { + private static final long serialVersionUID = -4448291795913908270L; + + private final int minValue; + private final int maxValue; + + private final int initValue; + + public NumberFormatter(final SliderSettings settings) { + minValue = settings.minValue; + maxValue = settings.maxValue; + + initValue = settings.initValue; + } + + @Override + public Object stringToValue(final String text) throws ParseException { + try { + final int val = Integer.parseInt(text); + + if (val < minValue) + throw new ParseException("Value must be greater than " + minValue, 0); + else if (val > maxValue) + throw new ParseException("Value must be smaller than " + maxValue, 0); + else return val; + } catch (final NumberFormatException nfex) { + final ParseException pex = new ParseException("Value must be a valid integer", 0); + + pex.initCause(nfex); + + throw pex; + } + } + + @Override + public String valueToString(final Object value) throws ParseException { + if (value == null) return Integer.toString(initValue); + + return Integer.toString((Integer) value); + } + } + + /** + * Represents the settings for a slider + * + * @author ben + * + */ + public static class SliderSettings { + /** + * The minimum value of the slider + */ + public final int minValue; + /** + * The maximum value of the slider + */ + public final int maxValue; + + /** + * The initial value of the slider + */ + public final int initValue; + + /** + * Create a new slider settings, with the initial value in the + * middle + * + * @param min + * The minimum value of the slider + * @param max + * The maximum value of the slider + */ + public SliderSettings(final int min, final int max) { + this(min, max, (min + max) / 2); + } + + /** + * Create a new set of slider sttings + * + * @param min + * The minimum slider value + * @param max + * The maximum slider value + * @param init + * Th initial slider value + */ + public SliderSettings(final int min, final int max, final int init) { + minValue = min; + maxValue = max; + + initValue = init; + } + } + + private static final long serialVersionUID = 2956394160569961404L; + private final JSlider slider; + private final JFormattedTextField field; + + /** + * Create a new slider input panel + * + * @param lab + * The label for the field + * @param settings + * The settings for slider values + * @param majorTick + * The setting for where to place big ticks + * @param minorTick + * The setting for where to place small ticks + * @param action + * The action to execute for a given value + */ + public SliderInputPanel(final String lab, final SliderSettings settings, final int majorTick, + final int minorTick, final Consumer<Integer> action) { + setLayout(new HLayout(3)); + + final JLabel label = new JLabel(lab); + + slider = new JSlider(settings.minValue, settings.maxValue, settings.initValue); + field = new JFormattedTextField(new NumberFormatter(settings)); + + slider.setMajorTickSpacing(majorTick); + slider.setMinorTickSpacing(minorTick); + slider.setPaintTicks(true); + slider.setPaintLabels(true); + + slider.addChangeListener((event) -> { + if (slider.getValueIsAdjusting()) { + // Do nothing + } else { + final int val = slider.getValue(); + + field.setValue(val); + + action.accept(val); + } + }); + + field.setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT); + field.setColumns(15); + field.addPropertyChangeListener("value", (event) -> { + final Object value = field.getValue(); + + if (value == null) { + // Do nothing + } else { + slider.setValue((Integer) value); + } + }); + + add(label); + add(slider); + add(field); + } + + /** + * Reset the values in this panel to a specified value + * + * @param value + * The value to reset the fields to + */ + public void resetValues(final int value) { + slider.setValue(value); + + field.setValue(value); + } +} diff --git a/base/src/main/java/bjc/utils/gui/panels/package-info.java b/base/src/main/java/bjc/utils/gui/panels/package-info.java new file mode 100644 index 0000000..4361885 --- /dev/null +++ b/base/src/main/java/bjc/utils/gui/panels/package-info.java @@ -0,0 +1,5 @@ +/** + * @author ben + * + */ +package bjc.utils.gui.panels;
\ No newline at end of file |
