Merge pull request #1419 from psikoi/color-scheme-orange-dark
"RuneLite Obsidian" Client Redesign
@@ -77,12 +77,12 @@
|
||||
<dependency>
|
||||
<groupId>net.runelite.pushingpixels</groupId>
|
||||
<artifactId>substance</artifactId>
|
||||
<version>8.0.00-dev</version>
|
||||
<version>8.0.02</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.runelite.pushingpixels</groupId>
|
||||
<artifactId>trident</artifactId>
|
||||
<version>1.4</version>
|
||||
<version>1.5.00</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -41,6 +41,8 @@ public class RuneLiteProperties
|
||||
private static final String RUNESCAPE_VERSION = "runescape.version";
|
||||
private static final String DISCORD_APP_ID = "runelite.discord.appid";
|
||||
private static final String DISCORD_INVITE = "runelite.discord.invite";
|
||||
private static final String GITHUB_LINK = "runelite.github.link";
|
||||
private static final String PATREON_LINK = "runelite.patreon.link";
|
||||
|
||||
private final Properties properties = new Properties();
|
||||
|
||||
@@ -82,4 +84,14 @@ public class RuneLiteProperties
|
||||
{
|
||||
return properties.getProperty(DISCORD_INVITE);
|
||||
}
|
||||
}
|
||||
|
||||
public String getGithubLink()
|
||||
{
|
||||
return properties.getProperty(GITHUB_LINK);
|
||||
}
|
||||
|
||||
public String getPatreonLink()
|
||||
{
|
||||
return properties.getProperty(PATREON_LINK);
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,6 @@ import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
@@ -61,6 +60,7 @@ import javax.swing.JTextField;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.ChangeListener;
|
||||
import javax.swing.event.DocumentEvent;
|
||||
import javax.swing.event.DocumentListener;
|
||||
@@ -75,16 +75,22 @@ import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.plugins.PluginInstantiationException;
|
||||
import net.runelite.client.plugins.PluginManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.DynamicGridLayout;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.ui.components.ComboBoxListRenderer;
|
||||
import net.runelite.client.ui.components.IconTextField;
|
||||
|
||||
@Slf4j
|
||||
public class ConfigPanel extends PluginPanel
|
||||
{
|
||||
private static final int TEXT_FIELD_WIDTH = 7;
|
||||
private static final int SPINNER_FIELD_WIDTH = 6;
|
||||
private static BufferedImage CONFIG_ICON;
|
||||
private static BufferedImage UNCHECK_ICON;
|
||||
private static BufferedImage CHECK_ICON;
|
||||
|
||||
private static final ImageIcon CONFIG_ICON;
|
||||
private static final ImageIcon ON_SWITCHER;
|
||||
private static final ImageIcon OFF_SWITCHER;
|
||||
private static final ImageIcon SEARCH;
|
||||
|
||||
static
|
||||
{
|
||||
@@ -92,14 +98,15 @@ public class ConfigPanel extends PluginPanel
|
||||
{
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
CONFIG_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("config_icon.png"));
|
||||
UNCHECK_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("disabled.png"));
|
||||
CHECK_ICON = ImageIO.read(ConfigPanel.class.getResourceAsStream("enabled.png"));
|
||||
CONFIG_ICON = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("config_edit_icon.png")));
|
||||
ON_SWITCHER = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("switchers/on.png")));
|
||||
OFF_SWITCHER = new ImageIcon(ImageIO.read(ConfigPanel.class.getResourceAsStream("switchers/off.png")));
|
||||
SEARCH = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("search.png")));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.warn("Failed to read icon", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +114,7 @@ public class ConfigPanel extends PluginPanel
|
||||
private final ConfigManager configManager;
|
||||
private final ScheduledExecutorService executorService;
|
||||
private final RuneLiteConfig runeLiteConfig;
|
||||
private final JTextField searchBar = new JTextField();
|
||||
private final IconTextField searchBar = new IconTextField();
|
||||
private Map<String, JPanel> children = new TreeMap<>();
|
||||
private int scrollBarPosition = 0;
|
||||
|
||||
@@ -119,6 +126,10 @@ public class ConfigPanel extends PluginPanel
|
||||
this.executorService = executorService;
|
||||
this.runeLiteConfig = runeLiteConfig;
|
||||
|
||||
searchBar.setIcon(SEARCH);
|
||||
searchBar.setPreferredSize(new Dimension(100, 30));
|
||||
searchBar.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
searchBar.setHoverBackgroundColor(ColorScheme.DARK_GRAY_HOVER_COLOR);
|
||||
searchBar.getDocument().addDocumentListener(new DocumentListener()
|
||||
{
|
||||
@Override
|
||||
@@ -140,6 +151,10 @@ public class ConfigPanel extends PluginPanel
|
||||
}
|
||||
});
|
||||
|
||||
setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
setLayout(new DynamicGridLayout(0, 1, 0, 5));
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
rebuildPluginList();
|
||||
openConfigList();
|
||||
}
|
||||
@@ -150,42 +165,54 @@ public class ConfigPanel extends PluginPanel
|
||||
Map<String, JPanel> newChildren = new TreeMap<>();
|
||||
|
||||
pluginManager.getPlugins().stream()
|
||||
.filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).hidden())
|
||||
.sorted(Comparator.comparing(left -> left.getClass().getAnnotation(PluginDescriptor.class).name()))
|
||||
.forEach(plugin ->
|
||||
{
|
||||
final Config pluginConfigProxy = pluginManager.getPluginConfigProxy(plugin);
|
||||
final String pluginName = plugin.getClass().getAnnotation(PluginDescriptor.class).name();
|
||||
.filter(plugin -> !plugin.getClass().getAnnotation(PluginDescriptor.class).hidden())
|
||||
.sorted(Comparator.comparing(left -> left.getClass().getAnnotation(PluginDescriptor.class).name()))
|
||||
.forEach(plugin ->
|
||||
{
|
||||
final Config pluginConfigProxy = pluginManager.getPluginConfigProxy(plugin);
|
||||
final String pluginName = plugin.getClass().getAnnotation(PluginDescriptor.class).name();
|
||||
|
||||
final JPanel groupPanel = buildGroupPanel();
|
||||
groupPanel.add(new JLabel(pluginName), BorderLayout.CENTER);
|
||||
final JPanel groupPanel = buildGroupPanel();
|
||||
|
||||
final JPanel buttonPanel = new JPanel();
|
||||
buttonPanel.setLayout(new GridLayout(1, 2, 3, 0));
|
||||
groupPanel.add(buttonPanel, BorderLayout.LINE_END);
|
||||
JLabel name = new JLabel(pluginName);
|
||||
name.setForeground(Color.WHITE);
|
||||
|
||||
final JButton editConfigButton = buildConfigButton(pluginConfigProxy);
|
||||
buttonPanel.add(editConfigButton);
|
||||
groupPanel.add(name, BorderLayout.CENTER);
|
||||
|
||||
final JButton toggleButton = buildToggleButton(plugin);
|
||||
buttonPanel.add(toggleButton);
|
||||
final JPanel buttonPanel = new JPanel();
|
||||
buttonPanel.setOpaque(false);
|
||||
buttonPanel.setLayout(new GridLayout(1, 2));
|
||||
groupPanel.add(buttonPanel, BorderLayout.LINE_END);
|
||||
|
||||
newChildren.put(pluginName, groupPanel);
|
||||
});
|
||||
final JLabel editConfigButton = buildConfigButton(pluginConfigProxy);
|
||||
buttonPanel.add(editConfigButton);
|
||||
|
||||
final JLabel toggleButton = buildToggleButton(plugin);
|
||||
toggleButton.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
buttonPanel.add(toggleButton);
|
||||
|
||||
newChildren.put(pluginName, groupPanel);
|
||||
});
|
||||
|
||||
final JPanel groupPanel = buildGroupPanel();
|
||||
groupPanel.add(new JLabel("RuneLite"), BorderLayout.CENTER);
|
||||
|
||||
JLabel name = new JLabel("RuneLite");
|
||||
name.setForeground(Color.WHITE);
|
||||
|
||||
groupPanel.add(name, BorderLayout.CENTER);
|
||||
|
||||
final JPanel buttonPanel = new JPanel();
|
||||
buttonPanel.setLayout(new GridLayout(1, 2, 3, 0));
|
||||
buttonPanel.setOpaque(false);
|
||||
buttonPanel.setLayout(new GridLayout(1, 2));
|
||||
groupPanel.add(buttonPanel, BorderLayout.LINE_END);
|
||||
|
||||
final JButton editConfigButton = buildConfigButton(runeLiteConfig);
|
||||
final JLabel editConfigButton = buildConfigButton(runeLiteConfig);
|
||||
buttonPanel.add(editConfigButton);
|
||||
|
||||
final JButton toggleButton = buildToggleButton(null);
|
||||
final JLabel toggleButton = buildToggleButton(null);
|
||||
toggleButton.setVisible(false);
|
||||
buttonPanel.add(toggleButton);
|
||||
|
||||
newChildren.put("RuneLite", groupPanel);
|
||||
|
||||
children = newChildren;
|
||||
@@ -197,15 +224,17 @@ public class ConfigPanel extends PluginPanel
|
||||
// Create base panel for the config button and enabled/disabled button
|
||||
final JPanel groupPanel = new JPanel();
|
||||
groupPanel.setLayout(new BorderLayout(3, 0));
|
||||
groupPanel.setPreferredSize(new Dimension(PluginPanel.PANEL_WIDTH, 20));
|
||||
groupPanel.setOpaque(false);
|
||||
return groupPanel;
|
||||
}
|
||||
|
||||
private JButton buildConfigButton(Config config)
|
||||
private JLabel buildConfigButton(Config config)
|
||||
{
|
||||
// Create edit config button and disable it by default
|
||||
final JButton editConfigButton = new JButton(new ImageIcon(CONFIG_ICON));
|
||||
editConfigButton.setPreferredSize(new Dimension(32, 0));
|
||||
editConfigButton.setEnabled(false);
|
||||
final JLabel editConfigButton = new JLabel(CONFIG_ICON);
|
||||
editConfigButton.setPreferredSize(new Dimension(25, 0));
|
||||
editConfigButton.setVisible(false);
|
||||
|
||||
// If we have configuration proxy enable the button and add edit config listener
|
||||
if (config != null)
|
||||
@@ -215,8 +244,15 @@ public class ConfigPanel extends PluginPanel
|
||||
|
||||
if (!configEmpty)
|
||||
{
|
||||
editConfigButton.addActionListener(ae -> openGroupConfigPanel(config, configDescriptor, configManager));
|
||||
editConfigButton.setEnabled(true);
|
||||
editConfigButton.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
openGroupConfigPanel(config, configDescriptor, configManager);
|
||||
}
|
||||
});
|
||||
editConfigButton.setVisible(true);
|
||||
editConfigButton.setToolTipText("Edit plugin configuration");
|
||||
}
|
||||
}
|
||||
@@ -224,11 +260,11 @@ public class ConfigPanel extends PluginPanel
|
||||
return editConfigButton;
|
||||
}
|
||||
|
||||
private JButton buildToggleButton(Plugin plugin)
|
||||
private JLabel buildToggleButton(Plugin plugin)
|
||||
{
|
||||
// Create enabling/disabling button
|
||||
final JButton toggleButton = new JButton(new ImageIcon(CHECK_ICON));
|
||||
toggleButton.setPreferredSize(new Dimension(32, 0));
|
||||
final JLabel toggleButton = new JLabel(ON_SWITCHER);
|
||||
toggleButton.setPreferredSize(new Dimension(25, 0));
|
||||
|
||||
if (plugin == null)
|
||||
{
|
||||
@@ -238,36 +274,43 @@ public class ConfigPanel extends PluginPanel
|
||||
|
||||
highlightButton(toggleButton, pluginManager.isPluginEnabled(plugin));
|
||||
|
||||
toggleButton.addActionListener(e -> executorService.submit(() ->
|
||||
toggleButton.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
final boolean enabled = pluginManager.isPluginEnabled(plugin);
|
||||
pluginManager.setPluginEnabled(plugin, !enabled);
|
||||
|
||||
try
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
if (enabled)
|
||||
executorService.submit(() ->
|
||||
{
|
||||
pluginManager.stopPlugin(plugin);
|
||||
}
|
||||
else
|
||||
{
|
||||
pluginManager.startPlugin(plugin);
|
||||
}
|
||||
}
|
||||
catch (PluginInstantiationException ex)
|
||||
{
|
||||
log.warn("Error during starting/stopping plugin {}", plugin.getClass().getSimpleName(), ex);
|
||||
}
|
||||
final boolean enabled = pluginManager.isPluginEnabled(plugin);
|
||||
pluginManager.setPluginEnabled(plugin, !enabled);
|
||||
|
||||
highlightButton(toggleButton, !enabled);
|
||||
}));
|
||||
try
|
||||
{
|
||||
if (enabled)
|
||||
{
|
||||
pluginManager.stopPlugin(plugin);
|
||||
}
|
||||
else
|
||||
{
|
||||
pluginManager.startPlugin(plugin);
|
||||
}
|
||||
}
|
||||
catch (PluginInstantiationException ex)
|
||||
{
|
||||
log.warn("Error during starting/stopping plugin {}", plugin.getClass().getSimpleName(), ex);
|
||||
}
|
||||
|
||||
highlightButton(toggleButton, !enabled);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return toggleButton;
|
||||
}
|
||||
|
||||
private void highlightButton(JButton button, boolean enabled)
|
||||
private void highlightButton(JLabel button, boolean enabled)
|
||||
{
|
||||
button.setIcon(enabled ? new ImageIcon(CHECK_ICON) : new ImageIcon(UNCHECK_ICON));
|
||||
button.setIcon(enabled ? ON_SWITCHER : OFF_SWITCHER);
|
||||
button.setToolTipText(enabled ? "Disable plugin" : "Enable plugin");
|
||||
}
|
||||
|
||||
@@ -301,7 +344,11 @@ public class ConfigPanel extends PluginPanel
|
||||
private void openConfigList()
|
||||
{
|
||||
removeAll();
|
||||
add(new JLabel("Plugin Configuration", SwingConstants.CENTER));
|
||||
|
||||
JLabel title = new JLabel("Configuration", SwingConstants.LEFT);
|
||||
title.setForeground(Color.WHITE);
|
||||
|
||||
add(title);
|
||||
add(searchBar);
|
||||
|
||||
onSearchBarChanged();
|
||||
@@ -331,6 +378,7 @@ public class ConfigPanel extends PluginPanel
|
||||
if (component instanceof JCheckBox)
|
||||
{
|
||||
JCheckBox checkbox = (JCheckBox) component;
|
||||
checkbox.setOpaque(false);
|
||||
configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), "" + checkbox.isSelected());
|
||||
}
|
||||
|
||||
@@ -355,6 +403,8 @@ public class ConfigPanel extends PluginPanel
|
||||
if (component instanceof JComboBox)
|
||||
{
|
||||
JComboBox jComboBox = (JComboBox) component;
|
||||
jComboBox.setRenderer(new ComboBoxListRenderer());
|
||||
jComboBox.setForeground(Color.WHITE);
|
||||
configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), ((Enum) jComboBox.getSelectedItem()).name());
|
||||
}
|
||||
}
|
||||
@@ -376,6 +426,7 @@ public class ConfigPanel extends PluginPanel
|
||||
}
|
||||
|
||||
JPanel item = new JPanel();
|
||||
item.setOpaque(false);
|
||||
item.setLayout(new BorderLayout());
|
||||
name = cid.getItem().name();
|
||||
JLabel configEntryName = new JLabel(name);
|
||||
@@ -385,6 +436,8 @@ public class ConfigPanel extends PluginPanel
|
||||
if (cid.getType() == boolean.class)
|
||||
{
|
||||
JCheckBox checkbox = new JCheckBox();
|
||||
checkbox.setOpaque(false);
|
||||
checkbox.setBackground(ColorScheme.LIGHT_GRAY_COLOR);
|
||||
checkbox.setSelected(Boolean.parseBoolean(configManager.getConfiguration(cd.getGroup().keyName(), cid.getItem().keyName())));
|
||||
checkbox.addActionListener(ae -> changeConfiguration(config, checkbox, cd, cid));
|
||||
|
||||
@@ -462,6 +515,7 @@ public class ConfigPanel extends PluginPanel
|
||||
if (cid.getType() == Dimension.class)
|
||||
{
|
||||
JPanel dimensionPanel = new JPanel();
|
||||
dimensionPanel.setOpaque(false);
|
||||
dimensionPanel.setLayout(new BorderLayout());
|
||||
|
||||
String str = configManager.getConfiguration(cd.getGroup().keyName(), cid.getItem().keyName());
|
||||
@@ -482,7 +536,7 @@ public class ConfigPanel extends PluginPanel
|
||||
heightSpinnerTextField.setColumns(4);
|
||||
|
||||
ChangeListener listener = e ->
|
||||
configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), widthSpinner.getValue() + "x" + heightSpinner.getValue());
|
||||
configManager.setConfiguration(cd.getGroup().keyName(), cid.getItem().keyName(), widthSpinner.getValue() + "x" + heightSpinner.getValue());
|
||||
|
||||
widthSpinner.addChangeListener(listener);
|
||||
heightSpinner.addChangeListener(listener);
|
||||
@@ -498,6 +552,9 @@ public class ConfigPanel extends PluginPanel
|
||||
{
|
||||
Class<? extends Enum> type = (Class<? extends Enum>) cid.getType();
|
||||
JComboBox box = new JComboBox(type.getEnumConstants());
|
||||
box.setPreferredSize(new Dimension(box.getPreferredSize().width, 25));
|
||||
box.setRenderer(new ComboBoxListRenderer());
|
||||
box.setForeground(Color.WHITE);
|
||||
box.setFocusable(false);
|
||||
box.setPrototypeDisplayValue("XXXXXXXX"); //sorry but this is the way to keep the size of the combobox in check.
|
||||
try
|
||||
@@ -541,4 +598,4 @@ public class ConfigPanel extends PluginPanel
|
||||
revalidate();
|
||||
getScrollPane().getVerticalScrollBar().setValue(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,6 +78,7 @@ public class ConfigPlugin extends Plugin
|
||||
navButton = NavigationButton.builder()
|
||||
.name("Configuration")
|
||||
.icon(icon)
|
||||
.priority(0)
|
||||
.panel(configPanel)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ import javax.swing.JButton;
|
||||
import javax.swing.JPanel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
|
||||
@Slf4j
|
||||
@@ -52,6 +53,8 @@ public class DevToolsPanel extends PluginPanel
|
||||
this.plugin = plugin;
|
||||
this.widgetInspector = widgetInspector;
|
||||
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
varTracker = new VarTracker(client);
|
||||
add(createOptionsPanel());
|
||||
}
|
||||
@@ -59,6 +62,7 @@ public class DevToolsPanel extends PluginPanel
|
||||
private JPanel createOptionsPanel()
|
||||
{
|
||||
final JPanel container = new JPanel();
|
||||
container.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
container.setLayout(new GridLayout(0, 2, 3, 3));
|
||||
|
||||
final JButton renderPlayersBtn = new JButton("Players");
|
||||
|
||||
@@ -122,6 +122,7 @@ public class DevToolsPlugin extends Plugin
|
||||
navButton = NavigationButton.builder()
|
||||
.name("Developer Tools")
|
||||
.icon(icon)
|
||||
.priority(1)
|
||||
.panel(panel)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -27,15 +27,16 @@ package net.runelite.client.plugins.farmingtracker;
|
||||
import java.awt.Color;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
public enum CropState
|
||||
{
|
||||
HARVESTABLE(Color.GREEN),
|
||||
GROWING(Color.GREEN),
|
||||
DISEASED(Color.ORANGE),
|
||||
DEAD(Color.RED);
|
||||
HARVESTABLE(ColorScheme.PROGRESS_COMPLETE_COLOR),
|
||||
GROWING(ColorScheme.PROGRESS_COMPLETE_COLOR),
|
||||
DISEASED(ColorScheme.PROGRESS_INPROGRESS_COLOR),
|
||||
DEAD(ColorScheme.PROGRESS_ERROR_COLOR);
|
||||
|
||||
private final Color color;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Abex
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -24,13 +25,19 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.farmingtracker;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.GroupLayout;
|
||||
import java.awt.GridLayout;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.Getter;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.components.ThinProgressBar;
|
||||
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||
|
||||
@Getter
|
||||
class FarmingPatchPanel extends JPanel
|
||||
@@ -38,42 +45,43 @@ class FarmingPatchPanel extends JPanel
|
||||
private final FarmingPatch patch;
|
||||
private final JLabel icon = new JLabel();
|
||||
private final JLabel estimate = new JLabel();
|
||||
private final JProgressBar progress = new JProgressBar();
|
||||
private final ThinProgressBar progress = new ThinProgressBar();
|
||||
|
||||
FarmingPatchPanel(FarmingPatch patch)
|
||||
{
|
||||
this.patch = patch;
|
||||
|
||||
GroupLayout layout = new GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
setLayout(new BorderLayout());
|
||||
setOpaque(false);
|
||||
setBorder(new EmptyBorder(7, 0, 0, 0));
|
||||
|
||||
JPanel topContainer = new JPanel();
|
||||
topContainer.setBorder(new EmptyBorder(7, 7, 6, 0));
|
||||
topContainer.setLayout(new BorderLayout());
|
||||
topContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
final JLabel location = new JLabel(patch.getRegion().getName() + " " + patch.getName());
|
||||
location.setFont(FontManager.getRunescapeSmallFont());
|
||||
icon.setMinimumSize(new Dimension(36, 32));
|
||||
|
||||
layout.setVerticalGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(GroupLayout.Alignment.CENTER)
|
||||
.addComponent(icon)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(1)
|
||||
.addComponent(location)
|
||||
.addGap(1)
|
||||
.addComponent(estimate)
|
||||
)
|
||||
)
|
||||
.addComponent(progress, 8, 8, 8)
|
||||
.addGap(4)
|
||||
);
|
||||
JPanel infoPanel = new JPanel();
|
||||
infoPanel.setOpaque(false);
|
||||
infoPanel.setLayout(new GridLayout(2, 1));
|
||||
infoPanel.setBorder(new EmptyBorder(4, 4, 4, 0));
|
||||
|
||||
layout.setHorizontalGroup(layout.createParallelGroup()
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(icon)
|
||||
.addGroup(layout.createParallelGroup()
|
||||
.addComponent(location)
|
||||
.addComponent(estimate)
|
||||
)
|
||||
)
|
||||
.addComponent(progress)
|
||||
);
|
||||
final JLabel location = new JShadowedLabel(patch.getRegion().getName()
|
||||
+ (Strings.isNullOrEmpty(patch.getName()) ? "" : " (" + patch.getName() + ")"));
|
||||
location.setFont(FontManager.getRunescapeSmallFont());
|
||||
location.setForeground(Color.WHITE);
|
||||
|
||||
estimate.setFont(FontManager.getRunescapeSmallFont());
|
||||
estimate.setForeground(Color.GRAY);
|
||||
|
||||
infoPanel.add(location);
|
||||
infoPanel.add(estimate);
|
||||
|
||||
topContainer.add(icon, BorderLayout.WEST);
|
||||
topContainer.add(infoPanel, BorderLayout.CENTER);
|
||||
|
||||
add(topContainer, BorderLayout.NORTH);
|
||||
add(progress, BorderLayout.SOUTH);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Abex
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -24,11 +25,13 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.farmingtracker;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.Image;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
@@ -37,9 +40,10 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
@@ -47,7 +51,11 @@ import net.runelite.api.vars.Autoweed;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.game.AsyncBufferedImage;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.ui.components.materialtabs.MaterialTab;
|
||||
import net.runelite.client.ui.components.materialtabs.MaterialTabGroup;
|
||||
|
||||
@Slf4j
|
||||
class FarmingTrackerPanel extends PluginPanel
|
||||
@@ -61,6 +69,10 @@ class FarmingTrackerPanel extends PluginPanel
|
||||
|
||||
private List<FarmingPatchPanel> patchPanels = new ArrayList<>();
|
||||
|
||||
/* This is the panel the tabs' respective panels will be displayed on. */
|
||||
private final JPanel display = new JPanel();
|
||||
private final MaterialTabGroup tabGroup = new MaterialTabGroup(display);
|
||||
|
||||
FarmingTrackerPanel(
|
||||
Client client,
|
||||
ItemManager itemManager,
|
||||
@@ -77,11 +89,19 @@ class FarmingTrackerPanel extends PluginPanel
|
||||
this.config = config;
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
display.setOpaque(false);
|
||||
display.setBorder(new EmptyBorder(10, 10, 8, 10));
|
||||
|
||||
tabGroup.setBorder(new EmptyBorder(10, 1, 0, 0));
|
||||
|
||||
add(tabGroup, BorderLayout.NORTH);
|
||||
add(display, BorderLayout.CENTER);
|
||||
|
||||
JTabbedPane tabs = new JTabbedPane();
|
||||
farmingWorld.getTabs().forEach((tab, patches) ->
|
||||
{
|
||||
JPanel panel = new JPanel(new GridBagLayout())
|
||||
JPanel container = new JPanel(new GridBagLayout())
|
||||
{
|
||||
@Override
|
||||
public Dimension getPreferredSize()
|
||||
@@ -89,7 +109,7 @@ class FarmingTrackerPanel extends PluginPanel
|
||||
return new Dimension(PluginPanel.PANEL_WIDTH, super.getPreferredSize().height);
|
||||
}
|
||||
};
|
||||
panel.setBorder(new EmptyBorder(2, 6, 6, 6));
|
||||
container.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
@@ -97,43 +117,82 @@ class FarmingTrackerPanel extends PluginPanel
|
||||
c.gridx = 0;
|
||||
c.gridy = 0;
|
||||
|
||||
PatchImplementation lastImpl = null;
|
||||
|
||||
boolean first = true;
|
||||
for (FarmingPatch patch : patches)
|
||||
{
|
||||
FarmingPatchPanel p = new FarmingPatchPanel(patch);
|
||||
|
||||
/* Show labels to subdivide tabs into sections */
|
||||
if (patch.getImplementation() != lastImpl && !Strings.isNullOrEmpty(patch.getImplementation().getName()))
|
||||
{
|
||||
JLabel groupLabel = new JLabel(patch.getImplementation().getName());
|
||||
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
groupLabel.setBorder(new EmptyBorder(4, 0, 0, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
groupLabel.setBorder(new EmptyBorder(15, 0, 0, 0));
|
||||
}
|
||||
|
||||
groupLabel.setFont(FontManager.getRunescapeSmallFont());
|
||||
|
||||
container.add(groupLabel, c);
|
||||
c.gridy++;
|
||||
lastImpl = patch.getImplementation();
|
||||
}
|
||||
|
||||
patchPanels.add(p);
|
||||
panel.add(p, c);
|
||||
container.add(p, c);
|
||||
c.gridy++;
|
||||
|
||||
/* This is a weird hack to remove the top border on the first tracker of every tab */
|
||||
if (first)
|
||||
{
|
||||
first = false;
|
||||
p.setBorder(null);
|
||||
}
|
||||
}
|
||||
|
||||
JPanel wrapped = new JPanel(new BorderLayout());
|
||||
wrapped.add(panel, BorderLayout.NORTH);
|
||||
wrapped.add(container, BorderLayout.NORTH);
|
||||
wrapped.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
JScrollPane scroller = new JScrollPane(wrapped);
|
||||
scroller.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
scroller.getVerticalScrollBar().setUnitIncrement(16);
|
||||
scroller.getVerticalScrollBar().setPreferredSize(new Dimension(16, 0));
|
||||
scroller.getVerticalScrollBar().setBorder(new EmptyBorder(0, 9, 0, 0));
|
||||
scroller.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
MaterialTab materialTab = new MaterialTab("", tabGroup, scroller);
|
||||
materialTab.setName(tab.getName());
|
||||
|
||||
AsyncBufferedImage icon = itemManager.getImage(tab.getItemID());
|
||||
tabs.addTab(null, null, scroller, tab.getName());
|
||||
int idx = tabs.getTabCount() - 1;
|
||||
Runnable resize = () ->
|
||||
{
|
||||
tabs.setIconAt(idx, new ImageIcon(icon.getScaledInstance(24, 21, Image.SCALE_SMOOTH)));
|
||||
BufferedImage subIcon = icon.getSubimage(0, 0, 32, 32);
|
||||
materialTab.setIcon(new ImageIcon(subIcon.getScaledInstance(24, 24, Image.SCALE_SMOOTH)));
|
||||
materialTab.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
materialTab.setVerticalAlignment(SwingConstants.CENTER);
|
||||
materialTab.setOpaque(true);
|
||||
materialTab.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
materialTab.setPreferredSize(new Dimension(30, 27));
|
||||
};
|
||||
icon.onChanged(resize);
|
||||
resize.run();
|
||||
|
||||
materialTab.setOnSelectEvent(() -> config.setPatch(tab));
|
||||
|
||||
tabGroup.addTab(materialTab);
|
||||
if (config.patch() == tab)
|
||||
{
|
||||
tabs.setSelectedComponent(scroller);
|
||||
tabGroup.select(materialTab);
|
||||
}
|
||||
tabs.addChangeListener(e ->
|
||||
{
|
||||
if (tabs.getSelectedComponent() == scroller)
|
||||
{
|
||||
config.setPatch(tab);
|
||||
}
|
||||
});
|
||||
});
|
||||
add(tabs, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
void update()
|
||||
@@ -178,10 +237,11 @@ class FarmingTrackerPanel extends PluginPanel
|
||||
PatchState state = unixTime <= 0 ? null : patch.getImplementation().forVarbitValue(value);
|
||||
if (state == null)
|
||||
{
|
||||
panel.getIcon().setIcon(null);
|
||||
itemManager.getImage(Produce.WEEDS.getItemID()).addTo(panel.getIcon());
|
||||
panel.getIcon().setToolTipText("Unknown state");
|
||||
panel.getProgress().setMaximum(0);
|
||||
panel.getProgress().setMaximumValue(0);
|
||||
panel.getProgress().setValue(0);
|
||||
panel.getProgress().setVisible(false);
|
||||
panel.getEstimate().setText("Unknown");
|
||||
panel.getProgress().setBackground(null);
|
||||
}
|
||||
@@ -298,9 +358,20 @@ class FarmingTrackerPanel extends PluginPanel
|
||||
}
|
||||
}
|
||||
|
||||
panel.getProgress().setBackground(state.getCropState().getColor().darker());
|
||||
panel.getProgress().setMaximum(stages - 1);
|
||||
panel.getProgress().setValue(stage);
|
||||
/* Hide any fully grown weeds' progress bar. */
|
||||
if (state.getProduce() != Produce.WEEDS
|
||||
|| (state.getProduce() == Produce.WEEDS && !autoweed && stage < stages - 1))
|
||||
{
|
||||
panel.getProgress().setVisible(true);
|
||||
panel.getProgress().setForeground(state.getCropState().getColor().darker());
|
||||
panel.getProgress().setMaximumValue(stages - 1);
|
||||
panel.getProgress().setValue(stage);
|
||||
panel.getProgress().update();
|
||||
}
|
||||
else
|
||||
{
|
||||
panel.getProgress().setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@ public class FarmingTrackerPlugin extends Plugin
|
||||
.name("Farming Tracker")
|
||||
.icon(icon)
|
||||
.panel(panel)
|
||||
.priority(4)
|
||||
.build();
|
||||
|
||||
pluginToolbar.addNavigation(navButton);
|
||||
|
||||
@@ -60,24 +60,24 @@ public class FarmingWorld
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Ardougne", 10290,
|
||||
new FarmingPatch("Bush", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
||||
));
|
||||
add(new FarmingRegion("Ardougne", 10548,
|
||||
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("Flower", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Brimhaven", 11058,
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.FRUIT_TREE),
|
||||
new FarmingPatch("Spirit Tree", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
|
||||
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Catherby", 11062,
|
||||
new FarmingPatch("North", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("South", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("Flower", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
|
||||
));
|
||||
add(new FarmingRegion("Catherby", 11317,
|
||||
@@ -85,20 +85,20 @@ public class FarmingWorld
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Champion's Guild", 12596,
|
||||
new FarmingPatch("Bush", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Draynor Manor", 12340,
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BELLADONNA)
|
||||
new FarmingPatch("Belladonna", Varbits.FARMING_4771, PatchImplementation.BELLADONNA)
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Entrana", 11060,
|
||||
new FarmingPatch("Hops", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Etceteria", 10300,
|
||||
new FarmingPatch("Bush", Varbits.FARMING_4771, PatchImplementation.BUSH),
|
||||
new FarmingPatch("Spirit Tree", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH),
|
||||
new FarmingPatch("", Varbits.FARMING_4772, PatchImplementation.SPIRIT_TREE)
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Falador", 11828,
|
||||
@@ -107,7 +107,7 @@ public class FarmingWorld
|
||||
add(new FarmingRegion("Falador", 12083,
|
||||
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("Flower", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
|
||||
)
|
||||
{
|
||||
@@ -141,11 +141,11 @@ public class FarmingWorld
|
||||
add(new FarmingRegion("Kourend", 7222,
|
||||
new FarmingPatch("North East", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("South West", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("Flower", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
|
||||
));
|
||||
add(new FarmingRegion("Kourend", 6711,
|
||||
new FarmingPatch("Spirit Tree", Varbits.FARMING_4771, PatchImplementation.SPIRIT_TREE)
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.SPIRIT_TREE)
|
||||
));
|
||||
add(new FarmingRegion("Kourend", 7223,
|
||||
new FarmingPatch("West 1", Varbits.GRAPES_4953, PatchImplementation.GRAPES),
|
||||
@@ -167,7 +167,7 @@ public class FarmingWorld
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Lumbridge", 12851,
|
||||
new FarmingPatch("Hops", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.HOPS)
|
||||
));
|
||||
add(new FarmingRegion("Lumbridge", 12594,
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.TREE)
|
||||
@@ -179,17 +179,17 @@ public class FarmingWorld
|
||||
add(new FarmingRegion("Morytania", 14391,
|
||||
new FarmingPatch("North West", Varbits.FARMING_4771, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("South East", Varbits.FARMING_4772, PatchImplementation.ALLOTMENT),
|
||||
new FarmingPatch("Flower", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
new FarmingPatch("", Varbits.FARMING_4773, PatchImplementation.FLOWER),
|
||||
new FarmingPatch("", Varbits.FARMING_4774, PatchImplementation.HERB)
|
||||
));
|
||||
|
||||
|
||||
add(new FarmingRegion("Port Sarim", 12082,
|
||||
new FarmingPatch("Spirit tree", Varbits.FARMING_4771, PatchImplementation.SPIRIT_TREE)
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.SPIRIT_TREE)
|
||||
));
|
||||
|
||||
add(new FarmingRegion("Rimmington", 11570,
|
||||
new FarmingPatch("Bush", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
||||
new FarmingPatch("", Varbits.FARMING_4771, PatchImplementation.BUSH)
|
||||
), 11826);
|
||||
|
||||
add(new FarmingRegion("Seers' Village", 10551,
|
||||
|
||||
@@ -31,7 +31,7 @@ import lombok.RequiredArgsConstructor;
|
||||
@Getter
|
||||
public enum PatchImplementation
|
||||
{
|
||||
CACTUS(Tab.SPECIAL)
|
||||
CACTUS(Tab.SPECIAL, "")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -84,7 +84,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
BELLADONNA(Tab.SPECIAL)
|
||||
BELLADONNA(Tab.SPECIAL, "")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -122,7 +122,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
MUSHROOM(Tab.SPECIAL)
|
||||
MUSHROOM(Tab.SPECIAL, "")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -160,7 +160,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
ALLOTMENT(Tab.ALLOTMENT)
|
||||
ALLOTMENT(Tab.ALLOTMENT, "")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -473,240 +473,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
FLOWER(Tab.SPECIAL)
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
{
|
||||
if (value >= 0 && value <= 3)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7842,7841,7840
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3 - value);
|
||||
}
|
||||
if (value >= 4 && value <= 7)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843,7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 8 && value <= 11)
|
||||
{
|
||||
// Marigold[,Inspect,,Guide,] 7867,7868,7869,7870
|
||||
return new PatchState(Produce.MARIGOLD, CropState.GROWING, value - 8);
|
||||
}
|
||||
if (value == 12)
|
||||
{
|
||||
// Marigold[Pick,Inspect,,Guide,] 7871
|
||||
return new PatchState(Produce.MARIGOLD, CropState.HARVESTABLE, 12 - value);
|
||||
}
|
||||
if (value >= 13 && value <= 16)
|
||||
{
|
||||
// Rosemary[,Inspect,,Guide,] 7899,7900,7901,7902
|
||||
return new PatchState(Produce.ROSEMARY, CropState.GROWING, value - 13);
|
||||
}
|
||||
if (value == 17)
|
||||
{
|
||||
// Rosemary[Pick,Inspect,,Guide,] 7903
|
||||
return new PatchState(Produce.ROSEMARY, CropState.HARVESTABLE, 17 - value);
|
||||
}
|
||||
if (value >= 18 && value <= 21)
|
||||
{
|
||||
// Nasturtium[,Inspect,,Guide,] 7883,7884,7885,7886
|
||||
return new PatchState(Produce.NASTURTIUM, CropState.GROWING, value - 18);
|
||||
}
|
||||
if (value == 22)
|
||||
{
|
||||
// Nasturtium[Pick,Inspect,,Guide,] 7887
|
||||
return new PatchState(Produce.NASTURTIUM, CropState.HARVESTABLE, 22 - value);
|
||||
}
|
||||
if (value >= 23 && value <= 26)
|
||||
{
|
||||
// Woad[,Inspect,,Guide,] 7919,7920,7921,7922
|
||||
return new PatchState(Produce.WOAD, CropState.GROWING, value - 23);
|
||||
}
|
||||
if (value == 27)
|
||||
{
|
||||
// Woad[Pick,Inspect,,Guide,] 7923
|
||||
return new PatchState(Produce.WOAD, CropState.HARVESTABLE, 27 - value);
|
||||
}
|
||||
if (value >= 28 && value <= 31)
|
||||
{
|
||||
// Limpwurt[,Inspect,,Guide,] 7851,7852,7853,7854
|
||||
return new PatchState(Produce.LIMPWURT, CropState.GROWING, value - 28);
|
||||
}
|
||||
if (value == 32)
|
||||
{
|
||||
// Limpwurt[Pick,Inspect,,Guide,] 7855
|
||||
return new PatchState(Produce.LIMPWURT, CropState.HARVESTABLE, 32 - value);
|
||||
}
|
||||
if (value >= 33 && value <= 35)
|
||||
{
|
||||
// Scarecrow[Rake,Inspect,,Guide,Remove] 7918,7917,7916
|
||||
return new PatchState(Produce.SCARECROW, CropState.GROWING, 35 - value);
|
||||
}
|
||||
if (value == 36)
|
||||
{
|
||||
// Scarecrow[Remove,Inspect,,Guide,] 7915
|
||||
return new PatchState(Produce.SCARECROW, CropState.GROWING, 0);
|
||||
}
|
||||
if (value >= 37 && value <= 71)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 72 && value <= 75)
|
||||
{
|
||||
// Marigold[,Inspect,,Guide,] 7872,7873,7874,7875
|
||||
return new PatchState(Produce.MARIGOLD, CropState.GROWING, value - 72);
|
||||
}
|
||||
if (value == 76)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 77 && value <= 80)
|
||||
{
|
||||
// Rosemary[,Inspect,,Guide,] 7904,7905,7906,7907
|
||||
return new PatchState(Produce.ROSEMARY, CropState.GROWING, value - 77);
|
||||
}
|
||||
if (value == 81)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 82 && value <= 85)
|
||||
{
|
||||
// Nasturtium[,Inspect,,Guide,] 7888,7889,7890,7891
|
||||
return new PatchState(Produce.NASTURTIUM, CropState.GROWING, value - 82);
|
||||
}
|
||||
if (value == 86)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 87 && value <= 90)
|
||||
{
|
||||
// Woad[,Inspect,,Guide,] 7924,7925,7926,7927
|
||||
return new PatchState(Produce.WOAD, CropState.GROWING, value - 87);
|
||||
}
|
||||
if (value == 91)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 92 && value <= 95)
|
||||
{
|
||||
// Limpwurt[,Inspect,,Guide,] 7856,7857,7858,7859
|
||||
return new PatchState(Produce.LIMPWURT, CropState.GROWING, value - 92);
|
||||
}
|
||||
if (value >= 96 && value <= 136)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 137 && value <= 139)
|
||||
{
|
||||
// Diseased marigold[Cure,Inspect,,Guide,] 7876,7877,7878
|
||||
return new PatchState(Produce.MARIGOLD, CropState.DISEASED, value - 136);
|
||||
}
|
||||
if (value >= 140 && value <= 141)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 142 && value <= 144)
|
||||
{
|
||||
// Diseased rosemary[Cure,Inspect,,Guide,] 7908,7909,7910
|
||||
return new PatchState(Produce.ROSEMARY, CropState.DISEASED, value - 141);
|
||||
}
|
||||
if (value >= 145 && value <= 146)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 147 && value <= 149)
|
||||
{
|
||||
// Diseased nasturtium[Cure,Inspect,,Guide,] 7892,7893,7894
|
||||
return new PatchState(Produce.NASTURTIUM, CropState.DISEASED, value - 146);
|
||||
}
|
||||
if (value >= 150 && value <= 151)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 152 && value <= 154)
|
||||
{
|
||||
// Diseased woad[Cure,Inspect,,Guide,] 7928,7929,7930
|
||||
return new PatchState(Produce.WOAD, CropState.DISEASED, value - 151);
|
||||
}
|
||||
if (value >= 155 && value <= 156)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 157 && value <= 159)
|
||||
{
|
||||
// Diseased limpwurt[Cure,Inspect,,Guide,] 7860,7861,7862
|
||||
return new PatchState(Produce.LIMPWURT, CropState.DISEASED, value - 156);
|
||||
}
|
||||
if (value >= 160 && value <= 200)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 201 && value <= 203)
|
||||
{
|
||||
// Dead marigold[Clear,Inspect,,Guide,] 7879,7880,7881,7882
|
||||
return new PatchState(Produce.MARIGOLD, CropState.DEAD, value - 200);
|
||||
}
|
||||
if (value == 205)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 206 && value <= 208)
|
||||
{
|
||||
// Dead rosemary[Clear,Inspect,,Guide,] 7911,7912,7913,7914
|
||||
return new PatchState(Produce.ROSEMARY, CropState.DEAD, value - 205);
|
||||
}
|
||||
if (value == 210)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 211 && value <= 213)
|
||||
{
|
||||
// Dead nasturtium[Clear,Inspect,,Guide,] 7895,7896,7897,7898
|
||||
return new PatchState(Produce.NASTURTIUM, CropState.DEAD, value - 210);
|
||||
}
|
||||
if (value == 215)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 216 && value <= 218)
|
||||
{
|
||||
// Dead woad[Clear,Inspect,,Guide,] 7931,7932,7933,7934
|
||||
return new PatchState(Produce.WOAD, CropState.DEAD, value - 215);
|
||||
}
|
||||
if (value == 220)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 221 && value <= 224)
|
||||
{
|
||||
// Dead limpwurt[Clear,Inspect,,Guide,] 7863,7864,7865,7866
|
||||
return new PatchState(Produce.LIMPWURT, CropState.DEAD, value - 220);
|
||||
}
|
||||
if (value >= 225 && value <= 255)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
HERB(Tab.HERB)
|
||||
HERB(Tab.HERB, "")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -970,7 +737,240 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
BUSH(Tab.SPECIAL)
|
||||
FLOWER(Tab.HERB, "Flowers")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
{
|
||||
if (value >= 0 && value <= 3)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7842,7841,7840
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3 - value);
|
||||
}
|
||||
if (value >= 4 && value <= 7)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843,7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 8 && value <= 11)
|
||||
{
|
||||
// Marigold[,Inspect,,Guide,] 7867,7868,7869,7870
|
||||
return new PatchState(Produce.MARIGOLD, CropState.GROWING, value - 8);
|
||||
}
|
||||
if (value == 12)
|
||||
{
|
||||
// Marigold[Pick,Inspect,,Guide,] 7871
|
||||
return new PatchState(Produce.MARIGOLD, CropState.HARVESTABLE, 12 - value);
|
||||
}
|
||||
if (value >= 13 && value <= 16)
|
||||
{
|
||||
// Rosemary[,Inspect,,Guide,] 7899,7900,7901,7902
|
||||
return new PatchState(Produce.ROSEMARY, CropState.GROWING, value - 13);
|
||||
}
|
||||
if (value == 17)
|
||||
{
|
||||
// Rosemary[Pick,Inspect,,Guide,] 7903
|
||||
return new PatchState(Produce.ROSEMARY, CropState.HARVESTABLE, 17 - value);
|
||||
}
|
||||
if (value >= 18 && value <= 21)
|
||||
{
|
||||
// Nasturtium[,Inspect,,Guide,] 7883,7884,7885,7886
|
||||
return new PatchState(Produce.NASTURTIUM, CropState.GROWING, value - 18);
|
||||
}
|
||||
if (value == 22)
|
||||
{
|
||||
// Nasturtium[Pick,Inspect,,Guide,] 7887
|
||||
return new PatchState(Produce.NASTURTIUM, CropState.HARVESTABLE, 22 - value);
|
||||
}
|
||||
if (value >= 23 && value <= 26)
|
||||
{
|
||||
// Woad[,Inspect,,Guide,] 7919,7920,7921,7922
|
||||
return new PatchState(Produce.WOAD, CropState.GROWING, value - 23);
|
||||
}
|
||||
if (value == 27)
|
||||
{
|
||||
// Woad[Pick,Inspect,,Guide,] 7923
|
||||
return new PatchState(Produce.WOAD, CropState.HARVESTABLE, 27 - value);
|
||||
}
|
||||
if (value >= 28 && value <= 31)
|
||||
{
|
||||
// Limpwurt[,Inspect,,Guide,] 7851,7852,7853,7854
|
||||
return new PatchState(Produce.LIMPWURT, CropState.GROWING, value - 28);
|
||||
}
|
||||
if (value == 32)
|
||||
{
|
||||
// Limpwurt[Pick,Inspect,,Guide,] 7855
|
||||
return new PatchState(Produce.LIMPWURT, CropState.HARVESTABLE, 32 - value);
|
||||
}
|
||||
if (value >= 33 && value <= 35)
|
||||
{
|
||||
// Scarecrow[Rake,Inspect,,Guide,Remove] 7918,7917,7916
|
||||
return new PatchState(Produce.SCARECROW, CropState.GROWING, 35 - value);
|
||||
}
|
||||
if (value == 36)
|
||||
{
|
||||
// Scarecrow[Remove,Inspect,,Guide,] 7915
|
||||
return new PatchState(Produce.SCARECROW, CropState.GROWING, 0);
|
||||
}
|
||||
if (value >= 37 && value <= 71)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 72 && value <= 75)
|
||||
{
|
||||
// Marigold[,Inspect,,Guide,] 7872,7873,7874,7875
|
||||
return new PatchState(Produce.MARIGOLD, CropState.GROWING, value - 72);
|
||||
}
|
||||
if (value == 76)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 77 && value <= 80)
|
||||
{
|
||||
// Rosemary[,Inspect,,Guide,] 7904,7905,7906,7907
|
||||
return new PatchState(Produce.ROSEMARY, CropState.GROWING, value - 77);
|
||||
}
|
||||
if (value == 81)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 82 && value <= 85)
|
||||
{
|
||||
// Nasturtium[,Inspect,,Guide,] 7888,7889,7890,7891
|
||||
return new PatchState(Produce.NASTURTIUM, CropState.GROWING, value - 82);
|
||||
}
|
||||
if (value == 86)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 87 && value <= 90)
|
||||
{
|
||||
// Woad[,Inspect,,Guide,] 7924,7925,7926,7927
|
||||
return new PatchState(Produce.WOAD, CropState.GROWING, value - 87);
|
||||
}
|
||||
if (value == 91)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 92 && value <= 95)
|
||||
{
|
||||
// Limpwurt[,Inspect,,Guide,] 7856,7857,7858,7859
|
||||
return new PatchState(Produce.LIMPWURT, CropState.GROWING, value - 92);
|
||||
}
|
||||
if (value >= 96 && value <= 136)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 137 && value <= 139)
|
||||
{
|
||||
// Diseased marigold[Cure,Inspect,,Guide,] 7876,7877,7878
|
||||
return new PatchState(Produce.MARIGOLD, CropState.DISEASED, value - 136);
|
||||
}
|
||||
if (value >= 140 && value <= 141)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 142 && value <= 144)
|
||||
{
|
||||
// Diseased rosemary[Cure,Inspect,,Guide,] 7908,7909,7910
|
||||
return new PatchState(Produce.ROSEMARY, CropState.DISEASED, value - 141);
|
||||
}
|
||||
if (value >= 145 && value <= 146)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 147 && value <= 149)
|
||||
{
|
||||
// Diseased nasturtium[Cure,Inspect,,Guide,] 7892,7893,7894
|
||||
return new PatchState(Produce.NASTURTIUM, CropState.DISEASED, value - 146);
|
||||
}
|
||||
if (value >= 150 && value <= 151)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 152 && value <= 154)
|
||||
{
|
||||
// Diseased woad[Cure,Inspect,,Guide,] 7928,7929,7930
|
||||
return new PatchState(Produce.WOAD, CropState.DISEASED, value - 151);
|
||||
}
|
||||
if (value >= 155 && value <= 156)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 157 && value <= 159)
|
||||
{
|
||||
// Diseased limpwurt[Cure,Inspect,,Guide,] 7860,7861,7862
|
||||
return new PatchState(Produce.LIMPWURT, CropState.DISEASED, value - 156);
|
||||
}
|
||||
if (value >= 160 && value <= 200)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 201 && value <= 203)
|
||||
{
|
||||
// Dead marigold[Clear,Inspect,,Guide,] 7879,7880,7881,7882
|
||||
return new PatchState(Produce.MARIGOLD, CropState.DEAD, value - 200);
|
||||
}
|
||||
if (value == 205)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 206 && value <= 208)
|
||||
{
|
||||
// Dead rosemary[Clear,Inspect,,Guide,] 7911,7912,7913,7914
|
||||
return new PatchState(Produce.ROSEMARY, CropState.DEAD, value - 205);
|
||||
}
|
||||
if (value == 210)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 211 && value <= 213)
|
||||
{
|
||||
// Dead nasturtium[Clear,Inspect,,Guide,] 7895,7896,7897,7898
|
||||
return new PatchState(Produce.NASTURTIUM, CropState.DEAD, value - 210);
|
||||
}
|
||||
if (value == 215)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 216 && value <= 218)
|
||||
{
|
||||
// Dead woad[Clear,Inspect,,Guide,] 7931,7932,7933,7934
|
||||
return new PatchState(Produce.WOAD, CropState.DEAD, value - 215);
|
||||
}
|
||||
if (value == 220)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
if (value >= 221 && value <= 224)
|
||||
{
|
||||
// Dead limpwurt[Clear,Inspect,,Guide,] 7863,7864,7865,7866
|
||||
return new PatchState(Produce.LIMPWURT, CropState.DEAD, value - 220);
|
||||
}
|
||||
if (value >= 225 && value <= 255)
|
||||
{
|
||||
// Flower Patch[Rake,Inspect,,Guide,] 7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843,7843
|
||||
return new PatchState(Produce.WEEDS, CropState.GROWING, 3);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
},
|
||||
BUSH(Tab.BUSH, "")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -1209,7 +1209,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
FRUIT_TREE(Tab.FRUIT_TREE)
|
||||
FRUIT_TREE(Tab.FRUIT_TREE, "Fruit trees")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -1458,7 +1458,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
HOPS(Tab.SPECIAL)
|
||||
HOPS(Tab.SPECIAL, "Hops")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -1761,7 +1761,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
TREE(Tab.TREE)
|
||||
TREE(Tab.TREE, "")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -2049,7 +2049,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
HARDWOOD_TREE(Tab.TREE)
|
||||
HARDWOOD_TREE(Tab.TREE, "Hardwood Trees")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -2137,7 +2137,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
SPIRIT_TREE(Tab.TREE)
|
||||
SPIRIT_TREE(Tab.TREE, "Spirit Trees")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -2185,7 +2185,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
SEAWEED(Tab.SPECIAL)
|
||||
SEAWEED(Tab.SPECIAL, "Seaweed")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -2223,7 +2223,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
CALQUAT(Tab.FRUIT_TREE)
|
||||
CALQUAT(Tab.FRUIT_TREE, "Calquat")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -2271,7 +2271,7 @@ public enum PatchImplementation
|
||||
return null;
|
||||
}
|
||||
},
|
||||
GRAPES(Tab.SPECIAL)
|
||||
GRAPES(Tab.BUSH, "Grapes")
|
||||
{
|
||||
@Override
|
||||
PatchState forVarbitValue(int value)
|
||||
@@ -2300,4 +2300,6 @@ public enum PatchImplementation
|
||||
abstract PatchState forVarbitValue(int value);
|
||||
|
||||
private final Tab tab;
|
||||
|
||||
private final String name;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ public enum Tab
|
||||
HERB("Herbs", ItemID.GRIMY_RANARR_WEED),
|
||||
TREE("Trees", ItemID.MAHOGANY_LOGS),
|
||||
FRUIT_TREE("Fruit Trees", ItemID.PINEAPPLE),
|
||||
BUSH("Bushes", ItemID.REDBERRIES),
|
||||
SPECIAL("Special", ItemID.MUSHROOM);
|
||||
|
||||
private final String name;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Lotto <https://github.com/devLotto>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,6 +29,7 @@ import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.font.FontRenderContext;
|
||||
@@ -43,13 +45,16 @@ import javax.swing.BoxLayout;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.util.LinkBrowser;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
import net.runelite.http.api.RuneLiteAPI;
|
||||
import net.runelite.http.api.feed.FeedItem;
|
||||
import net.runelite.http.api.feed.FeedItemType;
|
||||
@@ -63,8 +68,10 @@ import okhttp3.ResponseBody;
|
||||
@Slf4j
|
||||
class FeedPanel extends PluginPanel
|
||||
{
|
||||
private static BufferedImage RUNELITE_ICON;
|
||||
private static BufferedImage OSRS_ICON;
|
||||
private static final ImageIcon RUNELITE_ICON;
|
||||
private static final ImageIcon OSRS_ICON;
|
||||
private static final ImageIcon RESET_ICON;
|
||||
private static final ImageIcon RESET_ICON_CLICK; //used as a click effect (darker version of the reset icon)
|
||||
|
||||
private static final Color TWEET_BACKGROUND = new Color(15, 15, 15);
|
||||
private static final Color OSRS_NEWS_BACKGROUND = new Color(36, 30, 19);
|
||||
@@ -74,6 +81,11 @@ class FeedPanel extends PluginPanel
|
||||
private static final int CONTENT_WIDTH = 148;
|
||||
private static final int TIME_WIDTH = 20;
|
||||
|
||||
/**
|
||||
* Holds all feed items.
|
||||
*/
|
||||
private final JPanel feedContainer = new JPanel();
|
||||
|
||||
private static final Comparator<FeedItem> FEED_ITEM_COMPARATOR = (o1, o2) ->
|
||||
{
|
||||
if (o1.getType() != o2.getType())
|
||||
@@ -97,24 +109,16 @@ class FeedPanel extends PluginPanel
|
||||
{
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
RUNELITE_ICON = ImageIO.read(FeedPanel.class.getResourceAsStream("runelite.png"));
|
||||
BufferedImage reset = ImageIO.read(FeedPanel.class.getResourceAsStream("reset.png"));
|
||||
RUNELITE_ICON = new ImageIcon(ImageIO.read(FeedPanel.class.getResourceAsStream("runelite.png")));
|
||||
OSRS_ICON = new ImageIcon(ImageIO.read(FeedPanel.class.getResourceAsStream("osrs.png")));
|
||||
RESET_ICON = new ImageIcon(reset);
|
||||
RESET_ICON_CLICK = new ImageIcon(SwingUtil.grayscaleOffset(reset, -100));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.warn("Client icon failed to load", e);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
OSRS_ICON = ImageIO.read(FeedPanel.class.getResourceAsStream("osrs.png"));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.warn("OSRS icon failed to load", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +129,56 @@ class FeedPanel extends PluginPanel
|
||||
{
|
||||
this.config = config;
|
||||
this.feedSupplier = feedSupplier;
|
||||
|
||||
setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
feedContainer.setLayout(new GridLayout(0, 1, 0, 4));
|
||||
feedContainer.setOpaque(false);
|
||||
|
||||
/**
|
||||
* This header contains the "News Feed" title and a refresh icon button.
|
||||
*/
|
||||
JPanel header = new JPanel();
|
||||
header.setOpaque(false);
|
||||
header.setLayout(new BorderLayout());
|
||||
header.setBorder(new EmptyBorder(0, 0, 9, 0));
|
||||
|
||||
/**
|
||||
* A refresh icon button, when clicked, it will swap icons for feedback effect and then call
|
||||
* the rebuildFeed method.
|
||||
*/
|
||||
JLabel reset = new JLabel();
|
||||
reset.setIcon(RESET_ICON);
|
||||
reset.setVerticalAlignment(SwingConstants.CENTER);
|
||||
reset.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
reset.setToolTipText("Refresh");
|
||||
|
||||
reset.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
reset.setIcon(RESET_ICON_CLICK);
|
||||
rebuildFeed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent mouseEvent)
|
||||
{
|
||||
reset.setIcon(RESET_ICON);
|
||||
}
|
||||
});
|
||||
|
||||
JLabel title = new JLabel("News feed");
|
||||
title.setForeground(Color.WHITE);
|
||||
|
||||
header.add(title, BorderLayout.WEST);
|
||||
header.add(reset, BorderLayout.EAST);
|
||||
|
||||
add(header, BorderLayout.NORTH);
|
||||
add(feedContainer, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
void rebuildFeed()
|
||||
@@ -138,7 +192,7 @@ class FeedPanel extends PluginPanel
|
||||
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
removeAll();
|
||||
feedContainer.removeAll();
|
||||
|
||||
feed.getItems()
|
||||
.stream()
|
||||
@@ -207,14 +261,14 @@ class FeedPanel extends PluginPanel
|
||||
case OSRS_NEWS:
|
||||
if (OSRS_ICON != null)
|
||||
{
|
||||
avatar.setIcon(new ImageIcon(OSRS_ICON));
|
||||
avatar.setIcon(OSRS_ICON);
|
||||
}
|
||||
avatarAndRight.setBackground(OSRS_NEWS_BACKGROUND);
|
||||
break;
|
||||
default:
|
||||
if (RUNELITE_ICON != null)
|
||||
{
|
||||
avatar.setIcon(new ImageIcon(RUNELITE_ICON));
|
||||
avatar.setIcon(RUNELITE_ICON);
|
||||
}
|
||||
avatarAndRight.setBackground(BLOG_POST_BACKGROUND);
|
||||
break;
|
||||
@@ -296,7 +350,7 @@ class FeedPanel extends PluginPanel
|
||||
}
|
||||
});
|
||||
|
||||
add(avatarAndRight);
|
||||
feedContainer.add(avatarAndRight);
|
||||
}
|
||||
|
||||
private String durationToString(Duration duration)
|
||||
|
||||
@@ -93,6 +93,7 @@ public class FeedPlugin extends Plugin
|
||||
navButton = NavigationButton.builder()
|
||||
.name("News Feed")
|
||||
.icon(icon)
|
||||
.priority(8)
|
||||
.panel(feedPanel)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Seth <https://github.com/sethtroll>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -32,14 +33,17 @@ import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.CompoundBorder;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.LineBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.game.AsyncBufferedImage;
|
||||
import net.runelite.client.util.LinkBrowser;
|
||||
import net.runelite.client.util.StackFormatter;
|
||||
|
||||
/**
|
||||
* This panel displays an individual item result in the
|
||||
* Grand Exchange search plugin.
|
||||
*/
|
||||
@Slf4j
|
||||
class GrandExchangeItemPanel extends JPanel
|
||||
{
|
||||
@@ -52,7 +56,8 @@ class GrandExchangeItemPanel extends JPanel
|
||||
layout.setHgap(5);
|
||||
setLayout(layout);
|
||||
setToolTipText(name);
|
||||
|
||||
setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
|
||||
|
||||
Color background = getBackground();
|
||||
|
||||
addMouseListener(new MouseAdapter()
|
||||
@@ -60,7 +65,7 @@ class GrandExchangeItemPanel extends JPanel
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e)
|
||||
{
|
||||
setBackground(getBackground().darker().darker());
|
||||
setBackground(getBackground().brighter());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,11 +81,7 @@ class GrandExchangeItemPanel extends JPanel
|
||||
}
|
||||
});
|
||||
|
||||
setBorder(new CompoundBorder
|
||||
(
|
||||
new LineBorder(getBackground().brighter(), 1),
|
||||
new EmptyBorder(5, 5, 5, 5)
|
||||
));
|
||||
setBorder(new EmptyBorder(5, 5, 5, 0));
|
||||
|
||||
// Icon
|
||||
JLabel itemIcon = new JLabel();
|
||||
@@ -97,6 +98,9 @@ class GrandExchangeItemPanel extends JPanel
|
||||
|
||||
// Item name
|
||||
JLabel itemName = new JLabel();
|
||||
itemName.setForeground(Color.WHITE);
|
||||
itemName.setMaximumSize(new Dimension(0, 0)); // to limit the label's size for
|
||||
itemName.setPreferredSize(new Dimension(0, 0)); // items with longer names
|
||||
itemName.setText(name);
|
||||
rightPanel.add(itemName);
|
||||
|
||||
@@ -110,13 +114,13 @@ class GrandExchangeItemPanel extends JPanel
|
||||
{
|
||||
gePriceLabel.setText("N/A");
|
||||
}
|
||||
gePriceLabel.setForeground(Color.GREEN);
|
||||
gePriceLabel.setForeground(ColorScheme.GRAND_EXCHANGE_PRICE);
|
||||
rightPanel.add(gePriceLabel);
|
||||
|
||||
// Alch price
|
||||
JLabel haPriceLabel = new JLabel();
|
||||
haPriceLabel.setText(StackFormatter.formatNumber(haPrice.intValue()) + " alch");
|
||||
haPriceLabel.setForeground(Color.orange);
|
||||
haPriceLabel.setForeground(ColorScheme.GRAND_EXCHANGE_ALCH);
|
||||
rightPanel.add(haPriceLabel);
|
||||
|
||||
add(rightPanel, BorderLayout.CENTER);
|
||||
@@ -131,4 +135,4 @@ class GrandExchangeItemPanel extends JPanel
|
||||
|
||||
LinkBrowser.browse(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -28,38 +29,73 @@ package net.runelite.client.plugins.grandexchange;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.CardLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.border.TitledBorder;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.GrandExchangeOffer;
|
||||
import net.runelite.api.GrandExchangeOfferState;
|
||||
import static net.runelite.api.GrandExchangeOfferState.CANCELLED_BUY;
|
||||
import static net.runelite.api.GrandExchangeOfferState.CANCELLED_SELL;
|
||||
import static net.runelite.api.GrandExchangeOfferState.EMPTY;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.components.ThinProgressBar;
|
||||
import net.runelite.client.util.StackFormatter;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
|
||||
@Slf4j
|
||||
public class GrandExchangeOfferSlot extends JPanel
|
||||
{
|
||||
private static final Color GE_INPROGRESS_ORANGE = new Color(0xd8, 0x80, 0x20).brighter();
|
||||
private static final Color GE_FINISHED_GREEN = new Color(0, 0x5f, 0);
|
||||
private static final Color GE_CANCELLED_RED = new Color(0x8f, 0, 0);
|
||||
private static final String FACE_CARD = "FACE_CARD";
|
||||
private static final String DETAILS_CARD = "DETAILS_CARD";
|
||||
|
||||
private static final String INFO_CARD = "INFO_CARD";
|
||||
private static final String EMPTY_CARD = "EMPTY_CARD";
|
||||
private static final ImageIcon RIGHT_ARROW_ICON;
|
||||
private static final ImageIcon LEFT_ARROW_ICON;
|
||||
|
||||
private final JPanel container = new JPanel();
|
||||
private final CardLayout cardLayout = new CardLayout();
|
||||
|
||||
private final JLabel itemIcon = new JLabel();
|
||||
private final TitledBorder itemName = BorderFactory.createTitledBorder("Nothing");
|
||||
private final JLabel offerState = new JLabel("Text so the label has height");
|
||||
private final JProgressBar progressBar = new JProgressBar();
|
||||
private final JLabel itemName = new JLabel();
|
||||
private final JLabel offerInfo = new JLabel();
|
||||
private final JLabel switchFaceViewIcon = new JLabel();
|
||||
|
||||
private final JLabel itemPrice = new JLabel();
|
||||
private final JLabel offerSpent = new JLabel();
|
||||
private final JLabel switchDetailsViewIcon = new JLabel();
|
||||
|
||||
private final ThinProgressBar progressBar = new ThinProgressBar();
|
||||
|
||||
private boolean showingFace = true;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
RIGHT_ARROW_ICON = new ImageIcon(ImageIO.read(GrandExchangeOfferSlot.class.getResourceAsStream("arrow_right.png")));
|
||||
LEFT_ARROW_ICON = new ImageIcon(ImageIO.read(GrandExchangeOfferSlot.class.getResourceAsStream("arrow_left.png")));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This (sub)panel is used for each GE slot displayed
|
||||
@@ -72,123 +108,188 @@ public class GrandExchangeOfferSlot extends JPanel
|
||||
|
||||
private void buildPanel()
|
||||
{
|
||||
setBorder(BorderFactory.createCompoundBorder(
|
||||
// Add a margin underneath each slot panel to space them out
|
||||
BorderFactory.createEmptyBorder(0, 0, 3, 0),
|
||||
itemName
|
||||
));
|
||||
setLayout(new BorderLayout());
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
setBorder(new EmptyBorder(7, 0, 0, 0));
|
||||
|
||||
// The default border color is kind of dark, so we change it to something lighter
|
||||
itemName.setBorder(BorderFactory.createLineBorder(getBackground().brighter()));
|
||||
final MouseListener ml = new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
super.mousePressed(mouseEvent);
|
||||
switchPanel();
|
||||
}
|
||||
|
||||
progressBar.setStringPainted(true);
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
super.mouseEntered(mouseEvent);
|
||||
container.setBackground(ColorScheme.MEDIUM_GRAY_COLOR.brighter());
|
||||
}
|
||||
|
||||
setLayout(cardLayout);
|
||||
@Override
|
||||
public void mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
super.mouseExited(mouseEvent);
|
||||
container.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
|
||||
}
|
||||
};
|
||||
|
||||
// Card for when the slot has an offer in it
|
||||
JPanel infoCard = new JPanel();
|
||||
add(infoCard, INFO_CARD);
|
||||
// Add padding to give the icon and progress bar room to breathe
|
||||
infoCard.setBorder(BorderFactory.createEmptyBorder(0, 2, 2, 2));
|
||||
container.setLayout(cardLayout);
|
||||
container.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
|
||||
|
||||
infoCard.setLayout(new BoxLayout(infoCard, BoxLayout.X_AXIS));
|
||||
// Icon on the left
|
||||
infoCard.add(itemIcon);
|
||||
JPanel faceCard = new JPanel();
|
||||
faceCard.setOpaque(false);
|
||||
faceCard.setLayout(new BorderLayout());
|
||||
faceCard.addMouseListener(ml);
|
||||
|
||||
// Info on the right
|
||||
JPanel offerStatePanel = new JPanel();
|
||||
offerStatePanel.setLayout(new BoxLayout(offerStatePanel, BoxLayout.Y_AXIS));
|
||||
offerStatePanel.add(offerState);
|
||||
offerStatePanel.add(progressBar);
|
||||
infoCard.add(offerStatePanel);
|
||||
itemIcon.setVerticalAlignment(JLabel.CENTER);
|
||||
itemIcon.setHorizontalAlignment(JLabel.CENTER);
|
||||
itemIcon.setPreferredSize(new Dimension(45, 45));
|
||||
|
||||
// Card for when the slot is empty
|
||||
JPanel emptySlotCard = new JPanel();
|
||||
add(emptySlotCard, EMPTY_CARD);
|
||||
// Counteract the height lost to the text at the top of the TitledBorder
|
||||
int itemNameBorderHeight = itemName.getBorderInsets(this).top;
|
||||
emptySlotCard.setBorder(BorderFactory.createEmptyBorder(0, 0, (itemNameBorderHeight - 1) / 2, 0));
|
||||
// Center the "Empty" label horizontally
|
||||
emptySlotCard.setLayout( new BoxLayout(emptySlotCard, BoxLayout.X_AXIS));
|
||||
emptySlotCard.add(Box.createHorizontalGlue());
|
||||
emptySlotCard.add(new JLabel(getNameForState(EMPTY)), BorderLayout.CENTER);
|
||||
emptySlotCard.add(Box.createHorizontalGlue());
|
||||
itemName.setForeground(Color.WHITE);
|
||||
itemName.setVerticalAlignment(JLabel.BOTTOM);
|
||||
itemName.setFont(FontManager.getRunescapeSmallFont());
|
||||
|
||||
cardLayout.show(this, EMPTY_CARD);
|
||||
offerInfo.setForeground(ColorScheme.LIGHT_GRAY_COLOR);
|
||||
offerInfo.setVerticalAlignment(JLabel.TOP);
|
||||
offerInfo.setFont(FontManager.getRunescapeSmallFont());
|
||||
|
||||
switchFaceViewIcon.setIcon(RIGHT_ARROW_ICON);
|
||||
switchFaceViewIcon.setVerticalAlignment(JLabel.CENTER);
|
||||
switchFaceViewIcon.setHorizontalAlignment(JLabel.CENTER);
|
||||
switchFaceViewIcon.setPreferredSize(new Dimension(30, 45));
|
||||
|
||||
JPanel offerFaceDetails = new JPanel();
|
||||
offerFaceDetails.setOpaque(false);
|
||||
offerFaceDetails.setLayout(new GridLayout(2, 1, 0, 2));
|
||||
|
||||
offerFaceDetails.add(itemName);
|
||||
offerFaceDetails.add(offerInfo);
|
||||
|
||||
faceCard.add(offerFaceDetails, BorderLayout.CENTER);
|
||||
faceCard.add(itemIcon, BorderLayout.WEST);
|
||||
faceCard.add(switchFaceViewIcon, BorderLayout.EAST);
|
||||
|
||||
JPanel detailsCard = new JPanel();
|
||||
detailsCard.setOpaque(false);
|
||||
detailsCard.setLayout(new BorderLayout());
|
||||
detailsCard.setBorder(new EmptyBorder(0, 15, 0, 0));
|
||||
detailsCard.addMouseListener(ml);
|
||||
|
||||
itemPrice.setForeground(Color.WHITE);
|
||||
itemPrice.setVerticalAlignment(JLabel.BOTTOM);
|
||||
itemPrice.setFont(FontManager.getRunescapeSmallFont());
|
||||
|
||||
offerSpent.setForeground(Color.WHITE);
|
||||
offerSpent.setVerticalAlignment(JLabel.TOP);
|
||||
offerSpent.setFont(FontManager.getRunescapeSmallFont());
|
||||
|
||||
switchDetailsViewIcon.setIcon(LEFT_ARROW_ICON);
|
||||
switchDetailsViewIcon.setVerticalAlignment(JLabel.CENTER);
|
||||
switchDetailsViewIcon.setHorizontalAlignment(JLabel.CENTER);
|
||||
switchDetailsViewIcon.setPreferredSize(new Dimension(30, 45));
|
||||
|
||||
JPanel offerDetails = new JPanel();
|
||||
offerDetails.setOpaque(false);
|
||||
offerDetails.setLayout(new GridLayout(2, 1));
|
||||
|
||||
offerDetails.add(itemPrice);
|
||||
offerDetails.add(offerSpent);
|
||||
|
||||
detailsCard.add(offerDetails, BorderLayout.CENTER);
|
||||
detailsCard.add(switchDetailsViewIcon, BorderLayout.EAST);
|
||||
|
||||
container.add(faceCard, FACE_CARD);
|
||||
container.add(detailsCard, DETAILS_CARD);
|
||||
|
||||
cardLayout.show(container, FACE_CARD);
|
||||
|
||||
add(container, BorderLayout.CENTER);
|
||||
add(progressBar, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
|
||||
void updateOffer(ItemComposition offerItem, BufferedImage itemImage, @Nullable GrandExchangeOffer newOffer)
|
||||
{
|
||||
if (newOffer == null || newOffer.getState() == EMPTY)
|
||||
{
|
||||
cardLayout.show(this, EMPTY_CARD);
|
||||
itemName.setTitle("Nothing");
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
cardLayout.show(this, INFO_CARD);
|
||||
cardLayout.show(container, FACE_CARD);
|
||||
|
||||
itemName.setTitle(offerItem.getName());
|
||||
itemName.setText(offerItem.getName());
|
||||
itemIcon.setIcon(new ImageIcon(itemImage));
|
||||
|
||||
boolean shouldStack = offerItem.isStackable() || newOffer.getTotalQuantity() > 1;
|
||||
ImageIcon newItemIcon = new ImageIcon(itemImage);
|
||||
itemIcon.setIcon(newItemIcon);
|
||||
boolean buying = newOffer.getState() == GrandExchangeOfferState.BOUGHT
|
||||
|| newOffer.getState() == GrandExchangeOfferState.BUYING
|
||||
|| newOffer.getState() == GrandExchangeOfferState.CANCELLED_BUY;
|
||||
|
||||
offerState.setText(getNameForState(newOffer.getState())
|
||||
+ " at "
|
||||
+ StackFormatter.formatNumber(newOffer.getState() == GrandExchangeOfferState.BOUGHT ? (newOffer.getSpent() / newOffer.getTotalQuantity()) : newOffer.getPrice())
|
||||
+ (newOffer.getTotalQuantity() > 1 ? " gp ea" : " gp"));
|
||||
String offerState = (buying ? "Bought " : "Sold ")
|
||||
+ StackFormatter.quantityToRSDecimalStack(newOffer.getQuantitySold()) + " / "
|
||||
+ StackFormatter.quantityToRSDecimalStack(newOffer.getTotalQuantity());
|
||||
|
||||
progressBar.setMaximum(newOffer.getTotalQuantity());
|
||||
offerInfo.setText(offerState);
|
||||
|
||||
itemPrice.setText(htmlLabel("Price each: ", newOffer.getPrice() + ""));
|
||||
|
||||
String action = buying ? "Spent: " : "Received: ";
|
||||
|
||||
offerSpent.setText(htmlLabel(action, StackFormatter.formatNumber(newOffer.getSpent()) + " / "
|
||||
+ StackFormatter.formatNumber(newOffer.getPrice() * newOffer.getTotalQuantity())));
|
||||
|
||||
progressBar.setForeground(getProgressColor(newOffer));
|
||||
progressBar.setMaximumValue(newOffer.getTotalQuantity());
|
||||
progressBar.setValue(newOffer.getQuantitySold());
|
||||
progressBar.setBackground(getColorForState(newOffer.getState()));
|
||||
progressBar.setString(newOffer.getQuantitySold() + "/" + newOffer.getTotalQuantity());
|
||||
progressBar.update();
|
||||
|
||||
/* Couldn't set the tooltip for the container panel as the children override it, so I'm setting
|
||||
* the tooltips on the children instead. */
|
||||
for (Component c : container.getComponents())
|
||||
{
|
||||
if (c instanceof JPanel)
|
||||
{
|
||||
JPanel panel = (JPanel) c;
|
||||
panel.setToolTipText(htmlTooltip(((int) progressBar.getPercentage()) + "%"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
private String getNameForState(GrandExchangeOfferState state)
|
||||
private String htmlTooltip(String value)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case CANCELLED_BUY:
|
||||
return "Buying cancelled";
|
||||
case CANCELLED_SELL:
|
||||
return "Selling cancelled";
|
||||
case BUYING:
|
||||
return "Buying";
|
||||
case BOUGHT:
|
||||
return "Bought";
|
||||
case SELLING:
|
||||
return "Selling";
|
||||
case SOLD:
|
||||
return "Sold";
|
||||
case EMPTY:
|
||||
default:
|
||||
return "Empty";
|
||||
|
||||
}
|
||||
return "<html><body style = 'color:" + SwingUtil.toHexColor(ColorScheme.LIGHT_GRAY_COLOR) + "'>Progress: <span style = 'color:white'>" + value + "</span></body></html>";
|
||||
}
|
||||
|
||||
private Color getColorForState(GrandExchangeOfferState state)
|
||||
private String htmlLabel(String key, String value)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case CANCELLED_BUY:
|
||||
case CANCELLED_SELL:
|
||||
return GE_CANCELLED_RED;
|
||||
case BUYING:
|
||||
case SELLING:
|
||||
return GE_INPROGRESS_ORANGE;
|
||||
case BOUGHT:
|
||||
case SOLD:
|
||||
return GE_FINISHED_GREEN;
|
||||
case EMPTY:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
return "<html><body style = 'color:white'>" + key + "<span style = 'color:" + SwingUtil.toHexColor(ColorScheme.LIGHT_GRAY_COLOR) + "'>" + value + "</span></body></html>";
|
||||
}
|
||||
|
||||
private void switchPanel()
|
||||
{
|
||||
this.showingFace = !this.showingFace;
|
||||
cardLayout.show(container, showingFace ? FACE_CARD : DETAILS_CARD);
|
||||
}
|
||||
|
||||
private Color getProgressColor(GrandExchangeOffer offer)
|
||||
{
|
||||
if (offer.getState() == CANCELLED_BUY || offer.getState() == CANCELLED_SELL)
|
||||
{
|
||||
return ColorScheme.PROGRESS_ERROR_COLOR;
|
||||
}
|
||||
|
||||
if (offer.getQuantitySold() == offer.getTotalQuantity())
|
||||
{
|
||||
return ColorScheme.PROGRESS_COMPLETE_COLOR;
|
||||
}
|
||||
|
||||
return ColorScheme.PROGRESS_INPROGRESS_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.grandexchange;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.CardLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GrandExchangeOffer;
|
||||
import net.runelite.api.GrandExchangeOfferState;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.components.PluginErrorPanel;
|
||||
|
||||
public class GrandExchangeOffersPanel extends JPanel
|
||||
{
|
||||
private static final String ERROR_PANEL = "ERROR_PANEL";
|
||||
private static final String OFFERS_PANEL = "OFFERS_PANEL";
|
||||
|
||||
private static final int MAX_OFFERS = 8;
|
||||
|
||||
private final GridBagConstraints constraints = new GridBagConstraints();
|
||||
private final CardLayout cardLayout = new CardLayout();
|
||||
|
||||
/* The offers container, this will hold all the individual ge offers panels */
|
||||
private final JPanel offerPanel = new JPanel();
|
||||
|
||||
/* The error panel, this displays an error message */
|
||||
private final PluginErrorPanel errorPanel = new PluginErrorPanel();
|
||||
|
||||
/* The center panel, this holds either the error panel or the offers container */
|
||||
private final JPanel container = new JPanel(cardLayout);
|
||||
|
||||
private final Client client;
|
||||
private final ItemManager itemManager;
|
||||
private final ScheduledExecutorService executor;
|
||||
|
||||
private GrandExchangeOfferSlot[] offerSlotPanels = new GrandExchangeOfferSlot[MAX_OFFERS];
|
||||
|
||||
public GrandExchangeOffersPanel(Client client, ItemManager itemManager, ScheduledExecutorService executor)
|
||||
{
|
||||
this.client = client;
|
||||
this.itemManager = itemManager;
|
||||
this.executor = executor;
|
||||
init();
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
setLayout(new BorderLayout());
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
constraints.fill = GridBagConstraints.HORIZONTAL;
|
||||
constraints.weightx = 1;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 0;
|
||||
|
||||
/* This panel wraps the offers panel and limits its height */
|
||||
JPanel offersWrapper = new JPanel(new BorderLayout());
|
||||
offersWrapper.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
offersWrapper.add(offerPanel, BorderLayout.NORTH);
|
||||
|
||||
offerPanel.setLayout(new GridBagLayout());
|
||||
offerPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
offerPanel.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
/* This panel wraps the error panel and limits its height */
|
||||
JPanel errorWrapper = new JPanel(new BorderLayout());
|
||||
errorWrapper.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
errorWrapper.add(errorPanel, BorderLayout.NORTH);
|
||||
|
||||
errorPanel.setBorder(new EmptyBorder(50, 20, 20, 20));
|
||||
errorPanel.setContent("No offers detected", "No grand exchange offers were found on your account.");
|
||||
|
||||
container.add(offersWrapper, OFFERS_PANEL);
|
||||
container.add(errorWrapper, ERROR_PANEL);
|
||||
|
||||
add(container, BorderLayout.CENTER);
|
||||
|
||||
resetOffers();
|
||||
}
|
||||
|
||||
void resetOffers()
|
||||
{
|
||||
offerPanel.removeAll();
|
||||
for (int i = 0; i < offerSlotPanels.length; i++)
|
||||
{
|
||||
offerSlotPanels[i] = null;
|
||||
}
|
||||
updateEmptyOffersPanel();
|
||||
}
|
||||
|
||||
void updateOffer(ItemComposition item, BufferedImage itemImage, GrandExchangeOffer newOffer, int slot)
|
||||
{
|
||||
/* If slot was previously filled, and is now empty, remove it from the list */
|
||||
if (newOffer == null || newOffer.getState() == GrandExchangeOfferState.EMPTY)
|
||||
{
|
||||
if (offerSlotPanels[slot] != null)
|
||||
{
|
||||
offerPanel.remove(offerSlotPanels[slot]);
|
||||
offerSlotPanels[slot] = null;
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
removeTopMargin();
|
||||
updateEmptyOffersPanel();
|
||||
return;
|
||||
}
|
||||
|
||||
/* If slot was empty, and is now filled, add it to the list */
|
||||
if (offerSlotPanels[slot] == null)
|
||||
{
|
||||
GrandExchangeOfferSlot newSlot = new GrandExchangeOfferSlot();
|
||||
offerSlotPanels[slot] = newSlot;
|
||||
offerPanel.add(newSlot, constraints);
|
||||
constraints.gridy++;
|
||||
}
|
||||
|
||||
offerSlotPanels[slot].updateOffer(item, itemImage, newOffer);
|
||||
|
||||
removeTopMargin();
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
|
||||
updateEmptyOffersPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the border for the first offer slot.
|
||||
*/
|
||||
private void removeTopMargin()
|
||||
{
|
||||
|
||||
if (offerPanel.getComponentCount() <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
JPanel firstItem = (JPanel) offerPanel.getComponent(0);
|
||||
firstItem.setBorder(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calculates the amount of empty ge offer slots, if all slots are empty,
|
||||
* it shows the error panel.
|
||||
*/
|
||||
private void updateEmptyOffersPanel()
|
||||
{
|
||||
int nullCount = 0;
|
||||
for (GrandExchangeOfferSlot slot : offerSlotPanels)
|
||||
{
|
||||
if (slot == null)
|
||||
{
|
||||
nullCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nullCount == MAX_OFFERS)
|
||||
{
|
||||
offerPanel.removeAll();
|
||||
cardLayout.show(container, ERROR_PANEL);
|
||||
}
|
||||
else
|
||||
{
|
||||
cardLayout.show(container, OFFERS_PANEL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018, SomeoneWithAnInternetConnection
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -26,58 +27,58 @@
|
||||
package net.runelite.client.plugins.grandexchange;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.inject.Inject;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GrandExchangeOffer;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.ui.components.materialtabs.MaterialTab;
|
||||
import net.runelite.client.ui.components.materialtabs.MaterialTabGroup;
|
||||
|
||||
@Slf4j
|
||||
class GrandExchangePanel extends PluginPanel
|
||||
{
|
||||
private static final int MAX_OFFERS = 8;
|
||||
|
||||
// this panel will hold either the ge search panel or the ge offers panel
|
||||
private final JPanel display = new JPanel();
|
||||
|
||||
private final MaterialTabGroup tabGroup = new MaterialTabGroup(display);
|
||||
private final MaterialTab searchTab;
|
||||
|
||||
@Getter
|
||||
private GrandExchangeSearchPanel searchPanel;
|
||||
|
||||
private GrandExchangeOfferSlot[] offerSlotPanels = new GrandExchangeOfferSlot[MAX_OFFERS];
|
||||
|
||||
private JPanel offerPanel = new JPanel();
|
||||
|
||||
private JTabbedPane tabbedPane = new JTabbedPane();
|
||||
@Getter
|
||||
private GrandExchangeOffersPanel offersPanel;
|
||||
|
||||
@Inject
|
||||
GrandExchangePanel(Client client, ItemManager itemManager, ScheduledExecutorService executor)
|
||||
{
|
||||
setLayout(new BorderLayout());
|
||||
add(tabbedPane, BorderLayout.NORTH);
|
||||
super(false);
|
||||
|
||||
// Offer Panel
|
||||
offerPanel.setLayout(new BoxLayout(offerPanel, BoxLayout.Y_AXIS));
|
||||
for (int i = 0; i < offerSlotPanels.length; ++i)
|
||||
{
|
||||
offerSlotPanels[i] = new GrandExchangeOfferSlot();
|
||||
offerPanel.add(offerSlotPanels[i]);
|
||||
}
|
||||
setLayout(new BorderLayout());
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
// Search Panel
|
||||
searchPanel = new GrandExchangeSearchPanel(client, itemManager, executor);
|
||||
|
||||
tabbedPane.addTab("Offers", offerPanel);
|
||||
tabbedPane.addTab("Search", searchPanel);
|
||||
}
|
||||
//Offers Panel
|
||||
offersPanel = new GrandExchangeOffersPanel(client, itemManager, executor);
|
||||
|
||||
void updateOffer(ItemComposition item, BufferedImage itemImage, GrandExchangeOffer newOffer, int slot)
|
||||
{
|
||||
offerSlotPanels[slot].updateOffer(item, itemImage, newOffer);
|
||||
MaterialTab offersTab = new MaterialTab("Offers", tabGroup, offersPanel);
|
||||
searchTab = new MaterialTab("Search", tabGroup, searchPanel);
|
||||
|
||||
tabGroup.setBorder(new EmptyBorder(5, 0, 0, 0));
|
||||
tabGroup.addTab(offersTab);
|
||||
tabGroup.addTab(searchTab);
|
||||
tabGroup.select(offersTab); // selects the default selected tab
|
||||
|
||||
add(tabGroup, BorderLayout.NORTH);
|
||||
add(display, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
void showSearch()
|
||||
@@ -87,7 +88,7 @@ class GrandExchangePanel extends PluginPanel
|
||||
return;
|
||||
}
|
||||
|
||||
tabbedPane.setSelectedComponent(searchPanel);
|
||||
tabGroup.select(searchTab);
|
||||
revalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,7 @@ import net.runelite.api.ItemComposition;
|
||||
import net.runelite.api.MenuEntry;
|
||||
import net.runelite.api.events.ConfigChanged;
|
||||
import net.runelite.api.events.FocusChanged;
|
||||
import net.runelite.api.events.GameStateChanged;
|
||||
import net.runelite.api.events.GrandExchangeOfferChanged;
|
||||
import net.runelite.api.events.MenuEntryAdded;
|
||||
import net.runelite.api.widgets.WidgetID;
|
||||
@@ -113,6 +114,7 @@ public class GrandExchangePlugin extends Plugin
|
||||
button = NavigationButton.builder()
|
||||
.name("GE Offers")
|
||||
.icon(icon)
|
||||
.priority(3)
|
||||
.panel(panel)
|
||||
.build();
|
||||
|
||||
@@ -161,7 +163,16 @@ public class GrandExchangePlugin extends Plugin
|
||||
ItemComposition offerItem = itemManager.getItemComposition(offer.getItemId());
|
||||
boolean shouldStack = offerItem.isStackable() || offer.getTotalQuantity() > 1;
|
||||
BufferedImage itemImage = itemManager.getImage(offer.getItemId(), offer.getTotalQuantity(), shouldStack);
|
||||
SwingUtilities.invokeLater(() -> panel.updateOffer(offerItem, itemImage, offerEvent.getOffer(), offerEvent.getSlot()));
|
||||
SwingUtilities.invokeLater(() -> panel.getOffersPanel().updateOffer(offerItem, itemImage, offerEvent.getOffer(), offerEvent.getSlot()));
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onGameStateChanged(GameStateChanged gameStateChanged)
|
||||
{
|
||||
if (gameStateChanged.getGameState() == GameState.LOGIN_SCREEN)
|
||||
{
|
||||
panel.getOffersPanel().resetOffers();
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Seth <https://github.com/sethtroll>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -26,19 +27,19 @@ package net.runelite.client.plugins.grandexchange;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.CardLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -46,26 +47,69 @@ import net.runelite.api.Client;
|
||||
import net.runelite.api.ItemComposition;
|
||||
import net.runelite.client.game.AsyncBufferedImage;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.plugins.hiscore.IconTextField;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.components.IconTextField;
|
||||
import net.runelite.client.ui.components.PluginErrorPanel;
|
||||
import net.runelite.http.api.item.Item;
|
||||
import net.runelite.http.api.item.ItemPrice;
|
||||
import net.runelite.http.api.item.SearchResult;
|
||||
|
||||
/**
|
||||
* This panel holds the search section of the Grand Exchange Plugin.
|
||||
* It should display a search bar and either item results or a error panel.
|
||||
*/
|
||||
@Slf4j
|
||||
class GrandExchangeSearchPanel extends JPanel
|
||||
{
|
||||
private static final List<GrandExchangeItems> ITEMS_LIST = new ArrayList<>();
|
||||
private static final String ERROR_PANEL = "ERROR_PANEL";
|
||||
private static final String RESULTS_PANEL = "RESULTS_PANEL";
|
||||
|
||||
private static final ImageIcon SEARCH_ICON;
|
||||
private static final ImageIcon LOADING_ICON;
|
||||
private static final ImageIcon ERROR_ICON;
|
||||
|
||||
private final GridBagConstraints constraints = new GridBagConstraints();
|
||||
private final CardLayout cardLayout = new CardLayout();
|
||||
|
||||
private final Client client;
|
||||
private final ItemManager itemManager;
|
||||
private final ScheduledExecutorService executor;
|
||||
|
||||
private Icon search;
|
||||
private final IconTextField searchBox = new IconTextField();
|
||||
|
||||
private IconTextField searchBox = new IconTextField();
|
||||
private JPanel container = new JPanel();
|
||||
private JPanel searchItemsPanel = new JPanel();
|
||||
private JLabel searchingLabel = new JLabel();
|
||||
/* The main container, this holds the search bar and the center panel */
|
||||
private final JPanel container = new JPanel();
|
||||
|
||||
/* The results container, this will hold all the individual ge item panels */
|
||||
private final JPanel searchItemsPanel = new JPanel();
|
||||
|
||||
/* The center panel, this holds either the error panel or the results container */
|
||||
private final JPanel centerPanel = new JPanel(cardLayout);
|
||||
|
||||
/* The error panel, this displays an error message */
|
||||
private final PluginErrorPanel errorPanel = new PluginErrorPanel();
|
||||
|
||||
/* The results wrapper, this scrolling panel wraps the results container */
|
||||
private JScrollPane resultsWrapper;
|
||||
|
||||
private List<GrandExchangeItems> itemsList = new ArrayList<>();
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
SEARCH_ICON = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("search_darker.png")));
|
||||
LOADING_ICON = new ImageIcon(IconTextField.class.getResource("loading_spinner.gif"));
|
||||
ERROR_ICON = new ImageIcon(ImageIO.read(IconTextField.class.getResourceAsStream("error.png")));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
GrandExchangeSearchPanel(Client client, ItemManager itemManager, ScheduledExecutorService executor)
|
||||
{
|
||||
@@ -78,38 +122,54 @@ class GrandExchangeSearchPanel extends JPanel
|
||||
void init()
|
||||
{
|
||||
setLayout(new BorderLayout());
|
||||
container.setLayout(new BorderLayout());
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
// Search Box
|
||||
try
|
||||
{
|
||||
BufferedImage icon;
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
icon = ImageIO.read(GrandExchangePlugin.class.getResourceAsStream("search.png"));
|
||||
}
|
||||
search = new ImageIcon(icon);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
log.warn("Failed to read icon", e);
|
||||
}
|
||||
container.setLayout(new BorderLayout(5, 5));
|
||||
container.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
container.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
searchBox.setIcon(search);
|
||||
searchBox.setPreferredSize(new Dimension(100, 30));
|
||||
searchBox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
|
||||
searchBox.setHoverBackgroundColor(ColorScheme.MEDIUM_GRAY_COLOR.brighter());
|
||||
searchBox.setIcon(SEARCH_ICON);
|
||||
searchBox.addActionListener(e -> executor.execute(() -> priceLookup(false)));
|
||||
|
||||
searchItemsPanel.setLayout(new GridBagLayout());
|
||||
searchItemsPanel.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
constraints.fill = GridBagConstraints.HORIZONTAL;
|
||||
constraints.weightx = 1;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 0;
|
||||
|
||||
/* This panel wraps the results panel and guarantees the scrolling behaviour */
|
||||
JPanel wrapper = new JPanel(new BorderLayout());
|
||||
wrapper.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
wrapper.add(searchItemsPanel, BorderLayout.NORTH);
|
||||
|
||||
resultsWrapper = new JScrollPane(wrapper);
|
||||
resultsWrapper.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
resultsWrapper.getVerticalScrollBar().setPreferredSize(new Dimension(12, 0));
|
||||
resultsWrapper.getVerticalScrollBar().setBorder(new EmptyBorder(0, 5, 0, 0));
|
||||
resultsWrapper.setVisible(false);
|
||||
|
||||
/* This panel wraps the error panel and limits its height */
|
||||
JPanel errorWrapper = new JPanel(new BorderLayout());
|
||||
errorWrapper.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
errorWrapper.add(errorPanel, BorderLayout.NORTH);
|
||||
|
||||
errorPanel.setContent("Grand Exchange Search",
|
||||
"Here you can search for an item by its name to find price information.");
|
||||
|
||||
centerPanel.add(resultsWrapper, RESULTS_PANEL);
|
||||
centerPanel.add(errorWrapper, ERROR_PANEL);
|
||||
|
||||
cardLayout.show(centerPanel, ERROR_PANEL);
|
||||
|
||||
container.add(searchBox, BorderLayout.NORTH);
|
||||
container.add(centerPanel, BorderLayout.CENTER);
|
||||
|
||||
// Searching label
|
||||
searchingLabel.setHorizontalAlignment(JLabel.CENTER);
|
||||
searchingLabel.setForeground(Color.YELLOW);
|
||||
|
||||
// Items Panel
|
||||
searchItemsPanel.setLayout(new GridLayout(0, 1, 0, 3));
|
||||
searchItemsPanel.setBorder(new EmptyBorder(3, 0, 0, 0));
|
||||
|
||||
container.add(searchItemsPanel, BorderLayout.SOUTH);
|
||||
add(container, BorderLayout.NORTH);
|
||||
add(container, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
void priceLookup(String item)
|
||||
@@ -130,7 +190,9 @@ class GrandExchangeSearchPanel extends JPanel
|
||||
|
||||
// Input is not empty, add searching label
|
||||
searchItemsPanel.removeAll();
|
||||
showSearchString("Searching...");
|
||||
searchBox.setBackground(ColorScheme.MEDIUM_GRAY_COLOR);
|
||||
searchBox.setEditable(false);
|
||||
searchBox.setIcon(LOADING_ICON);
|
||||
|
||||
SearchResult result;
|
||||
|
||||
@@ -141,13 +203,19 @@ class GrandExchangeSearchPanel extends JPanel
|
||||
catch (ExecutionException ex)
|
||||
{
|
||||
log.warn("Unable to search for item {}", lookup, ex);
|
||||
showSearchString("Error performing search");
|
||||
searchBox.setIcon(ERROR_ICON);
|
||||
searchBox.setEditable(true);
|
||||
errorPanel.setContent("Error fetching results", "An error occured why trying to fetch item data, please try again later.");
|
||||
cardLayout.show(centerPanel, ERROR_PANEL);
|
||||
return;
|
||||
}
|
||||
|
||||
itemsList.clear();
|
||||
|
||||
if (result != null && !result.getItems().isEmpty())
|
||||
{
|
||||
cardLayout.show(centerPanel, RESULTS_PANEL);
|
||||
|
||||
for (Item item : result.getItems())
|
||||
{
|
||||
int itemId = item.getId();
|
||||
@@ -170,7 +238,7 @@ class GrandExchangeSearchPanel extends JPanel
|
||||
|
||||
AsyncBufferedImage itemImage = itemManager.getImage(itemId);
|
||||
|
||||
ITEMS_LIST.add(new GrandExchangeItems(itemImage, item.getName(), itemId, itemPrice != null ? itemPrice.getPrice() : 0, itemComp.getPrice() * 0.6));
|
||||
itemsList.add(new GrandExchangeItems(itemImage, item.getName(), itemId, itemPrice != null ? itemPrice.getPrice() : 0, itemComp.getPrice() * 0.6));
|
||||
|
||||
// If using hotkey to lookup item, stop after finding match.
|
||||
if (exactMatch && item.getName().equalsIgnoreCase(lookup))
|
||||
@@ -179,44 +247,51 @@ class GrandExchangeSearchPanel extends JPanel
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
searchBox.setIcon(ERROR_ICON);
|
||||
errorPanel.setContent("No results found.", "No items were found with that name, please try again.");
|
||||
cardLayout.show(centerPanel, ERROR_PANEL);
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(() ->
|
||||
{
|
||||
if (ITEMS_LIST.isEmpty())
|
||||
int index = 0;
|
||||
for (GrandExchangeItems item : itemsList)
|
||||
{
|
||||
showSearchString("No results found.");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (GrandExchangeItems item : ITEMS_LIST)
|
||||
GrandExchangeItemPanel panel = new GrandExchangeItemPanel(item.getIcon(), item.getName(),
|
||||
item.getItemId(), item.getGePrice(), item.getHaPrice());
|
||||
|
||||
/*
|
||||
Add the first item directly, wrap the rest with margin. This margin hack is because
|
||||
gridbaglayout does not support inter-element margins.
|
||||
*/
|
||||
if (index++ > 0)
|
||||
{
|
||||
GrandExchangeItemPanel panel = new GrandExchangeItemPanel(item.getIcon(), item.getName(),
|
||||
item.getItemId(), item.getGePrice(), item.getHaPrice());
|
||||
|
||||
searchItemsPanel.add(panel);
|
||||
JPanel marginWrapper = new JPanel(new BorderLayout());
|
||||
marginWrapper.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
marginWrapper.setBorder(new EmptyBorder(5, 0, 0, 0));
|
||||
marginWrapper.add(panel, BorderLayout.NORTH);
|
||||
searchItemsPanel.add(marginWrapper, constraints);
|
||||
}
|
||||
else
|
||||
{
|
||||
searchItemsPanel.add(panel, constraints);
|
||||
}
|
||||
|
||||
constraints.gridy++;
|
||||
}
|
||||
|
||||
// Remove searching label after search is complete
|
||||
showSearchString(null);
|
||||
ITEMS_LIST.clear();
|
||||
// remove focus from the search bar
|
||||
searchItemsPanel.requestFocusInWindow();
|
||||
searchBox.setEditable(true);
|
||||
|
||||
// Remove searching label after search is complete
|
||||
if (!itemsList.isEmpty())
|
||||
{
|
||||
searchBox.setIcon(SEARCH_ICON);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showSearchString(String str)
|
||||
{
|
||||
if (str != null)
|
||||
{
|
||||
remove(searchingLabel);
|
||||
searchingLabel.setText(str);
|
||||
add(searchingLabel, BorderLayout.CENTER);
|
||||
}
|
||||
else
|
||||
{
|
||||
remove(searchingLabel);
|
||||
}
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -25,10 +26,8 @@
|
||||
package net.runelite.client.plugins.hiscore;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.GridLayout;
|
||||
@@ -39,31 +38,24 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Inject;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.ButtonGroup;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JToggleButton;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.event.MouseInputAdapter;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.MatteBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Experience;
|
||||
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.components.IconTextField;
|
||||
import net.runelite.client.util.StackFormatter;
|
||||
import net.runelite.http.api.hiscore.HiscoreClient;
|
||||
import net.runelite.http.api.hiscore.HiscoreEndpoint;
|
||||
@@ -102,13 +94,17 @@ import net.runelite.http.api.hiscore.Skill;
|
||||
@Slf4j
|
||||
public class HiscorePanel extends PluginPanel
|
||||
{
|
||||
private static final String SKILL_NAME = "SKILL_NAME";
|
||||
private static final String SKILL = "SKILL";
|
||||
/* The maximum allowed username length in runescape accounts */
|
||||
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.
|
||||
*/
|
||||
private static final Set<HiscoreSkill> SKILLS = new LinkedHashSet<>(Arrays.asList(
|
||||
private static final List<HiscoreSkill> SKILLS = ImmutableList.of(
|
||||
ATTACK, HITPOINTS, MINING,
|
||||
STRENGTH, AGILITY, SMITHING,
|
||||
DEFENCE, HERBLORE, FISHING,
|
||||
@@ -117,7 +113,7 @@ public class HiscorePanel extends PluginPanel
|
||||
MAGIC, FLETCHING, WOODCUTTING,
|
||||
RUNECRAFT, SLAYER, FARMING,
|
||||
CONSTRUCTION, HUNTER
|
||||
));
|
||||
);
|
||||
|
||||
@Inject
|
||||
ScheduledExecutorService executor;
|
||||
@@ -132,24 +128,45 @@ public class HiscorePanel extends PluginPanel
|
||||
private final List<JLabel> skillLabels = new ArrayList<>();
|
||||
|
||||
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 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
|
||||
public HiscorePanel(HiscoreConfig config)
|
||||
{
|
||||
super();
|
||||
this.config = config;
|
||||
|
||||
// Panel "constants"
|
||||
// This was an EtchedBorder, but the style would change when the window was maximized.
|
||||
Border subPanelBorder = BorderFactory.createLineBorder(this.getBackground().brighter(), 2);
|
||||
setBorder(new EmptyBorder(10, 10, 0, 10));
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
// Create GBL to arrange sub items
|
||||
GridBagLayout gridBag = new GridBagLayout();
|
||||
@@ -160,28 +177,11 @@ public class HiscorePanel extends PluginPanel
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.anchor = GridBagConstraints.NORTH;
|
||||
|
||||
// Search box
|
||||
JPanel inputPanel = new JPanel();
|
||||
inputPanel.setLayout(new BorderLayout(7, 7));
|
||||
inputPanel.setBorder(subPanelBorder);
|
||||
|
||||
Icon 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.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.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@@ -192,7 +192,6 @@ public class HiscorePanel extends PluginPanel
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (client == null)
|
||||
{
|
||||
return;
|
||||
@@ -206,97 +205,20 @@ public class HiscorePanel extends PluginPanel
|
||||
}
|
||||
}
|
||||
});
|
||||
inputPanel.add(input, BorderLayout.CENTER);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 0;
|
||||
c.weightx = 1;
|
||||
c.weighty = 0;
|
||||
c.insets = new Insets(0, 0, 3, 0);
|
||||
gridBag.setConstraints(inputPanel, c);
|
||||
add(inputPanel);
|
||||
|
||||
// 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);
|
||||
c.insets = new Insets(0, 0, 10, 0);
|
||||
gridBag.setConstraints(input, c);
|
||||
add(input);
|
||||
|
||||
/* The container for all the endpoint selectors */
|
||||
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())
|
||||
{
|
||||
try
|
||||
@@ -307,25 +229,32 @@ public class HiscorePanel extends PluginPanel
|
||||
iconImage = ImageIO.read(HiscorePanel.class.getResourceAsStream(
|
||||
endpoint.name().toLowerCase() + ".png"));
|
||||
}
|
||||
JToggleButton button = new JToggleButton();
|
||||
button.setIcon(new ImageIcon(iconImage));
|
||||
button.setPreferredSize(new Dimension(24, 24));
|
||||
button.setBackground(Color.WHITE);
|
||||
button.setFocusPainted(false);
|
||||
button.setActionCommand(endpoint.name());
|
||||
button.setToolTipText(endpoint.getName() + " Hiscores");
|
||||
button.addActionListener((e -> executor.execute(this::lookup)));
|
||||
button.addMouseListener(new MouseAdapter()
|
||||
|
||||
JPanel panel = new JPanel();
|
||||
JLabel label = new JLabel();
|
||||
|
||||
label.setIcon(new ImageIcon(iconImage));
|
||||
|
||||
panel.add(label);
|
||||
panel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
panel.setToolTipText(endpoint.getName() + " Hiscores");
|
||||
panel.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e)
|
||||
public void mouseClicked(MouseEvent e)
|
||||
{
|
||||
if (loading)
|
||||
{
|
||||
return;
|
||||
}
|
||||
executor.execute(HiscorePanel.this::lookup);
|
||||
selectedEndPoint = endpoint;
|
||||
updateButtons();
|
||||
}
|
||||
});
|
||||
endpointButtons.add(button);
|
||||
endpointButtonGroup.add(button);
|
||||
endpointPanel.add(button);
|
||||
|
||||
endPoints.add(panel);
|
||||
endpointPanel.add(panel);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
@@ -333,156 +262,61 @@ public class HiscorePanel extends PluginPanel
|
||||
}
|
||||
}
|
||||
|
||||
endpointButtons.get(0).setSelected(true);
|
||||
endpointButtons.get(0).setBackground(Color.CYAN);
|
||||
/* Default endpoint is the general (normal) endpoint */
|
||||
selectedEndPoint = HiscoreEndpoint.NORMAL;
|
||||
updateButtons();
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 5;
|
||||
// Last item has a nonzero weighty so it will expand to fill vertical space
|
||||
c.weighty = 1;
|
||||
c.gridy = 1;
|
||||
gridBag.setConstraints(endpointPanel, c);
|
||||
add(endpointPanel);
|
||||
}
|
||||
|
||||
void addInputKeyListener(KeyListener l)
|
||||
{
|
||||
this.input.addKeyListener(l);
|
||||
}
|
||||
// Panel that holds skill icons
|
||||
GridLayout stats = new GridLayout(8, 3);
|
||||
statsPanel.setLayout(stats);
|
||||
statsPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
statsPanel.setBorder(new EmptyBorder(5, 0, 5, 0));
|
||||
|
||||
void removeInputKeyListener(KeyListener l)
|
||||
{
|
||||
this.input.removeKeyListener(l);
|
||||
}
|
||||
|
||||
private void changeDetail(String skillName, HiscoreSkill skill)
|
||||
{
|
||||
if (result == null || result.getPlayer() == null)
|
||||
// For each skill on the ingame skill panel, create a Label and add it to the UI
|
||||
for (HiscoreSkill skill : SKILLS)
|
||||
{
|
||||
return;
|
||||
JPanel panel = makeSkillPanel(skill);
|
||||
panel.setOpaque(false);
|
||||
statsPanel.add(panel);
|
||||
}
|
||||
|
||||
String text;
|
||||
int progress = -1;
|
||||
switch (skillName)
|
||||
{
|
||||
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;
|
||||
c.gridx = 0;
|
||||
c.gridy = 2;
|
||||
gridBag.setConstraints(statsPanel, c);
|
||||
add(statsPanel);
|
||||
|
||||
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;
|
||||
double xpGoal = xpForNextLevel != -1 ? xpForNextLevel - xpForCurrentLevel : 100;
|
||||
progress = (int) ((xpGained / xpGoal) * 100f);
|
||||
totalPanel.add(makeSkillPanel(null)); //combat has no hiscore skill, refered to as null
|
||||
totalPanel.add(makeSkillPanel(OVERALL));
|
||||
|
||||
}
|
||||
text = "Skill: " + skillName + System.lineSeparator()
|
||||
+ "Rank: " + rank + System.lineSeparator()
|
||||
+ "Experience: " + exp + System.lineSeparator()
|
||||
+ "Remaining XP: " + remainingXp;
|
||||
break;
|
||||
}
|
||||
}
|
||||
c.gridx = 0;
|
||||
c.gridy = 3;
|
||||
gridBag.setConstraints(totalPanel, c);
|
||||
add(totalPanel);
|
||||
|
||||
details.setFont(UIManager.getFont("Label.font"));
|
||||
details.setText(text);
|
||||
JPanel minigamePanel = new JPanel();
|
||||
// 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)
|
||||
{
|
||||
progressBar.setVisible(true);
|
||||
progressBar.setValue(progress);
|
||||
progressBar.setBackground(Color.getHSBColor((progress / 100.f) * (120.f / 360.f), 1, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
progressBar.setVisible(false);
|
||||
}
|
||||
minigamePanel.add(makeSkillPanel(CLUE_SCROLL_ALL));
|
||||
minigamePanel.add(makeSkillPanel(LAST_MAN_STANDING));
|
||||
minigamePanel.add(makeSkillPanel(BOUNTY_HUNTER_ROGUE));
|
||||
minigamePanel.add(makeSkillPanel(BOUNTY_HUNTER_HUNTER));
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 4;
|
||||
gridBag.setConstraints(minigamePanel, c);
|
||||
add(minigamePanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -492,16 +326,14 @@ public class HiscorePanel extends PluginPanel
|
||||
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();
|
||||
label.setFont(FontManager.getRunescapeSmallFont());
|
||||
label.setText("--");
|
||||
|
||||
// Store the skill that the label displays so we can tell them apart
|
||||
label.putClientProperty(SKILL_NAME, skillName);
|
||||
label.putClientProperty(SKILL, skill);
|
||||
|
||||
String skillIcon = "skill_icons_small/" + skillName.toLowerCase() + ".png";
|
||||
String skillIcon = "skill_icons_small/" + (skill == null ? "combat" : skill.getName().toLowerCase()) + ".png";
|
||||
log.debug("Loading skill icon from {}", skillIcon);
|
||||
|
||||
try
|
||||
@@ -518,36 +350,31 @@ public class HiscorePanel extends PluginPanel
|
||||
log.warn(null, ex);
|
||||
}
|
||||
|
||||
// Show skill details on hover
|
||||
label.addMouseListener(new MouseInputAdapter()
|
||||
{
|
||||
@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);
|
||||
boolean totalLabel = skill == HiscoreSkill.OVERALL || skill == null; //overall or combat
|
||||
label.setIconTextGap(totalLabel ? 10 : 4);
|
||||
|
||||
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));
|
||||
|
||||
return skillPanel;
|
||||
}
|
||||
|
||||
public void lookup(String username)
|
||||
{
|
||||
input.setText(username);
|
||||
|
||||
selectedEndPoint = HiscoreEndpoint.NORMAL; //reset the endpoint to regular player
|
||||
updateButtons();
|
||||
|
||||
lookup();
|
||||
}
|
||||
|
||||
private void lookup()
|
||||
{
|
||||
String lookup = input.getText();
|
||||
details.setText("Loading...");
|
||||
progressBar.setVisible(false);
|
||||
|
||||
lookup = sanitize(lookup);
|
||||
|
||||
@@ -556,43 +383,77 @@ public class HiscorePanel extends PluginPanel
|
||||
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)
|
||||
{
|
||||
label.setText("--");
|
||||
}
|
||||
|
||||
// if for some reason no endpoint was selected, default to normal
|
||||
if (selectedEndPoint == null)
|
||||
{
|
||||
selectedEndPoint = HiscoreEndpoint.NORMAL;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
HiscoreEndpoint endpoint = HiscoreEndpoint.valueOf(endpointButtonGroup.getSelection().getActionCommand());
|
||||
log.debug("Hiscore endpoint " + endpoint.name() + " selected");
|
||||
|
||||
result = hiscoreClient.lookup(lookup, endpoint);
|
||||
log.debug("Hiscore endpoint " + selectedEndPoint.name() + " selected");
|
||||
result = hiscoreClient.lookup(lookup, selectedEndPoint);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
log.warn("Error fetching Hiscore data " + ex.getMessage());
|
||||
details.setText("Error fetching Hiscore data");
|
||||
progressBar.setVisible(false);
|
||||
input.setIcon(ERROR_ICON);
|
||||
input.setEditable(true);
|
||||
loading = false;
|
||||
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)
|
||||
{
|
||||
String skillName = (String) label.getClientProperty(SKILL_NAME);
|
||||
HiscoreSkill skill = (HiscoreSkill) label.getClientProperty(SKILL);
|
||||
HiscoreSkill skill = find(index);
|
||||
|
||||
if (skillName.equals("Combat"))
|
||||
if (skill == null)
|
||||
{
|
||||
if (result.getPlayer() != null)
|
||||
{
|
||||
int combatLevel = Experience.getCombatLevel(
|
||||
result.getAttack().getLevel(),
|
||||
result.getStrength().getLevel(),
|
||||
result.getDefence().getLevel(),
|
||||
result.getHitpoints().getLevel(),
|
||||
result.getMagic().getLevel(),
|
||||
result.getRanged().getLevel(),
|
||||
result.getPrayer().getLevel()
|
||||
result.getAttack().getLevel(),
|
||||
result.getStrength().getLevel(),
|
||||
result.getDefence().getLevel(),
|
||||
result.getHitpoints().getLevel(),
|
||||
result.getMagic().getLevel(),
|
||||
result.getRanged().getLevel(),
|
||||
result.getPrayer().getLevel()
|
||||
);
|
||||
label.setText(Integer.toString(combatLevel));
|
||||
}
|
||||
@@ -600,7 +461,6 @@ public class HiscorePanel extends PluginPanel
|
||||
else if (result.getSkill(skill) != null && result.getSkill(skill).getRank() != -1)
|
||||
{
|
||||
Skill s = result.getSkill(skill);
|
||||
|
||||
int level;
|
||||
if (config.virtualLevels() && SKILLS.contains(skill))
|
||||
{
|
||||
@@ -613,12 +473,191 @@ public class HiscorePanel extends PluginPanel
|
||||
|
||||
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
|
||||
details.setFont(UIManager.getFont("Label.font").deriveFont(Font.ITALIC));
|
||||
details.setText("Hover over a skill for details");
|
||||
progressBar.setVisible(false);
|
||||
switch (index - SKILLS.size())
|
||||
{
|
||||
case 0:
|
||||
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)
|
||||
@@ -626,20 +665,18 @@ public class HiscorePanel extends PluginPanel
|
||||
return lookup.replace('\u00A0', ' ');
|
||||
}
|
||||
|
||||
/*
|
||||
When an endpoint gets selected, this method will correctly display the selected one
|
||||
with an orange underline.
|
||||
*/
|
||||
private void updateButtons()
|
||||
{
|
||||
for (JToggleButton button : endpointButtons)
|
||||
for (JPanel panel : endPoints)
|
||||
{
|
||||
Color color;
|
||||
if (button.isSelected())
|
||||
{
|
||||
color = Color.CYAN;
|
||||
}
|
||||
else
|
||||
{
|
||||
color = Color.WHITE;
|
||||
}
|
||||
button.setBackground(color);
|
||||
panel.setBorder(new EmptyBorder(0, 0, 1, 0));
|
||||
}
|
||||
|
||||
int selectedIndex = selectedEndPoint.ordinal();
|
||||
endPoints.get(selectedIndex).setBorder(new MatteBorder(0, 0, 1, 0, ColorScheme.BRAND_ORANGE));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -98,12 +98,13 @@ public class HiscorePlugin extends Plugin
|
||||
BufferedImage icon;
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
icon = ImageIO.read(getClass().getResourceAsStream("hiscore.gif"));
|
||||
icon = ImageIO.read(getClass().getResourceAsStream("normal.png"));
|
||||
}
|
||||
|
||||
navButton = NavigationButton.builder()
|
||||
.name("Hiscore")
|
||||
.icon(icon)
|
||||
.priority(5)
|
||||
.panel(hiscorePanel)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Abex
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -27,14 +28,22 @@ package net.runelite.client.plugins.info;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.google.inject.Inject;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Singleton;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.GroupLayout;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.LayoutStyle;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
@@ -42,8 +51,10 @@ import net.runelite.api.events.SessionClose;
|
||||
import net.runelite.api.events.SessionOpen;
|
||||
import net.runelite.client.RuneLiteProperties;
|
||||
import net.runelite.client.account.SessionManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.util.LinkBrowser;
|
||||
import net.runelite.client.util.RunnableExceptionLogger;
|
||||
|
||||
@Slf4j
|
||||
@@ -52,6 +63,14 @@ public class InfoPanel extends PluginPanel
|
||||
{
|
||||
private static final String RUNELITE_LOGIN = "https://runelite_login/";
|
||||
|
||||
private static final ImageIcon ARROW_RIGHT_ICON;
|
||||
private static final ImageIcon GITHUB_ICON;
|
||||
private static final ImageIcon DISCORD_ICON;
|
||||
private static final ImageIcon PATREON_ICON;
|
||||
|
||||
private final JLabel loggedLabel = new JLabel();
|
||||
private final JRichTextPane emailLabel = new JRichTextPane();
|
||||
|
||||
@Inject
|
||||
@Nullable
|
||||
private Client client;
|
||||
@@ -68,33 +87,58 @@ public class InfoPanel extends PluginPanel
|
||||
@Inject
|
||||
private ScheduledExecutorService executor;
|
||||
|
||||
private final GroupLayout layout = new GroupLayout(this);
|
||||
private final JLabel usernameHeader = new JLabel();
|
||||
private final JRichTextPane username = new JRichTextPane();
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
ARROW_RIGHT_ICON = new ImageIcon(ImageIO.read(InfoPanel.class.getResourceAsStream("arrow_right.png")));
|
||||
GITHUB_ICON = new ImageIcon(ImageIO.read(InfoPanel.class.getResourceAsStream("github_icon.png")));
|
||||
DISCORD_ICON = new ImageIcon(ImageIO.read(InfoPanel.class.getResourceAsStream("discord_icon.png")));
|
||||
PATREON_ICON = new ImageIcon(ImageIO.read(InfoPanel.class.getResourceAsStream("patreon_icon.png")));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
setLayout(layout);
|
||||
setLayout(new BorderLayout());
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
|
||||
JPanel versionPanel = new JPanel();
|
||||
versionPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
versionPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
versionPanel.setLayout(new GridLayout(0, 1));
|
||||
|
||||
final Font smallFont = FontManager.getRunescapeSmallFont();
|
||||
|
||||
final JLabel runeliteVersionHeader = new JLabel("RuneLite version");
|
||||
runeliteVersionHeader.setFont(smallFont);
|
||||
final JLabel runeliteVersion = new JLabel(runeLiteProperties.getVersion());
|
||||
JLabel version = new JLabel(htmlLabel("RuneLite version: ", runeLiteProperties.getVersion()));
|
||||
version.setFont(smallFont);
|
||||
|
||||
final JLabel runescapeVersionHeader = new JLabel("OldSchool Engine");
|
||||
runescapeVersionHeader.setFont(smallFont);
|
||||
JLabel revision = new JLabel();
|
||||
revision.setFont(smallFont);
|
||||
|
||||
String engineVer = "Unknown";
|
||||
if (client != null)
|
||||
{
|
||||
engineVer = String.format("Rev %s", runeLiteProperties.getRunescapeVersion());
|
||||
}
|
||||
final JLabel runescapeVersion = new JLabel(engineVer);
|
||||
|
||||
usernameHeader.setFont(smallFont);
|
||||
username.enableAutoLinkHandler(false);
|
||||
username.addHyperlinkListener(e ->
|
||||
revision.setText(htmlLabel("Oldschool revision: ", engineVer));
|
||||
|
||||
loggedLabel.setForeground(ColorScheme.LIGHT_GRAY_COLOR);
|
||||
loggedLabel.setFont(smallFont);
|
||||
|
||||
emailLabel.setForeground(Color.WHITE);
|
||||
emailLabel.setFont(smallFont);
|
||||
emailLabel.enableAutoLinkHandler(false);
|
||||
emailLabel.addHyperlinkListener(e ->
|
||||
{
|
||||
if (HyperlinkEvent.EventType.ACTIVATED.equals(e.getEventType()) && e.getURL() != null)
|
||||
{
|
||||
@@ -105,51 +149,74 @@ public class InfoPanel extends PluginPanel
|
||||
}
|
||||
});
|
||||
|
||||
versionPanel.add(version);
|
||||
versionPanel.add(revision);
|
||||
versionPanel.add(Box.createGlue());
|
||||
versionPanel.add(loggedLabel);
|
||||
versionPanel.add(emailLabel);
|
||||
|
||||
updateLoggedIn();
|
||||
|
||||
final JRichTextPane issueLink = new JRichTextPane("text/html",
|
||||
"RuneLite is open source!<br>"
|
||||
+ "Found an issue? Want a feature?<br>"
|
||||
+ "<a href=\"https://github.com/runelite/runelite/issues\">"
|
||||
+ "Open an issue on GitHub!"
|
||||
+ "</a>"
|
||||
);
|
||||
JPanel actionsContainer = new JPanel();
|
||||
actionsContainer.setBorder(new EmptyBorder(10, 0, 0, 0));
|
||||
actionsContainer.setOpaque(false);
|
||||
actionsContainer.setLayout(new GridLayout(3, 1, 0, 10));
|
||||
|
||||
setBorder(BorderFactory.createEmptyBorder(2, 6, 6, 6));
|
||||
actionsContainer.add(buildLinkPanel(GITHUB_ICON, "Report an issue or", "make a suggestion", runeLiteProperties.getGithubLink()));
|
||||
actionsContainer.add(buildLinkPanel(DISCORD_ICON, "Talk to us on our", "discord server", runeLiteProperties.getDiscordInvite()));
|
||||
actionsContainer.add(buildLinkPanel(PATREON_ICON, "Become a patron to", "help support RuneLite", runeLiteProperties.getPatreonLink()));
|
||||
|
||||
layout.setVerticalGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup()
|
||||
.addComponent(runeliteVersionHeader)
|
||||
.addComponent(runescapeVersionHeader)
|
||||
).addGroup(layout.createParallelGroup()
|
||||
.addComponent(runeliteVersion)
|
||||
.addComponent(runescapeVersion)
|
||||
).addGap(6)
|
||||
.addComponent(usernameHeader)
|
||||
.addGroup(layout.createParallelGroup()
|
||||
.addComponent(username)
|
||||
)
|
||||
.addGap(12)
|
||||
.addComponent(issueLink)
|
||||
);
|
||||
|
||||
layout.setHorizontalGroup(layout.createParallelGroup()
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(runeliteVersionHeader)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(runescapeVersionHeader))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(runeliteVersion)
|
||||
.addPreferredGap(LayoutStyle.ComponentPlacement.UNRELATED, GroupLayout.PREFERRED_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(runescapeVersion))
|
||||
.addComponent(usernameHeader)
|
||||
.addComponent(username)
|
||||
.addComponent(issueLink)
|
||||
);
|
||||
add(versionPanel, BorderLayout.NORTH);
|
||||
add(actionsContainer, BorderLayout.CENTER);
|
||||
|
||||
eventBus.register(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a link panel with a given icon, text and url to redirect to.
|
||||
*/
|
||||
private static JPanel buildLinkPanel(ImageIcon icon, String topText, String bottomText, String url)
|
||||
{
|
||||
JPanel container = new JPanel();
|
||||
container.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
container.setLayout(new BorderLayout());
|
||||
container.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
container.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
LinkBrowser.browse(url);
|
||||
}
|
||||
});
|
||||
|
||||
JLabel iconLabel = new JLabel(icon);
|
||||
container.add(iconLabel, BorderLayout.WEST);
|
||||
|
||||
JPanel textContainer = new JPanel();
|
||||
textContainer.setOpaque(false);
|
||||
textContainer.setLayout(new GridLayout(2, 1));
|
||||
textContainer.setBorder(new EmptyBorder(5, 10, 5, 10));
|
||||
|
||||
JLabel topLine = new JLabel(topText);
|
||||
topLine.setForeground(Color.WHITE);
|
||||
topLine.setFont(FontManager.getRunescapeSmallFont());
|
||||
|
||||
JLabel bottomLine = new JLabel(bottomText);
|
||||
bottomLine.setForeground(Color.WHITE);
|
||||
bottomLine.setFont(FontManager.getRunescapeSmallFont());
|
||||
|
||||
textContainer.add(topLine);
|
||||
textContainer.add(bottomLine);
|
||||
|
||||
container.add(textContainer, BorderLayout.CENTER);
|
||||
|
||||
JLabel arrowLabel = new JLabel(ARROW_RIGHT_ICON);
|
||||
container.add(arrowLabel, BorderLayout.EAST);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
private void updateLoggedIn()
|
||||
{
|
||||
final String name = sessionManager.getAccountSession() != null
|
||||
@@ -158,18 +225,23 @@ public class InfoPanel extends PluginPanel
|
||||
|
||||
if (name != null)
|
||||
{
|
||||
username.setContentType("text/plain");
|
||||
username.setText(name);
|
||||
usernameHeader.setText("Logged in as");
|
||||
emailLabel.setContentType("text/plain");
|
||||
emailLabel.setText(name);
|
||||
loggedLabel.setText("Logged in as");
|
||||
}
|
||||
else
|
||||
{
|
||||
username.setContentType("text/html");
|
||||
username.setText("<a href=\"" + RUNELITE_LOGIN + "\">Login</a> to sync settings to the cloud.");
|
||||
usernameHeader.setText("Not logged in");
|
||||
emailLabel.setContentType("text/html");
|
||||
emailLabel.setText("<a href=\"" + RUNELITE_LOGIN + "\">Login</a> to sync settings to the cloud.");
|
||||
loggedLabel.setText("Not logged in");
|
||||
}
|
||||
}
|
||||
|
||||
private static String htmlLabel(String key, String value)
|
||||
{
|
||||
return "<html><body style = 'color:#a5a5a5'>" + key + "<span style = 'color:white'>" + value + "</span></body></html>";
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onSessionOpen(SessionOpen sessionOpen)
|
||||
{
|
||||
|
||||
@@ -58,6 +58,7 @@ public class InfoPlugin extends Plugin
|
||||
navButton = NavigationButton.builder()
|
||||
.name("Info")
|
||||
.icon(icon)
|
||||
.priority(9)
|
||||
.panel(panel)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.awt.Color;
|
||||
import javax.swing.GroupLayout;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
|
||||
class BookPanel extends JPanel
|
||||
@@ -36,6 +37,9 @@ class BookPanel extends JPanel
|
||||
|
||||
BookPanel(Book b)
|
||||
{
|
||||
setBorder(new EmptyBorder(3, 3, 3, 3));
|
||||
setOpaque(false);
|
||||
|
||||
GroupLayout layout = new GroupLayout(this);
|
||||
this.setLayout(layout);
|
||||
|
||||
@@ -74,4 +78,4 @@ class BookPanel extends JPanel
|
||||
{
|
||||
location.setForeground(target ? Color.GREEN : Color.WHITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Abex
|
||||
* Copyright (c) 2018 Psikoi
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -25,35 +26,71 @@
|
||||
package net.runelite.client.plugins.kourendlibrary;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.IOException;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Singleton;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.GroupLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.CompoundBorder;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
|
||||
@Singleton
|
||||
public class KourendLibraryPanel extends PluginPanel
|
||||
{
|
||||
private static final ImageIcon RESET_ICON;
|
||||
private static final ImageIcon RESET_CLICK_ICON;
|
||||
|
||||
@Inject
|
||||
private Library library;
|
||||
|
||||
private final HashMap<Book, BookPanel> bookPanels = new HashMap<>();
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized (ImageIO.class)
|
||||
{
|
||||
BufferedImage resetIcon = ImageIO.read(KourendLibraryPanel.class.getResourceAsStream("reset.png"));
|
||||
RESET_ICON = new ImageIcon(resetIcon);
|
||||
RESET_CLICK_ICON = new ImageIcon(SwingUtil.grayscaleOffset(resetIcon, -100));
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
GroupLayout layout = new GroupLayout(this);
|
||||
setLayout(layout);
|
||||
setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
JPanel books = new JPanel(new GridBagLayout());
|
||||
books.setOpaque(false);
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weightx = 1;
|
||||
@@ -70,21 +107,45 @@ public class KourendLibraryPanel extends PluginPanel
|
||||
c.gridy++;
|
||||
});
|
||||
|
||||
JButton reset = new JButton("Reset");
|
||||
reset.addActionListener(e ->
|
||||
JLabel reset = new JLabel(RESET_ICON);
|
||||
reset.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
library.reset();
|
||||
update();
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
reset.setIcon(RESET_CLICK_ICON);
|
||||
library.reset();
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent mouseEvent)
|
||||
{
|
||||
reset.setIcon(RESET_ICON);
|
||||
}
|
||||
});
|
||||
|
||||
JPanel header = new JPanel();
|
||||
header.setOpaque(false);
|
||||
header.setLayout(new BorderLayout());
|
||||
header.setBorder(new CompoundBorder(
|
||||
BorderFactory.createMatteBorder(0, 0, 1, 0, new Color(58, 58, 58)),
|
||||
BorderFactory.createEmptyBorder(0, 0, 10, 0)));
|
||||
|
||||
JLabel pluginName = new JLabel("Kourend Library Plugin");
|
||||
pluginName.setForeground(Color.WHITE);
|
||||
|
||||
header.add(reset, BorderLayout.EAST);
|
||||
header.add(pluginName, BorderLayout.CENTER);
|
||||
|
||||
layout.setHorizontalGroup(layout.createParallelGroup()
|
||||
.addComponent(books)
|
||||
.addComponent(reset)
|
||||
.addComponent(header)
|
||||
);
|
||||
layout.setVerticalGroup(layout.createSequentialGroup()
|
||||
.addComponent(header)
|
||||
.addGap(10)
|
||||
.addComponent(books)
|
||||
.addGap(4)
|
||||
.addComponent(reset)
|
||||
);
|
||||
|
||||
update();
|
||||
@@ -134,4 +195,4 @@ public class KourendLibraryPanel extends PluginPanel
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,6 +94,7 @@ public class KourendLibraryPlugin extends Plugin
|
||||
|
||||
navButton = NavigationButton.builder()
|
||||
.name("Kourend Library")
|
||||
.priority(6)
|
||||
.icon(icon)
|
||||
.panel(panel)
|
||||
.build();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Charlie Waters
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -24,13 +25,17 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.notes;
|
||||
|
||||
import java.awt.Color;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JTextArea;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Document;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
@@ -50,14 +55,24 @@ public class NotesPanel extends PluginPanel
|
||||
getParent().add(this, BorderLayout.CENTER);
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
setBorder(BorderFactory.createEmptyBorder(2, 6, 6, 6));
|
||||
setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
final JLabel notesHeader = new JLabel("Notes");
|
||||
notesHeader.setForeground(Color.WHITE);
|
||||
notesHeader.setBorder(new EmptyBorder(1, 0, 10, 0));
|
||||
|
||||
add(notesHeader, BorderLayout.NORTH);
|
||||
|
||||
notesEditor.setLineWrap(true);
|
||||
notesEditor.setWrapStyleWord(true);
|
||||
|
||||
JPanel notesContainer = new JPanel();
|
||||
notesContainer.setLayout(new BorderLayout());
|
||||
notesContainer.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
notesEditor.setOpaque(false);
|
||||
|
||||
// load note text
|
||||
String data = config.notesData();
|
||||
notesEditor.setText(data);
|
||||
@@ -90,7 +105,10 @@ public class NotesPanel extends PluginPanel
|
||||
}
|
||||
}
|
||||
});
|
||||
add(notesEditor, BorderLayout.CENTER);
|
||||
notesContainer.add(notesEditor, BorderLayout.CENTER);
|
||||
notesContainer.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
|
||||
add(notesContainer, BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
void setNotes(String data)
|
||||
|
||||
@@ -74,6 +74,7 @@ public class NotesPlugin extends Plugin
|
||||
navButton = NavigationButton.builder()
|
||||
.name("Notes")
|
||||
.icon(icon)
|
||||
.priority(7)
|
||||
.panel(panel)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import javax.swing.JButton;
|
||||
import javax.swing.JPanel;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.client.game.SkillIconManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
|
||||
class SkillCalculatorPanel extends PluginPanel
|
||||
@@ -64,10 +65,13 @@ class SkillCalculatorPanel extends PluginPanel
|
||||
uiButtonGridConstraints.insets = new Insets(2, 2, 2, 2);
|
||||
|
||||
uiButtonGrid.setLayout(uiButtonGridLayout);
|
||||
uiButtonGrid.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
uiButtonGrid.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
|
||||
addCalculatorButtons();
|
||||
|
||||
final UICalculatorInputArea uiInput = new UICalculatorInputArea();
|
||||
uiInput.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
uiCalculator = new SkillCalculator(client, uiInput);
|
||||
|
||||
add(uiButtonGrid);
|
||||
|
||||
@@ -75,7 +75,12 @@ public class SkillCalculatorPlugin extends Plugin
|
||||
SkillCalculator.itemManager = itemManager;
|
||||
|
||||
uiPanel = new SkillCalculatorPanel(skillIconManager, client);
|
||||
uiNavigationButton = NavigationButton.builder().name("Skill Calculator").icon(icon).panel(uiPanel).build();
|
||||
uiNavigationButton = NavigationButton.builder()
|
||||
.name("Skill Calculator")
|
||||
.icon(icon)
|
||||
.priority(6)
|
||||
.panel(uiPanel)
|
||||
.build();
|
||||
pluginToolbar.addNavigation(uiNavigationButton);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import net.runelite.client.plugins.skillcalculator.beans.SkillDataEntry;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.JShadowedLabel;
|
||||
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||
|
||||
class UIActionSlot extends JPanel
|
||||
{
|
||||
|
||||
@@ -33,7 +33,7 @@ import javax.swing.BorderFactory;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.JShadowedLabel;
|
||||
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||
|
||||
class UICombinedActionSlot extends JPanel
|
||||
{
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.xptracker;
|
||||
|
||||
import java.awt.Color;
|
||||
import lombok.Getter;
|
||||
|
||||
public enum SkillColor
|
||||
{
|
||||
ATTACK(105, 32, 7),
|
||||
DEFENCE(98, 119, 190),
|
||||
STRENGTH(4, 149, 90),
|
||||
HITPOINTS(131, 126, 126),
|
||||
RANGED(109, 144, 23),
|
||||
PRAYER(159, 147, 35),
|
||||
MAGIC(50, 80, 193),
|
||||
COOKING(112, 35, 134),
|
||||
WOODCUTTING(52, 140, 37),
|
||||
FLETCHING(3, 141, 125),
|
||||
FISHING(106, 132, 164),
|
||||
FIREMAKING(189, 120, 25),
|
||||
CRAFTING(151, 110, 77),
|
||||
SMITHING(108, 107, 82),
|
||||
MINING(93, 143, 167),
|
||||
HERBLORE(7, 133, 9),
|
||||
AGILITY(58, 60, 137),
|
||||
THIEVING(108, 52, 87),
|
||||
SLAYER(100, 100, 100),
|
||||
FARMING(101, 152, 63),
|
||||
RUNECRAFT(170, 141, 26),
|
||||
HUNTER(92, 89, 65),
|
||||
CONSTRUCTION(130, 116, 95);
|
||||
|
||||
@Getter
|
||||
private final Color color;
|
||||
|
||||
SkillColor(int red, int green, int blue)
|
||||
{
|
||||
this.color = new Color(red, green, blue);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -26,54 +27,54 @@ package net.runelite.client.plugins.xptracker;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.LookupOp;
|
||||
import java.awt.image.LookupTable;
|
||||
import java.io.IOException;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JLayeredPane;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.CompoundBorder;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.border.LineBorder;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.client.game.SkillIconManager;
|
||||
import net.runelite.client.ui.JShadowedLabel;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.components.ProgressBar;
|
||||
import net.runelite.client.util.LinkBrowser;
|
||||
import org.pushingpixels.substance.internal.SubstanceSynapse;
|
||||
import net.runelite.client.util.StackFormatter;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
|
||||
@Slf4j
|
||||
class XpInfoBox extends JPanel
|
||||
{
|
||||
private static final Rectangle ICON_BOUNDS = new Rectangle(0, 0, 26, 26);
|
||||
|
||||
private final Client client;
|
||||
private final JPanel panel;
|
||||
|
||||
@Getter(AccessLevel.PACKAGE)
|
||||
private final Skill skill;
|
||||
|
||||
/* The tracker's wrapping container */
|
||||
private final JPanel container = new JPanel();
|
||||
|
||||
/* Contains the skill icon and the stats panel */
|
||||
private final JPanel headerPanel = new JPanel();
|
||||
|
||||
/* Contains all the skill information (exp gained, per hour, etc) */
|
||||
private final JPanel statsPanel = new JPanel();
|
||||
private final JProgressBar progressBar = new JProgressBar();
|
||||
private final JLabel xpHr = new JLabel();
|
||||
private final JLabel xpGained = new JLabel();
|
||||
private final JLabel xpLeft = new JLabel();
|
||||
|
||||
private final ProgressBar progressBar = new ProgressBar();
|
||||
|
||||
private final JLabel expGained = new JLabel();
|
||||
private final JLabel expHour = new JLabel();
|
||||
private final JLabel expLeft = new JLabel();
|
||||
private final JLabel actionsLeft = new JLabel();
|
||||
private final JLabel levelLabel = new JShadowedLabel();
|
||||
|
||||
XpInfoBox(XpTrackerPlugin xpTrackerPlugin, Client client, JPanel panel, Skill skill, SkillIconManager iconManager) throws IOException
|
||||
{
|
||||
@@ -82,121 +83,81 @@ class XpInfoBox extends JPanel
|
||||
this.skill = skill;
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
setBorder(new CompoundBorder
|
||||
(
|
||||
new EmptyBorder(2, 0, 2, 0),
|
||||
new LineBorder(getBackground().brighter(), 1)
|
||||
));
|
||||
|
||||
// Expand stats panel on click
|
||||
Color backgroundColor = getBackground();
|
||||
|
||||
MouseListener panelMouseListener = new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e)
|
||||
{
|
||||
container.setBackground(backgroundColor.darker().darker());
|
||||
}
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e)
|
||||
{
|
||||
container.setBackground(backgroundColor);
|
||||
}
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e)
|
||||
{
|
||||
if (SwingUtilities.isLeftMouseButton(e))
|
||||
{
|
||||
showStatsPanel();
|
||||
}
|
||||
}
|
||||
};
|
||||
setBorder(new EmptyBorder(10, 0, 0, 0));
|
||||
setOpaque(false);
|
||||
|
||||
container.setLayout(new BorderLayout());
|
||||
container.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
container.addMouseListener(panelMouseListener);
|
||||
container.setOpaque(true);
|
||||
container.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
|
||||
// Create open xp tracker menu
|
||||
final JMenuItem openXpTracker = new JMenuItem("Open XP tracker");
|
||||
final JMenuItem openXpTracker = new JMenuItem("Open online tracker");
|
||||
openXpTracker.addActionListener(e -> LinkBrowser.browse(XpPanel.buildXpTrackerUrl(client.getLocalPlayer(), skill)));
|
||||
|
||||
// Create reset menu
|
||||
final JMenuItem reset = new JMenuItem("Reset");
|
||||
reset.addActionListener(e -> reset());
|
||||
|
||||
// Create popup menu
|
||||
final JPopupMenu popupMenu = new JPopupMenu();
|
||||
popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
popupMenu.add(openXpTracker);
|
||||
popupMenu.add(reset);
|
||||
container.setComponentPopupMenu(popupMenu);
|
||||
|
||||
// Create icon panel
|
||||
final JPanel iconBarPanel = new JPanel();
|
||||
iconBarPanel.setLayout(new BorderLayout(5, 0));
|
||||
iconBarPanel.setOpaque(false);
|
||||
JLabel skillIcon = new JLabel(new ImageIcon(iconManager.getSkillImage(skill)));
|
||||
skillIcon.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
skillIcon.setVerticalAlignment(SwingConstants.CENTER);
|
||||
skillIcon.setPreferredSize(new Dimension(35, 35));
|
||||
|
||||
// Create skill/reset icon
|
||||
final BufferedImage skillImage = iconManager.getSkillImage(skill);
|
||||
final JButton skillIcon = new JButton();
|
||||
headerPanel.setOpaque(false);
|
||||
headerPanel.setLayout(new BorderLayout());
|
||||
|
||||
skillIcon.putClientProperty(SubstanceSynapse.FLAT_LOOK, Boolean.TRUE);
|
||||
skillIcon.putClientProperty(SubstanceSynapse.BUTTON_NEVER_PAINT_BACKGROUND, Boolean.TRUE);
|
||||
skillIcon.setIcon(new ImageIcon(skillImage));
|
||||
skillIcon.setRolloverIcon(new ImageIcon(createHoverImage(skillImage)));
|
||||
|
||||
skillIcon.setToolTipText("Reset " + skill.getName() + " tracker");
|
||||
skillIcon.addActionListener(e -> xpTrackerPlugin.resetSkillState(skill));
|
||||
skillIcon.setBounds(ICON_BOUNDS);
|
||||
skillIcon.setOpaque(false);
|
||||
skillIcon.setFocusPainted(false);
|
||||
|
||||
// Create level label
|
||||
levelLabel.setHorizontalAlignment(JLabel.CENTER);
|
||||
levelLabel.setForeground(Color.YELLOW);
|
||||
levelLabel.setBounds(ICON_BOUNDS);
|
||||
levelLabel.setOpaque(false);
|
||||
|
||||
// Create pane for grouping skill icon and level label
|
||||
final JLayeredPane layeredPane = new JLayeredPane();
|
||||
layeredPane.add(skillIcon, new Integer(1));
|
||||
layeredPane.add(levelLabel, new Integer(2));
|
||||
layeredPane.setPreferredSize(ICON_BOUNDS.getSize());
|
||||
iconBarPanel.add(layeredPane, BorderLayout.LINE_START);
|
||||
|
||||
// Create progress bar
|
||||
progressBar.setStringPainted(true);
|
||||
progressBar.setValue(0);
|
||||
progressBar.setMinimum(0);
|
||||
progressBar.setMaximum(100);
|
||||
progressBar.setBackground(Color.RED);
|
||||
progressBar.addMouseListener(panelMouseListener);
|
||||
iconBarPanel.add(progressBar, BorderLayout.CENTER);
|
||||
|
||||
container.add(iconBarPanel, BorderLayout.NORTH);
|
||||
|
||||
// Stats panel
|
||||
statsPanel.setLayout(new GridLayout(2, 2));
|
||||
statsPanel.setBorder(new EmptyBorder(3, 0, 0, 0));
|
||||
statsPanel.setLayout(new BorderLayout());
|
||||
statsPanel.setBorder(new EmptyBorder(9, 5, 9, 10));
|
||||
statsPanel.setOpaque(false);
|
||||
|
||||
statsPanel.add(xpGained);
|
||||
xpHr.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
statsPanel.add(xpHr);
|
||||
statsPanel.add(xpLeft);
|
||||
actionsLeft.setHorizontalAlignment(SwingConstants.RIGHT);
|
||||
statsPanel.add(actionsLeft);
|
||||
JPanel leftPanel = new JPanel();
|
||||
leftPanel.setOpaque(false);
|
||||
leftPanel.setLayout(new GridLayout(2, 1));
|
||||
|
||||
add(container, BorderLayout.CENTER);
|
||||
}
|
||||
expGained.setFont(FontManager.getRunescapeSmallFont());
|
||||
expHour.setFont(FontManager.getRunescapeSmallFont());
|
||||
|
||||
private void showStatsPanel()
|
||||
{
|
||||
if (statsPanel.isShowing())
|
||||
{
|
||||
container.remove(statsPanel);
|
||||
revalidate();
|
||||
}
|
||||
else
|
||||
{
|
||||
container.add(statsPanel, BorderLayout.SOUTH);
|
||||
revalidate();
|
||||
}
|
||||
leftPanel.add(expGained);
|
||||
leftPanel.add(expHour);
|
||||
|
||||
JPanel rightPanel = new JPanel();
|
||||
rightPanel.setOpaque(false);
|
||||
rightPanel.setLayout(new GridLayout(2, 1));
|
||||
|
||||
expLeft.setFont(FontManager.getRunescapeSmallFont());
|
||||
actionsLeft.setFont(FontManager.getRunescapeSmallFont());
|
||||
|
||||
rightPanel.add(expLeft);
|
||||
rightPanel.add(actionsLeft);
|
||||
|
||||
statsPanel.add(leftPanel, BorderLayout.WEST);
|
||||
statsPanel.add(rightPanel, BorderLayout.EAST);
|
||||
|
||||
headerPanel.add(skillIcon, BorderLayout.WEST);
|
||||
headerPanel.add(statsPanel, BorderLayout.CENTER);
|
||||
|
||||
JPanel progressWrapper = new JPanel();
|
||||
progressWrapper.setOpaque(false);
|
||||
progressWrapper.setLayout(new BorderLayout());
|
||||
progressWrapper.setBorder(new EmptyBorder(0, 7, 7, 7));
|
||||
|
||||
progressBar.setMaximumValue(100);
|
||||
progressBar.setBackground(new Color(61, 56, 49));
|
||||
progressBar.setForeground(SkillColor.values()[skill.ordinal()].getColor());
|
||||
|
||||
progressWrapper.add(progressBar, BorderLayout.NORTH);
|
||||
|
||||
container.add(headerPanel, BorderLayout.NORTH);
|
||||
container.add(progressWrapper, BorderLayout.SOUTH);
|
||||
|
||||
add(container, BorderLayout.NORTH);
|
||||
}
|
||||
|
||||
void reset()
|
||||
@@ -221,46 +182,46 @@ class XpInfoBox extends JPanel
|
||||
panel.revalidate();
|
||||
}
|
||||
|
||||
levelLabel.setText(String.valueOf(xpSnapshotSingle.getCurrentLevel()));
|
||||
xpGained.setText(XpPanel.formatLine(xpSnapshotSingle.getXpGainedInSession(), "xp gained"));
|
||||
xpLeft.setText(XpPanel.formatLine(xpSnapshotSingle.getXpRemainingToGoal(), "xp left"));
|
||||
actionsLeft.setText(XpPanel.formatLine(xpSnapshotSingle.getActionsRemainingToGoal(), "actions left"));
|
||||
// Update information labels
|
||||
expGained.setText(htmlLabel("XP Gained: ", xpSnapshotSingle.getXpGainedInSession()));
|
||||
expLeft.setText(htmlLabel("XP Left: ", xpSnapshotSingle.getXpRemainingToGoal()));
|
||||
actionsLeft.setText(htmlLabel("Actions: ", xpSnapshotSingle.getActionsRemainingToGoal()));
|
||||
|
||||
final int progress = xpSnapshotSingle.getSkillProgressToGoal();
|
||||
|
||||
progressBar.setValue(progress);
|
||||
progressBar.setBackground(Color.getHSBColor((progress / 100.f) * (120.f / 360.f), 1, 1));
|
||||
// Update progress bar
|
||||
progressBar.setValue(xpSnapshotSingle.getSkillProgressToGoal());
|
||||
progressBar.setCenterLabel(xpSnapshotSingle.getSkillProgressToGoal() + "%");
|
||||
progressBar.setLeftLabel("Lvl. " + xpSnapshotSingle.getCurrentLevel());
|
||||
progressBar.setRightLabel("Lvl. " + (xpSnapshotSingle.getCurrentLevel() + 1));
|
||||
|
||||
progressBar.setToolTipText("<html>"
|
||||
+ XpPanel.formatLine(xpSnapshotSingle.getActionsInSession(), "actions")
|
||||
+ xpSnapshotSingle.getActionsInSession() + " actions done"
|
||||
+ "<br/>"
|
||||
+ XpPanel.formatLine(xpSnapshotSingle.getActionsPerHour(), "actions/hr")
|
||||
+ xpSnapshotSingle.getActionsPerHour() + " actions/hr"
|
||||
+ "<br/>"
|
||||
+ xpSnapshotSingle.getTimeTillGoal() + " till next lvl"
|
||||
+ "</html>");
|
||||
|
||||
progressBar.repaint();
|
||||
}
|
||||
|
||||
// Always update xp/hr as time always changes
|
||||
xpHr.setText(XpPanel.formatLine(xpSnapshotSingle.getXpPerHour(), "xp/hr"));
|
||||
// Update exp per hour seperately, everytime (not only when there's an update)
|
||||
expHour.setText(htmlLabel("XP/Hour: ", xpSnapshotSingle.getXpPerHour()));
|
||||
}
|
||||
|
||||
private static BufferedImage createHoverImage(BufferedImage image)
|
||||
public static String htmlLabel(String key, int value)
|
||||
{
|
||||
LookupTable lookup = new LookupTable(0, 4)
|
||||
String valueStr = value + "";
|
||||
|
||||
if (value > 9999999 || value < -9999999)
|
||||
{
|
||||
@Override
|
||||
public int[] lookupPixel(int[] src, int[] dest)
|
||||
{
|
||||
if (dest[3] != 0)
|
||||
{
|
||||
dest[3] = 60;
|
||||
}
|
||||
valueStr = "Lots!";
|
||||
}
|
||||
else
|
||||
{
|
||||
valueStr = StackFormatter.quantityToRSDecimalStack(value);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
};
|
||||
|
||||
LookupOp op = new LookupOp(lookup, new RenderingHints(null));
|
||||
return op.filter(image, null);
|
||||
return "<html><body style = 'color:" + SwingUtil.toHexColor(ColorScheme.LIGHT_GRAY_COLOR) + "'>" + key + "<span style = 'color:white'>" + valueStr + "</span></body></html>";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Cameron <moberg@tuta.io>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -29,64 +30,93 @@ import java.awt.GridLayout;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Actor;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.Skill;
|
||||
import net.runelite.client.game.SkillIconManager;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
import net.runelite.client.ui.components.PluginErrorPanel;
|
||||
import net.runelite.client.util.LinkBrowser;
|
||||
import net.runelite.client.util.StackFormatter;
|
||||
import okhttp3.HttpUrl;
|
||||
|
||||
@Slf4j
|
||||
class XpPanel extends PluginPanel
|
||||
{
|
||||
private final Map<Skill, XpInfoBox> infoBoxes = new HashMap<>();
|
||||
private final JLabel totalXpGained = new JLabel();
|
||||
private final JLabel totalXpHr = new JLabel();
|
||||
|
||||
private final JLabel overallExpGained = new JLabel(XpInfoBox.htmlLabel("Gained: ", 0));
|
||||
private final JLabel overallExpHour = new JLabel(XpInfoBox.htmlLabel("Per hour: ", 0));
|
||||
|
||||
private final JPanel overallPanel = new JPanel();
|
||||
|
||||
/* This displays the "No exp gained" text */
|
||||
private final PluginErrorPanel errorPanel = new PluginErrorPanel();
|
||||
|
||||
XpPanel(XpTrackerPlugin xpTrackerPlugin, Client client, SkillIconManager iconManager)
|
||||
{
|
||||
super();
|
||||
|
||||
setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
final JPanel layoutPanel = new JPanel();
|
||||
layoutPanel.setLayout(new BorderLayout(0, 3));
|
||||
layoutPanel.setOpaque(false);
|
||||
layoutPanel.setLayout(new BorderLayout());
|
||||
add(layoutPanel);
|
||||
|
||||
final JPanel totalPanel = new JPanel();
|
||||
totalPanel.setLayout(new BorderLayout());
|
||||
totalPanel.setBorder(BorderFactory.createLineBorder(getBackground().brighter(), 1, true));
|
||||
overallPanel.setBorder(new EmptyBorder(10, 10, 10, 10));
|
||||
overallPanel.setBackground(ColorScheme.DARKER_GRAY_COLOR);
|
||||
overallPanel.setLayout(new BorderLayout());
|
||||
overallPanel.setVisible(false); // this will only become visible when the player gets exp
|
||||
|
||||
final JPanel infoPanel = new JPanel();
|
||||
infoPanel.setLayout(new GridLayout(4, 1));
|
||||
infoPanel.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
|
||||
// Create open xp tracker menu
|
||||
final JMenuItem openXpTracker = new JMenuItem("Open online tracker");
|
||||
openXpTracker.addActionListener(e -> LinkBrowser.browse(XpPanel.buildXpTrackerUrl(client.getLocalPlayer(), Skill.OVERALL)));
|
||||
|
||||
final JButton resetButton = new JButton("Reset All");
|
||||
resetButton.addActionListener(e -> xpTrackerPlugin.resetAndInitState());
|
||||
// Create reset all menu
|
||||
final JMenuItem reset = new JMenuItem("Reset All");
|
||||
reset.addActionListener(e -> xpTrackerPlugin.resetAndInitState());
|
||||
|
||||
final JButton openTrackerButton = new JButton("Open XP tracker");
|
||||
openTrackerButton.addActionListener(e -> LinkBrowser.browse(buildXpTrackerUrl(client.getLocalPlayer(), Skill.OVERALL)));
|
||||
// Create popup menu
|
||||
final JPopupMenu popupMenu = new JPopupMenu();
|
||||
popupMenu.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
popupMenu.add(openXpTracker);
|
||||
popupMenu.add(reset);
|
||||
overallPanel.setComponentPopupMenu(popupMenu);
|
||||
|
||||
totalXpGained.setText(formatLine(0, "total xp gained"));
|
||||
totalXpHr.setText(formatLine(0, "total xp/hr"));
|
||||
final JLabel overallIcon = new JLabel(new ImageIcon(iconManager.getSkillImage(Skill.OVERALL)));
|
||||
|
||||
final JPanel overallInfo = new JPanel();
|
||||
overallInfo.setOpaque(false);
|
||||
overallInfo.setLayout(new GridLayout(2, 1));
|
||||
overallInfo.setBorder(new EmptyBorder(0, 10, 0, 0));
|
||||
|
||||
overallExpGained.setFont(FontManager.getRunescapeSmallFont());
|
||||
overallExpHour.setFont(FontManager.getRunescapeSmallFont());
|
||||
|
||||
overallInfo.add(overallExpGained);
|
||||
overallInfo.add(overallExpHour);
|
||||
|
||||
overallPanel.add(overallIcon, BorderLayout.WEST);
|
||||
overallPanel.add(overallInfo, BorderLayout.CENTER);
|
||||
|
||||
infoPanel.add(totalXpGained);
|
||||
infoPanel.add(totalXpHr);
|
||||
infoPanel.add(resetButton);
|
||||
infoPanel.add(openTrackerButton);
|
||||
totalPanel.add(infoPanel, BorderLayout.CENTER);
|
||||
layoutPanel.add(totalPanel, BorderLayout.NORTH);
|
||||
|
||||
final JPanel infoBoxPanel = new JPanel();
|
||||
infoBoxPanel.setOpaque(false);
|
||||
infoBoxPanel.setLayout(new BoxLayout(infoBoxPanel, BoxLayout.Y_AXIS));
|
||||
layoutPanel.add(infoBoxPanel, BorderLayout.CENTER);
|
||||
layoutPanel.add(overallPanel, BorderLayout.NORTH);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -96,7 +126,6 @@ class XpPanel extends PluginPanel
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
infoBoxes.put(skill, new XpInfoBox(xpTrackerPlugin, client, infoBoxPanel, skill, iconManager));
|
||||
}
|
||||
}
|
||||
@@ -104,6 +133,10 @@ class XpPanel extends PluginPanel
|
||||
{
|
||||
log.warn(null, e);
|
||||
}
|
||||
|
||||
errorPanel.setContent("Exp trackers", "You have not gained experience yet.");
|
||||
errorPanel.setBorder(new EmptyBorder(0, 0, 0, 0));
|
||||
add(errorPanel);
|
||||
}
|
||||
|
||||
static String buildXpTrackerUrl(final Actor player, final Skill skill)
|
||||
@@ -150,30 +183,23 @@ class XpPanel extends PluginPanel
|
||||
}
|
||||
}
|
||||
|
||||
void updateTotal(XpSnapshotTotal xpSnapshotTotal)
|
||||
|
||||
public void updateTotal(XpSnapshotTotal xpSnapshotTotal)
|
||||
{
|
||||
// if player has gained exp and hasn't switched displays yet, hide error panel and show overall info
|
||||
if (xpSnapshotTotal.getXpGainedInSession() > 0 && !overallPanel.isVisible())
|
||||
{
|
||||
overallPanel.setVisible(true);
|
||||
remove(errorPanel);
|
||||
}
|
||||
|
||||
SwingUtilities.invokeLater(() -> rebuildAsync(xpSnapshotTotal));
|
||||
}
|
||||
|
||||
private void rebuildAsync(XpSnapshotTotal xpSnapshotTotal)
|
||||
{
|
||||
totalXpGained.setText(formatLine(xpSnapshotTotal.getXpGainedInSession(), "total xp gained"));
|
||||
totalXpHr.setText(formatLine(xpSnapshotTotal.getXpPerHour(), "total xp/hr"));
|
||||
overallExpGained.setText(XpInfoBox.htmlLabel("Gained: ", xpSnapshotTotal.getXpGainedInSession()));
|
||||
overallExpHour.setText(XpInfoBox.htmlLabel("Per hour: ", xpSnapshotTotal.getXpPerHour()));
|
||||
}
|
||||
|
||||
static String formatLine(double number, String description)
|
||||
{
|
||||
String numberStr;
|
||||
if (number < 100000)
|
||||
{
|
||||
numberStr = StackFormatter.formatNumber(number);
|
||||
}
|
||||
else
|
||||
{
|
||||
int num = (int) (Math.log(number) / Math.log(1000));
|
||||
numberStr = String.format("%.1f%c", number / Math.pow(1000, num), "KMB".charAt(num - 1));
|
||||
}
|
||||
|
||||
return numberStr + " " + description;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,7 @@ public class XpTrackerPlugin extends Plugin
|
||||
navButton = NavigationButton.builder()
|
||||
.name("XP Tracker")
|
||||
.icon(icon)
|
||||
.priority(2)
|
||||
.panel(xpPanel)
|
||||
.build();
|
||||
|
||||
|
||||
@@ -67,11 +67,12 @@ import net.runelite.client.events.PluginToolbarButtonAdded;
|
||||
import net.runelite.client.events.PluginToolbarButtonRemoved;
|
||||
import net.runelite.client.events.TitleToolbarButtonAdded;
|
||||
import net.runelite.client.events.TitleToolbarButtonRemoved;
|
||||
import net.runelite.client.ui.skin.SubstanceRuneLiteLookAndFeel;
|
||||
import net.runelite.client.input.KeyManager;
|
||||
import net.runelite.client.util.OSType;
|
||||
import net.runelite.client.util.OSXUtil;
|
||||
import net.runelite.client.util.SwingUtil;
|
||||
import org.pushingpixels.substance.api.skin.SubstanceGraphiteLookAndFeel;
|
||||
import org.pushingpixels.substance.internal.SubstanceSynapse;
|
||||
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
|
||||
import org.pushingpixels.substance.internal.utils.SubstanceTitlePaneUtilities;
|
||||
|
||||
@@ -327,7 +328,7 @@ public class ClientUI
|
||||
SwingUtil.setupDefaults();
|
||||
|
||||
// Use substance look and feel
|
||||
SwingUtil.setTheme(new SubstanceGraphiteLookAndFeel());
|
||||
SwingUtil.setTheme(new SubstanceRuneLiteLookAndFeel());
|
||||
|
||||
// Use custom UI font
|
||||
SwingUtil.setFont(FontManager.getRunescapeFont());
|
||||
@@ -362,6 +363,8 @@ public class ClientUI
|
||||
navContainer.setLayout(new BorderLayout(0, 0));
|
||||
navContainer.setMinimumSize(new Dimension(0, 0));
|
||||
navContainer.setMaximumSize(new Dimension(0, Integer.MAX_VALUE));
|
||||
// To reduce substance's colorization (tinting)
|
||||
navContainer.putClientProperty(SubstanceSynapse.COLORIZATION_FACTOR, 1.0);
|
||||
container.add(navContainer);
|
||||
|
||||
pluginToolbar = new ClientPluginToolbar();
|
||||
@@ -565,6 +568,7 @@ public class ClientUI
|
||||
|
||||
/**
|
||||
* Get offset of game canvas in game window
|
||||
*
|
||||
* @return game canvas offset
|
||||
*/
|
||||
public Point getCanvasOffset()
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui;
|
||||
|
||||
import java.awt.Color;
|
||||
|
||||
/**
|
||||
* This class serves to hold commonly used UI colors.
|
||||
*/
|
||||
public class ColorScheme
|
||||
{
|
||||
/* The orange color used for the branding's accents */
|
||||
public static final Color BRAND_ORANGE = new Color(220, 138, 0);
|
||||
|
||||
/* The orange color used for the branding's accents, with lowered opacity */
|
||||
public static final Color BRAND_ORANGE_TRANSPARENT = new Color(220, 138, 0, 120);
|
||||
|
||||
public static final Color DARKER_GRAY_COLOR = new Color(30, 30, 30);
|
||||
public static final Color DARK_GRAY_COLOR = new Color(40, 40, 40);
|
||||
public static final Color MEDIUM_GRAY_COLOR = new Color(77, 77, 77);
|
||||
public static final Color LIGHT_GRAY_COLOR = new Color(165, 165, 165);
|
||||
public static final Color DARK_GRAY_HOVER_COLOR = new Color(35, 35, 35);
|
||||
|
||||
/* The color for the green progress bar (used in ge offers, farming tracker, etc)*/
|
||||
public static final Color PROGRESS_COMPLETE_COLOR = new Color(55, 240, 70);
|
||||
|
||||
/* The color for the red progress bar (used in ge offers, farming tracker, etc)*/
|
||||
public static final Color PROGRESS_ERROR_COLOR = new Color(230, 30, 30);
|
||||
|
||||
/* The color for the orange progress bar (used in ge offers, farming tracker, etc)*/
|
||||
public static final Color PROGRESS_INPROGRESS_COLOR = new Color(230, 150, 30);
|
||||
|
||||
/* The color for the price indicator in the ge search results */
|
||||
public static final Color GRAND_EXCHANGE_PRICE = new Color(110, 225, 110);
|
||||
|
||||
/* The color for the high alch indicator in the ge search results */
|
||||
public static final Color GRAND_EXCHANGE_ALCH = new Color(240, 207, 123);
|
||||
|
||||
/* The background color of the scrollbar's track */
|
||||
public static final Color SCROLL_TRACK_COLOR = new Color(25, 25, 25);
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.Insets;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Grid layout implementation with support for cells with unequal size.
|
||||
*
|
||||
* See https://www.javaworld.com/article/2077486/core-java/java-tip-121--flex-your-grid-layout.html
|
||||
*/
|
||||
public class DynamicGridLayout extends GridLayout
|
||||
{
|
||||
public DynamicGridLayout()
|
||||
{
|
||||
this(1, 0, 0, 0);
|
||||
}
|
||||
|
||||
public DynamicGridLayout(int rows, int cols)
|
||||
{
|
||||
this(rows, cols, 0, 0);
|
||||
}
|
||||
|
||||
public DynamicGridLayout(int rows, int cols, int hgap, int vgap)
|
||||
{
|
||||
super(rows, cols, hgap, vgap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension preferredLayoutSize(Container parent)
|
||||
{
|
||||
synchronized (parent.getTreeLock())
|
||||
{
|
||||
return calculateSize(parent, Component::getPreferredSize);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension minimumLayoutSize(Container parent)
|
||||
{
|
||||
synchronized (parent.getTreeLock())
|
||||
{
|
||||
return calculateSize(parent, Component::getMinimumSize);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void layoutContainer(Container parent)
|
||||
{
|
||||
synchronized (parent.getTreeLock())
|
||||
{
|
||||
final Insets insets = parent.getInsets();
|
||||
final int ncomponents = parent.getComponentCount();
|
||||
int nrows = getRows();
|
||||
int ncols = getColumns();
|
||||
|
||||
if (ncomponents == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (nrows > 0)
|
||||
{
|
||||
ncols = (ncomponents + nrows - 1) / nrows;
|
||||
}
|
||||
else
|
||||
{
|
||||
nrows = (ncomponents + ncols - 1) / ncols;
|
||||
}
|
||||
|
||||
final int hgap = getHgap();
|
||||
final int vgap = getVgap();
|
||||
|
||||
// scaling factors
|
||||
final Dimension pd = preferredLayoutSize(parent);
|
||||
final double sw = (1.0 * parent.getWidth()) / pd.width;
|
||||
final double sh = (1.0 * parent.getHeight()) / pd.height;
|
||||
|
||||
final int[] w = new int[ncols];
|
||||
final int[] h = new int[nrows];
|
||||
|
||||
// calculate dimensions for all components + apply scaling
|
||||
for (int i = 0; i < ncomponents; i++)
|
||||
{
|
||||
final int r = i / ncols;
|
||||
final int c = i % ncols;
|
||||
final Component comp = parent.getComponent(i);
|
||||
final Dimension d = comp.getPreferredSize();
|
||||
d.width = (int) (sw * d.width);
|
||||
d.height = (int) (sh * d.height);
|
||||
|
||||
if (w[c] < d.width)
|
||||
{
|
||||
w[c] = d.width;
|
||||
}
|
||||
|
||||
if (h[r] < d.height)
|
||||
{
|
||||
h[r] = d.height;
|
||||
}
|
||||
}
|
||||
|
||||
// Apply new bounds to all child components
|
||||
for (int c = 0, x = insets.left; c < ncols; c++)
|
||||
{
|
||||
for (int r = 0, y = insets.top; r < nrows; r++)
|
||||
{
|
||||
int i = r * ncols + c;
|
||||
|
||||
if (i < ncomponents)
|
||||
{
|
||||
parent.getComponent(i).setBounds(x, y, w[c], h[r]);
|
||||
}
|
||||
|
||||
y += h[r] + vgap;
|
||||
}
|
||||
|
||||
x += w[c] + hgap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate outer size of the layout based on it's children and sizer
|
||||
* @param parent parent component
|
||||
* @param sizer functioning returning dimension of the child component
|
||||
* @return outer size
|
||||
*/
|
||||
private Dimension calculateSize(final Container parent, final Function<Component, Dimension> sizer)
|
||||
{
|
||||
final int ncomponents = parent.getComponentCount();
|
||||
int nrows = getRows();
|
||||
int ncols = getColumns();
|
||||
|
||||
if (nrows > 0)
|
||||
{
|
||||
ncols = (ncomponents + nrows - 1) / nrows;
|
||||
}
|
||||
else
|
||||
{
|
||||
nrows = (ncomponents + ncols - 1) / ncols;
|
||||
}
|
||||
|
||||
final int[] w = new int[ncols];
|
||||
final int[] h = new int[nrows];
|
||||
|
||||
// Calculate dimensions for all components
|
||||
for (int i = 0; i < ncomponents; i++)
|
||||
{
|
||||
final int r = i / ncols;
|
||||
final int c = i % ncols;
|
||||
final Component comp = parent.getComponent(i);
|
||||
final Dimension d = sizer.apply(comp);
|
||||
|
||||
if (w[c] < d.width)
|
||||
{
|
||||
w[c] = d.width;
|
||||
}
|
||||
|
||||
if (h[r] < d.height)
|
||||
{
|
||||
h[r] = d.height;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate total width and height of the layout
|
||||
int nw = 0;
|
||||
|
||||
for (int j = 0; j < ncols; j++)
|
||||
{
|
||||
nw += w[j];
|
||||
}
|
||||
|
||||
int nh = 0;
|
||||
|
||||
for (int i = 0; i < nrows; i++)
|
||||
{
|
||||
nh += h[i];
|
||||
}
|
||||
|
||||
final Insets insets = parent.getInsets();
|
||||
|
||||
// Apply insets and horizontal and vertical gap to layout
|
||||
return new Dimension(
|
||||
insets.left + insets.right + nw + (ncols - 1) * getHgap(),
|
||||
insets.top + insets.bottom + nh + (nrows - 1) * getVgap());
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,12 @@ public class NavigationButton
|
||||
*/
|
||||
private PluginPanel panel;
|
||||
|
||||
|
||||
/**
|
||||
* The order in which the button should be displayed in the side bar. (from lower to higher)
|
||||
*/
|
||||
private int priority;
|
||||
|
||||
/**
|
||||
* Map of key-value pairs for setting the popup menu
|
||||
*/
|
||||
|
||||
@@ -60,13 +60,14 @@ public abstract class PluginPanel extends JPanel
|
||||
{
|
||||
setBorder(BORDER_PADDING);
|
||||
setLayout(new GridLayout(0, 1, 0, 3));
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
final JPanel northPanel = new JPanel();
|
||||
northPanel.setLayout(new BorderLayout());
|
||||
northPanel.add(this, BorderLayout.NORTH);
|
||||
northPanel.setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
|
||||
scrollPane = new JScrollPane(northPanel);
|
||||
scrollPane.getVerticalScrollBar().setUnitIncrement(16); //Otherwise scrollspeed is really slow
|
||||
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
|
||||
|
||||
wrappedPanel = new JPanel();
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
*/
|
||||
package net.runelite.client.ui;
|
||||
|
||||
import com.google.common.collect.ComparisonChain;
|
||||
import com.google.common.eventbus.EventBus;
|
||||
import java.util.Comparator;
|
||||
import java.util.TreeSet;
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@@ -39,7 +39,11 @@ import net.runelite.client.events.PluginToolbarButtonRemoved;
|
||||
public class PluginToolbar
|
||||
{
|
||||
private final EventBus eventBus;
|
||||
private final TreeSet<NavigationButton> buttons = new TreeSet<>(Comparator.comparing(NavigationButton::getName));
|
||||
private final TreeSet<NavigationButton> buttons = new TreeSet<>((a, b) ->
|
||||
ComparisonChain.start()
|
||||
.compare(a.getPriority(), b.getPriority())
|
||||
.compare(a.getName(), b.getName())
|
||||
.result());
|
||||
|
||||
@Inject
|
||||
private PluginToolbar(final EventBus eventBus)
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui.components;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
/**
|
||||
* A custom list renderer to avoid substance's weird coloring.
|
||||
* Substance was making selected items' foreground color black, this
|
||||
* was very hard to see in the dark gray background, this makes the selected
|
||||
* item white and adds some padding to the elements for more readable list.
|
||||
*/
|
||||
public final class ComboBoxListRenderer extends JLabel implements ListCellRenderer
|
||||
{
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList list, Object o, int index, boolean isSelected, boolean cellHasFocus)
|
||||
{
|
||||
if (isSelected)
|
||||
{
|
||||
setBackground(ColorScheme.DARK_GRAY_COLOR);
|
||||
setForeground(Color.WHITE);
|
||||
}
|
||||
else
|
||||
{
|
||||
setBackground(list.getBackground());
|
||||
setForeground(ColorScheme.LIGHT_GRAY_COLOR);
|
||||
}
|
||||
|
||||
setBorder(new EmptyBorder(5, 5, 5, 0));
|
||||
|
||||
String text = (String) o.toString();
|
||||
setText(text);
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui.components;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollBar;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicScrollBarUI;
|
||||
import lombok.Setter;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
/**
|
||||
* This scroll bar UI is to be used for the "RuneLite Obsidian" client theme.
|
||||
* It is a part of the client's redesign as detailed on issue #1342
|
||||
*/
|
||||
public class CustomScrollBarUI extends BasicScrollBarUI
|
||||
{
|
||||
|
||||
/* The background color of the bar's thumb */
|
||||
@Setter
|
||||
private Color thumbColor = ColorScheme.MEDIUM_GRAY_COLOR;
|
||||
|
||||
/* The background color of the bar's track */
|
||||
@Setter
|
||||
private Color trackColor = ColorScheme.SCROLL_TRACK_COLOR;
|
||||
|
||||
/**
|
||||
* Overrides the painting of the bar's track (the darker part underneath that extends
|
||||
* the full page length).
|
||||
*/
|
||||
@Override
|
||||
protected void paintTrack(Graphics graphics, JComponent jComponent, Rectangle rectangle)
|
||||
{
|
||||
graphics.setColor(trackColor);
|
||||
graphics.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the painting of the bar's thumb (the lighter part on top that users
|
||||
* use to slide up and down the page).
|
||||
*/
|
||||
@Override
|
||||
protected void paintThumb(Graphics graphics, JComponent jComponent, Rectangle rectangle)
|
||||
{
|
||||
graphics.setColor(thumbColor);
|
||||
graphics.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty JButton to be used as the scroll bar's arrows (to disable the arrows).
|
||||
*/
|
||||
protected JButton createEmptyButton()
|
||||
{
|
||||
JButton button = new JButton();
|
||||
Dimension zeroDim = new Dimension(0, 0);
|
||||
button.setPreferredSize(zeroDim);
|
||||
button.setMinimumSize(zeroDim);
|
||||
button.setMaximumSize(zeroDim);
|
||||
return button;
|
||||
}
|
||||
|
||||
public static ComponentUI createUI(JComponent c)
|
||||
{
|
||||
JScrollBar bar = (JScrollBar) c;
|
||||
bar.setUnitIncrement(16);
|
||||
bar.setPreferredSize(new Dimension(7, 0));
|
||||
return new CustomScrollBarUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies an empty button to the decrease (down arrow) button.
|
||||
*/
|
||||
@Override
|
||||
protected JButton createDecreaseButton(int orientation)
|
||||
{
|
||||
return createEmptyButton();
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies an empty button to the increase (up arrow) button.
|
||||
*/
|
||||
@Override
|
||||
protected JButton createIncreaseButton(int orientation)
|
||||
{
|
||||
return createEmptyButton();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2018, Psikoi <Adam@sigterm.info>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui.components;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.KeyListener;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.text.Document;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
/**
|
||||
* This component is a JTextField with an icon on its left side.
|
||||
*/
|
||||
public class IconTextField extends JPanel
|
||||
{
|
||||
private final JTextField textField;
|
||||
|
||||
//to support gifs, the icon needs to be wrapped in a JLabel
|
||||
private final JLabel iconWrapperLabel;
|
||||
|
||||
//the default background color, this needs to be stored for hover effects
|
||||
private Color backgroundColor = ColorScheme.DARKER_GRAY_COLOR;
|
||||
//the default hover background color, this needs to be stored for hover effects
|
||||
private Color hoverBackgroundColor;
|
||||
|
||||
// the input can be blocked (no clicking, no editing, no hover effects)
|
||||
private boolean blocked;
|
||||
|
||||
public IconTextField()
|
||||
{
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
this.iconWrapperLabel = new JLabel();
|
||||
this.iconWrapperLabel.setPreferredSize(new Dimension(30, 0));
|
||||
this.iconWrapperLabel.setVerticalAlignment(JLabel.CENTER);
|
||||
this.iconWrapperLabel.setHorizontalAlignment(JLabel.CENTER);
|
||||
|
||||
this.textField = new JTextField();
|
||||
this.textField.setBorder(null);
|
||||
this.textField.setOpaque(false);
|
||||
this.textField.setSelectedTextColor(Color.WHITE);
|
||||
this.textField.setSelectionColor(ColorScheme.BRAND_ORANGE_TRANSPARENT);
|
||||
|
||||
add(iconWrapperLabel, BorderLayout.WEST);
|
||||
add(textField, BorderLayout.CENTER);
|
||||
|
||||
textField.addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent mouseEvent)
|
||||
{
|
||||
if (blocked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (hoverBackgroundColor != null)
|
||||
{
|
||||
IconTextField.super.setBackground(hoverBackgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent mouseEvent)
|
||||
{
|
||||
IconTextField.super.setBackground(backgroundColor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void addActionListener(ActionListener actionListener)
|
||||
{
|
||||
textField.addActionListener(actionListener);
|
||||
}
|
||||
|
||||
public void setIcon(ImageIcon icon)
|
||||
{
|
||||
iconWrapperLabel.setIcon(icon);
|
||||
}
|
||||
|
||||
public String getText()
|
||||
{
|
||||
return textField.getText();
|
||||
}
|
||||
|
||||
public void setText(String text)
|
||||
{
|
||||
textField.setText(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackground(Color color)
|
||||
{
|
||||
if (color == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
super.setBackground(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)
|
||||
{
|
||||
if (hoverBackgroundColor == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.hoverBackgroundColor = hoverBackgroundColor;
|
||||
}
|
||||
|
||||
public void setEditable(boolean editable)
|
||||
{
|
||||
this.blocked = !editable;
|
||||
textField.setEditable(editable);
|
||||
textField.setFocusable(editable);
|
||||
if (!editable)
|
||||
{
|
||||
super.setBackground(backgroundColor);
|
||||
}
|
||||
}
|
||||
|
||||
public Document getDocument()
|
||||
{
|
||||
return textField.getDocument();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui.components;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||
|
||||
/**
|
||||
* A component to display an error/info message (to be used on a plugin panel)
|
||||
* Example uses are: no ge search results found, no ge offers found.
|
||||
*/
|
||||
public class PluginErrorPanel extends JPanel
|
||||
{
|
||||
private final JLabel noResultsTitle = new JShadowedLabel();
|
||||
private final JLabel noResultsDescription = new JShadowedLabel();
|
||||
|
||||
public PluginErrorPanel()
|
||||
{
|
||||
setOpaque(false);
|
||||
setBorder(new EmptyBorder(50, 10, 0, 10));
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
noResultsTitle.setForeground(Color.WHITE);
|
||||
noResultsTitle.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
|
||||
noResultsDescription.setFont(FontManager.getRunescapeSmallFont());
|
||||
noResultsDescription.setForeground(Color.GRAY);
|
||||
noResultsDescription.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
|
||||
add(noResultsTitle, BorderLayout.NORTH);
|
||||
add(noResultsDescription, BorderLayout.CENTER);
|
||||
|
||||
setVisible(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the content of the panel to the given parameters.
|
||||
* The description has to be wrapped in html so that its text can be wrapped.
|
||||
*/
|
||||
public void setContent(String title, String description)
|
||||
{
|
||||
noResultsTitle.setText(title);
|
||||
noResultsDescription.setText("<html><body style = 'text-align:center'>" + description + "</body></html>");
|
||||
setVisible(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui.components;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.SwingConstants;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import lombok.Setter;
|
||||
import net.runelite.client.ui.FontManager;
|
||||
import net.runelite.client.ui.components.shadowlabel.JShadowedLabel;
|
||||
|
||||
/**
|
||||
* A progress bar to be displayed underneath the GE offer item panels
|
||||
*/
|
||||
public class ProgressBar extends JPanel
|
||||
{
|
||||
@Setter
|
||||
private int maximumValue;
|
||||
|
||||
@Setter
|
||||
private int value;
|
||||
|
||||
private final JLabel leftLabel = new JShadowedLabel();
|
||||
private final JLabel rightLabel = new JShadowedLabel();
|
||||
private final JLabel centerLabel = new JShadowedLabel();
|
||||
|
||||
public ProgressBar()
|
||||
{
|
||||
setLayout(new BorderLayout());
|
||||
setBackground(Color.GREEN.darker());
|
||||
setPreferredSize(new Dimension(100, 16));
|
||||
|
||||
leftLabel.setFont(FontManager.getRunescapeSmallFont());
|
||||
leftLabel.setForeground(Color.WHITE);
|
||||
leftLabel.setBorder(new EmptyBorder(2, 5, 0, 0));
|
||||
|
||||
rightLabel.setFont(FontManager.getRunescapeSmallFont());
|
||||
rightLabel.setForeground(Color.WHITE);
|
||||
rightLabel.setBorder(new EmptyBorder(2, 0, 0, 5));
|
||||
|
||||
centerLabel.setFont(FontManager.getRunescapeSmallFont());
|
||||
centerLabel.setForeground(Color.WHITE);
|
||||
centerLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
centerLabel.setBorder(new EmptyBorder(2, 0, 0, 0));
|
||||
|
||||
add(leftLabel, BorderLayout.WEST);
|
||||
add(centerLabel, BorderLayout.CENTER);
|
||||
add(rightLabel, BorderLayout.EAST);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g)
|
||||
{
|
||||
double percentage = getPercentage();
|
||||
int topWidth = (int) (getSize().width * (percentage / 100));
|
||||
|
||||
super.paint(g);
|
||||
g.setColor(getForeground());
|
||||
g.fillRect(0, 0, topWidth, 16);
|
||||
super.paintComponents(g);
|
||||
}
|
||||
|
||||
|
||||
public void setLeftLabel(String txt)
|
||||
{
|
||||
this.leftLabel.setText(txt);
|
||||
}
|
||||
|
||||
public void setRightLabel(String txt)
|
||||
{
|
||||
this.rightLabel.setText(txt);
|
||||
}
|
||||
|
||||
public void setCenterLabel(String txt)
|
||||
{
|
||||
this.centerLabel.setText(txt);
|
||||
}
|
||||
|
||||
public double getPercentage()
|
||||
{
|
||||
if (value == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (value * 100) / maximumValue;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Adam <Adam@sigterm.info>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -23,54 +23,71 @@
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.plugins.hiscore;
|
||||
package net.runelite.client.ui.components;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.border.Border;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import javax.swing.JPanel;
|
||||
import lombok.Setter;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
public class IconTextField extends JTextField
|
||||
/**
|
||||
* A progress bar to be displayed underneath the GE offer item panels
|
||||
*/
|
||||
public class ThinProgressBar extends JPanel
|
||||
{
|
||||
private Border border;
|
||||
private Icon icon;
|
||||
@Setter
|
||||
private int maximumValue;
|
||||
|
||||
@Override
|
||||
public void setBorder(Border border)
|
||||
@Setter
|
||||
private int value;
|
||||
|
||||
private final JPanel topBar = new JPanel();
|
||||
|
||||
public ThinProgressBar()
|
||||
{
|
||||
this.border = border;
|
||||
setLayout(new BorderLayout());
|
||||
setBackground(Color.GREEN.darker());
|
||||
|
||||
if (icon == null)
|
||||
topBar.setPreferredSize(new Dimension(100, 4));
|
||||
topBar.setBackground(ColorScheme.PROGRESS_COMPLETE_COLOR);
|
||||
|
||||
add(topBar, BorderLayout.WEST);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the UI based on the percentage progress
|
||||
*/
|
||||
public void update()
|
||||
{
|
||||
double percentage = getPercentage();
|
||||
int topWidth = (int) (getSize().width * (percentage / 100));
|
||||
|
||||
topBar.setPreferredSize(new Dimension(topWidth, 4));
|
||||
topBar.repaint();
|
||||
|
||||
revalidate();
|
||||
repaint();
|
||||
}
|
||||
|
||||
public double getPercentage()
|
||||
{
|
||||
if (value == 0)
|
||||
{
|
||||
super.setBorder(border);
|
||||
}
|
||||
else
|
||||
{
|
||||
Border margin = BorderFactory.createEmptyBorder(0, icon.getIconWidth() + 4, 0, 0);
|
||||
Border compound = BorderFactory.createCompoundBorder(border, margin);
|
||||
super.setBorder(compound);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (value * 100) / maximumValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics graphics)
|
||||
public void setForeground(Color color)
|
||||
{
|
||||
super.paintComponent(graphics);
|
||||
|
||||
Insets iconInsets = border.getBorderInsets(this);
|
||||
icon.paintIcon(this, graphics, iconInsets.left, iconInsets.top);
|
||||
if (topBar != null)
|
||||
{
|
||||
topBar.setBackground(color);
|
||||
}
|
||||
setBackground(color.darker());
|
||||
}
|
||||
|
||||
public void setIcon(Icon icon)
|
||||
{
|
||||
this.icon = icon;
|
||||
resetBorder();
|
||||
}
|
||||
|
||||
private void resetBorder()
|
||||
{
|
||||
setBorder(border);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui.components.materialtabs;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.CompoundBorder;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import net.runelite.client.ui.ColorScheme;
|
||||
|
||||
/**
|
||||
* This class represents a Material Design inspired tab.
|
||||
* <p>
|
||||
* Each tab will communicate with it's containing group when it's clicked
|
||||
* and that group will display the tab's content on it's own display.
|
||||
*
|
||||
* @author Psikoi
|
||||
*/
|
||||
public class MaterialTab extends JLabel
|
||||
{
|
||||
private static final Border SELECTED_BORDER = new CompoundBorder(
|
||||
BorderFactory.createMatteBorder(0, 0, 1, 0, ColorScheme.BRAND_ORANGE),
|
||||
BorderFactory.createEmptyBorder(5, 10, 5, 10));
|
||||
|
||||
private static final Border UNSELECTED_BORDER = BorderFactory
|
||||
.createEmptyBorder(5, 10, 5, 10);
|
||||
|
||||
/* The tab's containing group */
|
||||
private final MaterialTabGroup group;
|
||||
|
||||
/* The tab's associated content display */
|
||||
@Getter
|
||||
private final JComponent content;
|
||||
|
||||
/* To be execuded when the tab is selected */
|
||||
@Setter
|
||||
private Runnable onSelectEvent;
|
||||
|
||||
@Getter
|
||||
private boolean selected;
|
||||
|
||||
public MaterialTab(String string, MaterialTabGroup group, JComponent content)
|
||||
{
|
||||
super(string);
|
||||
|
||||
this.group = group;
|
||||
this.content = content;
|
||||
|
||||
if (selected)
|
||||
{
|
||||
select();
|
||||
}
|
||||
else
|
||||
{
|
||||
unselect();
|
||||
}
|
||||
|
||||
addMouseListener(new MouseAdapter()
|
||||
{
|
||||
@Override
|
||||
public void mousePressed(MouseEvent mouseEvent)
|
||||
{
|
||||
group.select(MaterialTab.this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void select()
|
||||
{
|
||||
setBorder(SELECTED_BORDER);
|
||||
setForeground(Color.WHITE);
|
||||
selected = true;
|
||||
if (onSelectEvent != null)
|
||||
{
|
||||
onSelectEvent.run();
|
||||
}
|
||||
}
|
||||
|
||||
public void unselect()
|
||||
{
|
||||
setBorder(UNSELECTED_BORDER);
|
||||
setForeground(Color.GRAY);
|
||||
selected = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui.components.materialtabs;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.FlowLayout;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
/**
|
||||
* This class will be a container (group) for the new Material Tabs. It will
|
||||
* contain a list of tabs and a display (JPanel). When a tab is selected, the
|
||||
* JPanel "display" will display the content associated with that tab.
|
||||
* <p>
|
||||
* How to use these tabs:
|
||||
* <ol>
|
||||
* <li>1 - Create displays (JPanels) for each tab</li>
|
||||
* <li>2 - Create an empty JPanel to serve as the group's display</li>
|
||||
* <li>3 - Create a new MaterialGroup, passing the panel in step 2 as a param</li>
|
||||
* <li>4 - Create new tabs, passing the group in step 3 and one of the panels in
|
||||
* step 1 as params</li>
|
||||
* <li>5 - Add the tabs to the group using the MaterialTabGroup#addTab method</li>
|
||||
* <li>6 - Select one of the tabs using the MaterialTab#select method</li>
|
||||
* </ol>
|
||||
*
|
||||
* @author Psikoi
|
||||
*/
|
||||
public class MaterialTabGroup extends JPanel
|
||||
{
|
||||
/* The panel on which the content tab's content will be displayed on. */
|
||||
private final JPanel display;
|
||||
/* A list of all the tabs contained in this group. */
|
||||
private final List<MaterialTab> tabs = new ArrayList<>();
|
||||
|
||||
public MaterialTabGroup(JPanel display)
|
||||
{
|
||||
this.display = display;
|
||||
this.display.setLayout(new BorderLayout());
|
||||
setLayout(new FlowLayout(FlowLayout.CENTER, 8, 0));
|
||||
setOpaque(false);
|
||||
}
|
||||
|
||||
/* Returns the tab on a certain index. */
|
||||
public MaterialTab getTab(int index)
|
||||
{
|
||||
|
||||
if (tabs == null || tabs.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return tabs.get(index);
|
||||
}
|
||||
|
||||
public void addTab(MaterialTab tab)
|
||||
{
|
||||
tabs.add(tab);
|
||||
add(tab, BorderLayout.NORTH);
|
||||
}
|
||||
|
||||
/***
|
||||
* Selects a tab from the group, and sets the display's content to the
|
||||
* tab's associated content.
|
||||
* @param selectedTab - The tab to select
|
||||
*/
|
||||
public boolean select(MaterialTab selectedTab)
|
||||
{
|
||||
if (!tabs.contains(selectedTab))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
display.removeAll();
|
||||
|
||||
for (MaterialTab tab : tabs)
|
||||
{
|
||||
if (tab.equals(selectedTab))
|
||||
{
|
||||
tab.select();
|
||||
display.add(tab.getContent());
|
||||
display.revalidate();
|
||||
display.repaint();
|
||||
}
|
||||
else
|
||||
{
|
||||
tab.unselect();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui;
|
||||
package net.runelite.client.ui.components.shadowlabel;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Point;
|
||||
@@ -22,7 +22,7 @@
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui;
|
||||
package net.runelite.client.ui.components.shadowlabel;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import javax.swing.JLabel;
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui.skin;
|
||||
|
||||
import javax.swing.AbstractButton;
|
||||
import org.pushingpixels.substance.api.ComponentState;
|
||||
import org.pushingpixels.substance.api.SubstanceColorSchemeBundle;
|
||||
import org.pushingpixels.substance.api.SubstanceSkin;
|
||||
import org.pushingpixels.substance.api.SubstanceSlices.ColorSchemeAssociationKind;
|
||||
import org.pushingpixels.substance.api.SubstanceSlices.DecorationAreaType;
|
||||
import org.pushingpixels.substance.api.colorscheme.ColorSchemeSingleColorQuery;
|
||||
import org.pushingpixels.substance.api.colorscheme.SubstanceColorScheme;
|
||||
import org.pushingpixels.substance.api.painter.border.ClassicBorderPainter;
|
||||
import org.pushingpixels.substance.api.painter.border.CompositeBorderPainter;
|
||||
import org.pushingpixels.substance.api.painter.border.DelegateBorderPainter;
|
||||
import org.pushingpixels.substance.api.painter.decoration.MatteDecorationPainter;
|
||||
import org.pushingpixels.substance.api.painter.fill.FractionBasedFillPainter;
|
||||
import org.pushingpixels.substance.api.painter.highlight.ClassicHighlightPainter;
|
||||
import org.pushingpixels.substance.api.painter.overlay.BottomLineOverlayPainter;
|
||||
import org.pushingpixels.substance.api.painter.overlay.BottomShadowOverlayPainter;
|
||||
import org.pushingpixels.substance.api.painter.overlay.TopBezelOverlayPainter;
|
||||
import org.pushingpixels.substance.api.painter.overlay.TopLineOverlayPainter;
|
||||
import org.pushingpixels.substance.api.shaper.ClassicButtonShaper;
|
||||
import org.pushingpixels.substance.internal.utils.SubstanceColorUtilities;
|
||||
|
||||
public class ObsidianSkin extends SubstanceSkin
|
||||
{
|
||||
/**
|
||||
* Display name for <code>this</code> skin.
|
||||
*/
|
||||
private static final String NAME = "RuneLite";
|
||||
|
||||
/**
|
||||
* Creates a new <code>RuneLite</code> skin.
|
||||
*/
|
||||
ObsidianSkin()
|
||||
{
|
||||
final SubstanceSkin.ColorSchemes schemes = SubstanceSkin
|
||||
.getColorSchemes(getClass().getResource(NAME + ".colorschemes"));
|
||||
final SubstanceColorScheme activeScheme = schemes.get("RuneLite Active");
|
||||
final SubstanceColorScheme enabledScheme = schemes.get("RuneLite Enabled");
|
||||
|
||||
final SubstanceColorSchemeBundle defaultSchemeBundle = new SubstanceColorSchemeBundle(
|
||||
activeScheme, enabledScheme, enabledScheme);
|
||||
defaultSchemeBundle.registerColorScheme(enabledScheme, 0.6f,
|
||||
ComponentState.DISABLED_UNSELECTED);
|
||||
defaultSchemeBundle.registerColorScheme(activeScheme, 0.6f,
|
||||
ComponentState.DISABLED_SELECTED);
|
||||
|
||||
// borders
|
||||
final SubstanceColorScheme borderDisabledSelectedScheme = schemes
|
||||
.get("RuneLite Selected Disabled Border");
|
||||
final SubstanceColorScheme borderScheme = schemes.get("RuneLite Border");
|
||||
defaultSchemeBundle.registerColorScheme(borderDisabledSelectedScheme,
|
||||
ColorSchemeAssociationKind.BORDER, ComponentState.DISABLED_SELECTED);
|
||||
defaultSchemeBundle.registerColorScheme(borderScheme, ColorSchemeAssociationKind.BORDER);
|
||||
|
||||
// marks
|
||||
final SubstanceColorScheme markActiveScheme = schemes.get("RuneLite Mark Active");
|
||||
defaultSchemeBundle.registerColorScheme(markActiveScheme, ColorSchemeAssociationKind.MARK,
|
||||
ComponentState.getActiveStates());
|
||||
defaultSchemeBundle.registerColorScheme(markActiveScheme, 0.6f,
|
||||
ColorSchemeAssociationKind.MARK, ComponentState.DISABLED_SELECTED,
|
||||
ComponentState.DISABLED_UNSELECTED);
|
||||
|
||||
// separators
|
||||
final SubstanceColorScheme separatorScheme = schemes.get("RuneLite Separator");
|
||||
defaultSchemeBundle.registerColorScheme(separatorScheme,
|
||||
ColorSchemeAssociationKind.SEPARATOR);
|
||||
|
||||
// tab borders
|
||||
defaultSchemeBundle.registerColorScheme(schemes.get("RuneLite Tab Border"),
|
||||
ColorSchemeAssociationKind.TAB_BORDER, ComponentState.getActiveStates());
|
||||
|
||||
final SubstanceColorScheme watermarkScheme = schemes.get("RuneLite Watermark");
|
||||
|
||||
this.registerDecorationAreaSchemeBundle(defaultSchemeBundle, watermarkScheme,
|
||||
DecorationAreaType.NONE);
|
||||
|
||||
final SubstanceColorSchemeBundle decorationsSchemeBundle = new SubstanceColorSchemeBundle(
|
||||
activeScheme, enabledScheme, enabledScheme);
|
||||
decorationsSchemeBundle.registerColorScheme(enabledScheme, 0.5f,
|
||||
ComponentState.DISABLED_UNSELECTED);
|
||||
|
||||
// borders
|
||||
decorationsSchemeBundle.registerColorScheme(borderDisabledSelectedScheme,
|
||||
ColorSchemeAssociationKind.BORDER, ComponentState.DISABLED_SELECTED);
|
||||
decorationsSchemeBundle.registerColorScheme(borderScheme,
|
||||
ColorSchemeAssociationKind.BORDER);
|
||||
|
||||
// marks
|
||||
decorationsSchemeBundle.registerColorScheme(markActiveScheme,
|
||||
ColorSchemeAssociationKind.MARK, ComponentState.getActiveStates());
|
||||
|
||||
// separators
|
||||
final SubstanceColorScheme separatorDecorationsScheme = schemes
|
||||
.get("RuneLite Decorations Separator");
|
||||
decorationsSchemeBundle.registerColorScheme(separatorDecorationsScheme,
|
||||
ColorSchemeAssociationKind.SEPARATOR);
|
||||
|
||||
final SubstanceColorScheme decorationsWatermarkScheme = schemes
|
||||
.get("RuneLite Decorations Watermark");
|
||||
|
||||
this.registerDecorationAreaSchemeBundle(decorationsSchemeBundle, decorationsWatermarkScheme,
|
||||
DecorationAreaType.TOOLBAR, DecorationAreaType.GENERAL, DecorationAreaType.FOOTER);
|
||||
|
||||
final SubstanceColorSchemeBundle headerSchemeBundle = new SubstanceColorSchemeBundle(activeScheme,
|
||||
enabledScheme, enabledScheme);
|
||||
headerSchemeBundle.registerColorScheme(enabledScheme, 0.5f,
|
||||
ComponentState.DISABLED_UNSELECTED);
|
||||
|
||||
// borders
|
||||
final SubstanceColorScheme headerBorderScheme = schemes.get("RuneLite Header Border");
|
||||
headerSchemeBundle.registerColorScheme(borderDisabledSelectedScheme,
|
||||
ColorSchemeAssociationKind.BORDER, ComponentState.DISABLED_SELECTED);
|
||||
headerSchemeBundle.registerColorScheme(headerBorderScheme,
|
||||
ColorSchemeAssociationKind.BORDER);
|
||||
// marks
|
||||
headerSchemeBundle.registerColorScheme(markActiveScheme, ColorSchemeAssociationKind.MARK,
|
||||
ComponentState.getActiveStates());
|
||||
|
||||
headerSchemeBundle.registerHighlightColorScheme(activeScheme, 0.7f,
|
||||
ComponentState.ROLLOVER_UNSELECTED, ComponentState.ROLLOVER_ARMED,
|
||||
ComponentState.ARMED);
|
||||
headerSchemeBundle.registerHighlightColorScheme(activeScheme, 0.8f,
|
||||
ComponentState.SELECTED);
|
||||
headerSchemeBundle.registerHighlightColorScheme(activeScheme, 1.0f,
|
||||
ComponentState.ROLLOVER_SELECTED);
|
||||
|
||||
final SubstanceColorScheme headerWatermarkScheme = schemes.get("RuneLite Header Watermark");
|
||||
|
||||
this.registerDecorationAreaSchemeBundle(headerSchemeBundle, headerWatermarkScheme,
|
||||
DecorationAreaType.PRIMARY_TITLE_PANE, DecorationAreaType.SECONDARY_TITLE_PANE,
|
||||
DecorationAreaType.HEADER);
|
||||
|
||||
setTabFadeStart(0.2);
|
||||
setTabFadeEnd(0.9);
|
||||
|
||||
// Add overlay painters to paint drop shadows along the bottom
|
||||
// edges of toolbars and footers
|
||||
this.addOverlayPainter(BottomShadowOverlayPainter.getInstance(),
|
||||
DecorationAreaType.TOOLBAR);
|
||||
this.addOverlayPainter(BottomShadowOverlayPainter.getInstance(), DecorationAreaType.FOOTER);
|
||||
|
||||
// add an overlay painter to paint a dark line along the bottom
|
||||
// edge of toolbars
|
||||
final BottomLineOverlayPainter toolbarBottomLineOverlayPainter = new BottomLineOverlayPainter(
|
||||
(SubstanceColorScheme scheme) -> scheme.getUltraDarkColor().darker());
|
||||
this.addOverlayPainter(toolbarBottomLineOverlayPainter, DecorationAreaType.TOOLBAR);
|
||||
|
||||
// add an overlay painter to paint a dark line along the bottom
|
||||
// edge of toolbars
|
||||
final TopLineOverlayPainter toolbarTopLineOverlayPainter = new TopLineOverlayPainter(
|
||||
(SubstanceColorScheme scheme) -> SubstanceColorUtilities
|
||||
.getAlphaColor(scheme.getForegroundColor(), 32));
|
||||
this.addOverlayPainter(toolbarTopLineOverlayPainter, DecorationAreaType.TOOLBAR);
|
||||
|
||||
// add an overlay painter to paint a bezel line along the top
|
||||
// edge of footer
|
||||
final TopBezelOverlayPainter footerTopBezelOverlayPainter = new TopBezelOverlayPainter(
|
||||
(SubstanceColorScheme scheme) -> scheme.getUltraDarkColor().darker(),
|
||||
(SubstanceColorScheme scheme) -> SubstanceColorUtilities
|
||||
.getAlphaColor(scheme.getForegroundColor(), 32));
|
||||
this.addOverlayPainter(footerTopBezelOverlayPainter, DecorationAreaType.FOOTER);
|
||||
|
||||
this.setTabFadeStart(0.18);
|
||||
this.setTabFadeEnd(0.18);
|
||||
|
||||
// Set button shaper to use "flat" design
|
||||
this.buttonShaper = new ClassicButtonShaper()
|
||||
{
|
||||
@Override
|
||||
public float getCornerRadius(AbstractButton button, float insets)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
this.watermark = null;
|
||||
this.fillPainter = new FractionBasedFillPainter("RuneLite",
|
||||
new float[]{0.0f, 0.5f, 1.0f},
|
||||
new ColorSchemeSingleColorQuery[]{ColorSchemeSingleColorQuery.ULTRALIGHT,
|
||||
ColorSchemeSingleColorQuery.LIGHT, ColorSchemeSingleColorQuery.LIGHT});
|
||||
this.decorationPainter = new MatteDecorationPainter();
|
||||
this.highlightPainter = new ClassicHighlightPainter();
|
||||
this.borderPainter = new CompositeBorderPainter("RuneLite", new ClassicBorderPainter(),
|
||||
new DelegateBorderPainter("RuneLite Inner", new ClassicBorderPainter(), 0x40FFFFFF,
|
||||
0x20FFFFFF, 0x00FFFFFF,
|
||||
(SubstanceColorScheme scheme) -> scheme.tint(0.2f)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayName()
|
||||
{
|
||||
return NAME;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||
* Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package net.runelite.client.ui.skin;
|
||||
|
||||
import org.pushingpixels.substance.api.SubstanceLookAndFeel;
|
||||
|
||||
public class SubstanceRuneLiteLookAndFeel extends SubstanceLookAndFeel
|
||||
{
|
||||
public SubstanceRuneLiteLookAndFeel()
|
||||
{
|
||||
super(new ObsidianSkin());
|
||||
}
|
||||
}
|
||||
@@ -128,6 +128,61 @@ public class StackFormatter
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a quantity to stack size as it would
|
||||
* appear in RuneScape. (with decimals)
|
||||
* <p>
|
||||
* This differs from quantityToRSStack in that it displays
|
||||
* decimals. Ex: 27100 is 27,1k (not 27k)
|
||||
* <p>
|
||||
* This uses the NumberFormat singleton instead of the
|
||||
* NUMBER_FORMATTER variable to ensure the UK locale.
|
||||
*
|
||||
* @param quantity The quantity to convert.
|
||||
* @return The stack size as it would appear in RS, with decimals,
|
||||
* with K after 100,000 and M after 10,000,000
|
||||
*/
|
||||
public static String quantityToRSDecimalStack(int quantity)
|
||||
{
|
||||
|
||||
if (quantity < 10_000)
|
||||
{
|
||||
return Integer.toString(quantity);
|
||||
}
|
||||
else if (quantity < 1_000_000)
|
||||
{
|
||||
if (quantity % 1000 == 0)
|
||||
{
|
||||
return quantity / 1000 + "K";
|
||||
}
|
||||
return NUMBER_FORMATTER.format(quantity).substring(0, Integer.toString(quantity).length() - 1) + "K";
|
||||
}
|
||||
else if (quantity < 10_000_000)
|
||||
{
|
||||
if (quantity % 1_000_000 == 0)
|
||||
{
|
||||
return quantity / 1_000_000 + "M";
|
||||
}
|
||||
return NUMBER_FORMATTER.format(quantity).substring(0, Integer.toString(quantity).length() - 4) + "M";
|
||||
}
|
||||
else if (quantity < 1_000_000_000)
|
||||
{
|
||||
if (quantity % 1_000_000 == 0)
|
||||
{
|
||||
return quantity / 1_000_000 + "M";
|
||||
}
|
||||
return NUMBER_FORMATTER.format(quantity).substring(0, Integer.toString(quantity).length() - 4) + "M";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (quantity % 1_000_000_000 == 0)
|
||||
{
|
||||
return quantity / 1_000_000_000 + "B";
|
||||
}
|
||||
return NUMBER_FORMATTER.format(quantity).substring(0, Integer.toString(quantity).length() - 7) + "B";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a string representation of a stack
|
||||
* back to (close to) it's original value.
|
||||
@@ -147,8 +202,8 @@ public class StackFormatter
|
||||
*
|
||||
* @param number the long number to format
|
||||
* @return the formatted String
|
||||
* @exception ArithmeticException if rounding is needed with rounding
|
||||
* mode being set to RoundingMode.UNNECESSARY
|
||||
* @throws ArithmeticException if rounding is needed with rounding
|
||||
* mode being set to RoundingMode.UNNECESSARY
|
||||
* @see java.text.Format#format
|
||||
*/
|
||||
public static String formatNumber(final long number)
|
||||
@@ -161,8 +216,8 @@ public class StackFormatter
|
||||
*
|
||||
* @param number the double number to format
|
||||
* @return the formatted String
|
||||
* @exception ArithmeticException if rounding is needed with rounding
|
||||
* mode being set to RoundingMode.UNNECESSARY
|
||||
* @throws ArithmeticException if rounding is needed with rounding
|
||||
* mode being set to RoundingMode.UNNECESSARY
|
||||
* @see java.text.Format#format
|
||||
*/
|
||||
public static String formatNumber(double number)
|
||||
|
||||
@@ -25,12 +25,14 @@
|
||||
package net.runelite.client.util;
|
||||
|
||||
import java.awt.AWTException;
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Frame;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.SystemTray;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.TrayIcon;
|
||||
@@ -40,6 +42,8 @@ import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.LookupOp;
|
||||
import java.awt.image.LookupTable;
|
||||
import java.util.Enumeration;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.BiConsumer;
|
||||
@@ -59,6 +63,7 @@ import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE;
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.client.ui.NavigationButton;
|
||||
import net.runelite.client.ui.components.CustomScrollBarUI;
|
||||
import org.pushingpixels.substance.internal.SubstanceSynapse;
|
||||
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
|
||||
|
||||
@@ -77,8 +82,13 @@ public class SwingUtil
|
||||
// Force heavy-weight popups/tooltips.
|
||||
// Prevents them from being obscured by the game applet.
|
||||
ToolTipManager.sharedInstance().setLightWeightPopupEnabled(false);
|
||||
ToolTipManager.sharedInstance().setInitialDelay(300);
|
||||
JPopupMenu.setDefaultLightWeightPopupEnabled(false);
|
||||
|
||||
UIManager.put("Button.foreground", Color.WHITE);
|
||||
UIManager.put("MenuItem.foreground", Color.WHITE);
|
||||
UIManager.put("ScrollBarUI", CustomScrollBarUI.class.getName());
|
||||
|
||||
// Do not render shadows under popups/tooltips.
|
||||
// Fixes black boxes under popups that are above the game applet.
|
||||
System.setProperty("jgoodies.popupDropShadowEnabled", "false");
|
||||
@@ -88,6 +98,48 @@ public class SwingUtil
|
||||
System.setProperty("sun.awt.noerasebackground", "true");
|
||||
}
|
||||
|
||||
/**
|
||||
* Offsets an image in the grayscale (darkens/brightens) by an offset
|
||||
*/
|
||||
public static BufferedImage grayscaleOffset(BufferedImage image, int offset)
|
||||
{
|
||||
int numComponents = image.getColorModel().getNumComponents();
|
||||
int index = numComponents - 1;
|
||||
|
||||
LookupTable lookup = new LookupTable(0, numComponents)
|
||||
{
|
||||
@Override
|
||||
public int[] lookupPixel(int[] src, int[] dest)
|
||||
{
|
||||
if (dest[index] != 0)
|
||||
{
|
||||
dest[index] = dest[index] + offset;
|
||||
if (dest[index] < 0)
|
||||
{
|
||||
dest[index] = 0;
|
||||
}
|
||||
else if (dest[index] > 255)
|
||||
{
|
||||
dest[index] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
};
|
||||
|
||||
LookupOp op = new LookupOp(lookup, new RenderingHints(null));
|
||||
return op.filter(image, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a given color to it's hexidecimal equivalent.
|
||||
*/
|
||||
public static String toHexColor(Color color)
|
||||
{
|
||||
return "#" + Integer.toHexString(color.getRGB()).substring(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely sets Swing theme
|
||||
*
|
||||
@@ -210,7 +262,7 @@ public class SwingUtil
|
||||
result = JOptionPane.showConfirmDialog(
|
||||
frame,
|
||||
"Are you sure you want to exit?", "Exit",
|
||||
JOptionPane .OK_CANCEL_OPTION,
|
||||
JOptionPane.OK_CANCEL_OPTION,
|
||||
JOptionPane.QUESTION_MESSAGE);
|
||||
}
|
||||
}
|
||||
@@ -258,6 +310,7 @@ public class SwingUtil
|
||||
: navigationButton.getIcon();
|
||||
|
||||
final JButton button = new JButton();
|
||||
button.setMaximumSize(new Dimension(30, 30));
|
||||
button.setName(navigationButton.getName());
|
||||
button.setToolTipText(navigationButton.getTooltip());
|
||||
button.setIcon(new ImageIcon(scaledImage));
|
||||
|
||||
|
Before Width: | Height: | Size: 566 B After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 365 B After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 335 B |
|
Before Width: | Height: | Size: 417 B |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 388 B |
|
Before Width: | Height: | Size: 280 B After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 307 B After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 388 B |
|
Before Width: | Height: | Size: 365 B After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 122 B |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 503 B After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 692 B After Width: | Height: | Size: 218 B |
|
Before Width: | Height: | Size: 4.1 KiB |
@@ -2,4 +2,6 @@ runelite.title=RuneLite
|
||||
runelite.version=${project.version}
|
||||
runescape.version=${rs.version}
|
||||
runelite.discord.appid=409416265891971072
|
||||
runelite.discord.invite=https://discord.gg/R4BQ8tU
|
||||
runelite.discord.invite=https://discord.gg/R4BQ8tU
|
||||
runelite.github.link=https://github.com/runelite
|
||||
runelite.patreon.link=https://www.patreon.com/runelite
|
||||
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,166 @@
|
||||
# Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
|
||||
# Copyright (c) 2018, Psikoi <https://github.com/psikoi>
|
||||
# All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
# this list of conditions and the following disclaimer in the documentation
|
||||
# and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
RuneLite Enabled {
|
||||
kind=Dark
|
||||
colorUltraLight=#232323
|
||||
colorExtraLight=#232323
|
||||
colorLight=#232323
|
||||
colorMid=#232323
|
||||
colorDark=#232323
|
||||
colorUltraDark=#232323
|
||||
colorForeground=#C6C6C6
|
||||
}
|
||||
|
||||
RuneLite Active {
|
||||
kind=Light
|
||||
colorUltraLight=#4e4e4e
|
||||
colorExtraLight=#4e4e4e
|
||||
colorLight=#4e4e4e
|
||||
colorMid=#232323
|
||||
colorDark=#232323
|
||||
colorUltraDark=#232323
|
||||
colorForeground=#000000
|
||||
}
|
||||
|
||||
RuneLite Selected Disabled Border {
|
||||
kind=Dark
|
||||
colorUltraLight=#191919
|
||||
colorExtraLight=#191919
|
||||
colorLight=#191919
|
||||
colorMid=#191919
|
||||
colorDark=#191919
|
||||
colorUltraDark=#191919
|
||||
colorForeground=#C6C6C6
|
||||
}
|
||||
|
||||
RuneLite Border {
|
||||
kind=Dark
|
||||
colorUltraLight=#191919
|
||||
colorExtraLight=#191919
|
||||
colorLight=#191919
|
||||
colorMid=#191919
|
||||
colorDark=#191919
|
||||
colorUltraDark=#191919
|
||||
colorForeground=#C6C6C6
|
||||
}
|
||||
|
||||
RuneLite Tab Border {
|
||||
kind=Light
|
||||
colorUltraLight=#232323
|
||||
colorExtraLight=#232323
|
||||
colorLight=#232323
|
||||
colorMid=#232323
|
||||
colorDark=#232323
|
||||
colorUltraDark=#232323
|
||||
colorForeground=#232323
|
||||
}
|
||||
|
||||
RuneLite Mark Active {
|
||||
kind=Dark
|
||||
colorUltraLight=#191919
|
||||
colorExtraLight=#191919
|
||||
colorLight=#191919
|
||||
colorMid=#191919
|
||||
colorDark=#191919
|
||||
colorUltraDark=#191919
|
||||
colorForeground=#191919
|
||||
}
|
||||
|
||||
RuneLite Highlight {
|
||||
kind=Light
|
||||
colorUltraLight=#C6C6C6
|
||||
colorExtraLight=#C6C6C6
|
||||
colorLight=#C6C6C6
|
||||
colorMid=#C6C6C6
|
||||
colorDark=#C6C6C6
|
||||
colorUltraDark=#C6C6C6
|
||||
colorForeground=#191919
|
||||
}
|
||||
|
||||
RuneLite Watermark {
|
||||
kind=Light
|
||||
colorUltraLight=#313131
|
||||
colorExtraLight=#313131
|
||||
colorLight=#313131
|
||||
colorMid=#313131
|
||||
colorDark=#313131
|
||||
colorUltraDark=#313131
|
||||
colorForeground=#C6C6C6
|
||||
}
|
||||
|
||||
RuneLite Decorations Watermark {
|
||||
kind=Light
|
||||
colorUltraLight=#1e1e1e
|
||||
colorExtraLight=#1e1e1e
|
||||
colorLight=#1e1e1e
|
||||
colorMid=#1e1e1e
|
||||
colorDark=#1e1e1e
|
||||
colorUltraDark=#1e1e1e
|
||||
colorForeground=#1e1e1e
|
||||
}
|
||||
|
||||
RuneLite Separator {
|
||||
kind=Dark
|
||||
colorUltraLight=#232323
|
||||
colorExtraLight=#232323
|
||||
colorLight=#232323
|
||||
colorMid=#232323
|
||||
colorDark=#232323
|
||||
colorUltraDark=#232323
|
||||
colorForeground=#232323
|
||||
}
|
||||
|
||||
RuneLite Decorations Separator {
|
||||
kind=Dark
|
||||
colorUltraLight=#232323
|
||||
colorExtraLight=#232323
|
||||
colorLight=#232323
|
||||
colorMid=#232323
|
||||
colorDark=#232323
|
||||
colorUltraDark=#232323
|
||||
colorForeground=#232323
|
||||
}
|
||||
|
||||
RuneLite Header Watermark {
|
||||
kind=Dark
|
||||
colorUltraLight=#1e1e1e
|
||||
colorExtraLight=#1e1e1e
|
||||
colorLight=#1e1e1e
|
||||
colorMid=#1e1e1e
|
||||
colorDark=#1e1e1e
|
||||
colorUltraDark=#1e1e1e
|
||||
colorForeground=#C6C6C6
|
||||
}
|
||||
|
||||
RuneLite Header Border {
|
||||
kind=Dark
|
||||
colorUltraLight=#1e1e1e
|
||||
colorExtraLight=#1e1e1e
|
||||
colorLight=#1e1e1e
|
||||
colorMid=#1e1e1e
|
||||
colorDark=#1e1e1e
|
||||
colorUltraDark=#1e1e1e
|
||||
colorForeground=#C6C6C6
|
||||
}
|
||||
@@ -26,12 +26,39 @@ package net.runelite.client.util;
|
||||
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.util.Locale;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class StackFormatterTest
|
||||
{
|
||||
@Before
|
||||
public void setUp()
|
||||
{
|
||||
Locale.setDefault(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quantityToRSDecimalStackSize()
|
||||
{
|
||||
assertEquals("0", StackFormatter.quantityToRSDecimalStack(0));
|
||||
assertEquals("8500", StackFormatter.quantityToRSDecimalStack(8_500));
|
||||
assertEquals("10K", StackFormatter.quantityToRSDecimalStack(10_000));
|
||||
assertEquals("21,7K", StackFormatter.quantityToRSDecimalStack(21_700));
|
||||
assertEquals("100K", StackFormatter.quantityToRSDecimalStack(100_000));
|
||||
assertEquals("100,3K", StackFormatter.quantityToRSDecimalStack(100_300));
|
||||
assertEquals("1M", StackFormatter.quantityToRSDecimalStack(1_000_000));
|
||||
assertEquals("8,4M", StackFormatter.quantityToRSDecimalStack(8_450_000));
|
||||
assertEquals("10M", StackFormatter.quantityToRSDecimalStack(10_000_000));
|
||||
assertEquals("12,8M", StackFormatter.quantityToRSDecimalStack(12_800_000));
|
||||
assertEquals("100M", StackFormatter.quantityToRSDecimalStack(100_000_000));
|
||||
assertEquals("250,1M", StackFormatter.quantityToRSDecimalStack(250_100_000));
|
||||
assertEquals("1B", StackFormatter.quantityToRSDecimalStack(1_000_000_000));
|
||||
assertEquals("1,5B", StackFormatter.quantityToRSDecimalStack(1500_000_000));
|
||||
assertEquals("2,1B", StackFormatter.quantityToRSDecimalStack(Integer.MAX_VALUE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void quantityToRSStackSize()
|
||||
|
||||