chore: init
This commit is contained in:
@@ -0,0 +1,353 @@
|
||||
package com.example.essentialsplus.currency.ui;
|
||||
|
||||
import com.example.essentialsplus.currency.Currency;
|
||||
import com.example.essentialsplus.currency.CurrencyHistory;
|
||||
import com.example.essentialsplus.currency.CurrencyTracker;
|
||||
import com.example.essentialsplus.ui.TimeFilter;
|
||||
import com.example.essentialsplus.ui.Ui;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Cursor;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.FontMetrics;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.ui.DynamicGridLayout;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
|
||||
/** Points & Marks tab: every tracked minigame point, mark and token with the amount earned in the range. */
|
||||
public class CurrencyPanel extends JPanel
|
||||
{
|
||||
private final CurrencyTracker tracker;
|
||||
private final TimeFilter filter;
|
||||
private final CurrencyIcons icons;
|
||||
private final JPanel list = new JPanel(new DynamicGridLayout(0, 1, 0, 4));
|
||||
private final CurrencyCard hero;
|
||||
private CurrencyCard overviewCard;
|
||||
/** currency always shown on the overview card, null = what is being played */
|
||||
private Currency overviewPin;
|
||||
private boolean overviewShowTracked = true;
|
||||
|
||||
public CurrencyPanel(CurrencyTracker tracker, ItemManager itemManager, TimeFilter filter, Runnable onBack)
|
||||
{
|
||||
this.tracker = tracker;
|
||||
this.filter = filter;
|
||||
this.icons = new CurrencyIcons(itemManager);
|
||||
this.hero = new CurrencyCard(icons, () -> { });
|
||||
hero.setCursor(Cursor.getDefaultCursor());
|
||||
|
||||
setLayout(new BorderLayout(0, 6));
|
||||
setBackground(Ui.BG);
|
||||
setBorder(BorderFactory.createEmptyBorder(10, 8, 8, 8));
|
||||
|
||||
JPanel backRow = new JPanel(new BorderLayout(6, 0));
|
||||
backRow.setOpaque(false);
|
||||
JButton backBtn = new JButton("← Overview");
|
||||
backBtn.setFont(FontManager.getRunescapeSmallFont());
|
||||
backBtn.setForeground(Ui.ACCENT);
|
||||
backBtn.setFocusPainted(false);
|
||||
backBtn.setMargin(new java.awt.Insets(2, 2, 2, 2));
|
||||
backBtn.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
backBtn.addActionListener(e -> onBack.run());
|
||||
backRow.add(backBtn, BorderLayout.WEST);
|
||||
JLabel title = new JLabel("Points & Marks");
|
||||
title.setFont(FontManager.getRunescapeBoldFont());
|
||||
title.setForeground(Ui.ACCENT);
|
||||
title.setHorizontalAlignment(JLabel.RIGHT);
|
||||
backRow.add(title, BorderLayout.CENTER);
|
||||
add(backRow, BorderLayout.NORTH);
|
||||
|
||||
list.setOpaque(false);
|
||||
JPanel listWrap = new JPanel(new BorderLayout());
|
||||
listWrap.setOpaque(false);
|
||||
listWrap.add(list, BorderLayout.NORTH);
|
||||
JScrollPane scroll = new JScrollPane(listWrap);
|
||||
scroll.setBorder(null);
|
||||
scroll.setOpaque(false);
|
||||
scroll.getViewport().setOpaque(false);
|
||||
scroll.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scroll.getVerticalScrollBar().setUnitIncrement(16);
|
||||
scroll.getVerticalScrollBar().setPreferredSize(new Dimension(8, 0));
|
||||
add(scroll, BorderLayout.CENTER);
|
||||
refresh();
|
||||
}
|
||||
|
||||
public void setOverviewOptions(Currency pin, boolean showTracked)
|
||||
{
|
||||
overviewPin = pin;
|
||||
overviewShowTracked = showTracked;
|
||||
refresh();
|
||||
}
|
||||
|
||||
/** Currencies with data for the logged-in character, in enum order. */
|
||||
public List<Currency> tracked()
|
||||
{
|
||||
List<Currency> out = new ArrayList<>();
|
||||
CurrencyHistory h = tracker.history();
|
||||
if (h != null)
|
||||
{
|
||||
for (Currency c : Currency.values())
|
||||
{
|
||||
if (h.has(c))
|
||||
{
|
||||
out.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Card for the overview, kept up to date by {@link #refresh}. */
|
||||
public CurrencyCard createOverviewCard(Runnable onClick)
|
||||
{
|
||||
overviewCard = new CurrencyCard(icons, onClick);
|
||||
refresh();
|
||||
return overviewCard;
|
||||
}
|
||||
|
||||
/** Swing thread. */
|
||||
public void refresh()
|
||||
{
|
||||
CurrencyHistory h = tracker.history();
|
||||
long now = System.currentTimeMillis();
|
||||
String range = filter.inLabel();
|
||||
|
||||
List<Currency> shown = new ArrayList<>();
|
||||
if (h != null)
|
||||
{
|
||||
for (Currency c : Currency.values())
|
||||
{
|
||||
if (h.has(c))
|
||||
{
|
||||
shown.add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
Currency active = tracker.active();
|
||||
Currency featured = active;
|
||||
if (featured == null && h != null)
|
||||
{
|
||||
featured = Currency.byName(h.lastActive);
|
||||
if (featured == null)
|
||||
{
|
||||
long best = -1;
|
||||
for (Currency c : shown)
|
||||
{
|
||||
List<CurrencyHistory.Sample> s = h.samples(c);
|
||||
long t = s.get(s.size() - 1).t;
|
||||
if (t > best)
|
||||
{
|
||||
best = t;
|
||||
featured = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (CurrencyCard card : new CurrencyCard[]{hero, overviewCard})
|
||||
{
|
||||
if (card == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Currency c = featured;
|
||||
boolean pinned = card == overviewCard && overviewPin != null && h != null && h.has(overviewPin);
|
||||
if (pinned)
|
||||
{
|
||||
c = overviewPin;
|
||||
}
|
||||
card.setOptions(card != overviewCard || overviewShowTracked, pinned && c != active);
|
||||
if (c == null || h == null)
|
||||
{
|
||||
card.update(null, 0, 0, range, false, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
card.update(c, Math.max(0, h.amount(c)), h.change(c, filter, now)[0], range,
|
||||
c == active, h.lastGain(c), shown.size());
|
||||
}
|
||||
}
|
||||
|
||||
list.removeAll();
|
||||
list.add(hero);
|
||||
if (h == null || shown.isEmpty())
|
||||
{
|
||||
list.add(hint(h == null
|
||||
? "Log in to start tracking."
|
||||
: "Nothing tracked yet. Points show up once they change or are read in-game."));
|
||||
}
|
||||
else
|
||||
{
|
||||
// earned in the range first, then most recently earned
|
||||
shown.sort((a, b) ->
|
||||
{
|
||||
int byActive = Boolean.compare(b == active, a == active);
|
||||
if (byActive != 0)
|
||||
{
|
||||
return byActive;
|
||||
}
|
||||
return Long.compare(h.lastGain(b), h.lastGain(a));
|
||||
});
|
||||
addSection("POINTS", shown, h, active, now, false);
|
||||
addSection("MARKS & TOKENS", shown, h, active, now, true);
|
||||
}
|
||||
list.add(hint("Pest Control points are read while the lander or reward shop is open. "
|
||||
+ "Items count bank, inventory, gear, looting bag and seed vault."));
|
||||
list.revalidate();
|
||||
list.repaint();
|
||||
}
|
||||
|
||||
private void addSection(String name, List<Currency> shown, CurrencyHistory h, Currency active, long now, boolean items)
|
||||
{
|
||||
boolean header = false;
|
||||
for (Currency c : shown)
|
||||
{
|
||||
if ((c.source == Currency.Source.ITEM) != items)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!header)
|
||||
{
|
||||
list.add(header(name));
|
||||
header = true;
|
||||
}
|
||||
long[] change = h.change(c, filter, now);
|
||||
list.add(new Row(c, h.amount(c), change[0], change[1], h.lastGain(c), c == active));
|
||||
}
|
||||
}
|
||||
|
||||
private static JLabel header(String text)
|
||||
{
|
||||
JLabel l = new JLabel(text);
|
||||
l.setFont(FontManager.getRunescapeSmallFont());
|
||||
l.setForeground(Ui.MUTED);
|
||||
l.setBorder(BorderFactory.createEmptyBorder(6, 2, 0, 2));
|
||||
return l;
|
||||
}
|
||||
|
||||
private static JLabel hint(String text)
|
||||
{
|
||||
JLabel l = new JLabel("<html>" + text + "</html>");
|
||||
l.setFont(FontManager.getRunescapeSmallFont());
|
||||
l.setForeground(Ui.FAINT);
|
||||
l.setBorder(BorderFactory.createEmptyBorder(6, 4, 6, 4));
|
||||
return l;
|
||||
}
|
||||
|
||||
/** One currency: icon, name, amount, earned / spent in the range. */
|
||||
private final class Row extends JComponent
|
||||
{
|
||||
private static final int ICON = 28;
|
||||
private final Currency currency;
|
||||
private final long amount;
|
||||
private final long earned;
|
||||
private final long spent;
|
||||
private final long lastGain;
|
||||
private final boolean active;
|
||||
|
||||
Row(Currency currency, long amount, long earned, long spent, long lastGain, boolean active)
|
||||
{
|
||||
this.currency = currency;
|
||||
this.amount = amount;
|
||||
this.earned = earned;
|
||||
this.spent = spent;
|
||||
this.lastGain = lastGain;
|
||||
this.active = active;
|
||||
setToolTipText(currency.label + ": " + CurrencyCard.number(amount)
|
||||
+ (lastGain > 0 ? " - last earned " + CurrencyCard.ago(lastGain) : ""));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize()
|
||||
{
|
||||
return new Dimension(PluginPanel.PANEL_WIDTH - 24, 44);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g0)
|
||||
{
|
||||
Graphics2D g = Ui.prepare(g0);
|
||||
int w = getWidth();
|
||||
int h = getHeight();
|
||||
g.setColor(active ? Ui.CARD_SELECTED : Ui.CARD);
|
||||
g.fillRoundRect(0, 0, w, h, 6, 6);
|
||||
if (active)
|
||||
{
|
||||
g.setColor(Ui.UP);
|
||||
g.fillRoundRect(0, 6, 3, h - 12, 3, 3);
|
||||
}
|
||||
int pad = 8;
|
||||
icons.paint(g, currency, pad - 2, (h - ICON) / 2, ICON, this);
|
||||
int tx = pad + ICON + 6;
|
||||
|
||||
Font bold = FontManager.getRunescapeBoldFont();
|
||||
Font small = FontManager.getRunescapeSmallFont();
|
||||
g.setFont(bold);
|
||||
FontMetrics bfm = g.getFontMetrics();
|
||||
String value = CurrencyCard.number(Math.max(0, amount));
|
||||
int line1 = 5 + bfm.getAscent();
|
||||
g.setColor(Ui.GOLD);
|
||||
Ui.drawRight(g, value, w - pad, line1);
|
||||
|
||||
g.setFont(FontManager.getRunescapeFont());
|
||||
FontMetrics nfm = g.getFontMetrics();
|
||||
g.setColor(Ui.TEXT);
|
||||
int nameMax = w - pad - bfm.stringWidth(value) - 8 - tx;
|
||||
g.drawString(clip(nfm, currency.label, nameMax), tx, line1);
|
||||
|
||||
g.setFont(small);
|
||||
FontMetrics sfm = g.getFontMetrics();
|
||||
int line2 = line1 + sfm.getAscent() + 6;
|
||||
String plus = "+" + CurrencyCard.number(earned);
|
||||
g.setColor(earned > 0 ? Ui.UP : Ui.FAINT);
|
||||
g.drawString(plus, tx, line2);
|
||||
int x = tx + sfm.stringWidth(plus);
|
||||
if (spent < 0)
|
||||
{
|
||||
String minus = " -" + CurrencyCard.number(-spent);
|
||||
g.setColor(Ui.DOWN);
|
||||
g.drawString(minus, x, line2);
|
||||
x += sfm.stringWidth(minus);
|
||||
}
|
||||
g.setColor(Ui.FAINT);
|
||||
g.drawString(" " + filter.getLabel(), x, line2);
|
||||
g.setColor(active ? Ui.UP : Ui.FAINT);
|
||||
Ui.drawRight(g, active ? "now" : lastGain > 0 ? CurrencyCard.ago(lastGain) : "", w - pad, line2);
|
||||
g.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static String clip(FontMetrics fm, String s, int max)
|
||||
{
|
||||
if (fm.stringWidth(s) <= max)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
for (int i = s.length() - 1; i > 0; i--)
|
||||
{
|
||||
String t = s.substring(0, i) + "..";
|
||||
if (fm.stringWidth(t) <= max)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
/** Coalesced refresh from any thread. */
|
||||
public void refreshLater()
|
||||
{
|
||||
SwingUtilities.invokeLater(this::refresh);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user