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 3e186e72c7..32f711983e 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 @@ -38,9 +38,12 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; 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; @@ -68,6 +71,7 @@ import lombok.extern.slf4j.Slf4j; import net.runelite.client.config.ChatColorConfig; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigDescriptor; +import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; import net.runelite.client.config.ConfigItemDescriptor; import net.runelite.client.config.ConfigManager; @@ -89,6 +93,8 @@ public class ConfigPanel extends PluginPanel private static final int SPINNER_FIELD_WIDTH = 6; 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"; @@ -162,6 +168,8 @@ public class ConfigPanel extends PluginPanel private void initializePluginList() { + List pinnedPlugins = getPinnedPluginNames(); + // populate pluginList with all non-hidden plugins pluginManager.getPlugins().stream() .filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).hidden()) @@ -170,14 +178,23 @@ public class ConfigPanel extends PluginPanel final Config config = pluginManager.getPluginConfigProxy(plugin); final ConfigDescriptor configDescriptor = config == null ? null : configManager.getConfigDescriptor(config); - pluginList.add(new PluginListItem(this, plugin, config, configDescriptor)); + final PluginListItem listItem = new PluginListItem(this, plugin, config, configDescriptor); + listItem.setPinned(pinnedPlugins.contains(listItem.getName())); + pluginList.add(listItem); }); // add special entries for core client configurations - pluginList.add(new PluginListItem(this, runeLiteConfig, configManager.getConfigDescriptor(runeLiteConfig), - RUNELITE_PLUGIN, "RuneLite client settings", "client")); - pluginList.add(new PluginListItem(this, chatColorConfig, configManager.getConfigDescriptor(chatColorConfig), - CHAT_COLOR_PLUGIN, "Recolor chat text", "colour", "messages")); + final PluginListItem runeLite = new PluginListItem(this, runeLiteConfig, + configManager.getConfigDescriptor(runeLiteConfig), + RUNELITE_PLUGIN, "RuneLite client settings", "client"); + runeLite.setPinned(pinnedPlugins.contains(RUNELITE_PLUGIN)); + pluginList.add(runeLite); + + final PluginListItem chatColor = new PluginListItem(this, chatColorConfig, + configManager.getConfigDescriptor(chatColorConfig), + CHAT_COLOR_PLUGIN, "Recolor chat text", "colour", "messages"); + chatColor.setPinned(pinnedPlugins.contains(CHAT_COLOR_PLUGIN)); + pluginList.add(chatColor); pluginList.sort(Comparator.comparing(PluginListItem::getName)); } @@ -202,7 +219,7 @@ public class ConfigPanel extends PluginPanel } } - private void openConfigList() + void openConfigList() { currentMode = DisplayMode.PLUGIN_LIST; removeAll(); @@ -226,24 +243,28 @@ public class ConfigPanel extends PluginPanel pluginList.forEach(this::remove); + showMatchingPlugins(pluginList.stream().filter(PluginListItem::isPinned), text); + showMatchingPlugins(pluginList.stream().filter(item -> !item.isPinned()), text); + + revalidate(); + } + + private void showMatchingPlugins(Stream listItems, String text) + { if (text.isEmpty()) { - pluginList.forEach(this::add); - revalidate(); + listItems.forEach(this::add); return; } - // show plugins with keywords that matches all the given search terms final String[] searchTerms = text.toLowerCase().split(" "); - pluginList.forEach(listItem -> + listItems.forEach(listItem -> { if (listItem.matchesSearchTerms(searchTerms)) { add(listItem); } }); - - revalidate(); } void openGroupConfigPanel(Config config, ConfigDescriptor cd) @@ -560,6 +581,27 @@ public class ConfigPanel extends PluginPanel }); } + private List getPinnedPluginNames() + { + final String config = configManager.getConfiguration(RUNELITE_GROUP_NAME, PINNED_PLUGINS_CONFIG_KEY); + + if (config == null) + { + return new ArrayList<>(); + } + + return Arrays.asList(config.split(",")); + } + + void savePinnedPlugins() + { + String value = pluginList.stream() + .filter(PluginListItem::isPinned) + .map(PluginListItem::getName) + .collect(Collectors.joining(",")); + configManager.setConfiguration(RUNELITE_GROUP_NAME, PINNED_PLUGINS_CONFIG_KEY, value); + } + @Override public void onActivate() { 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 bbdd4b6954..0bbbd8c1ce 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 @@ -58,20 +58,24 @@ class PluginListItem extends JPanel private static final ImageIcon CONFIG_ICON_HOVER; private static final ImageIcon ON_SWITCHER; private static final ImageIcon OFF_SWITCHER; + private static final ImageIcon ON_STAR; + 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 final String name; + private @Getter final String name; 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 boolean isPluginEnabled = false; + private @Getter boolean isPinned = false; static { @@ -84,6 +88,8 @@ class PluginListItem extends JPanel 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"))); } } catch (IOException e) @@ -148,6 +154,10 @@ class PluginListItem extends JPanel add(nameLabel, BorderLayout.CENTER); + pinButton.setPreferredSize(new Dimension(25, 0)); + attachPinButtonListener(); + add(pinButton, BorderLayout.LINE_START); + final JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout(1, 2)); add(buttonPanel, BorderLayout.LINE_END); @@ -163,6 +173,20 @@ class PluginListItem extends JPanel 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 @@ -229,6 +253,13 @@ class PluginListItem extends JPanel toggleButton.setToolTipText(enabled ? "Disable plugin" : "Enable plugin"); } + void setPinned(boolean pinned) + { + isPinned = pinned; + pinButton.setIcon(pinned ? ON_STAR : OFF_STAR); + pinButton.setToolTipText(pinned ? "Unpin plugin" : "Pin 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/resources/net/runelite/client/plugins/config/stars/off.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/stars/off.png new file mode 100644 index 0000000000..b030162e0c Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/config/stars/off.png differ diff --git a/runelite-client/src/main/resources/net/runelite/client/plugins/config/stars/on.png b/runelite-client/src/main/resources/net/runelite/client/plugins/config/stars/on.png new file mode 100644 index 0000000000..3e416f5ab4 Binary files /dev/null and b/runelite-client/src/main/resources/net/runelite/client/plugins/config/stars/on.png differ