config panel: keep search bar at the top while scrolling
Add back and toggle buttons at the top of plugin configuration pages
This commit is contained in:
@@ -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<PluginListItem> 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<String> pinnedPlugins = getPinnedPluginNames();
|
||||
final List<String> 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<PluginListItem> 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("<html>" + name + ":<br>" + listItem.getDescription() + "</html>");
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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<String> 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.
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Daniel Teo <https://github.com/takuyakanbr>
|
||||
* 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 582 B |
Reference in New Issue
Block a user