Hiscore Plugin redesign

Overall:
- Applied new colors, positions and sizes, following issue #1342.

Search:
- Applied the new IconTextField, with search, error and loading
indicator (and respective image files).
- Blocked tabs witching while results are loading.

Endpoints:
- Moved the endpoints to right below the search bar (this follows
a more logical sequence of usage).
- Changed the endpoint presentation style and size. The selected
endpoint now displays a orange underline.
- Edited the endpoint icons to better fit the visual context.
- Changed the way currently selected endpoint is stored.

Stats:
- Changed the sizing of the labels/panels.
- Changed the font to a smaller version.

Total/Combat:
- Switched the order of the combat and total indicator
- Changed the font to a smaller version.

Clues/Minigames:
- Changed the font to a smaller version.

Details Panel:
- Completely removed the details panel, instead went for a more
in-line with the game approach, tooltips!
- Rewrote the way skills and labels are matched
- Added html progress bar to the next level
This commit is contained in:
Ruben Amendoeira
2018-04-22 04:39:05 +01:00
parent ab7e969320
commit d0f708e26a
8 changed files with 374 additions and 325 deletions

View File

@@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2017, Adam <Adam@sigterm.info> * Copyright (c) 2017, Adam <Adam@sigterm.info>
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -25,10 +26,8 @@
package net.runelite.client.plugins.hiscore; package net.runelite.client.plugins.hiscore;
import com.google.common.base.Strings; import com.google.common.base.Strings;
import java.awt.BorderLayout; import com.google.common.collect.ImmutableList;
import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; import java.awt.GridBagLayout;
import java.awt.GridLayout; import java.awt.GridLayout;
@@ -39,29 +38,22 @@ import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.inject.Inject; import javax.inject.Inject;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JProgressBar; import javax.swing.border.EmptyBorder;
import javax.swing.JTextArea; import javax.swing.border.MatteBorder;
import javax.swing.JToggleButton;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.event.MouseInputAdapter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.Experience; import net.runelite.api.Experience;
import net.runelite.api.Player; import net.runelite.api.Player;
import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.PluginPanel; import net.runelite.client.ui.PluginPanel;
import net.runelite.client.ui.components.IconTextField; import net.runelite.client.ui.components.IconTextField;
import net.runelite.client.util.StackFormatter; import net.runelite.client.util.StackFormatter;
@@ -102,13 +94,17 @@ import net.runelite.http.api.hiscore.Skill;
@Slf4j @Slf4j
public class HiscorePanel extends PluginPanel public class HiscorePanel extends PluginPanel
{ {
private static final String SKILL_NAME = "SKILL_NAME"; /* The maximum allowed username length in runescape accounts */
private static final String SKILL = "SKILL"; private static final int MAX_USERNAME_LENGTH = 12;
private static final ImageIcon SEARCH_ICON;
private static final ImageIcon LOADING_ICON;
private static final ImageIcon ERROR_ICON;
/** /**
* Real skills, ordered in the way they should be displayed in the panel. * Real skills, ordered in the way they should be displayed in the panel.
*/ */
private static final Set<HiscoreSkill> SKILLS = new LinkedHashSet<>(Arrays.asList( private static final List<HiscoreSkill> SKILLS = ImmutableList.of(
ATTACK, HITPOINTS, MINING, ATTACK, HITPOINTS, MINING,
STRENGTH, AGILITY, SMITHING, STRENGTH, AGILITY, SMITHING,
DEFENCE, HERBLORE, FISHING, DEFENCE, HERBLORE, FISHING,
@@ -117,7 +113,7 @@ public class HiscorePanel extends PluginPanel
MAGIC, FLETCHING, WOODCUTTING, MAGIC, FLETCHING, WOODCUTTING,
RUNECRAFT, SLAYER, FARMING, RUNECRAFT, SLAYER, FARMING,
CONSTRUCTION, HUNTER CONSTRUCTION, HUNTER
)); );
@Inject @Inject
ScheduledExecutorService executor; ScheduledExecutorService executor;
@@ -132,24 +128,45 @@ public class HiscorePanel extends PluginPanel
private final List<JLabel> skillLabels = new ArrayList<>(); private final List<JLabel> skillLabels = new ArrayList<>();
private final JPanel statsPanel = new JPanel(); private final JPanel statsPanel = new JPanel();
private final ButtonGroup endpointButtonGroup = new ButtonGroup();
private final JTextArea details = new JTextArea();
private final JProgressBar progressBar;
private List<JToggleButton> endpointButtons; /* A list of all the selectable endpoints (ironman, deadman, etc) */
private final List<JPanel> endPoints = new ArrayList<>();
private final HiscoreClient hiscoreClient = new HiscoreClient(); private final HiscoreClient hiscoreClient = new HiscoreClient();
private HiscoreResult result; private HiscoreResult result;
/* The currently selected endpoint */
private HiscoreEndpoint selectedEndPoint;
/* Used to prevent users from switching endpoint tabs while the results are loading */
private boolean loading = false;
static
{
try
{
synchronized (ImageIO.class)
{
SEARCH_ICON = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("search.png")));
LOADING_ICON = new ImageIcon(IconTextField.class.getResource("loading_spinner_darker.gif"));
ERROR_ICON = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("error.png")));
}
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
@Inject @Inject
public HiscorePanel(HiscoreConfig config) public HiscorePanel(HiscoreConfig config)
{ {
super(); super();
this.config = config; this.config = config;
// Panel "constants" setBorder(new EmptyBorder(10, 10, 0, 10));
// This was an EtchedBorder, but the style would change when the window was maximized. setBackground(ColorScheme.DARK_GRAY_COLOR);
Border subPanelBorder = BorderFactory.createLineBorder(this.getBackground().brighter(), 2);
// Create GBL to arrange sub items // Create GBL to arrange sub items
GridBagLayout gridBag = new GridBagLayout(); GridBagLayout gridBag = new GridBagLayout();
@@ -160,28 +177,11 @@ public class HiscorePanel extends PluginPanel
c.fill = GridBagConstraints.HORIZONTAL; c.fill = GridBagConstraints.HORIZONTAL;
c.anchor = GridBagConstraints.NORTH; c.anchor = GridBagConstraints.NORTH;
// Search box
JPanel inputPanel = new JPanel();
inputPanel.setLayout(new BorderLayout(7, 7));
inputPanel.setBorder(subPanelBorder);
ImageIcon search;
try
{
BufferedImage icon;
synchronized (ImageIO.class)
{
icon = ImageIO.read(HiscorePanel.class.getResourceAsStream("search.png"));
}
search = new ImageIcon(icon);
}
catch (IOException ex)
{
throw new RuntimeException(ex);
}
input = new IconTextField(); input = new IconTextField();
input.setIcon(search); input.setPreferredSize(new Dimension(100, 30));
input.setBackground(ColorScheme.DARKER_GRAY_COLOR);
input.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR);
input.setIcon(SEARCH_ICON);
input.addActionListener(e -> executor.execute(this::lookup)); input.addActionListener(e -> executor.execute(this::lookup));
input.addMouseListener(new MouseAdapter() input.addMouseListener(new MouseAdapter()
{ {
@@ -192,7 +192,6 @@ public class HiscorePanel extends PluginPanel
{ {
return; return;
} }
if (client == null) if (client == null)
{ {
return; return;
@@ -206,97 +205,20 @@ public class HiscorePanel extends PluginPanel
} }
} }
}); });
inputPanel.add(input, BorderLayout.CENTER);
c.gridx = 0; c.gridx = 0;
c.gridy = 0; c.gridy = 0;
c.weightx = 1; c.weightx = 1;
c.weighty = 0; c.weighty = 0;
c.insets = new Insets(0, 0, 3, 0); c.insets = new Insets(0, 0, 10, 0);
gridBag.setConstraints(inputPanel, c); gridBag.setConstraints(input, c);
add(inputPanel); add(input);
// Panel that holds skill icons
GridLayout stats = new GridLayout(8, 3);
statsPanel.setLayout(stats);
statsPanel.setBorder(subPanelBorder);
// For each skill on the ingame skill panel, create a Label and add it to the UI
for (HiscoreSkill skill : SKILLS)
{
JPanel panel = makeSkillPanel(skill.getName(), skill);
statsPanel.add(panel);
}
c.gridx = 0;
c.gridy = 1;
gridBag.setConstraints(statsPanel, c);
add(statsPanel);
JPanel totalPanel = new JPanel();
totalPanel.setBorder(subPanelBorder);
totalPanel.setLayout(new GridLayout(1, 2));
totalPanel.add(makeSkillPanel(OVERALL.getName(), OVERALL));
totalPanel.add(makeSkillPanel("Combat", null));
c.gridx = 0;
c.gridy = 2;
gridBag.setConstraints(totalPanel, c);
add(totalPanel);
JPanel minigamePanel = new JPanel();
minigamePanel.setBorder(subPanelBorder);
// These aren't all on one row because when there's a label with four or more digits it causes the details
// panel to change its size for some reason...
minigamePanel.setLayout(new GridLayout(2, 3));
minigamePanel.add(makeSkillPanel(CLUE_SCROLL_ALL.getName(), CLUE_SCROLL_ALL));
minigamePanel.add(makeSkillPanel(LAST_MAN_STANDING.getName(), LAST_MAN_STANDING));
minigamePanel.add(makeSkillPanel(BOUNTY_HUNTER_ROGUE.getName(), BOUNTY_HUNTER_ROGUE));
minigamePanel.add(makeSkillPanel(BOUNTY_HUNTER_HUNTER.getName(), BOUNTY_HUNTER_HUNTER));
c.gridx = 0;
c.gridy = 3;
gridBag.setConstraints(minigamePanel, c);
add(minigamePanel);
JPanel detailsPanel = new JPanel();
detailsPanel.setBorder(subPanelBorder);
detailsPanel.setLayout(new BorderLayout());
// Rather than using one JLabel for each line, make a JTextArea look and act like a JLabel
details.setEditable(false);
details.setCursor(null);
details.setOpaque(false);
details.setFocusable(false);
details.setWrapStyleWord(true);
details.setLineWrap(true);
details.setMargin(new Insets(2, 4, 4, 4));
details.setRows(6);
details.setText("");
detailsPanel.add(details, BorderLayout.CENTER);
progressBar = new JProgressBar();
progressBar.setStringPainted(true);
progressBar.setValue(0);
progressBar.setMinimum(0);
progressBar.setMaximum(100);
progressBar.setBackground(Color.RED);
progressBar.setVisible(false);
detailsPanel.add(progressBar, BorderLayout.SOUTH);
c.gridx = 0;
c.gridy = 4;
gridBag.setConstraints(detailsPanel, c);
add(detailsPanel);
/* The container for all the endpoint selectors */
JPanel endpointPanel = new JPanel(); JPanel endpointPanel = new JPanel();
endpointPanel.setBorder(subPanelBorder); endpointPanel.setOpaque(false);
endpointPanel.setLayout(new GridLayout(1, 5, 7, 1));
endpointButtons = new ArrayList<>();
for (HiscoreEndpoint endpoint : HiscoreEndpoint.values()) for (HiscoreEndpoint endpoint : HiscoreEndpoint.values())
{ {
try try
@@ -307,25 +229,32 @@ public class HiscorePanel extends PluginPanel
iconImage = ImageIO.read(HiscorePanel.class.getResourceAsStream( iconImage = ImageIO.read(HiscorePanel.class.getResourceAsStream(
endpoint.name().toLowerCase() + ".png")); endpoint.name().toLowerCase() + ".png"));
} }
JToggleButton button = new JToggleButton();
button.setIcon(new ImageIcon(iconImage)); JPanel panel = new JPanel();
button.setPreferredSize(new Dimension(24, 24)); JLabel label = new JLabel();
button.setBackground(Color.WHITE);
button.setFocusPainted(false); label.setIcon(new ImageIcon(iconImage));
button.setActionCommand(endpoint.name());
button.setToolTipText(endpoint.getName() + " Hiscores"); panel.add(label);
button.addActionListener((e -> executor.execute(this::lookup))); panel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
button.addMouseListener(new MouseAdapter() panel.setToolTipText(endpoint.getName() + " Hiscores");
panel.addMouseListener(new MouseAdapter()
{ {
@Override @Override
public void mouseReleased(MouseEvent e) public void mouseClicked(MouseEvent e)
{ {
if (loading)
{
return;
}
executor.execute(HiscorePanel.this::lookup);
selectedEndPoint = endpoint;
updateButtons(); updateButtons();
} }
}); });
endpointButtons.add(button);
endpointButtonGroup.add(button); endPoints.add(panel);
endpointPanel.add(button); endpointPanel.add(panel);
} }
catch (IOException ex) catch (IOException ex)
{ {
@@ -333,156 +262,61 @@ public class HiscorePanel extends PluginPanel
} }
} }
endpointButtons.get(0).setSelected(true); /* Default endpoint is the general (normal) endpoint */
endpointButtons.get(0).setBackground(Color.CYAN); selectedEndPoint = HiscoreEndpoint.NORMAL;
updateButtons();
c.gridx = 0; c.gridx = 0;
c.gridy = 5; c.gridy = 1;
// Last item has a nonzero weighty so it will expand to fill vertical space
c.weighty = 1;
gridBag.setConstraints(endpointPanel, c); gridBag.setConstraints(endpointPanel, c);
add(endpointPanel); add(endpointPanel);
}
void addInputKeyListener(KeyListener l) // Panel that holds skill icons
{ GridLayout stats = new GridLayout(8, 3);
this.input.addKeyListener(l); statsPanel.setLayout(stats);
} statsPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
statsPanel.setBorder(new EmptyBorder(5, 0, 5, 0));
void removeInputKeyListener(KeyListener l) // For each skill on the ingame skill panel, create a Label and add it to the UI
{ for (HiscoreSkill skill : SKILLS)
this.input.removeKeyListener(l);
}
private void changeDetail(String skillName, HiscoreSkill skill)
{
if (result == null || result.getPlayer() == null)
{ {
return; JPanel panel = makeSkillPanel(skill);
panel.setOpaque(false);
statsPanel.add(panel);
} }
String text; c.gridx = 0;
int progress = -1; c.gridy = 2;
switch (skillName) gridBag.setConstraints(statsPanel, c);
{ add(statsPanel);
case "Combat":
{
double combatLevel = Experience.getCombatLevelPrecise(
result.getAttack().getLevel(),
result.getStrength().getLevel(),
result.getDefence().getLevel(),
result.getHitpoints().getLevel(),
result.getMagic().getLevel(),
result.getRanged().getLevel(),
result.getPrayer().getLevel()
);
text = "Skill: Combat" + System.lineSeparator()
+ "Exact Combat Level: " + StackFormatter.formatNumber(combatLevel) + System.lineSeparator()
+ "Experience: " + StackFormatter.formatNumber(result.getAttack().getExperience()
+ result.getStrength().getExperience() + result.getDefence().getExperience()
+ result.getHitpoints().getExperience() + result.getMagic().getExperience()
+ result.getRanged().getExperience() + result.getPrayer().getExperience());
break;
}
case "Clue Scrolls (all)":
{
String allRank = (result.getClueScrollAll().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollAll().getRank());
String easyRank = (result.getClueScrollEasy().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollEasy().getRank());
String mediumRank = (result.getClueScrollMedium().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollMedium().getRank());
String hardRank = (result.getClueScrollHard().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollHard().getRank());
String eliteRank = (result.getClueScrollElite().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollElite().getRank());
String masterRank = (result.getClueScrollMaster().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollMaster().getRank());
String all = (result.getClueScrollAll().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollAll().getLevel()));
String easy = (result.getClueScrollEasy().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollEasy().getLevel()));
String medium = (result.getClueScrollMedium().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollMedium().getLevel()));
String hard = (result.getClueScrollHard().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollHard().getLevel()));
String elite = (result.getClueScrollElite().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollElite().getLevel()));
String master = (result.getClueScrollMaster().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollMaster().getLevel()));
text = "All clues: " + all + " | Rank: " + allRank + System.lineSeparator()
+ "Easy: " + easy + " | Rank: " + easyRank + System.lineSeparator()
+ "Medium: " + medium + " | Rank: " + mediumRank + System.lineSeparator()
+ "Hard: " + hard + " | Rank: " + hardRank + System.lineSeparator()
+ "Elite: " + elite + " | Rank: " + eliteRank + System.lineSeparator()
+ "Master: " + master + " | Rank: " + masterRank;
break;
}
case "Bounty Hunter - Rogue":
{
String rank = (result.getBountyHunterRogue().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getBountyHunterRogue().getRank());
text = "Bounty Hunter - Rogue Kills" + System.lineSeparator()
+ "Rank: " + rank;
break;
}
case "Bounty Hunter - Hunter":
{
String rank = (result.getBountyHunterHunter().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getBountyHunterHunter().getRank());
text = "Bounty Hunter - Hunter Kills" + System.lineSeparator()
+ "Rank: " + rank;
break;
}
case "Last Man Standing":
{
String rank = (result.getLastManStanding().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getLastManStanding().getRank());
text = "Last Man Standing" + System.lineSeparator()
+ "Rank: " + rank;
break;
}
case "Overall":
{
Skill requestedSkill = result.getSkill(skill);
String rank = (requestedSkill.getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(requestedSkill.getRank());
String exp = (requestedSkill.getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(requestedSkill.getExperience());
text = "Skill: " + skillName + System.lineSeparator()
+ "Rank: " + rank + System.lineSeparator()
+ "Experience: " + exp;
break;
}
default:
{
Skill requestedSkill = result.getSkill(skill);
String rank = (requestedSkill.getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(requestedSkill.getRank());
String exp = (requestedSkill.getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(requestedSkill.getExperience());
String remainingXp;
if (requestedSkill.getRank() == -1)
{
remainingXp = "Unranked";
}
else
{
int currentLevel = Experience.getLevelForXp((int) requestedSkill.getExperience());
int currentXp = (int) requestedSkill.getExperience();
int xpForCurrentLevel = Experience.getXpForLevel(currentLevel);
int xpForNextLevel = currentLevel + 1 <= Experience.MAX_VIRT_LEVEL ? Experience.getXpForLevel(currentLevel + 1) : -1;
remainingXp = xpForNextLevel != -1 ? StackFormatter.formatNumber(xpForNextLevel - currentXp) : "0"; JPanel totalPanel = new JPanel();
totalPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
totalPanel.setLayout(new GridLayout(1, 2));
double xpGained = currentXp - xpForCurrentLevel; totalPanel.add(makeSkillPanel(null)); //combat has no hiscore skill, refered to as null
double xpGoal = xpForNextLevel != -1 ? xpForNextLevel - xpForCurrentLevel : 100; totalPanel.add(makeSkillPanel(OVERALL));
progress = (int) ((xpGained / xpGoal) * 100f);
} c.gridx = 0;
text = "Skill: " + skillName + System.lineSeparator() c.gridy = 3;
+ "Rank: " + rank + System.lineSeparator() gridBag.setConstraints(totalPanel, c);
+ "Experience: " + exp + System.lineSeparator() add(totalPanel);
+ "Remaining XP: " + remainingXp;
break;
}
}
details.setFont(UIManager.getFont("Label.font")); JPanel minigamePanel = new JPanel();
details.setText(text); // These aren't all on one row because when there's a label with four or more digits it causes the details
// panel to change its size for some reason...
minigamePanel.setLayout(new GridLayout(2, 3));
minigamePanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
if (progress >= 0) minigamePanel.add(makeSkillPanel(CLUE_SCROLL_ALL));
{ minigamePanel.add(makeSkillPanel(LAST_MAN_STANDING));
progressBar.setVisible(true); minigamePanel.add(makeSkillPanel(BOUNTY_HUNTER_ROGUE));
progressBar.setValue(progress); minigamePanel.add(makeSkillPanel(BOUNTY_HUNTER_HUNTER));
progressBar.setBackground(Color.getHSBColor((progress / 100.f) * (120.f / 360.f), 1, 1));
}
else
{
progressBar.setVisible(false);
}
c.gridx = 0;
c.gridy = 4;
gridBag.setConstraints(minigamePanel, c);
add(minigamePanel);
} }
@Override @Override
@@ -492,16 +326,14 @@ public class HiscorePanel extends PluginPanel
input.requestFocusInWindow(); input.requestFocusInWindow();
} }
private JPanel makeSkillPanel(String skillName, HiscoreSkill skill) /* Builds a JPanel displaying an icon and level/number associated with it */
private JPanel makeSkillPanel(HiscoreSkill skill)
{ {
JLabel label = new JLabel(); JLabel label = new JLabel();
label.setFont(FontManager.getRunescapeSmallFont());
label.setText("--"); label.setText("--");
// Store the skill that the label displays so we can tell them apart String skillIcon = "skill_icons_small/" + (skill == null ? "combat" : skill.getName().toLowerCase()) + ".png";
label.putClientProperty(SKILL_NAME, skillName);
label.putClientProperty(SKILL, skill);
String skillIcon = "skill_icons_small/" + skillName.toLowerCase() + ".png";
log.debug("Loading skill icon from {}", skillIcon); log.debug("Loading skill icon from {}", skillIcon);
try try
@@ -518,36 +350,31 @@ public class HiscorePanel extends PluginPanel
log.warn(null, ex); log.warn(null, ex);
} }
// Show skill details on hover boolean totalLabel = skill == HiscoreSkill.OVERALL || skill == null; //overall or combat
label.addMouseListener(new MouseInputAdapter() label.setIconTextGap(totalLabel ? 10 : 4);
{
@Override
public void mouseEntered(MouseEvent e)
{
JLabel source = (JLabel) e.getSource();
String skillName = (String) source.getClientProperty(SKILL_NAME);
HiscoreSkill skill = (HiscoreSkill) label.getClientProperty(SKILL);
changeDetail(skillName, skill);
}
});
skillLabels.add(label);
JPanel skillPanel = new JPanel(); JPanel skillPanel = new JPanel();
skillPanel.setOpaque(false);
skillPanel.setBorder(new EmptyBorder(2, 0, 2, 0));
skillLabels.add(label);
skillPanel.add(skillLabels.get(skillLabels.size() - 1)); skillPanel.add(skillLabels.get(skillLabels.size() - 1));
return skillPanel; return skillPanel;
} }
public void lookup(String username) public void lookup(String username)
{ {
input.setText(username); input.setText(username);
selectedEndPoint = HiscoreEndpoint.NORMAL; //reset the endpoint to regular player
updateButtons();
lookup(); lookup();
} }
private void lookup() private void lookup()
{ {
String lookup = input.getText(); String lookup = input.getText();
details.setText("Loading...");
progressBar.setVisible(false);
lookup = sanitize(lookup); lookup = sanitize(lookup);
@@ -556,32 +383,66 @@ public class HiscorePanel extends PluginPanel
return; return;
} }
/* Runescape usernames can't be longer than 12 characters long */
if (lookup.length() > MAX_USERNAME_LENGTH)
{
input.setIcon(ERROR_ICON);
loading = false;
return;
}
input.setEditable(false);
input.setIcon(LOADING_ICON);
loading = true;
for (JLabel label : skillLabels) for (JLabel label : skillLabels)
{ {
label.setText("--"); label.setText("--");
} }
// if for some reason no endpoint was selected, default to normal
if (selectedEndPoint == null)
{
selectedEndPoint = HiscoreEndpoint.NORMAL;
}
try try
{ {
HiscoreEndpoint endpoint = HiscoreEndpoint.valueOf(endpointButtonGroup.getSelection().getActionCommand()); log.debug("Hiscore endpoint " + selectedEndPoint.name() + " selected");
log.debug("Hiscore endpoint " + endpoint.name() + " selected"); result = hiscoreClient.lookup(lookup, selectedEndPoint);
result = hiscoreClient.lookup(lookup, endpoint);
} }
catch (IOException ex) catch (IOException ex)
{ {
log.warn("Error fetching Hiscore data " + ex.getMessage()); log.warn("Error fetching Hiscore data " + ex.getMessage());
details.setText("Error fetching Hiscore data"); input.setIcon(ERROR_ICON);
progressBar.setVisible(false); input.setEditable(true);
loading = false;
return; return;
} }
/*
For some reason, the fetch results would sometimes return a not null object
with all null attributes, to check for that, i'll just null check one of the attributes.
*/
if (result.getAttack() == null)
{
input.setIcon(ERROR_ICON);
input.setEditable(true);
loading = false;
return;
}
//successful player search
input.setIcon(SEARCH_ICON);
input.setEditable(true);
loading = false;
int index = 0;
for (JLabel label : skillLabels) for (JLabel label : skillLabels)
{ {
String skillName = (String) label.getClientProperty(SKILL_NAME); HiscoreSkill skill = find(index);
HiscoreSkill skill = (HiscoreSkill) label.getClientProperty(SKILL);
if (skillName.equals("Combat")) if (skill == null)
{ {
if (result.getPlayer() != null) if (result.getPlayer() != null)
{ {
@@ -600,7 +461,6 @@ public class HiscorePanel extends PluginPanel
else if (result.getSkill(skill) != null && result.getSkill(skill).getRank() != -1) else if (result.getSkill(skill) != null && result.getSkill(skill).getRank() != -1)
{ {
Skill s = result.getSkill(skill); Skill s = result.getSkill(skill);
int level; int level;
if (config.virtualLevels() && SKILLS.contains(skill)) if (config.virtualLevels() && SKILLS.contains(skill))
{ {
@@ -613,12 +473,191 @@ public class HiscorePanel extends PluginPanel
label.setText(Integer.toString(level)); label.setText(Integer.toString(level));
} }
label.setToolTipText(detailsHtml(skill));
index++;
}
}
void addInputKeyListener(KeyListener l)
{
this.input.addInputKeyListener(l);
}
void removeInputKeyListener(KeyListener l)
{
this.input.removeInputKeyListener(l);
}
/*
Returns a hiscore skill based on it's display order.
*/
private HiscoreSkill find(int index)
{
if (index < SKILLS.size())
{
return SKILLS.get(index);
} }
// Clear details panel switch (index - SKILLS.size())
details.setFont(UIManager.getFont("Label.font").deriveFont(Font.ITALIC)); {
details.setText("Hover over a skill for details"); case 0:
progressBar.setVisible(false); return null;
case 1:
return HiscoreSkill.OVERALL;
case 2:
return HiscoreSkill.CLUE_SCROLL_ALL;
case 3:
return HiscoreSkill.LAST_MAN_STANDING;
case 4:
return HiscoreSkill.BOUNTY_HUNTER_ROGUE;
case 5:
return HiscoreSkill.BOUNTY_HUNTER_HUNTER;
}
return null;
}
/*
Builds a html string to display on tooltip (when hovering a skill).
*/
private String detailsHtml(HiscoreSkill skill)
{
String openingTags = "<html><body style = 'padding: 5px;color:#989898'>";
String closingTags = "</html><body>";
String content = "";
if (result != null)
{
if (skill == null)
{
double combatLevel = Experience.getCombatLevelPrecise(
result.getAttack().getLevel(),
result.getStrength().getLevel(),
result.getDefence().getLevel(),
result.getHitpoints().getLevel(),
result.getMagic().getLevel(),
result.getRanged().getLevel(),
result.getPrayer().getLevel()
);
double combatExperience = result.getAttack().getExperience()
+ result.getStrength().getExperience() + result.getDefence().getExperience()
+ result.getHitpoints().getExperience() + result.getMagic().getExperience()
+ result.getRanged().getExperience() + result.getPrayer().getExperience();
content += "<p><span style = 'color:white'>Skill:</span> Combat</p>";
content += "<p><span style = 'color:white'>Exact Combat Level:</span> " + StackFormatter.formatNumber(combatLevel) + "</p>";
content += "<p><span style = 'color:white'>Experience:</span> " + StackFormatter.formatNumber(combatExperience) + "</p>";
}
else
{
switch (skill)
{
case CLUE_SCROLL_ALL:
{
String rank = (result.getClueScrollAll().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollAll().getRank());
String allRank = (result.getClueScrollAll().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollAll().getRank());
String easyRank = (result.getClueScrollEasy().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollEasy().getRank());
String mediumRank = (result.getClueScrollMedium().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollMedium().getRank());
String hardRank = (result.getClueScrollHard().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollHard().getRank());
String eliteRank = (result.getClueScrollElite().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollElite().getRank());
String masterRank = (result.getClueScrollMaster().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getClueScrollMaster().getRank());
String all = (result.getClueScrollAll().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollAll().getLevel()));
String easy = (result.getClueScrollEasy().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollEasy().getLevel()));
String medium = (result.getClueScrollMedium().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollMedium().getLevel()));
String hard = (result.getClueScrollHard().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollHard().getLevel()));
String elite = (result.getClueScrollElite().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollElite().getLevel()));
String master = (result.getClueScrollMaster().getLevel() == -1 ? "0" : StackFormatter.formatNumber(result.getClueScrollMaster().getLevel()));
content += "<p><span style = 'color:white'>All:</span> " + all + " <span style = 'color:white'>Rank:</span> " + allRank + "</p>";
content += "<p><span style = 'color:white'>Easy:</span> " + easy + " <span style = 'color:white'>Rank:</span> " + easyRank + "</p>";
content += "<p><span style = 'color:white'>Medium:</span> " + medium + " <span style = 'color:white'>Rank:</span> " + mediumRank + "</p>";
content += "<p><span style = 'color:white'>Hard:</span> " + hard + " <span style = 'color:white'>Rank:</span> " + hardRank + "</p>";
content += "<p><span style = 'color:white'>Elite:</span> " + elite + " <span style = 'color:white'>Rank:</span> " + eliteRank + "</p>";
content += "<p><span style = 'color:white'>Master:</span> " + master + " <span style = 'color:white'>Rank:</span> " + masterRank + "</p>";
break;
}
case BOUNTY_HUNTER_ROGUE:
{
String rank = (result.getBountyHunterRogue().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getBountyHunterRogue().getRank());
content += "<p><span style = 'color:white'>Rank:</span> " + rank + "</p>";
break;
}
case BOUNTY_HUNTER_HUNTER:
{
String rank = (result.getBountyHunterHunter().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getBountyHunterHunter().getRank());
content += "<p><span style = 'color:white'>Rank:</span> " + rank + "</p>";
break;
}
case LAST_MAN_STANDING:
{
String rank = (result.getLastManStanding().getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(result.getLastManStanding().getRank());
content += "<p><span style = 'color:white'>Rank:</span> " + rank + "</p>";
break;
}
case OVERALL:
{
Skill requestedSkill = result.getSkill(skill);
String rank = (requestedSkill.getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(requestedSkill.getRank());
String exp = (requestedSkill.getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(requestedSkill.getExperience());
content += "<p><span style = 'color:white'>Skill:</span> " + skill.getName() + "</p>";
content += "<p><span style = 'color:white'>Rank:</span> " + rank + "</p>";
content += "<p><span style = 'color:white'>Experience:</span> " + exp + "</p>";
break;
}
default:
{
Skill requestedSkill = result.getSkill(skill);
String rank = (requestedSkill.getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(requestedSkill.getRank());
String exp = (requestedSkill.getRank() == -1) ? "Unranked" : StackFormatter.formatNumber(requestedSkill.getExperience());
String remainingXp;
if (requestedSkill.getRank() == -1)
{
remainingXp = "Unranked";
}
else
{
int currentLevel = Experience.getLevelForXp((int) requestedSkill.getExperience());
remainingXp = (currentLevel + 1 <= Experience.MAX_VIRT_LEVEL) ? StackFormatter.formatNumber(Experience.getXpForLevel(currentLevel + 1) - requestedSkill.getExperience()) : "0";
}
content += "<p><span style = 'color:white'>Skill:</span> " + skill.getName() + "</p>";
content += "<p><span style = 'color:white'>Rank:</span> " + rank + "</p>";
content += "<p><span style = 'color:white'>Experience:</span> " + exp + "</p>";
content += "<p><span style = 'color:white'>Remaining XP:</span> " + remainingXp + "</p>";
break;
}
}
}
}
/**
* Adds a html progress bar to the hover information
*/
if (SKILLS.contains(skill))
{
int currentLevel = Experience.getLevelForXp((int) result.getSkill(skill).getExperience());
int currentXp = (int) result.getSkill(skill).getExperience();
int xpForCurrentLevel = Experience.getXpForLevel(currentLevel);
int xpForNextLevel = currentLevel + 1 <= Experience.MAX_VIRT_LEVEL ? Experience.getXpForLevel(currentLevel + 1) : -1;
double xpGained = currentXp - xpForCurrentLevel;
double xpGoal = xpForNextLevel != -1 ? xpForNextLevel - xpForCurrentLevel : 100;
int progress = (int) ((xpGained / xpGoal) * 100f);
// had to wrap the bar with an empty div, if i added the margin directly to the bar, it would mess up
content += "<div style = 'margin-top:3px'>"
+ "<div style = 'background: #070707; border: 1px solid #070707; height: 6px; width: 100%;'>"
+ "<div style = 'height: 6px; width: " + progress + "%; background: #dc8a00;'>"
+ "</div>"
+ "</div>"
+ "</div>";
}
return openingTags + content + closingTags;
} }
private static String sanitize(String lookup) private static String sanitize(String lookup)
@@ -626,20 +665,18 @@ public class HiscorePanel extends PluginPanel
return lookup.replace('\u00A0', ' '); return lookup.replace('\u00A0', ' ');
} }
/*
When an endpoint gets selected, this method will correctly display the selected one
with an orange underline.
*/
private void updateButtons() private void updateButtons()
{ {
for (JToggleButton button : endpointButtons) for (JPanel panel : endPoints)
{ {
Color color; panel.setBorder(new EmptyBorder(0, 0, 1, 0));
if (button.isSelected())
{
color = Color.CYAN;
}
else
{
color = Color.WHITE;
}
button.setBackground(color);
} }
int selectedIndex = selectedEndPoint.ordinal();
endPoints.get(selectedIndex).setBorder(new MatteBorder(0, 0, 1, 0, ColorScheme.BRAND_ORANGE));
} }
} }

View File

@@ -30,6 +30,7 @@ import java.awt.BorderLayout;
import java.awt.Color; import java.awt.Color;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
@@ -129,6 +130,16 @@ public class IconTextField extends JPanel
this.backgroundColor = color; this.backgroundColor = color;
} }
public void addInputKeyListener(KeyListener l)
{
textField.addKeyListener(l);
}
public void removeInputKeyListener(KeyListener l)
{
textField.removeKeyListener(l);
}
public void setHoverBackgroundColor(Color hoverBackgroundColor) public void setHoverBackgroundColor(Color hoverBackgroundColor)
{ {
if (hoverBackgroundColor == null) if (hoverBackgroundColor == null)

View File

@@ -79,6 +79,7 @@ public class SwingUtil
// Force heavy-weight popups/tooltips. // Force heavy-weight popups/tooltips.
// Prevents them from being obscured by the game applet. // Prevents them from being obscured by the game applet.
ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false); ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false);
ToolTipManager.sharedInstance().setInitialDelay(300);
JPopupMenu.setDefaultLightWeightPopupEnabled(false); JPopupMenu.setDefaultLightWeightPopupEnabled(false);
UIManager.put("Button.foreground", Color.WHITE); UIManager.put("Button.foreground", Color.WHITE);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 B

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 307 B

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 388 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 365 B

After

Width:  |  Height:  |  Size: 14 KiB