Files
Runelite-EssentialsPlus/src/main/java/com/example/essentialsplus/ui/WealthPopout.java
T

340 lines
10 KiB
Java
Raw Normal View History

2026-09-18 17:18:53 +02:00
package com.example.essentialsplus.ui;
import com.example.essentialsplus.data.AccountData;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.swing.BorderFactory;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.WindowConstants;
import net.runelite.client.ui.DynamicGridLayout;
import net.runelite.client.ui.FontManager;
/** Large resizable analysis window with its own character selection. */
class WealthPopout extends JFrame
{
static final String AUTO = "__logged_in__";
private final WealthPanel panel;
private final WealthPanel.DetailView view;
private final Segmented rangeBar;
private final Segmented styleBar;
private final JComboBox<Choice> characterBox = new JComboBox<>();
private final JLabel sessionLabel = new JLabel();
private String choice = AUTO;
private String resolved = WealthPanel.ALL;
private List<String> comboKeys = new ArrayList<>();
private boolean updatingCombo;
private static final class Choice
{
final String key;
final String label;
Choice(String key, String label)
{
this.key = key;
this.label = label;
}
@Override
public String toString()
{
return label;
}
}
WealthPopout(WealthPanel panel, TimeRange range, Runnable onClose)
{
super("Wealth Tracker");
this.panel = panel;
setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
addWindowListener(new WindowAdapter()
{
@Override
public void windowClosed(WindowEvent e)
{
onClose.run();
}
});
view = new WealthPanel.DetailView(panel.getIcons(), true);
view.main.setMode(panel.getMainMode());
view.breakdown.setOnOpen((v, label) -> panel.openItems(v, label, resolved));
2026-09-30 16:48:47 +02:00
rangeBar = Segmented.ranges(panel.getTimeFilter(), panel::setRange);
rangeBar.setSelected(panel.isCustomSessionView() ? -1 : panel.getTimeFilter().getSlotIndex(range));
2026-09-18 17:18:53 +02:00
styleBar = new Segmented(new String[]{"Line", "Candles"}, panel.getMainMode() == WealthChart.Mode.CANDLES ? 1 : 0,
i -> panel.setMainMode(i == 1 ? WealthChart.Mode.CANDLES : WealthChart.Mode.LINE));
java.awt.event.MouseAdapter popoutRightClick = new java.awt.event.MouseAdapter()
{
@Override
public void mousePressed(java.awt.event.MouseEvent e)
{
if (e.isPopupTrigger())
{
showPopup(e);
}
}
@Override
public void mouseReleased(java.awt.event.MouseEvent e)
{
if (e.isPopupTrigger())
{
showPopup(e);
}
}
private void showPopup(java.awt.event.MouseEvent e)
{
if (!panel.isHourly())
{
return;
}
javax.swing.JPopupMenu menu = new javax.swing.JPopupMenu();
javax.swing.JMenuItem reset = new javax.swing.JMenuItem("Reset Hourly");
reset.addActionListener(a ->
{
panel.resetHourly(resolved);
panel.refreshLater();
});
menu.add(reset);
menu.show((java.awt.Component) e.getSource(), e.getX(), e.getY());
}
};
view.main.addMouseListener(popoutRightClick);
view.stats.addMouseListener(popoutRightClick);
characterBox.setFont(FontManager.getRunescapeBoldFont());
characterBox.setBackground(Ui.CARD);
characterBox.setForeground(Ui.TEXT);
characterBox.setFocusable(false);
characterBox.setPreferredSize(new Dimension(260, 30));
characterBox.setRenderer(new DefaultListCellRenderer()
{
@Override
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus)
{
JLabel l = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
l.setFont(FontManager.getRunescapeBoldFont());
l.setBorder(BorderFactory.createEmptyBorder(3, 8, 3, 8));
return l;
}
});
characterBox.addActionListener(e ->
{
if (updatingCombo)
{
return;
}
Choice c = (Choice) characterBox.getSelectedItem();
if (c != null)
{
choice = c.key;
panel.refreshLater();
}
});
JPanel root = new JPanel(new BorderLayout(12, 10));
root.setBackground(Ui.BG);
root.setBorder(BorderFactory.createEmptyBorder(12, 12, 12, 12));
// ---- top bar
JPanel top = new JPanel(new BorderLayout(12, 0));
top.setOpaque(false);
JPanel left = new JPanel(new FlowLayout(FlowLayout.LEFT, 12, 0));
left.setOpaque(false);
view.title.setFont(FontManager.getRunescapeBoldFont().deriveFont(24f));
view.title.setForeground(Ui.ACCENT);
left.add(view.title);
left.add(characterBox);
top.add(left, BorderLayout.WEST);
JPanel controls = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 0));
controls.setOpaque(false);
sessionLabel.setFont(FontManager.getRunescapeFont());
sessionLabel.setForeground(Ui.MUTED);
controls.add(sessionLabel);
controls.add(button("Session", panel::showSession));
controls.add(button("New session", panel::newSession));
styleBar.setPreferredSize(new Dimension(150, 30));
rangeBar.setPreferredSize(new Dimension(380, 30));
controls.add(styleBar);
controls.add(rangeBar);
top.add(controls, BorderLayout.EAST);
root.add(top, BorderLayout.NORTH);
// ---- charts
JPanel charts = new JPanel(new GridBagLayout());
charts.setOpaque(false);
int row = 0;
row = addChart(charts, row, "NET WORTH", view.main, 0.5);
row = addChart(charts, row, "CHANGE PER PERIOD", view.bars, 0.2);
addChart(charts, row, "COMPOSITION", view.stacked, 0.3);
root.add(charts, BorderLayout.CENTER);
// ---- side column
JPanel side = new JPanel(new DynamicGridLayout(0, 1, 0, 6));
side.setBackground(Ui.BG);
side.add(label("STATISTICS"));
side.add(view.stats);
side.add(label("BREAKDOWN (click to view items)"));
JPanel viewButtons = new JPanel(new java.awt.GridLayout(1, 4, 4, 0));
viewButtons.setOpaque(false);
viewButtons.add(button("Bank", () -> panel.openItems("bank", "Bank", resolved)));
viewButtons.add(button("Inventory", () -> panel.openItems("inventory", "Inventory", resolved)));
viewButtons.add(button("Equipment", () -> panel.openItems("equipment", "Equipment", resolved)));
viewButtons.add(button("GE", () -> panel.openItems("ge", "Grand Exchange", resolved)));
side.add(viewButtons);
side.add(view.breakdown);
side.add(label("WHAT CHANGED"));
side.add(view.movers);
side.add(label("MOST VALUABLE"));
side.add(view.topItems);
JPanel sideWrap = new JPanel(new BorderLayout());
sideWrap.setBackground(Ui.BG);
sideWrap.add(side, BorderLayout.NORTH);
JScrollPane scroll = new JScrollPane(sideWrap, ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scroll.setBorder(null);
scroll.getVerticalScrollBar().setUnitIncrement(16);
scroll.setPreferredSize(new Dimension(340, 10));
root.add(scroll, BorderLayout.EAST);
setContentPane(root);
setSize(1600, 900);
setMinimumSize(new Dimension(900, 560));
setLocationRelativeTo(panel);
}
private static int addChart(JPanel charts, int row, String title, JComponent chart, double weight)
{
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.fill = GridBagConstraints.BOTH;
c.weightx = 1;
c.gridy = row;
c.weighty = 0;
c.insets = new Insets(row == 0 ? 0 : 8, 0, 4, 0);
charts.add(label(title), c);
c.gridy = row + 1;
c.weighty = weight;
c.insets = new Insets(0, 0, 0, 0);
chart.setPreferredSize(new Dimension(10, 60));
charts.add(chart, c);
return row + 2;
}
/** Character shown in this window: the logged-in one by default, or the one picked in the box. */
String resolveSelection(List<AccountData> accounts, String activeKey)
{
if (AUTO.equals(choice))
{
if (activeKey != null && accounts.stream().anyMatch(a -> a.key.equals(activeKey)))
{
resolved = activeKey;
}
else if (accounts.stream().noneMatch(a -> a.key.equals(resolved)))
{
resolved = WealthPanel.ALL;
}
}
else if (WealthPanel.ALL.equals(choice) || accounts.stream().anyMatch(a -> a.key.equals(choice)))
{
resolved = choice;
}
else
{
choice = AUTO;
resolved = WealthPanel.ALL;
}
return resolved;
}
void setRange(int index)
{
rangeBar.setSelected(index);
}
void setMainMode(WealthChart.Mode mode)
{
styleBar.setSelected(mode == WealthChart.Mode.CANDLES ? 1 : 0);
view.main.setMode(mode);
}
void update(WealthPanel.Model m, List<AccountData> accounts, String selectionKey)
{
List<String> keys = new ArrayList<>();
accounts.forEach(a -> keys.add(a.key + "=" + a.name));
if (!keys.equals(comboKeys))
{
comboKeys = keys;
updatingCombo = true;
characterBox.removeAllItems();
characterBox.addItem(new Choice(AUTO, "Logged-in character"));
characterBox.addItem(new Choice(WealthPanel.ALL, "All characters"));
for (AccountData a : accounts)
{
characterBox.addItem(new Choice(a.key, a.name));
}
updatingCombo = false;
}
updatingCombo = true;
for (int i = 0; i < characterBox.getItemCount(); i++)
{
if (Objects.equals(characterBox.getItemAt(i).key, choice))
{
characterBox.setSelectedIndex(i);
break;
}
}
updatingCombo = false;
long sessionStart = panel.sessionStart();
sessionLabel.setText(panel.isSessionView() ? "Since session start" : sessionStart > 0 ? "Session: " + Ui.ago(sessionStart).replace(" ago", "") : "");
sessionLabel.setForeground(panel.isSessionView() ? Ui.ACCENT : Ui.MUTED);
view.update(m, 10);
panel.resolveNames(view.lastMovers);
}
private static JButton button(String text, Runnable action)
{
JButton b = new JButton(text);
b.setFont(FontManager.getRunescapeSmallFont());
b.setFocusPainted(false);
b.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
b.setPreferredSize(new Dimension(Math.max(70, text.length() * 8 + 20), 30));
b.addActionListener(e -> action.run());
return b;
}
private static JLabel label(String text)
{
JLabel l = new JLabel(text);
l.setFont(FontManager.getRunescapeSmallFont());
l.setForeground(Ui.MUTED);
return l;
}
}