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 characterBox = new JComboBox<>(); private final JLabel sessionLabel = new JLabel(); private String choice = AUTO; private String resolved = WealthPanel.ALL; private List 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)); rangeBar = Segmented.ranges(panel.getTimeFilter(), panel::setRange); rangeBar.setSelected(panel.isCustomSessionView() ? -1 : panel.getTimeFilter().getSlotIndex(range)); 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 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 accounts, String selectionKey) { List 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; } }