Merge pull request #10701 from abextm/loottracker-aggregate-opt
Optimize loottracker UI
This commit is contained in:
@@ -39,13 +39,19 @@ import java.util.List;
|
|||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.ButtonGroup;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
import javax.swing.JButton;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JMenuItem;
|
import javax.swing.JMenuItem;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JPopupMenu;
|
import javax.swing.JPopupMenu;
|
||||||
|
import javax.swing.JRadioButton;
|
||||||
|
import javax.swing.JToggleButton;
|
||||||
import javax.swing.border.EmptyBorder;
|
import javax.swing.border.EmptyBorder;
|
||||||
|
import javax.swing.plaf.basic.BasicButtonUI;
|
||||||
|
import javax.swing.plaf.basic.BasicToggleButtonUI;
|
||||||
import net.runelite.client.game.ItemManager;
|
import net.runelite.client.game.ItemManager;
|
||||||
import net.runelite.client.ui.ColorScheme;
|
import net.runelite.client.ui.ColorScheme;
|
||||||
import net.runelite.client.ui.FontManager;
|
import net.runelite.client.ui.FontManager;
|
||||||
@@ -54,6 +60,7 @@ import net.runelite.client.ui.components.PluginErrorPanel;
|
|||||||
import net.runelite.client.util.ColorUtil;
|
import net.runelite.client.util.ColorUtil;
|
||||||
import net.runelite.client.util.ImageUtil;
|
import net.runelite.client.util.ImageUtil;
|
||||||
import net.runelite.client.util.QuantityFormatter;
|
import net.runelite.client.util.QuantityFormatter;
|
||||||
|
import net.runelite.client.util.SwingUtil;
|
||||||
import net.runelite.http.api.loottracker.LootTrackerClient;
|
import net.runelite.http.api.loottracker.LootTrackerClient;
|
||||||
|
|
||||||
class LootTrackerPanel extends PluginPanel
|
class LootTrackerPanel extends PluginPanel
|
||||||
@@ -97,11 +104,11 @@ class LootTrackerPanel extends PluginPanel
|
|||||||
// Details and navigation
|
// Details and navigation
|
||||||
private final JPanel actionsContainer = new JPanel();
|
private final JPanel actionsContainer = new JPanel();
|
||||||
private final JLabel detailsTitle = new JLabel();
|
private final JLabel detailsTitle = new JLabel();
|
||||||
private final JLabel backBtn = new JLabel();
|
private final JButton backBtn = new JButton();
|
||||||
private final JLabel viewHiddenBtn = new JLabel();
|
private final JToggleButton viewHiddenBtn = new JToggleButton();
|
||||||
private final JLabel singleLootBtn = new JLabel();
|
private final JRadioButton singleLootBtn = new JRadioButton();
|
||||||
private final JLabel groupedLootBtn = new JLabel();
|
private final JRadioButton groupedLootBtn = new JRadioButton();
|
||||||
private final JLabel collapseBtn = new JLabel();
|
private final JButton collapseBtn = new JButton();
|
||||||
|
|
||||||
// Aggregate of all kills
|
// Aggregate of all kills
|
||||||
private final List<LootTrackerRecord> aggregateRecords = new ArrayList<>();
|
private final List<LootTrackerRecord> aggregateRecords = new ArrayList<>();
|
||||||
@@ -173,121 +180,64 @@ class LootTrackerPanel extends PluginPanel
|
|||||||
final JPanel viewControls = new JPanel(new GridLayout(1, 3, 10, 0));
|
final JPanel viewControls = new JPanel(new GridLayout(1, 3, 10, 0));
|
||||||
viewControls.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
viewControls.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
|
||||||
|
SwingUtil.removeButtonDecorations(collapseBtn);
|
||||||
collapseBtn.setIcon(EXPAND_ICON);
|
collapseBtn.setIcon(EXPAND_ICON);
|
||||||
collapseBtn.addMouseListener(new MouseAdapter()
|
collapseBtn.setSelectedIcon(COLLAPSE_ICON);
|
||||||
{
|
SwingUtil.addModalTooltip(collapseBtn, "Collapse All", "Un-Collapse All");
|
||||||
@Override
|
collapseBtn.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
public void mousePressed(MouseEvent e)
|
collapseBtn.setUI(new BasicButtonUI()); // substance breaks the layout
|
||||||
{
|
collapseBtn.addActionListener(ev -> changeCollapse());
|
||||||
changeCollapse();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
singleLootBtn.setIcon(SINGLE_LOOT_VIEW);
|
|
||||||
singleLootBtn.setToolTipText("Show each kill separately");
|
|
||||||
singleLootBtn.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mousePressed(MouseEvent mouseEvent)
|
|
||||||
{
|
|
||||||
changeGrouping(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseExited(MouseEvent mouseEvent)
|
|
||||||
{
|
|
||||||
singleLootBtn.setIcon(groupLoot ? SINGLE_LOOT_VIEW_FADED : SINGLE_LOOT_VIEW);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseEntered(MouseEvent mouseEvent)
|
|
||||||
{
|
|
||||||
singleLootBtn.setIcon(groupLoot ? SINGLE_LOOT_VIEW_HOVER : SINGLE_LOOT_VIEW);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
groupedLootBtn.setIcon(GROUPED_LOOT_VIEW);
|
|
||||||
groupedLootBtn.setToolTipText("Group loot by source");
|
|
||||||
groupedLootBtn.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mousePressed(MouseEvent mouseEvent)
|
|
||||||
{
|
|
||||||
changeGrouping(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseExited(MouseEvent mouseEvent)
|
|
||||||
{
|
|
||||||
groupedLootBtn.setIcon(groupLoot ? GROUPED_LOOT_VIEW : GROUPED_LOOT_VIEW_FADED);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseEntered(MouseEvent mouseEvent)
|
|
||||||
{
|
|
||||||
groupedLootBtn.setIcon(groupLoot ? GROUPED_LOOT_VIEW : GROUPED_LOOT_VIEW_HOVER);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
viewHiddenBtn.setIcon(VISIBLE_ICON);
|
|
||||||
viewHiddenBtn.setToolTipText("Show ignored items");
|
|
||||||
viewHiddenBtn.addMouseListener(new MouseAdapter()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public void mousePressed(MouseEvent mouseEvent)
|
|
||||||
{
|
|
||||||
changeItemHiding(!hideIgnoredItems);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseExited(MouseEvent mouseEvent)
|
|
||||||
{
|
|
||||||
viewHiddenBtn.setIcon(hideIgnoredItems ? INVISIBLE_ICON : VISIBLE_ICON);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseEntered(MouseEvent mouseEvent)
|
|
||||||
{
|
|
||||||
viewHiddenBtn.setIcon(hideIgnoredItems ? INVISIBLE_ICON_HOVER : VISIBLE_ICON_HOVER);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
viewControls.add(collapseBtn);
|
viewControls.add(collapseBtn);
|
||||||
|
|
||||||
|
SwingUtil.removeButtonDecorations(singleLootBtn);
|
||||||
|
singleLootBtn.setIcon(SINGLE_LOOT_VIEW_FADED);
|
||||||
|
singleLootBtn.setRolloverIcon(SINGLE_LOOT_VIEW_HOVER);
|
||||||
|
singleLootBtn.setSelectedIcon(SINGLE_LOOT_VIEW);
|
||||||
|
singleLootBtn.setToolTipText("Show each kill separately");
|
||||||
|
singleLootBtn.addActionListener(e -> changeGrouping(false));
|
||||||
|
|
||||||
|
SwingUtil.removeButtonDecorations(groupedLootBtn);
|
||||||
|
groupedLootBtn.setIcon(GROUPED_LOOT_VIEW_FADED);
|
||||||
|
groupedLootBtn.setRolloverIcon(GROUPED_LOOT_VIEW_HOVER);
|
||||||
|
groupedLootBtn.setSelectedIcon(GROUPED_LOOT_VIEW);
|
||||||
|
groupedLootBtn.setToolTipText("Group loot by source");
|
||||||
|
groupedLootBtn.addActionListener(e -> changeGrouping(true));
|
||||||
|
|
||||||
|
ButtonGroup groupSingleGroup = new ButtonGroup();
|
||||||
|
groupSingleGroup.add(singleLootBtn);
|
||||||
|
groupSingleGroup.add(groupedLootBtn);
|
||||||
|
|
||||||
viewControls.add(groupedLootBtn);
|
viewControls.add(groupedLootBtn);
|
||||||
viewControls.add(singleLootBtn);
|
viewControls.add(singleLootBtn);
|
||||||
viewControls.add(viewHiddenBtn);
|
|
||||||
changeGrouping(true);
|
changeGrouping(true);
|
||||||
|
|
||||||
|
SwingUtil.removeButtonDecorations(viewHiddenBtn);
|
||||||
|
viewHiddenBtn.setIconTextGap(0);
|
||||||
|
viewHiddenBtn.setIcon(VISIBLE_ICON);
|
||||||
|
viewHiddenBtn.setRolloverIcon(INVISIBLE_ICON_HOVER);
|
||||||
|
viewHiddenBtn.setSelectedIcon(INVISIBLE_ICON);
|
||||||
|
viewHiddenBtn.setRolloverSelectedIcon(VISIBLE_ICON_HOVER);
|
||||||
|
viewHiddenBtn.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
viewHiddenBtn.setUI(new BasicToggleButtonUI()); // substance breaks the layout and the pressed icon
|
||||||
|
SwingUtil.addModalTooltip(viewHiddenBtn, "Show ignored items", "Hide ignored items");
|
||||||
changeItemHiding(true);
|
changeItemHiding(true);
|
||||||
|
viewControls.add(viewHiddenBtn);
|
||||||
|
|
||||||
final JPanel leftTitleContainer = new JPanel(new BorderLayout(5, 0));
|
final JPanel leftTitleContainer = new JPanel(new BorderLayout(5, 0));
|
||||||
leftTitleContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
leftTitleContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||||
|
|
||||||
detailsTitle.setForeground(Color.WHITE);
|
detailsTitle.setForeground(Color.WHITE);
|
||||||
|
|
||||||
|
SwingUtil.removeButtonDecorations(backBtn);
|
||||||
backBtn.setIcon(BACK_ARROW_ICON);
|
backBtn.setIcon(BACK_ARROW_ICON);
|
||||||
|
backBtn.setRolloverIcon(BACK_ARROW_ICON_HOVER);
|
||||||
backBtn.setVisible(false);
|
backBtn.setVisible(false);
|
||||||
backBtn.addMouseListener(new MouseAdapter()
|
backBtn.addActionListener(ev ->
|
||||||
{
|
{
|
||||||
@Override
|
currentView = null;
|
||||||
public void mousePressed(MouseEvent mouseEvent)
|
backBtn.setVisible(false);
|
||||||
{
|
detailsTitle.setText("");
|
||||||
currentView = null;
|
rebuild();
|
||||||
backBtn.setVisible(false);
|
|
||||||
detailsTitle.setText("");
|
|
||||||
rebuild();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseExited(MouseEvent mouseEvent)
|
|
||||||
{
|
|
||||||
backBtn.setIcon(BACK_ARROW_ICON);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseEntered(MouseEvent mouseEvent)
|
|
||||||
{
|
|
||||||
backBtn.setIcon(BACK_ARROW_ICON_HOVER);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
leftTitleContainer.add(backBtn, BorderLayout.WEST);
|
leftTitleContainer.add(backBtn, BorderLayout.WEST);
|
||||||
@@ -367,16 +317,7 @@ class LootTrackerPanel extends PluginPanel
|
|||||||
|
|
||||||
void updateCollapseText()
|
void updateCollapseText()
|
||||||
{
|
{
|
||||||
if (isAllCollapsed())
|
collapseBtn.setSelected(isAllCollapsed());
|
||||||
{
|
|
||||||
collapseBtn.setToolTipText("Un-Collapse All");
|
|
||||||
collapseBtn.setIcon(COLLAPSE_ICON);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
collapseBtn.setToolTipText("Collapse All");
|
|
||||||
collapseBtn.setIcon(EXPAND_ICON);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAllCollapsed()
|
private boolean isAllCollapsed()
|
||||||
@@ -427,9 +368,8 @@ class LootTrackerPanel extends PluginPanel
|
|||||||
private void changeGrouping(boolean group)
|
private void changeGrouping(boolean group)
|
||||||
{
|
{
|
||||||
groupLoot = group;
|
groupLoot = group;
|
||||||
|
(group ? groupedLootBtn : singleLootBtn).setSelected(true);
|
||||||
rebuild();
|
rebuild();
|
||||||
groupedLootBtn.setIcon(group ? GROUPED_LOOT_VIEW : GROUPED_LOOT_VIEW_FADED);
|
|
||||||
singleLootBtn.setIcon(group ? SINGLE_LOOT_VIEW_FADED : SINGLE_LOOT_VIEW);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -440,8 +380,8 @@ class LootTrackerPanel extends PluginPanel
|
|||||||
private void changeItemHiding(boolean hide)
|
private void changeItemHiding(boolean hide)
|
||||||
{
|
{
|
||||||
hideIgnoredItems = hide;
|
hideIgnoredItems = hide;
|
||||||
|
viewHiddenBtn.setSelected(hide);
|
||||||
rebuild();
|
rebuild();
|
||||||
viewHiddenBtn.setIcon(hideIgnoredItems ? VISIBLE_ICON : INVISIBLE_ICON);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -488,7 +428,7 @@ class LootTrackerPanel extends PluginPanel
|
|||||||
*/
|
*/
|
||||||
private void rebuild()
|
private void rebuild()
|
||||||
{
|
{
|
||||||
logsContainer.removeAll();
|
SwingUtil.fastRemoveAll(logsContainer);
|
||||||
boxes.clear();
|
boxes.clear();
|
||||||
|
|
||||||
if (groupLoot)
|
if (groupLoot)
|
||||||
|
|||||||
@@ -612,7 +612,7 @@ public class LootTrackerPlugin extends Plugin
|
|||||||
}
|
}
|
||||||
|
|
||||||
config.setIgnoredItems(Text.toCSV(ignoredItemSet));
|
config.setIgnoredItems(Text.toCSV(ignoredItemSet));
|
||||||
panel.updateIgnoredRecords();
|
// the config changed will update the panel
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isIgnored(String name)
|
boolean isIgnored(String name)
|
||||||
|
|||||||
@@ -26,11 +26,16 @@ package net.runelite.client.util;
|
|||||||
|
|
||||||
import java.awt.AWTException;
|
import java.awt.AWTException;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Container;
|
||||||
|
import java.awt.EventQueue;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.Frame;
|
import java.awt.Frame;
|
||||||
import java.awt.Image;
|
import java.awt.Image;
|
||||||
import java.awt.Insets;
|
import java.awt.Insets;
|
||||||
|
import java.awt.SecondaryLoop;
|
||||||
import java.awt.SystemTray;
|
import java.awt.SystemTray;
|
||||||
|
import java.awt.Toolkit;
|
||||||
import java.awt.TrayIcon;
|
import java.awt.TrayIcon;
|
||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
@@ -50,6 +55,7 @@ import javax.swing.JMenuItem;
|
|||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPopupMenu;
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.LookAndFeel;
|
import javax.swing.LookAndFeel;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.ToolTipManager;
|
import javax.swing.ToolTipManager;
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.UnsupportedLookAndFeelException;
|
import javax.swing.UnsupportedLookAndFeelException;
|
||||||
@@ -293,4 +299,54 @@ public class SwingUtil
|
|||||||
{
|
{
|
||||||
button.addItemListener(l -> button.setToolTipText(button.isSelected() ? on : off));
|
button.addItemListener(l -> button.setToolTipText(button.isSelected() ? on : off));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes all of a component's children faster than calling removeAll() on it in many cases
|
||||||
|
*/
|
||||||
|
public static void fastRemoveAll(Container c)
|
||||||
|
{
|
||||||
|
// If we are not on the EDT this will deadlock, in addition to being totally unsafe
|
||||||
|
assert SwingUtilities.isEventDispatchThread();
|
||||||
|
|
||||||
|
// when a component is removed it has to be resized for some reason, but only if it's valid
|
||||||
|
// so we make sure to invalidate everything before removing it
|
||||||
|
c.invalidate();
|
||||||
|
for (int i = 0; i < c.getComponentCount(); i++)
|
||||||
|
{
|
||||||
|
Component ic = c.getComponent(i);
|
||||||
|
|
||||||
|
// removeAll and removeNotify are both recursive, so we have to recurse before them
|
||||||
|
if (ic instanceof Container)
|
||||||
|
{
|
||||||
|
fastRemoveAll((Container) ic);
|
||||||
|
}
|
||||||
|
|
||||||
|
// each removeNotify needs to remove anything from the event queue that is for that widget
|
||||||
|
// this however requires taking a lock, and is moderately slow, so we just execute all of
|
||||||
|
// those events with a secondary event loop
|
||||||
|
pumpPendingEvents();
|
||||||
|
|
||||||
|
// call removeNotify early; this is most of the work in removeAll, and generates events that
|
||||||
|
// the next secondaryLoop will pickup
|
||||||
|
ic.removeNotify();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually remove anything
|
||||||
|
c.removeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run any events currently in the event queue
|
||||||
|
*/
|
||||||
|
public static void pumpPendingEvents()
|
||||||
|
{
|
||||||
|
EventQueue eq = Toolkit.getDefaultToolkit().getSystemEventQueue();
|
||||||
|
|
||||||
|
if (eq.peekEvent() != null)
|
||||||
|
{
|
||||||
|
SecondaryLoop l = eq.createSecondaryLoop();
|
||||||
|
SwingUtilities.invokeLater(l::exit);
|
||||||
|
l.enter();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user