diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/blastfurnace/BlastFurnaceOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/blastfurnace/BlastFurnaceOverlay.java
index d57fd53fc9..48253cdfe3 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/blastfurnace/BlastFurnaceOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/blastfurnace/BlastFurnaceOverlay.java
@@ -35,6 +35,7 @@ import net.runelite.client.ui.overlay.Overlay;
import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.OverlayPosition;
+import net.runelite.client.ui.overlay.components.ComponentOrientation;
import net.runelite.client.ui.overlay.components.ImageComponent;
import net.runelite.client.ui.overlay.components.PanelComponent;
@@ -54,7 +55,7 @@ class BlastFurnaceOverlay extends Overlay
this.plugin = plugin;
this.client = client;
setPosition(OverlayPosition.TOP_LEFT);
- imagePanelComponent.setOrientation(PanelComponent.Orientation.HORIZONTAL);
+ imagePanelComponent.setOrientation(ComponentOrientation.HORIZONTAL);
getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Blast furnace overlay"));
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineOreCountOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineOreCountOverlay.java
index d4566f89c8..f660eb2b63 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineOreCountOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/blastmine/BlastMineOreCountOverlay.java
@@ -39,6 +39,7 @@ import net.runelite.client.ui.overlay.Overlay;
import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.OverlayPosition;
+import net.runelite.client.ui.overlay.components.ComponentOrientation;
import net.runelite.client.ui.overlay.components.ImageComponent;
import net.runelite.client.ui.overlay.components.PanelComponent;
@@ -57,7 +58,7 @@ class BlastMineOreCountOverlay extends Overlay
this.client = client;
this.config = config;
this.itemManager = itemManager;
- panelComponent.setOrientation(PanelComponent.Orientation.HORIZONTAL);
+ panelComponent.setOrientation(ComponentOrientation.HORIZONTAL);
getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Blast mine overlay"));
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusOverlay.java
index 5ddbf21f7a..2f384fcd80 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/cerberus/CerberusOverlay.java
@@ -31,6 +31,7 @@ import javax.inject.Singleton;
import net.runelite.client.game.SkillIconManager;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayPosition;
+import net.runelite.client.ui.overlay.components.ComponentOrientation;
import net.runelite.client.ui.overlay.components.ImageComponent;
import net.runelite.client.ui.overlay.components.PanelComponent;
@@ -47,7 +48,7 @@ public class CerberusOverlay extends Overlay
this.plugin = plugin;
this.iconManager = iconManager;
setPosition(OverlayPosition.BOTTOM_RIGHT);
- panelComponent.setOrientation(PanelComponent.Orientation.HORIZONTAL);
+ panelComponent.setOrientation(ComponentOrientation.HORIZONTAL);
}
@Override
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerOverlay.java
index 71da3492aa..7162be5290 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/inventoryviewer/InventoryViewerOverlay.java
@@ -37,6 +37,7 @@ import net.runelite.api.ItemContainer;
import net.runelite.client.game.ItemManager;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayPosition;
+import net.runelite.client.ui.overlay.components.ComponentOrientation;
import net.runelite.client.ui.overlay.components.ImageComponent;
import net.runelite.client.ui.overlay.components.PanelComponent;
@@ -58,7 +59,7 @@ class InventoryViewerOverlay extends Overlay
setPosition(OverlayPosition.BOTTOM_RIGHT);
panelComponent.setWrapping(4);
panelComponent.setGap(new Point(6, 4));
- panelComponent.setOrientation(PanelComponent.Orientation.HORIZONTAL);
+ panelComponent.setOrientation(ComponentOrientation.HORIZONTAL);
this.itemManager = itemManager;
this.client = client;
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesOverlay.java
index b5cc7858bf..9dbd2dc861 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/teamcapes/TeamCapesOverlay.java
@@ -36,6 +36,7 @@ import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.OverlayPriority;
+import net.runelite.client.ui.overlay.components.ComponentOrientation;
import net.runelite.client.ui.overlay.components.ImageComponent;
import net.runelite.client.ui.overlay.components.PanelComponent;
@@ -55,7 +56,7 @@ public class TeamCapesOverlay extends Overlay
this.plugin = plugin;
this.config = config;
this.manager = manager;
- panelComponent.setOrientation(PanelComponent.Orientation.HORIZONTAL);
+ panelComponent.setOrientation(ComponentOrientation.HORIZONTAL);
panelComponent.setWrapping(4);
getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "Teamcapes overlay"));
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java
index 4aac706e4f..d6fff3c47b 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBox.java
@@ -67,6 +67,9 @@ class XpInfoBox extends JPanel
private static final String HTML_LABEL_TEMPLATE =
"
%s%s";
+ private static final String REMOVE_STATE = "Remove from canvas";
+ private static final String ADD_STATE = "Add to canvas";
+
// Instance members
private final JPanel panel;
@@ -89,6 +92,7 @@ class XpInfoBox extends JPanel
private final JLabel expLeft = new JLabel();
private final JLabel actionsLeft = new JLabel();
private final JMenuItem pauseSkill = new JMenuItem("Pause");
+ private final JMenuItem canvasItem = new JMenuItem(ADD_STATE);
private final XpTrackerConfig xpTrackerConfig;
@@ -128,6 +132,21 @@ class XpInfoBox extends JPanel
popupMenu.add(reset);
popupMenu.add(resetOthers);
popupMenu.add(pauseSkill);
+ popupMenu.add(canvasItem);
+
+ canvasItem.addActionListener(e ->
+ {
+ if (canvasItem.getText().equals(REMOVE_STATE))
+ {
+ xpTrackerPlugin.removeOverlay(skill);
+ canvasItem.setText(ADD_STATE);
+ }
+ else
+ {
+ xpTrackerPlugin.addOverlay(skill);
+ canvasItem.setText(REMOVE_STATE);
+ }
+ });
JLabel skillIcon = new JLabel(new ImageIcon(iconManager.getSkillImage(skill)));
skillIcon.setHorizontalAlignment(SwingConstants.CENTER);
@@ -177,6 +196,7 @@ class XpInfoBox extends JPanel
void reset()
{
+ canvasItem.setText(ADD_STATE);
container.remove(statsPanel);
panel.remove(this);
panel.revalidate();
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBoxOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBoxOverlay.java
new file mode 100644
index 0000000000..d5172d6452
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpInfoBoxOverlay.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2018, Jasper Ketelaar
+ * 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 java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import lombok.AccessLevel;
+import lombok.Getter;
+import net.runelite.api.Experience;
+import net.runelite.api.Skill;
+import net.runelite.client.ui.FontManager;
+import net.runelite.client.ui.SkillColor;
+import net.runelite.client.ui.overlay.Overlay;
+import net.runelite.client.ui.overlay.OverlayMenuEntry;
+import net.runelite.client.ui.overlay.components.ComponentOrientation;
+import net.runelite.client.ui.overlay.components.ImageComponent;
+import net.runelite.client.ui.overlay.components.LineComponent;
+import net.runelite.client.ui.overlay.components.PanelComponent;
+import net.runelite.client.ui.overlay.components.ProgressBarComponent;
+import net.runelite.client.ui.overlay.components.SplitComponent;
+import net.runelite.client.util.StackFormatter;
+import static net.runelite.api.MenuAction.RUNELITE_OVERLAY_CONFIG;
+import static net.runelite.client.ui.overlay.OverlayManager.OPTION_CONFIGURE;
+
+class XpInfoBoxOverlay extends Overlay
+{
+ private static final int PANEL_PREFERRED_WIDTH = 150;
+ private static final int BORDER_SIZE = 2;
+ private static final int XP_AND_PROGRESS_BAR_GAP = 2;
+ private static final int XP_AND_ICON_GAP = 4;
+ private static final Rectangle XP_AND_ICON_COMPONENT_BORDER = new Rectangle(2, 1, 4, 0);
+
+ private final PanelComponent panel = new PanelComponent();
+ private final PanelComponent iconXpSplitPanel = new PanelComponent();
+ private final XpTrackerPlugin plugin;
+ private final XpTrackerConfig config;
+
+ @Getter(AccessLevel.PACKAGE)
+ private final Skill skill;
+ private final BufferedImage icon;
+
+ XpInfoBoxOverlay(
+ XpTrackerPlugin plugin,
+ XpTrackerConfig config,
+ Skill skill,
+ BufferedImage icon)
+ {
+ super(plugin);
+ this.plugin = plugin;
+ this.config = config;
+ this.skill = skill;
+ this.icon = icon;
+ panel.setBorder(new Rectangle(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE));
+ panel.setGap(new Point(0, XP_AND_PROGRESS_BAR_GAP));
+ panel.setPreferredSize(new Dimension(PANEL_PREFERRED_WIDTH, 0));
+ iconXpSplitPanel.setBorder(XP_AND_ICON_COMPONENT_BORDER);
+ iconXpSplitPanel.setBackgroundColor(null);
+ iconXpSplitPanel.setPreferredSize(new Dimension(PANEL_PREFERRED_WIDTH, 0));
+ getMenuEntries().add(new OverlayMenuEntry(RUNELITE_OVERLAY_CONFIG, OPTION_CONFIGURE, "XP Tracker overlay"));
+ }
+
+ @Override
+ public Dimension render(Graphics2D graphics)
+ {
+ panel.getChildren().clear();
+ iconXpSplitPanel.getChildren().clear();
+
+ //Setting the font to rs small font so that the overlay isn't huge
+ graphics.setFont(FontManager.getRunescapeSmallFont());
+
+ final XpSnapshotSingle snapshot = plugin.getSkillSnapshot(skill);
+
+ final LineComponent xpLine = LineComponent.builder()
+ .left(config.displayXpLeftOnScreen() ? "XP Left:" : "XP Gained:")
+ .right(StackFormatter.quantityToRSDecimalStack(config.displayXpLeftOnScreen()
+ ? snapshot.getXpRemainingToGoal() : snapshot.getXpGainedInSession()))
+ .build();
+
+ final LineComponent xpHour = LineComponent.builder()
+ .left("XP/Hour:")
+ .right(StackFormatter.quantityToRSDecimalStack(snapshot.getXpPerHour()))
+ .build();
+
+ final SplitComponent xpSplit = SplitComponent.builder()
+ .first(xpLine)
+ .second(xpHour)
+ .orientation(ComponentOrientation.VERTICAL)
+ .build();
+
+ final ImageComponent imageComponent = new ImageComponent(icon);
+ final SplitComponent iconXpSplit = SplitComponent.builder()
+ .first(imageComponent)
+ .second(xpSplit)
+ .orientation(ComponentOrientation.HORIZONTAL)
+ .gap(new Point(XP_AND_ICON_GAP, 0))
+ .build();
+
+ iconXpSplitPanel.getChildren().add(iconXpSplit);
+
+ final ProgressBarComponent progressBarComponent = new ProgressBarComponent();
+
+ progressBarComponent.setBackgroundColor(new Color(61, 56, 49));
+ progressBarComponent.setForegroundColor(SkillColor.find(skill).getColor());
+
+ progressBarComponent.setLeftLabel(String.valueOf(snapshot.getStartLevel()));
+ progressBarComponent.setRightLabel(snapshot.getEndGoalXp() == Experience.MAX_SKILL_XP
+ ? "200M"
+ : String.valueOf(snapshot.getEndLevel()));
+
+ progressBarComponent.setValue(snapshot.getSkillProgressToGoal());
+
+ panel.getChildren().add(iconXpSplitPanel);
+ panel.getChildren().add(progressBarComponent);
+
+ return panel.render(graphics);
+ }
+
+ @Override
+ public String getName()
+ {
+ return super.getName() + skill.getName();
+ }
+}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerConfig.java
index d32abf2aa9..f14b442825 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerConfig.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerConfig.java
@@ -74,4 +74,15 @@ public interface XpTrackerConfig extends Config
{
return 0;
}
+
+ @ConfigItem(
+ position = 4,
+ keyName = "onScreenXpLeft",
+ name = "Display XP Left on-screen",
+ description = "Display remaining experience instead of experience gained on on-screen trackers"
+ )
+ default boolean displayXpLeftOnScreen()
+ {
+ return false;
+ }
}
diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java
index a8d65962a5..7d3006ddc9 100644
--- a/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java
+++ b/runelite-client/src/main/java/net/runelite/client/plugins/xptracker/XpTrackerPlugin.java
@@ -59,6 +59,7 @@ import static net.runelite.client.plugins.xptracker.XpWorldType.NORMAL;
import net.runelite.client.task.Schedule;
import net.runelite.client.ui.ClientToolbar;
import net.runelite.client.ui.NavigationButton;
+import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.util.ImageUtil;
import net.runelite.http.api.xp.XpClient;
@@ -98,6 +99,9 @@ public class XpTrackerPlugin extends Plugin
@Inject
private NPCManager npcManager;
+ @Inject
+ private OverlayManager overlayManager;
+
private NavigationButton navButton;
private XpPanel xpPanel;
private XpWorldType lastWorldType;
@@ -142,6 +146,7 @@ public class XpTrackerPlugin extends Plugin
@Override
protected void shutDown() throws Exception
{
+ overlayManager.removeIf(e -> e instanceof XpInfoBoxOverlay);
xpState.reset();
clientToolbar.removeNavigation(navButton);
}
@@ -208,6 +213,27 @@ public class XpTrackerPlugin extends Plugin
return xpType;
}
+ /**
+ * Adds an overlay to the canvas for tracking a specific skill.
+ *
+ * @param skill the skill for which the overlay should be added
+ */
+ void addOverlay(Skill skill)
+ {
+ removeOverlay(skill);
+ overlayManager.add(new XpInfoBoxOverlay(this, xpTrackerConfig, skill, skillIconManager.getSkillImage(skill)));
+ }
+
+ /**
+ * Removes an overlay from the overlayManager if it's present.
+ *
+ * @param skill the skill for which the overlay should be removed.
+ */
+ void removeOverlay(Skill skill)
+ {
+ overlayManager.removeIf(e -> e instanceof XpInfoBoxOverlay && ((XpInfoBoxOverlay) e).getSkill() == skill);
+ }
+
/**
* Reset internal state and re-initialize all skills with XP currently cached by the RS client
* This is called by the user manually clicking resetSkillState in the UI.
@@ -230,6 +256,7 @@ public class XpTrackerPlugin extends Plugin
}
xpState.initializeSkill(skill, currentXp);
+ removeOverlay(skill);
}
}
@@ -242,6 +269,7 @@ public class XpTrackerPlugin extends Plugin
xpState.reset();
xpPanel.resetAllInfoBoxes();
xpPanel.updateTotal(new XpSnapshotSingle.XpSnapshotSingleBuilder().build());
+ overlayManager.removeIf(e -> e instanceof XpInfoBoxOverlay);
}
/**
@@ -254,6 +282,7 @@ public class XpTrackerPlugin extends Plugin
int currentXp = client.getSkillExperience(skill);
xpState.resetSkill(skill, currentXp);
xpPanel.resetSkill(skill);
+ removeOverlay(skill);
}
/**
@@ -272,7 +301,6 @@ public class XpTrackerPlugin extends Plugin
}
}
-
@Subscribe
public void onExperienceChanged(ExperienceChanged event)
{
diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ComponentOrientation.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ComponentOrientation.java
new file mode 100644
index 0000000000..e06875e970
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ComponentOrientation.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018, Jasper Ketelaar
+ * 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.overlay.components;
+
+public enum ComponentOrientation
+{
+ HORIZONTAL,
+ VERTICAL
+}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java
index 5ea81f2006..6baf20985e 100644
--- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java
+++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java
@@ -37,12 +37,6 @@ import lombok.Setter;
public class PanelComponent implements LayoutableRenderableEntity
{
- public enum Orientation
- {
- HORIZONTAL,
- VERTICAL;
- }
-
@Getter
private final Rectangle bounds = new Rectangle();
@@ -60,7 +54,7 @@ public class PanelComponent implements LayoutableRenderableEntity
private final List children = new ArrayList<>();
@Setter
- private Orientation orientation = Orientation.VERTICAL;
+ private ComponentOrientation orientation = ComponentOrientation.VERTICAL;
@Setter
private int wrapping = -1;
diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java
index ba4634deec..cadced4e96 100644
--- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java
+++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java
@@ -46,10 +46,14 @@ public class ProgressBarComponent implements LayoutableRenderableEntity
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.0");
private static final DecimalFormat DECIMAL_FORMAT_ABS = new DecimalFormat("#0");
+ private static final int SIDE_LABEL_OFFSET = 4;
+
private long minimum;
private long maximum = 100;
private double value;
private LabelDisplayMode labelDisplayMode = LabelDisplayMode.PERCENTAGE;
+ private String leftLabel;
+ private String rightLabel;
private Color foregroundColor = new Color(82, 161, 82);
private Color backgroundColor = new Color(255, 255, 255, 127);
private Color fontColor = Color.WHITE;
@@ -99,6 +103,24 @@ public class ProgressBarComponent implements LayoutableRenderableEntity
textComponent.setText(textToWrite);
textComponent.render(graphics);
+ if (leftLabel != null)
+ {
+ final TextComponent leftTextComponent = new TextComponent();
+ leftTextComponent.setPosition(new Point(barX + SIDE_LABEL_OFFSET, progressTextY));
+ leftTextComponent.setColor(fontColor);
+ leftTextComponent.setText(leftLabel);
+ leftTextComponent.render(graphics);
+ }
+
+ if (rightLabel != null)
+ {
+ final TextComponent leftTextComponent = new TextComponent();
+ leftTextComponent.setPosition(new Point(barX + width - metrics.stringWidth(rightLabel) - SIDE_LABEL_OFFSET, progressTextY));
+ leftTextComponent.setColor(fontColor);
+ leftTextComponent.setText(rightLabel);
+ leftTextComponent.render(graphics);
+ }
+
final Dimension dimension = new Dimension(width, height);
bounds.setLocation(preferredLocation);
bounds.setSize(dimension);
diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/SplitComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/SplitComponent.java
new file mode 100644
index 0000000000..75ab98f137
--- /dev/null
+++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/SplitComponent.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018, Jasper Ketelaar
+ * 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.overlay.components;
+
+import java.awt.Dimension;
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.Rectangle;
+import lombok.Builder;
+import lombok.Getter;
+import lombok.Setter;
+
+@Setter
+@Builder
+public class SplitComponent implements LayoutableRenderableEntity
+{
+ private LayoutableRenderableEntity first;
+ private LayoutableRenderableEntity second;
+
+ @Builder.Default
+ private Point preferredLocation = new Point();
+
+ @Builder.Default
+ private Dimension preferredSize = new Dimension(ComponentConstants.STANDARD_WIDTH, 0);
+
+ @Builder.Default
+ private ComponentOrientation orientation = ComponentOrientation.VERTICAL;
+
+ @Builder.Default
+ private Point gap = new Point(0, 0);
+
+ @Builder.Default
+ @Getter
+ private final Rectangle bounds = new Rectangle();
+
+ @Override
+ public Dimension render(Graphics2D graphics)
+ {
+ first.setPreferredLocation(preferredLocation);
+ first.setPreferredSize(preferredSize);
+
+ final Dimension firstDimension = first.render(graphics);
+ int x = 0, y = 0;
+
+ if (orientation == ComponentOrientation.VERTICAL)
+ {
+ y = firstDimension.height + gap.y;
+ }
+ else
+ {
+ x = firstDimension.width + gap.x;
+ }
+
+ second.setPreferredLocation(new Point(x + preferredLocation.x, y + preferredLocation.y));
+ // Make the second component fit to whatever size is left after the first component is rendered
+ second.setPreferredSize(new Dimension(preferredSize.width - x, preferredSize.height - y));
+
+ // The total width/height need to be determined as they are now always the same as the
+ // individual width/height (for example image width/height will just be the height of the image
+ // and not the height of the area the image is in
+ final Dimension secondDimension = second.render(graphics);
+ int totalWidth, totalHeight;
+
+ if (orientation == ComponentOrientation.VERTICAL)
+ {
+ totalWidth = Math.max(firstDimension.width, secondDimension.width);
+ totalHeight = y + secondDimension.height;
+ }
+ else
+ {
+ totalHeight = Math.max(firstDimension.height, secondDimension.height);
+ totalWidth = x + secondDimension.width;
+ }
+
+ final Dimension dimension = new Dimension(totalWidth, totalHeight);
+ bounds.setLocation(preferredLocation);
+ bounds.setSize(dimension);
+ return dimension;
+ }
+}
\ No newline at end of file
diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java
index 58f20aae63..08412783f1 100644
--- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java
+++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java
@@ -38,6 +38,7 @@ import net.runelite.api.Client;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayPosition;
+import net.runelite.client.ui.overlay.components.ComponentOrientation;
import net.runelite.client.ui.overlay.components.InfoBoxComponent;
import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity;
import net.runelite.client.ui.overlay.components.PanelComponent;
@@ -84,8 +85,8 @@ public class InfoBoxOverlay extends Overlay
panelComponent.getChildren().clear();
panelComponent.setWrapping(config.infoBoxWrap());
panelComponent.setOrientation(config.infoBoxVertical()
- ? PanelComponent.Orientation.VERTICAL
- : PanelComponent.Orientation.HORIZONTAL);
+ ? ComponentOrientation.VERTICAL
+ : ComponentOrientation.HORIZONTAL);
panelComponent.setPreferredSize(new Dimension(config.infoBoxSize(), config.infoBoxSize()));
for (InfoBox box : infoBoxes)