Merge pull request #386 from Abextm/panel-state-2

Allow PluginPanels to keep state
This commit is contained in:
Adam
2018-01-20 09:19:05 -05:00
committed by GitHub
8 changed files with 217 additions and 107 deletions

View File

@@ -30,7 +30,7 @@ import java.util.Map;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
public interface Client
public interface Client extends GameEngine
{
List<Player> getPlayers();

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018 Abex
* 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.api;
import java.awt.Canvas;
public interface GameEngine
{
Canvas getCanvas();
}

View File

@@ -24,23 +24,16 @@
*/
package net.runelite.client.plugins.config;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
import static javax.swing.JOptionPane.YES_NO_OPTION;
import static javax.swing.JOptionPane.YES_OPTION;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.ItemEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
import javax.swing.JButton;
@@ -52,12 +45,18 @@ import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import static javax.swing.JOptionPane.WARNING_MESSAGE;
import static javax.swing.JOptionPane.YES_NO_OPTION;
import static javax.swing.JOptionPane.YES_OPTION;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingConstants;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.config.ConfigDescriptor;
import net.runelite.client.config.ConfigItem;
@@ -72,75 +71,107 @@ public class ConfigPanel extends PluginPanel
private static final int SPINNER_FIELD_WIDTH = 6;
private final ConfigManager configManager;
private JTextField searchBar;
private final JTextField searchBar = new JTextField();
private Map<String, JPanel> children = new TreeMap<>();
private int scrollBarPosition = 0;
public ConfigPanel(ConfigManager configManager)
{
super();
this.configManager = configManager;
populateConfig();
searchBar.getDocument().addDocumentListener(new DocumentListener()
{
@Override
public void insertUpdate(DocumentEvent e)
{
onSearchBarChanged();
}
@Override
public void removeUpdate(DocumentEvent e)
{
onSearchBarChanged();
}
@Override
public void changedUpdate(DocumentEvent e)
{
onSearchBarChanged();
}
});
rebuildPluginList();
openConfigList();
}
final void rebuildPluginList()
{
Map<String, JPanel> newChildren = new TreeMap<>();
configManager.getConfigProxies().stream()
.map(configManager::getConfigDescriptor)
.filter(configDescriptor -> configDescriptor.getItems().stream()
.anyMatch(cid -> !cid.getItem().hidden()))
.forEach(cd ->
{
String groupName = cd.getGroup().name();
if (children.containsKey(groupName))
{
newChildren.put(groupName, children.get(groupName));
return;
}
JPanel groupPanel = new JPanel();
groupPanel.setLayout(new BorderLayout());
JButton viewGroupItemsButton = new JButton(groupName);
viewGroupItemsButton.addActionListener(ae -> openGroupConfigPanel(cd, configManager));
groupPanel.add(viewGroupItemsButton);
newChildren.put(groupName, groupPanel);
});
children = newChildren;
openConfigList();
}
private void onSearchBarChanged()
{
children.forEach((key, value) ->
{
final String text = searchBar.getText().toLowerCase();
final String labelToSearch = key.toLowerCase();
if (text.isEmpty() || labelToSearch.contains(text))
{
add(value);
}
else
{
remove(value);
}
});
revalidate();
}
@Override
public void invalidate()
public void onActivate()
{
super.invalidate();
if (searchBar != null)
super.onActivate();
if (searchBar.getParent() != null)
{
searchBar.requestFocusInWindow();
}
}
private void populateConfig()
private void openConfigList()
{
removeAll();
add(new JLabel("Plugin Configuration", SwingConstants.CENTER));
searchBar = new JTextField();
add(searchBar);
final Map<String, JPanel> children = new TreeMap<>();
configManager.getConfigProxies().stream()
.map(configManager::getConfigDescriptor)
.filter(configDescriptor -> configDescriptor.getItems().stream()
.anyMatch(cid -> !cid.getItem().hidden()))
.sorted(Comparator.comparing(left -> left.getGroup().name()))
.forEach(cd ->
{
JPanel groupPanel = new JPanel();
groupPanel.setLayout(new BorderLayout());
JButton viewGroupItemsButton = new JButton(cd.getGroup().name());
viewGroupItemsButton.addActionListener(ae -> openGroupConfigPanel(cd, configManager));
groupPanel.add(viewGroupItemsButton);
children.put(cd.getGroup().name(), groupPanel);
add(groupPanel);
});
searchBar.addKeyListener(new KeyAdapter()
{
@Override
public void keyTyped(KeyEvent e)
{
children.forEach((key, value) ->
{
final String text = searchBar.getText().toLowerCase();
final String labelToSearch = key.toLowerCase();
if (text.isEmpty() || labelToSearch.contains(text))
{
add(value);
}
else
{
remove(value);
}
});
revalidate();
}
});
revalidate();
onSearchBarChanged();
searchBar.requestFocusInWindow();
JScrollPane scrollbar = getScrollPane();
scrollbar.validate();
scrollbar.getVerticalScrollBar().setValue(scrollBarPosition);
}
private void changeConfiguration(JComponent component, ConfigDescriptor cd, ConfigItemDescriptor cid)
@@ -156,7 +187,7 @@ public class ConfigPanel extends PluginPanel
{
int value = JOptionPane.showOptionDialog(component, configItem.confirmationWarining(),
"Are you sure?", YES_NO_OPTION, WARNING_MESSAGE,
null, new String[] { "Yes", "No" }, "No");
null, new String[]{"Yes", "No"}, "No");
if (value != YES_OPTION)
{
checkbox.setSelected(originalState);
@@ -194,6 +225,7 @@ public class ConfigPanel extends PluginPanel
private void openGroupConfigPanel(ConfigDescriptor cd, ConfigManager configManager)
{
scrollBarPosition = getScrollPane().getVerticalScrollBar().getValue();
removeAll();
String name = cd.getGroup().name() + " Configuration";
JLabel title = new JLabel(name);
@@ -319,15 +351,9 @@ public class ConfigPanel extends PluginPanel
}
JButton backButton = new JButton("Back");
backButton.addActionListener(this::getBackButtonListener);
backButton.addActionListener(e -> openConfigList());
add(backButton);
revalidate();
getScrollPane().getVerticalScrollBar().setValue(0);
}
public void getBackButtonListener(ActionEvent e)
{
populateConfig();
}
}

View File

@@ -24,9 +24,12 @@
*/
package net.runelite.client.plugins.config;
import com.google.common.eventbus.Subscribe;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import javax.swing.SwingUtilities;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.events.PluginChanged;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.ui.ClientUI;
@@ -44,15 +47,18 @@ public class ConfigPlugin extends Plugin
@Inject
ConfigManager configManager;
private ConfigPanel configPanel;
private NavigationButton navButton;
@Override
protected void startUp() throws Exception
{
configPanel = new ConfigPanel(configManager);
navButton = new NavigationButton(
"Configuration",
ImageIO.read(getClass().getResourceAsStream("config_icon.png")),
() -> new ConfigPanel(configManager));
() -> configPanel);
ui.getPluginToolbar().addNavigation(navButton);
}
@@ -62,4 +68,10 @@ public class ConfigPlugin extends Plugin
{
ui.getPluginToolbar().removeNavigation(navButton);
}
@Subscribe
public void onPluginChanged(PluginChanged event)
{
SwingUtilities.invokeLater(configPanel::rebuildPluginList);
}
}

View File

@@ -326,6 +326,13 @@ public class HiscorePanel extends PluginPanel
details.setText(text);
}
@Override
public void onActivate()
{
super.onActivate();
input.requestFocusInWindow();
}
private JPanel makeSkillPanel(String skillName, HiscoreSkill skill)
{
JLabel label = new JLabel();

View File

@@ -28,6 +28,7 @@ import com.google.common.base.Strings;
import java.applet.Applet;
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Frame;
@@ -46,9 +47,7 @@ import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JRootPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
@@ -65,8 +64,7 @@ import org.pushingpixels.substance.internal.ui.SubstanceRootPaneUI;
@Slf4j
public class ClientUI extends JFrame
{
private static final int SCROLLBAR_WIDTH = 17;
private static final int PANEL_EXPANDED_WIDTH = PluginPanel.PANEL_WIDTH + SCROLLBAR_WIDTH;
private static final int PANEL_EXPANDED_WIDTH = PluginPanel.PANEL_WIDTH + PluginPanel.SCROLLBAR_WIDTH;
private static final BufferedImage ICON;
@Getter
@@ -74,7 +72,6 @@ public class ClientUI extends JFrame
private final Applet client;
private final RuneLiteProperties properties;
private JPanel container;
private JPanel navContainer;
private PluginToolbar pluginToolbar;
private PluginPanel pluginPanel;
@@ -158,6 +155,21 @@ public class ClientUI extends JFrame
setVisible(true);
toFront();
requestFocus();
giveClientFocus();
}
private void giveClientFocus()
{
if (client instanceof Client)
{
final Canvas c = ((Client) client).getCanvas();
c.requestFocusInWindow();
}
else
{
client.requestFocusInWindow();
}
}
private static void setUIFont(FontUIResource f)
@@ -211,7 +223,6 @@ public class ClientUI extends JFrame
return trayIcon;
}
@Override
public void setTitle(String extra)
{
@@ -239,14 +250,14 @@ public class ClientUI extends JFrame
}
});
container = new JPanel();
final JPanel container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS));
container.add(new ClientPanel(client));
navContainer = new JPanel();
navContainer.setLayout(new BorderLayout(0,0));
navContainer.setMinimumSize(new Dimension(0,0));
navContainer.setMaximumSize(new Dimension(0,Integer.MAX_VALUE));
navContainer.setLayout(new BorderLayout(0, 0));
navContainer.setMinimumSize(new Dimension(0, 0));
navContainer.setMaximumSize(new Dimension(0, Integer.MAX_VALUE));
container.add(navContainer);
pluginToolbar = new PluginToolbar(this);
@@ -271,18 +282,28 @@ public class ClientUI extends JFrame
pluginPanel = panel;
navContainer.setMinimumSize(new Dimension(PANEL_EXPANDED_WIDTH, 0));
navContainer.setMaximumSize(new Dimension(PANEL_EXPANDED_WIDTH, Integer.MAX_VALUE));
navContainer.add(wrapPanel(pluginPanel));
final JPanel wrappedPanel = panel.getWrappedPanel();
navContainer.add(wrappedPanel);
navContainer.revalidate();
// panel.onActivate has to go after giveClientFocus so it can get focus if it needs.
giveClientFocus();
panel.onActivate();
wrappedPanel.repaint();
revalidateMinimumSize();
}
void contract()
{
boolean wasMinimumWidth = this.getWidth() == (int) this.getMinimumSize().getWidth();
pluginPanel.onDeactivate();
navContainer.remove(0);
navContainer.setMinimumSize(new Dimension(0, 0));
navContainer.setMaximumSize(new Dimension(0, Integer.MAX_VALUE));
navContainer.revalidate();
giveClientFocus();
revalidateMinimumSize();
if (wasMinimumWidth)
{
@@ -291,35 +312,12 @@ public class ClientUI extends JFrame
pluginPanel = null;
}
private JPanel wrapPanel(PluginPanel panel)
{
final JPanel northPanel = new JPanel();
northPanel.setLayout(new BorderLayout());
northPanel.add(panel, BorderLayout.NORTH);
final JScrollPane scrollPane = new JScrollPane(northPanel);
scrollPane.getVerticalScrollBar().setUnitIncrement(16); //Otherwise scrollspeed is really slow
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
final JPanel panelWrap = new JPanel();
// Adjust the preferred size to expand to width of scrollbar to
// to preven scrollbar overlapping over contents
panelWrap.setPreferredSize(new Dimension(
PluginPanel.PANEL_WIDTH + SCROLLBAR_WIDTH,
0));
panelWrap.setLayout(new BorderLayout());
panelWrap.add(scrollPane, BorderLayout.CENTER);
return panelWrap;
}
private void checkExit()
{
int result = JOptionPane.OK_OPTION;
// only ask if not logged out
if (client != null && client instanceof Client && ((Client)client).getGameState() != GameState.LOGIN_SCREEN)
if (client != null && client instanceof Client && ((Client) client).getGameState() != GameState.LOGIN_SCREEN)
{
result = JOptionPane.showConfirmDialog(this, "Are you sure you want to exit?", "Exit", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
}

View File

@@ -24,22 +24,50 @@
*/
package net.runelite.client.ui;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.border.EmptyBorder;
import lombok.AccessLevel;
import lombok.Getter;
public abstract class PluginPanel extends JPanel
{
public static final int PANEL_WIDTH = 225;
static final int PANEL_WIDTH = 225;
static final int SCROLLBAR_WIDTH = 17;
private static final int OFFSET = 6;
private static final EmptyBorder BORDER_PADDING = new EmptyBorder(OFFSET, OFFSET, OFFSET, OFFSET);
@Getter(AccessLevel.PROTECTED)
private final JScrollPane scrollPane;
@Getter(AccessLevel.PACKAGE)
private final JPanel wrappedPanel;
public PluginPanel()
{
super();
setBorder(BORDER_PADDING);
setLayout(new GridLayout(0, 1, 0, 3));
final JPanel northPanel = new JPanel();
northPanel.setLayout(new BorderLayout());
northPanel.add(this, BorderLayout.NORTH);
scrollPane = new JScrollPane(northPanel);
scrollPane.getVerticalScrollBar().setUnitIncrement(16); //Otherwise scrollspeed is really slow
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
wrappedPanel = new JPanel();
// Adjust the preferred size to expand to width of scrollbar to
// to preven scrollbar overlapping over contents
wrappedPanel.setPreferredSize(new Dimension(PluginPanel.PANEL_WIDTH + SCROLLBAR_WIDTH, 0));
wrappedPanel.setLayout(new BorderLayout());
wrappedPanel.add(scrollPane, BorderLayout.CENTER);
}
@Override
@@ -47,4 +75,12 @@ public abstract class PluginPanel extends JPanel
{
return new Dimension(PANEL_WIDTH, super.getPreferredSize().height);
}
public void onActivate()
{
}
public void onDeactivate()
{
}
}

View File

@@ -88,12 +88,11 @@ public class PluginToolbar extends JToolBar
}
else
{
current = button;
current.setSelected(true);
PluginPanel pluginPanel = panelSupplier.get();
ui.expand(pluginPanel);
current = button;
current.setSelected(true);
}
}
}