From 96e263a4feeaf6ef2fc0bff6a442732cb624157d Mon Sep 17 00:00:00 2001 From: takuyakanbr Date: Mon, 25 Jun 2018 01:50:38 +0800 Subject: [PATCH] config panel: keep search bar at the top while scrolling Add back and toggle buttons at the top of plugin configuration pages --- .../client/plugins/config/ConfigPanel.java | 189 ++++++++++++------ .../client/plugins/config/PluginListItem.java | 184 ++++++++--------- .../client/ui/components/IconButton.java | 71 +++++++ .../plugins/config/config_back_icon.png | Bin 0 -> 582 bytes 4 files changed, 277 insertions(+), 167 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/ui/components/IconButton.java create mode 100644 runelite-client/src/main/resources/net/runelite/client/plugins/config/config_back_icon.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 32f711983e..d39cf4f510 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 @@ -24,6 +24,7 @@ */ package net.runelite.client.plugins.config; +import com.google.common.base.Splitter; import com.google.common.base.Strings; import java.awt.BorderLayout; import java.awt.Color; @@ -36,14 +37,14 @@ 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.ArrayList; -import java.util.Arrays; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.imageio.ImageIO; import javax.swing.BorderFactory; import javax.swing.ImageIcon; @@ -60,6 +61,7 @@ import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSpinner; import javax.swing.JTextArea; +import javax.swing.ScrollPaneConstants; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.SwingConstants; @@ -85,18 +87,25 @@ 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.IconButton; import net.runelite.client.ui.components.IconTextField; +import net.runelite.client.util.SwingUtil; @Slf4j public class ConfigPanel extends PluginPanel { private static final int SPINNER_FIELD_WIDTH = 6; + private static final int SCROLLBAR_WIDTH = 17; + private static final int OFFSET = 6; + private static final ImageIcon BACK_ICON; + private static final ImageIcon BACK_ICON_HOVER; private static final ImageIcon SEARCH; private static final String RUNELITE_GROUP_NAME = RuneLiteConfig.class.getAnnotation(ConfigGroup.class).keyName(); private static final String PINNED_PLUGINS_CONFIG_KEY = "pinnedPlugins"; private static final String RUNELITE_PLUGIN = "RuneLite"; private static final String CHAT_COLOR_PLUGIN = "Chat Color"; + private static final Splitter COMMA_SPLITTER = Splitter.on(','); private final PluginManager pluginManager; private final ConfigManager configManager; @@ -105,7 +114,12 @@ public class ConfigPanel extends PluginPanel private final ChatColorConfig chatColorConfig; private final IconTextField searchBar = new IconTextField(); private final List pluginList = new ArrayList<>(); - private DisplayMode currentMode = DisplayMode.PLUGIN_LIST; + + private final JPanel topPanel; + private final JPanel mainPanel; + private final JScrollPane scrollPane; + + private boolean showingPluginList = true; private int scrollBarPosition = 0; static @@ -114,6 +128,9 @@ public class ConfigPanel extends PluginPanel { synchronized (ImageIO.class) { + BufferedImage backIcon = ImageIO.read(ConfigPanel.class.getResourceAsStream("config_back_icon.png")); + BACK_ICON = new ImageIcon(backIcon); + BACK_ICON_HOVER = new ImageIcon(SwingUtil.grayscaleOffset(backIcon, -100)); SEARCH = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("search.png"))); } } @@ -126,7 +143,7 @@ public class ConfigPanel extends PluginPanel ConfigPanel(PluginManager pluginManager, ConfigManager configManager, ScheduledExecutorService executorService, RuneLiteConfig runeLiteConfig, ChatColorConfig chatColorConfig) { - super(); + super(false); this.pluginManager = pluginManager; this.configManager = configManager; this.executorService = executorService; @@ -134,7 +151,7 @@ public class ConfigPanel extends PluginPanel this.chatColorConfig = chatColorConfig; searchBar.setIcon(SEARCH); - searchBar.setPreferredSize(new Dimension(100, 30)); + searchBar.setPreferredSize(new Dimension(PluginPanel.PANEL_WIDTH - 20, 30)); searchBar.setBackground(ColorScheme.DARKER_GRAY_COLOR); searchBar.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR); searchBar.getDocument().addDocumentListener(new DocumentListener() @@ -158,27 +175,45 @@ public class ConfigPanel extends PluginPanel } }); - setBorder(new EmptyBorder(10, 10, 10, 10)); - setLayout(new DynamicGridLayout(0, 1, 0, 5)); + setLayout(new BorderLayout()); setBackground(ColorScheme.DARK_GRAY_COLOR); + topPanel = new JPanel(); + topPanel.setBorder(new EmptyBorder(10, 10, 10, 10)); + topPanel.setLayout(new BorderLayout(0, OFFSET)); + add(topPanel, BorderLayout.NORTH); + + mainPanel = new FixedWidthPanel(); + mainPanel.setBorder(new EmptyBorder(8, 10, 10, 10)); + mainPanel.setLayout(new DynamicGridLayout(0, 1, 0, 5)); + mainPanel.setAlignmentX(Component.LEFT_ALIGNMENT); + + JPanel northPanel = new FixedWidthPanel(); + northPanel.setLayout(new BorderLayout()); + northPanel.add(mainPanel, BorderLayout.NORTH); + + scrollPane = new JScrollPane(northPanel); + scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + add(scrollPane, BorderLayout.CENTER); + initializePluginList(); refreshPluginList(); } private void initializePluginList() { - List pinnedPlugins = getPinnedPluginNames(); + final List pinnedPlugins = getPinnedPluginNames(); // populate pluginList with all non-hidden plugins pluginManager.getPlugins().stream() .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).hidden()) .forEach(plugin -> { + final PluginDescriptor descriptor = plugin.getClass().getAnnotation(PluginDescriptor.class); final Config config = pluginManager.getPluginConfigProxy(plugin); final ConfigDescriptor configDescriptor = config == null ? null : configManager.getConfigDescriptor(config); - final PluginListItem listItem = new PluginListItem(this, plugin, config, configDescriptor); + final PluginListItem listItem = new PluginListItem(this, plugin, descriptor, config, configDescriptor); listItem.setPinned(pinnedPlugins.contains(listItem.getName())); pluginList.add(listItem); }); @@ -201,8 +236,6 @@ public class ConfigPanel extends PluginPanel void refreshPluginList() { - scrollBarPosition = getScrollPane().getVerticalScrollBar().getValue(); - // update enabled / disabled status of all items pluginList.forEach(listItem -> { @@ -213,7 +246,7 @@ public class ConfigPanel extends PluginPanel } }); - if (currentMode == DisplayMode.PLUGIN_LIST) + if (showingPluginList) { openConfigList(); } @@ -221,62 +254,80 @@ public class ConfigPanel extends PluginPanel void openConfigList() { - currentMode = DisplayMode.PLUGIN_LIST; - removeAll(); + if (showingPluginList) + { + scrollBarPosition = scrollPane.getVerticalScrollBar().getValue(); + } + + showingPluginList = true; + + topPanel.removeAll(); + mainPanel.removeAll(); JLabel title = new JLabel("Configuration", SwingConstants.LEFT); title.setForeground(Color.WHITE); - add(title); - add(searchBar); + topPanel.add(title, BorderLayout.NORTH); + topPanel.add(searchBar, BorderLayout.CENTER); onSearchBarChanged(); searchBar.requestFocusInWindow(); - JScrollPane scrollbar = getScrollPane(); - scrollbar.validate(); - scrollbar.getVerticalScrollBar().setValue(scrollBarPosition); + validate(); + scrollPane.getVerticalScrollBar().setValue(scrollBarPosition); } private void onSearchBarChanged() { final String text = searchBar.getText(); - pluginList.forEach(this::remove); + pluginList.forEach(mainPanel::remove); - showMatchingPlugins(pluginList.stream().filter(PluginListItem::isPinned), text); - showMatchingPlugins(pluginList.stream().filter(item -> !item.isPinned()), text); + showMatchingPlugins(true, text); + showMatchingPlugins(false, text); revalidate(); } - private void showMatchingPlugins(Stream listItems, String text) + private void showMatchingPlugins(boolean pinned, String text) { if (text.isEmpty()) { - listItems.forEach(this::add); + pluginList.stream().filter(item -> pinned == item.isPinned()).forEach(mainPanel::add); return; } final String[] searchTerms = text.toLowerCase().split(" "); - listItems.forEach(listItem -> + pluginList.forEach(listItem -> { - if (listItem.matchesSearchTerms(searchTerms)) + if (pinned == listItem.isPinned() && listItem.matchesSearchTerms(searchTerms)) { - add(listItem); + mainPanel.add(listItem); } }); } - void openGroupConfigPanel(Config config, ConfigDescriptor cd) + void openGroupConfigPanel(PluginListItem listItem, Config config, ConfigDescriptor cd) { - currentMode = DisplayMode.CONFIG_PANEL; - scrollBarPosition = getScrollPane().getVerticalScrollBar().getValue(); - removeAll(); - String name = cd.getGroup().name() + " Configuration"; - JLabel title = new JLabel(name, SwingConstants.CENTER); + showingPluginList = false; + + scrollBarPosition = scrollPane.getVerticalScrollBar().getValue(); + topPanel.removeAll(); + mainPanel.removeAll(); + + final IconButton topPanelBackButton = new IconButton(BACK_ICON, BACK_ICON_HOVER); + topPanelBackButton.setPreferredSize(new Dimension(22, 0)); + topPanelBackButton.setBorder(new EmptyBorder(0, 0, 0, 5)); + topPanelBackButton.addActionListener(e -> openConfigList()); + topPanelBackButton.setToolTipText("Back"); + topPanel.add(topPanelBackButton, BorderLayout.WEST); + + topPanel.add(listItem.createToggleButton(), BorderLayout.EAST); + + String name = listItem.getName(); + JLabel title = new JLabel(name); title.setForeground(Color.WHITE); - title.setToolTipText(cd.getGroup().description()); - add(title); + title.setToolTipText("" + name + ":
" + listItem.getDescription() + ""); + topPanel.add(title); for (ConfigItemDescriptor cid : cd.getItems()) { @@ -287,6 +338,7 @@ public class ConfigPanel extends PluginPanel JPanel item = new JPanel(); item.setLayout(new BorderLayout()); + item.setMinimumSize(new Dimension(PANEL_WIDTH, 0)); name = cid.getItem().name(); JLabel configEntryName = new JLabel(name); configEntryName.setForeground(Color.WHITE); @@ -298,7 +350,7 @@ public class ConfigPanel extends PluginPanel JCheckBox checkbox = new JCheckBox(); 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)); + checkbox.addActionListener(ae -> changeConfiguration(listItem, config, checkbox, cd, cid)); item.add(checkbox, BorderLayout.EAST); } @@ -312,7 +364,7 @@ public class ConfigPanel extends PluginPanel Component editor = spinner.getEditor(); JFormattedTextField spinnerTextField = ((JSpinner.DefaultEditor) editor).getTextField(); spinnerTextField.setColumns(SPINNER_FIELD_WIDTH); - spinner.addChangeListener(ce -> changeConfiguration(config, spinner, cd, cid)); + spinner.addChangeListener(ce -> changeConfiguration(listItem, config, spinner, cd, cid)); item.add(spinner, BorderLayout.EAST); } @@ -330,7 +382,7 @@ public class ConfigPanel extends PluginPanel @Override public void focusLost(FocusEvent e) { - changeConfiguration(config, textField, cd, cid); + changeConfiguration(listItem, config, textField, cd, cid); } }); @@ -374,7 +426,7 @@ public class ConfigPanel extends PluginPanel @Override public void windowClosing(WindowEvent e) { - changeConfiguration(config, jColorChooser, cd, cid); + changeConfiguration(listItem, config, jColorChooser, cd, cid); } }); parent.add(jColorChooser); @@ -443,7 +495,7 @@ public class ConfigPanel extends PluginPanel { if (e.getStateChange() == ItemEvent.SELECTED) { - changeConfiguration(config, box, cd, cid); + changeConfiguration(listItem, config, box, cd, cid); box.setToolTipText(box.getSelectedItem().toString()); } }); @@ -461,14 +513,14 @@ public class ConfigPanel extends PluginPanel @Override public void focusLost(FocusEvent e) { - changeConfiguration(config, button, cd, cid); + changeConfiguration(listItem, config, button, cd, cid); } }); item.add(button, BorderLayout.EAST); } - add(item); + mainPanel.add(item); } JButton resetButton = new JButton("Reset"); @@ -477,21 +529,21 @@ public class ConfigPanel extends PluginPanel configManager.setDefaultConfiguration(config, true); // Reload configuration panel - openGroupConfigPanel(config, cd); + openGroupConfigPanel(listItem, config, cd); }); - add(resetButton); + mainPanel.add(resetButton); JButton backButton = new JButton("Back"); backButton.addActionListener(e -> openConfigList()); - add(backButton); + mainPanel.add(backButton); revalidate(); - getScrollPane().getVerticalScrollBar().setValue(0); + scrollPane.getVerticalScrollBar().setValue(0); } - private void changeConfiguration(Config config, JComponent component, ConfigDescriptor cd, ConfigItemDescriptor cid) + private void changeConfiguration(PluginListItem listItem, Config config, JComponent component, ConfigDescriptor cd, ConfigItemDescriptor cid) { - ConfigItem configItem = cid.getItem(); + final ConfigItem configItem = cid.getItem(); if (!Strings.isNullOrEmpty(configItem.warning())) { @@ -501,7 +553,7 @@ public class ConfigPanel extends PluginPanel if (result != JOptionPane.YES_OPTION) { - openGroupConfigPanel(config, cd); + openGroupConfigPanel(listItem, config, cd); return; } } @@ -511,32 +563,27 @@ public class ConfigPanel extends PluginPanel JCheckBox checkbox = (JCheckBox) component; configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), "" + checkbox.isSelected()); } - - if (component instanceof JSpinner) + else if (component instanceof JSpinner) { JSpinner spinner = (JSpinner) component; configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), "" + spinner.getValue()); } - - if (component instanceof JTextArea) + else if (component instanceof JTextArea) { JTextArea textField = (JTextArea) component; configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), textField.getText()); } - - if (component instanceof JColorChooser) + else if (component instanceof JColorChooser) { JColorChooser jColorChooser = (JColorChooser) component; configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), String.valueOf(jColorChooser.getColor().getRGB())); } - - if (component instanceof JComboBox) + else if (component instanceof JComboBox) { JComboBox jComboBox = (JComboBox) component; configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), ((Enum) jComboBox.getSelectedItem()).name()); } - - if (component instanceof HotkeyButton) + else if (component instanceof HotkeyButton) { HotkeyButton hotkeyButton = (HotkeyButton) component; configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), hotkeyButton.getValue()); @@ -587,18 +634,19 @@ public class ConfigPanel extends PluginPanel if (config == null) { - return new ArrayList<>(); + return Collections.emptyList(); } - return Arrays.asList(config.split(",")); + return COMMA_SPLITTER.splitToList(config); } void savePinnedPlugins() { - String value = pluginList.stream() + final String value = pluginList.stream() .filter(PluginListItem::isPinned) .map(PluginListItem::getName) .collect(Collectors.joining(",")); + configManager.setConfiguration(RUNELITE_GROUP_NAME, PINNED_PLUGINS_CONFIG_KEY, value); } @@ -606,15 +654,26 @@ public class ConfigPanel extends PluginPanel public void onActivate() { super.onActivate(); + if (searchBar.getParent() != null) { searchBar.requestFocusInWindow(); } } - enum DisplayMode + @Override + public Dimension getPreferredSize() { - PLUGIN_LIST, - CONFIG_PANEL + return new Dimension(PANEL_WIDTH + SCROLLBAR_WIDTH, super.getPreferredSize().height); + } + + private class FixedWidthPanel extends JPanel + { + @Override + public Dimension getPreferredSize() + { + return new Dimension(PANEL_WIDTH, super.getPreferredSize().height); + } + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java index 0bbbd8c1ce..0514795de1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListItem.java @@ -28,8 +28,6 @@ import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.GridLayout; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.ArrayList; @@ -40,13 +38,13 @@ import javax.imageio.ImageIO; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; -import javax.swing.SwingConstants; import lombok.Getter; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigDescriptor; import net.runelite.client.plugins.Plugin; import net.runelite.client.plugins.PluginDescriptor; import net.runelite.client.ui.PluginPanel; +import net.runelite.client.ui.components.IconButton; import net.runelite.client.util.SwingUtil; import org.apache.commons.text.similarity.JaroWinklerDistance; @@ -62,35 +60,45 @@ class PluginListItem extends JPanel private static final ImageIcon OFF_STAR; private final ConfigPanel configPanel; - private @Getter @Nullable final Plugin plugin; - private @Nullable final Config config; - private @Nullable final ConfigDescriptor configDescriptor; - private @Getter final String name; + @Getter + @Nullable + private final Plugin plugin; + + @Getter + private final String name; + + @Getter private final String description; + private final List keywords = new ArrayList<>(); - private final JLabel pinButton = new JLabel(OFF_STAR); - private final JLabel configButton = new JLabel(CONFIG_ICON); - private final JLabel toggleButton = new JLabel(OFF_SWITCHER); + private final IconButton pinButton = new IconButton(OFF_STAR); + private final IconButton configButton = new IconButton(CONFIG_ICON, CONFIG_ICON_HOVER); + private final IconButton toggleButton = new IconButton(OFF_SWITCHER); private boolean isPluginEnabled = false; - private @Getter boolean isPinned = false; + + @Getter + private boolean isPinned = false; static { try { + BufferedImage configIcon; + synchronized (ImageIO.class) { - BufferedImage configIcon = ImageIO.read(ConfigPanel.class.getResourceAsStream("config_edit_icon.png")); + configIcon = ImageIO.read(ConfigPanel.class.getResourceAsStream("config_edit_icon.png")); CONFIG_ICON = new ImageIcon(configIcon); - CONFIG_ICON_HOVER = new ImageIcon(SwingUtil.grayscaleOffset(configIcon, -100)); ON_SWITCHER = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("switchers/on.png"))); OFF_SWITCHER = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("switchers/off.png"))); ON_STAR = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("stars/on.png"))); OFF_STAR = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("stars/off.png"))); } + + CONFIG_ICON_HOVER = new ImageIcon(SwingUtil.grayscaleOffset(configIcon, -100)); } catch (IOException e) { @@ -104,21 +112,11 @@ class PluginListItem extends JPanel * Note that {@code config} and {@code configDescriptor} can be {@code null} * if there is no configuration associated with the plugin. */ - PluginListItem(ConfigPanel configPanel, Plugin plugin, @Nullable Config config, - @Nullable ConfigDescriptor configDescriptor) + PluginListItem(ConfigPanel configPanel, Plugin plugin, PluginDescriptor descriptor, + @Nullable Config config, @Nullable ConfigDescriptor configDescriptor) { - final PluginDescriptor descriptor = plugin.getClass().getAnnotation(PluginDescriptor.class); - - this.configPanel = configPanel; - this.plugin = plugin; - this.config = config; - this.configDescriptor = configDescriptor; - this.name = descriptor.name(); - this.description = descriptor.description(); - Collections.addAll(keywords, name.toLowerCase().split(" ")); - Collections.addAll(keywords, descriptor.tags()); - - initialize(); + this(configPanel, plugin, config, configDescriptor, + descriptor.name(), descriptor.description(), descriptor.tags()); } /** @@ -126,21 +124,20 @@ class PluginListItem extends JPanel */ PluginListItem(ConfigPanel configPanel, Config config, ConfigDescriptor configDescriptor, String name, String description, String... tags) + { + this(configPanel, null, config, configDescriptor, name, description, tags); + } + + private PluginListItem(ConfigPanel configPanel, @Nullable Plugin plugin, @Nullable Config config, + @Nullable ConfigDescriptor configDescriptor, String name, String description, String... tags) { this.configPanel = configPanel; - this.plugin = null; - this.config = config; - this.configDescriptor = configDescriptor; + this.plugin = plugin; this.name = name; this.description = description; Collections.addAll(keywords, name.toLowerCase().split(" ")); Collections.addAll(keywords, tags); - initialize(); - } - - private void initialize() - { setLayout(new BorderLayout(3, 0)); setPreferredSize(new Dimension(PluginPanel.PANEL_WIDTH, 20)); @@ -154,103 +151,80 @@ class PluginListItem extends JPanel add(nameLabel, BorderLayout.CENTER); - pinButton.setPreferredSize(new Dimension(25, 0)); - attachPinButtonListener(); + pinButton.setPreferredSize(new Dimension(21, 0)); add(pinButton, BorderLayout.LINE_START); + pinButton.addActionListener(e -> + { + setPinned(!isPinned); + configPanel.savePinnedPlugins(); + configPanel.openConfigList(); + }); + final JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout(1, 2)); add(buttonPanel, BorderLayout.LINE_END); configButton.setPreferredSize(new Dimension(25, 0)); configButton.setVisible(false); - attachConfigButtonListener(); buttonPanel.add(configButton); + // add a listener to configButton only if there are config items to show + if (config != null && !configDescriptor.getItems().stream().allMatch(item -> item.getItem().hidden())) + { + configButton.addActionListener(e -> + { + configButton.setIcon(CONFIG_ICON); + configPanel.openGroupConfigPanel(PluginListItem.this, config, configDescriptor); + }); + + configButton.setVisible(true); + configButton.setToolTipText("Edit plugin configuration"); + } + toggleButton.setPreferredSize(new Dimension(25, 0)); - toggleButton.setHorizontalAlignment(SwingConstants.RIGHT); - attachToggleButtonListener(); + attachToggleButtonListener(toggleButton); buttonPanel.add(toggleButton); } - private void attachPinButtonListener() - { - pinButton.addMouseListener(new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent mouseEvent) - { - setPinned(!isPinned); - configPanel.savePinnedPlugins(); - configPanel.openConfigList(); - } - }); - } - - private void attachConfigButtonListener() - { - // no need for a listener if there are no config item to show - if (config == null || configDescriptor.getItems().stream().allMatch(item -> item.getItem().hidden())) - { - return; - } - - configButton.addMouseListener(new MouseAdapter() - { - @Override - public void mousePressed(MouseEvent mouseEvent) - { - configButton.setIcon(CONFIG_ICON); - configPanel.openGroupConfigPanel(config, configDescriptor); - } - - @Override - public void mouseEntered(MouseEvent e) - { - configButton.setIcon(CONFIG_ICON_HOVER); - } - - @Override - public void mouseExited(MouseEvent e) - { - configButton.setIcon(CONFIG_ICON); - } - }); - configButton.setVisible(true); - configButton.setToolTipText("Edit plugin configuration"); - } - - private void attachToggleButtonListener() + private void attachToggleButtonListener(IconButton button) { // no need for a listener if there is no plugin to enable / disable if (plugin == null) { - toggleButton.setEnabled(false); + button.setVisible(false); return; } - toggleButton.addMouseListener(new MouseAdapter() + button.addActionListener(e -> { - @Override - public void mousePressed(MouseEvent mouseEvent) + if (isPluginEnabled) { - if (isPluginEnabled) - { - configPanel.stopPlugin(plugin, PluginListItem.this); - } - else - { - configPanel.startPlugin(plugin, PluginListItem.this); - } + configPanel.stopPlugin(plugin, PluginListItem.this); } + else + { + configPanel.startPlugin(plugin, PluginListItem.this); + } + + setPluginEnabled(!isPluginEnabled); + updateToggleButton(button); }); } + IconButton createToggleButton() + { + IconButton button = new IconButton(OFF_SWITCHER); + button.setPreferredSize(new Dimension(25, 0)); + updateToggleButton(button); + attachToggleButtonListener(button); + return button; + } + void setPluginEnabled(boolean enabled) { isPluginEnabled = enabled; - toggleButton.setIcon(enabled ? ON_SWITCHER : OFF_SWITCHER); - toggleButton.setToolTipText(enabled ? "Disable plugin" : "Enable plugin"); + updateToggleButton(toggleButton); } void setPinned(boolean pinned) @@ -260,6 +234,12 @@ class PluginListItem extends JPanel pinButton.setToolTipText(pinned ? "Unpin plugin" : "Pin plugin"); } + private void updateToggleButton(IconButton button) + { + button.setIcon(isPluginEnabled ? ON_SWITCHER : OFF_SWITCHER); + button.setToolTipText(isPluginEnabled ? "Disable plugin" : "Enable plugin"); + } + /** * Checks if all the search terms in the given list matches at least one keyword. * @return true if all search terms matches at least one keyword, or false if otherwise. diff --git a/runelite-client/src/main/java/net/runelite/client/ui/components/IconButton.java b/runelite-client/src/main/java/net/runelite/client/ui/components/IconButton.java new file mode 100644 index 0000000000..1d54bf601c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/ui/components/IconButton.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2018, Daniel Teo + * 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.Insets; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.ImageIcon; +import javax.swing.JButton; + +/** + * A button that consists of an icon, without any background, borders, or margins. + */ +public class IconButton extends JButton +{ + public IconButton(ImageIcon icon) + { + this(icon, null); + } + + public IconButton(ImageIcon icon, ImageIcon hoverIcon) + { + setIcon(icon); + setBorderPainted(false); + setContentAreaFilled(false); + setFocusPainted(false); + setMargin(new Insets(0, 0, 0, 0)); + setOpaque(false); + setRolloverEnabled(false); + + if (hoverIcon != null) + { + addMouseListener(new MouseAdapter() + { + @Override + public void mouseEntered(MouseEvent e) + { + setIcon(hoverIcon); + } + + @Override + public void mouseExited(MouseEvent e) + { + setIcon(icon); + } + }); + } + } +} diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/config_back_icon.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/config_back_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8749d54b235b9f2f0468f451b2bce7dde51f3e80 GIT binary patch literal 582 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eO!3HGrSK0$PjNX|c5hW46K32*3xq68y`AMmI z6}bgKc?Jd>`-+0ZKU3DSQ?q=C>R+Sn(G^w>l+&D8W>s`m{}QHDnNmf9hZVl zQA(Oskc%7CG9b@ZDWjyMz)D}gyu4hm+*mKaC|%#s($Z4jz)0W7NEfI=x41H|B(Xv_ zuUHvm1jG!N)Z*l#%z~24{5%DanTbjHr6smXO8Ov6^r5x@y{8ZNACLnNq0~HJuoMCP zKTjs%JuvLHdAc};XiPkNabX@)ph(L@{!1*4E)x_4_Aq(AjpA`^bP#pU+F;|FD%`}> ztl-$tbZV=On;=VfR#4!XyiJX_V^7a0E>8Pr{OD7O*3y29KIeZ@?HXNTFBi=z&go`c zcJpcd0WRB^3umSD8$a+k$9(L1zo(6V&tr3uefcwzdyH?LtO?k*aMBt3KP`v8ACR`Y zcz|=Q5`$XAqAulEt_(dJ9CaIKxiWnDIJJd8Quz!2N~;@*^Cwrb-DOyMR5nN7_M{gm O`aNC!T-G@yGywo7c*hd} literal 0 HcmV?d00001