From 6ec0d60ec4e503ab384718d42fa268f7fd339459 Mon Sep 17 00:00:00 2001 From: Ruben Amendoeira Date: Sun, 22 Apr 2018 19:34:27 +0100 Subject: [PATCH] Configs slight design tweak - Updated the search bar to the new icon text field component. - Added new on/off icons based on the material design style. - Recoloured the background. - Recoloured the plugin name labels. - Replaced the config/toggle buttons for icon labels. - Hid config button if no config was found, instead of disabling it. - Left aligned the header title. - Added new ComboBoxListRenderer to prevent substance's ugly coloring. - Changed the panel title to "Configuration" - Used deathbeam's new layout manager DynamicGridLayout --- .../client/plugins/config/ConfigPanel.java | 183 ++++++++++----- .../runelite/client/ui/DynamicGridLayout.java | 215 ++++++++++++++++++ .../ui/components/ComboBoxListRenderer.java | 65 ++++++ .../client/ui/components/IconTextField.java | 6 + .../plugins/config/config_edit_icon.png | Bin 0 -> 15088 bytes .../client/plugins/config/disabled.png | Bin 335 -> 0 bytes .../client/plugins/config/enabled.png | Bin 417 -> 0 bytes .../client/plugins/config/switchers/off.png | Bin 0 -> 15659 bytes .../client/plugins/config/switchers/on.png | Bin 0 -> 15669 bytes 9 files changed, 406 insertions(+), 63 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/ui/DynamicGridLayout.java create mode 100644 runelite-client/src/main/java/net/runelite/client/ui/components/ComboBoxListRenderer.java create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/config/config_edit_icon.png delete mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/config/disabled.png delete mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/config/enabled.png create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/config/switchers/off.png create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/config/switchers/on.png diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java index 61b1e8b105..0a0b91256e 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/ConfigPanel.java @@ -37,7 +37,6 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Comparator; import java.util.Map; @@ -61,6 +60,7 @@ import javax.swing.JTextField; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; +import javax.swing.border.EmptyBorder; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; @@ -75,16 +75,22 @@ import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.plugins.PluginInstantiationException; import net.runelite.client.plugins.PluginManager; +import net.runelite.client.ui.ColorScheme; +import net.runelite.client.ui.DynamicGridLayout; import net.runelite.client.ui.PluginPanel; +import net.runelite.client.ui.components.ComboBoxListRenderer; +import net.runelite.client.ui.components.IconTextField; @Slf4j public class ConfigPanel extends PluginPanel { private static final int TEXT_FIELD_WIDTH = 7; private static final int SPINNER_FIELD_WIDTH = 6; - private static BufferedImage CONFIG_ICON; - private static BufferedImage UNCHECK_ICON; - private static BufferedImage CHECK_ICON; + + private static final ImageIcon CONFIG_ICON; + private static final ImageIcon ON_SWITCHER; + private static final ImageIcon OFF_SWITCHER; + private static final ImageIcon SEARCH; static { @@ -92,14 +98,15 @@ public class ConfigPanel extends PluginPanel { synchronized (ImageIO.class) { - CONFIG_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("config_icon.png")); - UNCHECK_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("disabled.png")); - CHECK_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("enabled.png")); + CONFIG_ICON = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("config_edit_icon.png"))); + ON_SWITCHER = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("switchers/on.png"))); + OFF_SWITCHER = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("switchers/off.png"))); + SEARCH = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("search.png"))); } } catch (IOException e) { - log.warn("Failed to read icon", e); + throw new RuntimeException(e); } } @@ -107,7 +114,7 @@ public class ConfigPanel extends PluginPanel private final ConfigManager configManager; private final ScheduledExecutorService executorService; private final RuneLiteConfig runeLiteConfig; - private final JTextField searchBar = new JTextField(); + private final IconTextField searchBar = new IconTextField(); private Map children = new TreeMap<>(); private int scrollBarPosition = 0; @@ -119,6 +126,10 @@ public class ConfigPanel extends PluginPanel this.executorService = executorService; this.runeLiteConfig = runeLiteConfig; + searchBar.setIcon(SEARCH); + searchBar.setPreferredSize(new Dimension(100, 30)); + searchBar.setBackground(ColorScheme.DARKER_GRAY_COLOR); + searchBar.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR); searchBar.getDocument().addDocumentListener(new DocumentListener() { @Override @@ -140,6 +151,10 @@ public class ConfigPanel extends PluginPanel } }); + setBorder(new EmptyBorder(10, 10, 10, 10)); + setLayout(new DynamicGridLayout(0, 1, 0, 5)); + setBackground(ColorScheme.DARK_GRAY_COLOR); + rebuildPluginList(); openConfigList(); } @@ -150,42 +165,54 @@ public class ConfigPanel extends PluginPanel Map newChildren = new TreeMap<>(); pluginManager.getPlugins().stream() - .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).hidden()) - .sorted(Comparator.comparing(left -> left.getClass().getAnnotation(PluginDescriptor.class).name())) - .forEach(plugin -> - { - final Config pluginConfigProxy = pluginManager.getPluginConfigProxy(plugin); - final String pluginName = plugin.getClass().getAnnotation(PluginDescriptor.class).name(); + .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).hidden()) + .sorted(Comparator.comparing(left -> left.getClass().getAnnotation(PluginDescriptor.class).name())) + .forEach(plugin -> + { + final Config pluginConfigProxy = pluginManager.getPluginConfigProxy(plugin); + final String pluginName = plugin.getClass().getAnnotation(PluginDescriptor.class).name(); - final JPanel groupPanel = buildGroupPanel(); - groupPanel.add(new JLabel(pluginName), BorderLayout.CENTER); + final JPanel groupPanel = buildGroupPanel(); - final JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new GridLayout(1, 2, 3, 0)); - groupPanel.add(buttonPanel, BorderLayout.LINE_END); + JLabel name = new JLabel(pluginName); + name.setForeground(Color.WHITE); - final JButton editConfigButton = buildConfigButton(pluginConfigProxy); - buttonPanel.add(editConfigButton); + groupPanel.add(name, BorderLayout.CENTER); - final JButton toggleButton = buildToggleButton(plugin); - buttonPanel.add(toggleButton); + final JPanel buttonPanel = new JPanel(); + buttonPanel.setOpaque(false); + buttonPanel.setLayout(new GridLayout(1, 2)); + groupPanel.add(buttonPanel, BorderLayout.LINE_END); - newChildren.put(pluginName, groupPanel); - }); + final JLabel editConfigButton = buildConfigButton(pluginConfigProxy); + buttonPanel.add(editConfigButton); + final JLabel toggleButton = buildToggleButton(plugin); + toggleButton.setHorizontalAlignment(SwingConstants.RIGHT); + buttonPanel.add(toggleButton); + + newChildren.put(pluginName, groupPanel); + }); final JPanel groupPanel = buildGroupPanel(); - groupPanel.add(new JLabel("RuneLite"), BorderLayout.CENTER); + + JLabel name = new JLabel("RuneLite"); + name.setForeground(Color.WHITE); + + groupPanel.add(name, BorderLayout.CENTER); final JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new GridLayout(1, 2, 3, 0)); + buttonPanel.setOpaque(false); + buttonPanel.setLayout(new GridLayout(1, 2)); groupPanel.add(buttonPanel, BorderLayout.LINE_END); - final JButton editConfigButton = buildConfigButton(runeLiteConfig); + final JLabel editConfigButton = buildConfigButton(runeLiteConfig); buttonPanel.add(editConfigButton); - final JButton toggleButton = buildToggleButton(null); + final JLabel toggleButton = buildToggleButton(null); + toggleButton.setVisible(false); buttonPanel.add(toggleButton); + newChildren.put("RuneLite", groupPanel); children = newChildren; @@ -197,15 +224,17 @@ public class ConfigPanel extends PluginPanel // Create base panel for the config button and enabled/disabled button final JPanel groupPanel = new JPanel(); groupPanel.setLayout(new BorderLayout(3, 0)); + groupPanel.setPreferredSize(new Dimension(PluginPanel.PANEL_WIDTH, 20)); + groupPanel.setOpaque(false); return groupPanel; } - private JButton buildConfigButton(Config config) + private JLabel buildConfigButton(Config config) { // Create edit config button and disable it by default - final JButton editConfigButton = new JButton(new ImageIcon(CONFIG_ICON)); - editConfigButton.setPreferredSize(new Dimension(32, 0)); - editConfigButton.setEnabled(false); + final JLabel editConfigButton = new JLabel(CONFIG_ICON); + editConfigButton.setPreferredSize(new Dimension(25, 0)); + editConfigButton.setVisible(false); // If we have configuration proxy enable the button and add edit config listener if (config != null) @@ -215,8 +244,15 @@ public class ConfigPanel extends PluginPanel if (!configEmpty) { - editConfigButton.addActionListener(ae -> openGroupConfigPanel(config, configDescriptor, configManager)); - editConfigButton.setEnabled(true); + editConfigButton.addMouseListener(new MouseAdapter() + { + @Override + public void mousePressed(MouseEvent mouseEvent) + { + openGroupConfigPanel(config, configDescriptor, configManager); + } + }); + editConfigButton.setVisible(true); editConfigButton.setToolTipText("Edit plugin configuration"); } } @@ -224,11 +260,11 @@ public class ConfigPanel extends PluginPanel return editConfigButton; } - private JButton buildToggleButton(Plugin plugin) + private JLabel buildToggleButton(Plugin plugin) { // Create enabling/disabling button - final JButton toggleButton = new JButton(new ImageIcon(CHECK_ICON)); - toggleButton.setPreferredSize(new Dimension(32, 0)); + final JLabel toggleButton = new JLabel(ON_SWITCHER); + toggleButton.setPreferredSize(new Dimension(25, 0)); if (plugin == null) { @@ -238,36 +274,43 @@ public class ConfigPanel extends PluginPanel highlightButton(toggleButton, pluginManager.isPluginEnabled(plugin)); - toggleButton.addActionListener(e -> executorService.submit(() -> + toggleButton.addMouseListener(new MouseAdapter() { - final boolean enabled = pluginManager.isPluginEnabled(plugin); - pluginManager.setPluginEnabled(plugin, !enabled); - - try + @Override + public void mousePressed(MouseEvent mouseEvent) { - if (enabled) + executorService.submit(() -> { - pluginManager.stopPlugin(plugin); - } - else - { - pluginManager.startPlugin(plugin); - } - } - catch (PluginInstantiationException ex) - { - log.warn("Error during starting/stopping plugin {}", plugin.getClass().getSimpleName(), ex); - } + final boolean enabled = pluginManager.isPluginEnabled(plugin); + pluginManager.setPluginEnabled(plugin, !enabled); - highlightButton(toggleButton, !enabled); - })); + try + { + if (enabled) + { + pluginManager.stopPlugin(plugin); + } + else + { + pluginManager.startPlugin(plugin); + } + } + catch (PluginInstantiationException ex) + { + log.warn("Error during starting/stopping plugin {}", plugin.getClass().getSimpleName(), ex); + } + + highlightButton(toggleButton, !enabled); + }); + } + }); return toggleButton; } - private void highlightButton(JButton button, boolean enabled) + private void highlightButton(JLabel button, boolean enabled) { - button.setIcon(enabled ? new ImageIcon(CHECK_ICON) : new ImageIcon(UNCHECK_ICON)); + button.setIcon(enabled ? ON_SWITCHER : OFF_SWITCHER); button.setToolTipText(enabled ? "Disable plugin" : "Enable plugin"); } @@ -301,7 +344,11 @@ public class ConfigPanel extends PluginPanel private void openConfigList() { removeAll(); - add(new JLabel("Plugin Configuration", SwingConstants.CENTER)); + + JLabel title = new JLabel("Configuration", SwingConstants.LEFT); + title.setForeground(Color.WHITE); + + add(title); add(searchBar); onSearchBarChanged(); @@ -331,6 +378,7 @@ public class ConfigPanel extends PluginPanel if (component instanceof JCheckBox) { JCheckBox checkbox = (JCheckBox) component; + checkbox.setOpaque(false); configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), "" + checkbox.isSelected()); } @@ -355,6 +403,8 @@ public class ConfigPanel extends PluginPanel if (component instanceof JComboBox) { JComboBox jComboBox = (JComboBox) component; + jComboBox.setRenderer(new ComboBoxListRenderer()); + jComboBox.setForeground(Color.WHITE); configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), ((Enum) jComboBox.getSelectedItem()).name()); } } @@ -376,6 +426,7 @@ public class ConfigPanel extends PluginPanel } JPanel item = new JPanel(); + item.setOpaque(false); item.setLayout(new BorderLayout()); name = cid.getItem().name(); JLabel configEntryName = new JLabel(name); @@ -385,6 +436,8 @@ public class ConfigPanel extends PluginPanel if (cid.getType() == boolean.class) { JCheckBox checkbox = new JCheckBox(); + checkbox.setOpaque(false); + checkbox.setBackground(ColorScheme.LIGHT_GRAY_COLOR); checkbox.setSelected(Boolean.parseBoolean(configManager.getConfiguration(cd.getGroup().keyName(), cid.getItem().keyName()))); checkbox.addActionListener(ae -> changeConfiguration(config, checkbox, cd, cid)); @@ -462,6 +515,7 @@ public class ConfigPanel extends PluginPanel if (cid.getType() == Dimension.class) { JPanel dimensionPanel = new JPanel(); + dimensionPanel.setOpaque(false); dimensionPanel.setLayout(new BorderLayout()); String str = configManager.getConfiguration(cd.getGroup().keyName(), cid.getItem().keyName()); @@ -482,7 +536,7 @@ public class ConfigPanel extends PluginPanel heightSpinnerTextField.setColumns(4); ChangeListener listener = e -> - configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), widthSpinner.getValue() + "x" + heightSpinner.getValue()); + configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), widthSpinner.getValue() + "x" + heightSpinner.getValue()); widthSpinner.addChangeListener(listener); heightSpinner.addChangeListener(listener); @@ -498,6 +552,9 @@ public class ConfigPanel extends PluginPanel { Class type = (Class) cid.getType(); JComboBox box = new JComboBox(type.getEnumConstants()); + box.setPreferredSize(new Dimension(box.getPreferredSize().width, 25)); + box.setRenderer(new ComboBoxListRenderer()); + box.setForeground(Color.WHITE); box.setFocusable(false); box.setPrototypeDisplayValue("XXXXXXXX"); //sorry but this is the way to keep the size of the combobox in check. try @@ -541,4 +598,4 @@ public class ConfigPanel extends PluginPanel revalidate(); getScrollPane().getVerticalScrollBar().setValue(0); } -} +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/ui/DynamicGridLayout.java b/runelite-client/src/main/java/net/runelite/client/ui/DynamicGridLayout.java new file mode 100644 index 0000000000..8be06a706c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/ui/DynamicGridLayout.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2018, Tomas Slusny + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.ui; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.GridLayout; +import java.awt.Insets; +import java.util.function.Function; + +/** + * Grid layout implementation with support for cells with unequal size. + * + * See https://www.javaworld.com/article/2077486/core-java/java-tip-121--flex-your-grid-layout.html + */ +public class DynamicGridLayout extends GridLayout +{ + public DynamicGridLayout() + { + this(1, 0, 0, 0); + } + + public DynamicGridLayout(int rows, int cols) + { + this(rows, cols, 0, 0); + } + + public DynamicGridLayout(int rows, int cols, int hgap, int vgap) + { + super(rows, cols, hgap, vgap); + } + + @Override + public Dimension preferredLayoutSize(Container parent) + { + synchronized (parent.getTreeLock()) + { + return calculateSize(parent, Component::getPreferredSize); + } + } + + @Override + public Dimension minimumLayoutSize(Container parent) + { + synchronized (parent.getTreeLock()) + { + return calculateSize(parent, Component::getMinimumSize); + } + } + + @Override + public void layoutContainer(Container parent) + { + synchronized (parent.getTreeLock()) + { + final Insets insets = parent.getInsets(); + final int ncomponents = parent.getComponentCount(); + int nrows = getRows(); + int ncols = getColumns(); + + if (ncomponents == 0) + { + return; + } + + if (nrows > 0) + { + ncols = (ncomponents + nrows - 1) / nrows; + } + else + { + nrows = (ncomponents + ncols - 1) / ncols; + } + + final int hgap = getHgap(); + final int vgap = getVgap(); + + // scaling factors + final Dimension pd = preferredLayoutSize(parent); + final double sw = (1.0 * parent.getWidth()) / pd.width; + final double sh = (1.0 * parent.getHeight()) / pd.height; + + final int[] w = new int[ncols]; + final int[] h = new int[nrows]; + + // calculate dimensions for all components + apply scaling + for (int i = 0; i < ncomponents; i++) + { + final int r = i / ncols; + final int c = i % ncols; + final Component comp = parent.getComponent(i); + final Dimension d = comp.getPreferredSize(); + d.width = (int) (sw * d.width); + d.height = (int) (sh * d.height); + + if (w[c] < d.width) + { + w[c] = d.width; + } + + if (h[r] < d.height) + { + h[r] = d.height; + } + } + + // Apply new bounds to all child components + for (int c = 0, x = insets.left; c < ncols; c++) + { + for (int r = 0, y = insets.top; r < nrows; r++) + { + int i = r * ncols + c; + + if (i < ncomponents) + { + parent.getComponent(i).setBounds(x, y, w[c], h[r]); + } + + y += h[r] + vgap; + } + + x += w[c] + hgap; + } + } + } + + /** + * Calculate outer size of the layout based on it's children and sizer + * @param parent parent component + * @param sizer functioning returning dimension of the child component + * @return outer size + */ + private Dimension calculateSize(final Container parent, final Function sizer) + { + final int ncomponents = parent.getComponentCount(); + int nrows = getRows(); + int ncols = getColumns(); + + if (nrows > 0) + { + ncols = (ncomponents + nrows - 1) / nrows; + } + else + { + nrows = (ncomponents + ncols - 1) / ncols; + } + + final int[] w = new int[ncols]; + final int[] h = new int[nrows]; + + // Calculate dimensions for all components + for (int i = 0; i < ncomponents; i++) + { + final int r = i / ncols; + final int c = i % ncols; + final Component comp = parent.getComponent(i); + final Dimension d = sizer.apply(comp); + + if (w[c] < d.width) + { + w[c] = d.width; + } + + if (h[r] < d.height) + { + h[r] = d.height; + } + } + + // Calculate total width and height of the layout + int nw = 0; + + for (int j = 0; j < ncols; j++) + { + nw += w[j]; + } + + int nh = 0; + + for (int i = 0; i < nrows; i++) + { + nh += h[i]; + } + + final Insets insets = parent.getInsets(); + + // Apply insets and horizontal and vertical gap to layout + return new Dimension( + insets.left + insets.right + nw + (ncols - 1) * getHgap(), + insets.top + insets.bottom + nh + (nrows - 1) * getVgap()); + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/ui/components/ComboBoxListRenderer.java b/runelite-client/src/main/java/net/runelite/client/ui/components/ComboBoxListRenderer.java new file mode 100644 index 0000000000..c97e128374 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/ui/components/ComboBoxListRenderer.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2017, Psikoi + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package net.runelite.client.ui.components; + +import java.awt.Color; +import java.awt.Component; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import javax.swing.border.EmptyBorder; +import net.runelite.client.ui.ColorScheme; + +/** + * A custom list renderer to avoid substance's weird coloring. + * Substance was making selected items' foreground color black, this + * was very hard to see in the dark gray background, this makes the selected + * item white and adds some padding to the elements for more readable list. + */ +public final class ComboBoxListRenderer extends JLabel implements ListCellRenderer +{ + + @Override + public Component getListCellRendererComponent(JList list, Object o, int index, boolean isSelected, boolean cellHasFocus) + { + if (isSelected) + { + setBackground(ColorScheme.DARK_GRAY_COLOR); + setForeground(Color.WHITE); + } + else + { + setBackground(list.getBackground()); + setForeground(ColorScheme.LIGHT_GRAY_COLOR); + } + + setBorder(new EmptyBorder(5, 5, 5, 0)); + + String text = (String) o.toString(); + setText(text); + + return this; + } +} \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java b/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java index e016215756..0734851fb0 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java @@ -37,6 +37,7 @@ import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; +import javax.swing.text.Document; import net.runelite.client.ui.ColorScheme; /** @@ -160,4 +161,9 @@ public class IconTextField extends JPanel } } + public Document getDocument() + { + return textField.getDocument(); + } + } \ No newline at end of file diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/config_edit_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/config_edit_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..d88ec51f71de12f62da20dbb99138f6cdee0f152 GIT binary patch literal 15088 zcmeI3TZkJ~7{{lexW;ZRRa@Pm;qzE54jS zF5mf|@B8Nb&iTH~%RD>OTBLxhn3RCSy6U}Cr{N8pG=u6ONtFUI-h2*98&n8*R zC?pRlWue@hgp1bHnhOuE%~bTYC0#X=dy9#DTSEaF&r`SL6~>9~+pQW;JcGFdjOrbH#1m9uxVk{~L)kml0@C#5x6&}512ypqKP z`jvMLQ=2Ot=%hndA-U-LO^xSUtyZd)PC0Ik7gbf|1&Nm=4$a`aRoe$`&h~aiLAr5D z(9>P3>06G?25~{vS@sLbWRR%$>a45L>?N|j4m(7VZ-XW;rUZVNlcD!~n#*oIyfj1S zVI4N0?R&^i9O~CxbbQBKbVj7?$s-e^Jt>!axrbhFqcJqK=kH%Z2s%iIdU}=BCgkU! z=PbKA+`odBvTNAteaq}`&bml}GV)rgf7uGQbqYTw0e* zrMs3PVFpr7SspsAtFcpz&T`n<4#LOQk9LK+6?Uj5a6K5*Um@8oz+Ox1b*#WAtYZ!6 zL2oPSL3uz#Vclr|vU;8!H*0V^H-;dJA9Ej_qqPWaQh7z8!dat(c#i3}fD8B4&I%0Z-l6`#ZRnq3eG%9-XcYPG0qzcLZ0Dl= zTwht;Y8|Y^eDLR_p(;iv3WU{zn&7}#KXWvHKB&g}ayUOL3FyU(!Dq)cF5|8XWY@Ti zyY@XFvMs+Tb+Tc@F|XhsG-~e$(ajz#W)vljIu|~Sd(2vGSf4Lhs1JKVKM`{sA6yvf zxG>5wCUhL5t%}{2g*6zBqMJT+zsdJ*I0wqJ*Tt^pkN%3TW>hQ|O@aX-n-mwB52jLF z7!a~aagq68D#e8XA)6EznGdE?To@3tNpX?+U@FCh0U?_d7nu*HQd}4ivPp4~`Cux= zg#jU(6c?EfrczuO5VA>ek@;XM#f1SOn-mwB52jLF7!a~aagq68D#e8XA)6EznGdE? zTo@3tNpX?+U@FCh0U?_d7nu*HQd}4ivPp4~`Cux=g#jU(6c?EfrczuO5VA>ek@;XM z#f1SOn-mwB52jLF7!a~aagq68D#e8XA)6EznGdE?To@3tNyL@tKf(!Z^xS3(J)pVt z#%nL4hdWt)YOc&MYZDA}_$h|D{15v6kzwY>m`%6LGmQ2!!|ZUre)#rdXzml!rG1t5 zH}Agm;P@xP=4;14K9-o+nt+?PZMlv$zmnGeJomxM`R$FlU;jRF{JV+M=YBYSicOrH zxx7Vr`n|^wk7f4ke5?M;jw2ICk1l*Md)vilF1}g0@l5T)b6Zo#zaKmO(LJBP{`RTd zt2=g|eg3nt-)`Ri!pT1_iRZZ^=gvIx;hx_&F<)}d+1iDl?+Bhro!&oFdgtCppZphq CxLUOU literal 0 HcmV?d00001 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/disabled.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/disabled.png deleted file mode 100644 index 160d431a9512ba88d81280c55c0a6811b5233ef9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 335 zcmeAS@N?(olHy`uVBq!ia0vp^{2?0v z(btiIVPjv-@4(4GzCyA`kS_y6l_~>6Lo)-z&;LOBB?CjL0RzLU1O^7H84L{K`IF+0 zx&hT5^>lFzskpTycsFmefxzC)8bW~zt;eKOC-zL_xad&Ky|MATgPelzf=5d?p3GSM6Ft;+aPHg<(rY!-9Tn7J+9W9hEe&okq{ a$})(|y=9e~bA=n|AqG!ZKbLh*2~7ZrZFdj= diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/enabled.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/enabled.png deleted file mode 100644 index a48cfcd5cced8f49f31dd8f8a17d735bd2f5c8b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 417 zcmV;S0bc%zP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ-7fD1xRCwB?ld(zzQ4mGXUDg#Fi?o)0goR+0E`Onw zSljsn1}qFnIxDRd>}`ELI@$v!dj>?vCxeH8^nDHW?-6m_uMx#yeBi` zzoBtN-!G74aZT=|VCkYr5C%vxXA)_3ryjp#e8X**_k5jbxv{@00000 LNkvXXu0mjfT$7+V diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/switchers/off.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/switchers/off.png new file mode 100644 index 0000000000000000000000000000000000000000..ff25cc611a7c1dc7e0c79ae35183214f93ba534a GIT binary patch literal 15659 zcmeI3e{dA#8OJvQg3(|E9h6Z#52}H1x4U<_+}(0H@>3J#AY4*Buw~fWeJ@#aw|m^} zkxNKv5YbqbS{hr&7DXT^N|>aIE!CD-Gf`k#v<5>pRfIt-lsXQjX!()8dw01XZ<2R1 zQ~OWny_vh)=Y8Jq^X~h3pZD4KpM9))@jW@&GqWj*%BiX>cfbq{ZUVDgN{{XGYk z2CFY!HB`L%^s(GKHf)&k+}{S@J{fxJrK6D-`F1|H;fT!r`FxB0V()b|)O**w+Ar^& zN*$lG>Fc*n4QBBa<25XJTot6QR`W`eWPw(@lffDGkb4lHmrNOWH4(dCk+%k zsE(EYpo{0edpRd>?!dW{7Rq<{d<*kAWq$VulbDFQE9=23&RzGr8pA6;166PQV&YF6 zvj8_!3@w~G{pmYj-oD-V)X?M}@9&SwT&VNGrv z-V<9sJ$1YRF7*B zCny0UFDhPOj0S>`H$^!XMuWW2092h9)JbxY{>wM^>vfV?q`%+dVqC#8P%l+Bhd@p9 z;##4(L9mPZh0bh8l!E~RK;?DOfL{)C(IR~;E(fo*W?HX{bx|9N^d;JWI*+SbSEhu3 z&SESy2uz_>XSEwyi`80Sov$-7tc7OGw3#uO%v=G(6_|91kKUOLuN)!K$GOYzP7DXF zB7ME8205B;Y-}_(nvF`Rj%Mw4JI$DAlgR*k7{X1m%0~@ycy>I7&^Z3MMZ$&lj*?;W{cS?`s@a?$QDA7z-F+stY8pW zU}da6o84rO(}V-11sgHYl8^-J67Nszqs>KxgRvG?uosFpL!pTg3_h{I2Pedu4HmY* z%X)1#Yk@@=p35j(sm9cpj#LdQQ~XNErHH_3cF?0W zkE((P%VFwKz=#xpAIbQdcX@m6?tgvVAod2St1MUut# z+q_84=-Z5n#3F+rK=3BPh3A8K2`&T(-Xys2d=M|eg#f{u1Q(tU;w88cAb6AD!t+7A z1Q!AXZxUR1K8Tm#LV(~+f(y?F@e*7J5WGon;rSq5f(rqHHwi90AH+*=AwcjZ!G-68 zcnK~92;L;P@O%(2!G!?9n*Ggqz>3?Sf-mbbRplkM(U1Dui|*?!&VA(hocG<#mWO&jpY!y_WB(dB z+U7ku)YWyv57%$p8+q+l)80RLuus1%d-K*EkNx5M;VDLGu&et(N&Clh^0F6O7o7Xk zgmc~7=HIvO<6E!v4E}cd#4O5vFlW_dPiN_`d-xkGW}NumTp)bLTz6O5ysxslE}qw0!|?78}pp4+zWKD*g1FQNJa*Lu2pceYMimGew@=@ab5z-3FH|MeYqkq`*cjnB#ooA=rmfd!HXV-`S?r?40J8R8L3%W|%-FF2}I}R%=+@Gvpn?J|( z!R(IyeXh>-AKm)SKH2kG-LdTGtFvY^Z6~6KFI+x)?#;+RWGz*()bZrq+Yik@v}ygL z#&^D!+RpE9X!)wg@!kYq{?JX)-50p3&0m&WIY0RumU^!Cft{BgUD~g`j9XQ)xO`9P Hs)zmq-qc~w literal 0 HcmV?d00001 diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/switchers/on.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/switchers/on.png new file mode 100644 index 0000000000000000000000000000000000000000..43028e1716185029617ba25dbad6d574040502b1 GIT binary patch literal 15669 zcmeI3e{d7W701sM8Za2#gcL*C<`6V7wxzq%FH46kY%C`hAW&q}*zT0!ba%2ZNOwYa zwq?g54o(9SAb&wVK@bJrT2BCc&j;^0)4vQpzY-EI zg0C6T+D4TiX5Oa1^N44DT0{_ecB#7B?{85wMQu@{q_?`7jK-9Z6c!00ey;cN11sM0 z&#gSZ?fF4}>C}zU_z#PV4}QG<=nKZ0!dK2L9QgeUyH-fIu3L9z)1$k;eapP|H~I(e zi~4U&8L8a(@kfOVdwQln`yZzkB{q-!JTL=qziha?}rh zShD?R9}W*5jnAL0aGil)|FQJdKXgBK`T5>&?RtIMwF^}L(KR4Dcn=})={V8WSUAB);3+XIMu0>G56_JI2+`4vmX_x{M%q2$ z>@_KrS)3fL?wL>~#-#~lx+f`1q(X9qTp<70>X^uBN~~T{!tP|2Wy%Do5_(pV#rI3H zptP$?Tof$Htam1w=;1Wc4U`TeZ8b7XJx#M_8*4F_(hN(}SwWILp%^}p`vRwNlZlek z7mlL{QmA86Q8GPqWB7cmS5`Gn=0&f^4d!l=B!Lwz_7LX`g4qe>jL~AY^2T70u^2;O z$|0+jHira9Vv@P?F`+#Q->N4P2%X&cg2IFF>GWXjL7Fx@7%+yw*a1krM<@j560+NjX2EJPI_yrfkqHHZ z_MkvJ9rpBG#tAcKs9H${+0>DhWgyoQm8VYJnA)!|2XTmz;D( z(KU$;&T_n7d)&O9zM|lwa#}Nwl~$%?(%9vk9D-#0EcwJ^w6};dD*cn861^r4qADS+ zor{T8%^*W2von)Xb7gRN7p2$gu=GDz2$gI5@0MY5yXya988TVSw{UW^D7dN71Riae z+{z`_Gk0f=R-Umt(IxO~NQp%_%`HW^W|4}@%`Pg_m>JWRsX^6BSc&-*L3CSO)OgL~ zs=xu$pFCftQa5n#ayrXV=I+Dw~nbI>0aSei;N1z!h=9S&?d%(<^y>#E(i$P#JJFWATP!R0YRG>7n%>`#ke3KXcOZ?^MSk= z7X$=tVq9oGkQd{EfS^r`3(W`eVq6dqw25({`9NNb3j%^RF)lP8$cu47K+q<}h2{f! zF)j!Q+Qhifd>}8z1pz^u7#ErkN z@?u;N5VVPLq4_{wj0*ySHZd+VAIOVwK|s(Z#)aksc`+^s2-?KB(0m{-#svXEn-~|G z59GzTARuTHi7P*I6I7JJ_0M*2&vW~sfo5<=l;mpzK7#1{CP8%f5X9#r;QJCm1f~;t zw>N<6rB4yWJmqZDojbr~UDoTVs*j&Ly|ZE^xRtx*xepcx9xX8i@|QpL%&PD8^t{?P z^`!UiJ*NG$U%Ni1%&~2U_u)sL9ymgIw9Ed$wynjdONx7YjuZ~wx^k|n)Xa6AsC}Z|qPO!d91F#oM&X7uLX=k}5pJ3l=*>%A%e z=)R+Wq@;V7>VJ?v_5