From 4076f75e342dad7f7d51c106c139b7a004fe6926 Mon Sep 17 00:00:00 2001 From: Tomas Slusny Date: Wed, 13 Dec 2017 18:26:56 -0500 Subject: [PATCH] runelite-client: Make overlay UI reuseable and look native --- .../java/net/runelite/client/RuneLite.java | 5 + .../net/runelite/client/callback/Hooks.java | 9 +- .../aoewarnings/AoeWarningOverlay.java | 5 +- .../AttackIndicatorOverlay.java | 79 +----- .../client/plugins/boosts/BoostsOverlay.java | 65 ++--- .../cluescrolls/ClueScrollOverlay.java | 55 +--- .../plugins/devtools/DevToolsOverlay.java | 5 +- .../plugins/fightcave/FightCaveOverlay.java | 5 +- .../plugins/fishing/FishingOverlay.java | 69 ++--- .../plugins/fishing/FishingSpotOverlay.java | 5 +- .../grounditems/GroundItemsOverlay.java | 4 +- .../idlenotifier/IdleNotifierPlugin.java | 7 +- .../plugins/implings/ImplingsOverlay.java | 52 ++-- .../instancemap/InstanceMapOverlay.java | 4 +- .../jewellerycount/JewelleryCountOverlay.java | 5 +- .../mousehighlight/MouseHighlightOverlay.java | 24 +- .../opponentinfo/OpponentInfoOverlay.java | 51 ++-- .../pestcontrol/PestControlOverlay.java | 13 +- .../plugins/prayflick/PrayerFlickOverlay.java | 5 +- .../plugins/runecraft/BindNeckOverlay.java | 7 +- .../plugins/runecraft/RunecraftOverlay.java | 5 +- .../plugins/runepouch/RunepouchOverlay.java | 20 +- .../client/plugins/slayer/SlayerOverlay.java | 7 +- .../plugins/specorb/SpecOrbOverlay.java | 4 +- .../volcanicmine/VolcanicMineOverlay.java | 4 +- .../woodcutting/WoodcuttingOverlay.java | 69 ++--- .../plugins/xpglobes/XpGlobesOverlay.java | 4 +- .../client/plugins/zulrah/ZulrahOverlay.java | 4 +- .../runelite/client/ui/overlay/Overlay.java | 94 +------ .../client/ui/overlay/OverlayPosition.java | 12 +- .../client/ui/overlay/OverlayPriority.java | 5 +- .../client/ui/overlay/OverlayRenderer.java | 243 +++++++++++++++--- .../client/ui/overlay/OverlayUtil.java | 29 +++ ...tipPriority.java => RenderableEntity.java} | 17 +- .../ui/overlay/TopDownRendererRight.java | 93 ------- .../components/BackgroundComponent.java | 69 +++++ .../InfoBoxComponent.java} | 80 +++--- .../ui/overlay/components/PanelComponent.java | 134 ++++++++++ .../TextComponent.java} | 53 ++-- .../overlay/components/TooltipComponent.java | 144 +++++++++++ .../ui/overlay/infobox/InfoBoxOverlay.java | 94 +++---- .../{tooltips => tooltip}/Tooltip.java | 31 +-- .../TooltipManager.java} | 28 +- .../ui/overlay/tooltip/TooltipOverlay.java | 87 +++++++ .../ui/overlay/tooltips/TooltipRenderer.java | 181 ------------- 45 files changed, 1036 insertions(+), 949 deletions(-) rename runelite-client/src/main/java/net/runelite/client/ui/overlay/{tooltips/TooltipPriority.java => RenderableEntity.java} (81%) delete mode 100644 runelite-client/src/main/java/net/runelite/client/ui/overlay/TopDownRendererRight.java create mode 100644 runelite-client/src/main/java/net/runelite/client/ui/overlay/components/BackgroundComponent.java rename runelite-client/src/main/java/net/runelite/client/ui/overlay/{TopDownRendererLeft.java => components/InfoBoxComponent.java} (52%) create mode 100644 runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java rename runelite-client/src/main/java/net/runelite/client/ui/overlay/{DynamicRenderer.java => components/TextComponent.java} (61%) create mode 100644 runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java rename runelite-client/src/main/java/net/runelite/client/ui/overlay/{tooltips => tooltip}/Tooltip.java (76%) rename runelite-client/src/main/java/net/runelite/client/ui/overlay/{Renderer.java => tooltip/TooltipManager.java} (74%) create mode 100644 runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java delete mode 100644 runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltips/TooltipRenderer.java diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java index 8386bcd770..9db3d54cec 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -65,6 +65,7 @@ import net.runelite.client.events.SessionOpen; import net.runelite.client.menus.MenuManager; import net.runelite.client.plugins.PluginManager; import net.runelite.client.ui.ClientUI; +import net.runelite.client.ui.overlay.OverlayRenderer; import net.runelite.http.api.account.AccountClient; import org.pushingpixels.substance.api.skin.SubstanceGraphiteLookAndFeel; @@ -108,6 +109,9 @@ public class RuneLite @Inject private ScheduledExecutorService executor; + @Inject + private OverlayRenderer overlayRenderer; + private WSClient wsclient; private AccountSession accountSession; @@ -169,6 +173,7 @@ public class RuneLite configManager.load(); + eventBus.register(overlayRenderer); eventBus.register(menuManager); eventBus.register(chatMessageManager); diff --git a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java index 7476e7346c..a455f04066 100644 --- a/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java +++ b/runelite-client/src/main/java/net/runelite/client/callback/Hooks.java @@ -27,6 +27,7 @@ package net.runelite.client.callback; import com.google.common.eventbus.EventBus; import com.google.inject.Injector; import java.awt.Graphics; +import java.awt.Graphics2D; import java.awt.image.BufferedImage; import lombok.extern.slf4j.Slf4j; import net.runelite.api.Actor; @@ -58,6 +59,7 @@ public class Hooks private static final Scheduler scheduler = injector.getInstance(Scheduler.class); private static final InfoBoxManager infoBoxManager = injector.getInstance(InfoBoxManager.class); private static final ChatMessageManager chatMessageManager = injector.getInstance(ChatMessageManager.class); + private static final OverlayRenderer renderer = injector.getInstance(OverlayRenderer.class); private static final DeathChecker death = new DeathChecker(client, eventBus); private static final GameTick tick = new GameTick(); @@ -94,13 +96,12 @@ public class Hooks public static void draw(MainBufferProvider mainBufferProvider, Graphics graphics, int x, int y) { - BufferedImage image = (BufferedImage) mainBufferProvider.getImage(); - - OverlayRenderer renderer = injector.getInstance(OverlayRenderer.class); + final BufferedImage image = (BufferedImage) mainBufferProvider.getImage(); + final Graphics2D graphics2d = (Graphics2D) image.getGraphics(); try { - renderer.render(image); + renderer.render(graphics2d); } catch (Exception ex) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningOverlay.java index 544b2613d6..254a272966 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/aoewarnings/AoeWarningOverlay.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.aoewarnings; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.Polygon; import java.time.Instant; import java.util.Iterator; @@ -51,14 +52,14 @@ public class AoeWarningOverlay extends Overlay @Inject public AoeWarningOverlay(@Nullable Client client, AoeWarningPlugin plugin, AoeWarningConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.client = client; this.plugin = plugin; this.config = config; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { if (!config.enabled()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/attackindicator/AttackIndicatorOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/attackindicator/AttackIndicatorOverlay.java index e063ba99e1..134cd45907 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/attackindicator/AttackIndicatorOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/attackindicator/AttackIndicatorOverlay.java @@ -24,102 +24,39 @@ */ package net.runelite.client.plugins.attackindicator; -import java.awt.Color; import java.awt.Dimension; -import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Point; -import java.awt.Rectangle; -import javax.annotation.Nullable; import javax.inject.Inject; -import net.runelite.api.Client; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.ui.FontManager; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.components.PanelComponent; public class AttackIndicatorOverlay extends Overlay { - private static final int ANCHOR_X = -4; - private static final int ANCHOR_Y = -1; - private static final int BORDER_SIZE = 2; - private static final Color BACKGROUND_COLOR = new Color(56, 48, 35, 100); - private static final Color OUTSIDE_STROKE_COLOR = new Color(56, 48, 35, 255); - private static final Color INSIDE_STROKE_COLOR = new Color(90, 82, 69, 255); - - @Inject - @Nullable - Client client; - private final AttackIndicatorConfig config; private final AttackIndicatorPlugin plugin; + private final PanelComponent panelComponent = new PanelComponent(); @Inject public AttackIndicatorOverlay(AttackIndicatorPlugin plugin, AttackIndicatorConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.BOTTOM_RIGHT); this.plugin = plugin; this.config = config; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { if (!config.enabled()) { return null; } - Rectangle chatbox = getChatboxBounds(); - if (chatbox == null) - { - return null; - } - - // Setup string - graphics.setFont(FontManager.getRunescapeFont()); - FontMetrics fm = graphics.getFontMetrics(); - String attackStyleString = plugin.getAttackStyle().getName(); - - // Create anchor point - Point anchor = new Point(chatbox.x + chatbox.width + ANCHOR_X, chatbox.y + ANCHOR_Y); - - // Calculate size of background - Rectangle background = fm.getStringBounds(attackStyleString, graphics).getBounds(); - background.setBounds(background.x, background.y, background.width + BORDER_SIZE, background.height + BORDER_SIZE); - - // Render background - graphics.setColor(BACKGROUND_COLOR); - graphics.fillRect(anchor.x - background.width, anchor.y - background.height, background.width, background.height); - - // Render outside stroke - graphics.setColor(OUTSIDE_STROKE_COLOR); - graphics.drawRect(anchor.x - background.width, anchor.y - background.height, background.width + BORDER_SIZE / 2, background.height + BORDER_SIZE / 2); - - // Render inside stroke - graphics.setColor(INSIDE_STROKE_COLOR); - graphics.drawRect(anchor.x - background.width + BORDER_SIZE / 2, anchor.y - background.height + BORDER_SIZE / 2, background.width - BORDER_SIZE / 2, background.height - BORDER_SIZE / 2); - - // Render text with shadow - graphics.setColor(Color.BLACK); - graphics.drawString(attackStyleString, anchor.x - background.width + 3, anchor.y); - if (plugin.isWarnedSkillSelected()) - { - graphics.setColor(Color.RED); - } - else - { - graphics.setColor(Color.WHITE); - } - graphics.drawString(attackStyleString, anchor.x - background.width + 2, anchor.y - 1); - - return null; - } - - private Rectangle getChatboxBounds() - { - Widget chatbox = client.getWidget(WidgetInfo.CHATBOX); - return chatbox != null ? chatbox.getBounds() : null; + final String attackStyleString = plugin.getAttackStyle().getName(); + panelComponent.setTitle(attackStyleString); + panelComponent.setWidth(80); + return panelComponent.render(graphics, parent); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java index fc0e5e275a..8f7ae1a037 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/boosts/BoostsOverlay.java @@ -27,8 +27,8 @@ package net.runelite.client.plugins.boosts; import com.google.common.collect.ObjectArrays; import java.awt.Color; import java.awt.Dimension; -import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import javax.annotation.Nullable; import javax.inject.Inject; import net.runelite.api.Client; @@ -36,13 +36,10 @@ import net.runelite.api.Skill; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.PanelComponent; class BoostsOverlay extends Overlay { - private static final int WIDTH = 140; - - private static final Color BACKGROUND = new Color(Color.gray.getRed(), Color.gray.getGreen(), Color.gray.getBlue(), 127); - private static final Skill[] COMBAT = new Skill[] { Skill.ATTACK, Skill.STRENGTH, Skill.DEFENCE, Skill.RANGED, Skill.MAGIC @@ -54,26 +51,21 @@ class BoostsOverlay extends Overlay Skill.HUNTER, Skill.CONSTRUCTION }; - private static final int TOP_BORDER = 2; - private static final int BOTTOM_BORDER = 2; - private static final int LEFT_BORDER = 2; - private static final int RIGHT_BORDER = 2; - - private static final int SEPARATOR = 2; - private final Client client; private final BoostsConfig config; + private PanelComponent panelComponent; @Inject BoostsOverlay(@Nullable Client client, BoostsConfig config) { - super(OverlayPosition.TOP_LEFT, OverlayPriority.MED); + setPosition(OverlayPosition.TOP_LEFT); + setPriority(OverlayPriority.MED); this.client = client; this.config = config; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { if (!config.enabled()) { @@ -90,9 +82,8 @@ class BoostsOverlay extends Overlay show = COMBAT; } - FontMetrics metrics = graphics.getFontMetrics(); + panelComponent = new PanelComponent(); - int height = TOP_BORDER; for (Skill skill : show) { int boosted = client.getBoostedSkillLevel(skill), @@ -103,34 +94,9 @@ class BoostsOverlay extends Overlay continue; } - height += metrics.getHeight() + SEPARATOR; - } - - if (height == TOP_BORDER) - { - return null; - } - - height += BOTTOM_BORDER; - - graphics.setColor(BACKGROUND); - graphics.fillRect(0, 0, WIDTH, height); - - int y = TOP_BORDER; - for (Skill skill : show) - { - int boosted = client.getBoostedSkillLevel(skill), - base = client.getRealSkillLevel(skill); - - if (boosted == base) - { - continue; - } - - graphics.setColor(Color.white); - graphics.drawString(skill.getName(), LEFT_BORDER, y + metrics.getHeight()); String str; + Color strColor = Color.WHITE; if (!config.useRelativeBoost()) { str = boosted + "/" + base; @@ -142,18 +108,23 @@ class BoostsOverlay extends Overlay if (boost > 0) { str = "+" + str; - graphics.setColor(Color.GREEN.darker()); + strColor = Color.GREEN.darker(); } else { - graphics.setColor(Color.RED.darker()); + strColor = Color.RED.darker(); } } - graphics.drawString(str, WIDTH - RIGHT_BORDER - metrics.stringWidth(str), y + metrics.getHeight()); - y += metrics.getHeight() + SEPARATOR; + + panelComponent.getLines().add(new PanelComponent.Line( + skill.getName(), + Color.WHITE, + str, + strColor + )); } - return new Dimension(WIDTH, height); + return panelComponent.render(graphics, parent); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollOverlay.java index 2b79b54141..c3e51e7e56 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollOverlay.java @@ -26,10 +26,9 @@ */ package net.runelite.client.plugins.cluescrolls; -import java.awt.Color; import java.awt.Dimension; -import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import java.time.Duration; import java.time.Instant; import javax.annotation.Nullable; @@ -38,22 +37,15 @@ import net.runelite.api.Client; import net.runelite.api.ItemComposition; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.PanelComponent; public class ClueScrollOverlay extends Overlay { - private static final Color BACKGROUND = new Color(Color.gray.getRed(), Color.gray.getGreen(), Color.gray.getBlue(), 127); - - private static final int WIDTH = 140; - - private static final int TOP_BORDER = 2; - private static final int BOTTOM_BORDER = 2; - private static final int SEPERATOR = 2; - private static final Duration WAIT_DURATION = Duration.ofMinutes(4); private final Client client; private final ClueScrollConfig config; + private final PanelComponent panelComponent = new PanelComponent(); ClueScroll clue; Instant clueTimeout; @@ -61,13 +53,13 @@ public class ClueScrollOverlay extends Overlay @Inject public ClueScrollOverlay(@Nullable Client client, ClueScrollConfig config) { - super(OverlayPosition.TOP_LEFT, OverlayPriority.LOW); + setPosition(OverlayPosition.TOP_LEFT); this.client = client; this.config = config; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { if (!config.enabled()) { @@ -84,31 +76,12 @@ public class ClueScrollOverlay extends Overlay return null; } - FontMetrics fm = graphics.getFontMetrics(); - - int height = TOP_BORDER + fm.getHeight() + SEPERATOR + (clue.getIds().length * (fm.getHeight() + SEPERATOR)) + BOTTOM_BORDER; - - graphics.setColor(BACKGROUND); - graphics.fillRect(0, 0, WIDTH, height); - - int y = TOP_BORDER + fm.getHeight(); - - String reqHeader = "Required Items"; - graphics.setColor(Color.BLACK); - graphics.drawString(reqHeader, ((WIDTH - fm.stringWidth(reqHeader)) / 2) + 1, y + 1); - - graphics.setColor(Color.WHITE); - graphics.drawString(reqHeader, ((WIDTH - fm.stringWidth(reqHeader)) / 2), y); - - y += fm.getHeight() + SEPERATOR; + panelComponent.getLines().clear(); + panelComponent.setTitle("Required items"); if (clue.getIds().length == 0) { - graphics.setColor(Color.BLACK); - graphics.drawString("None", ((WIDTH - fm.stringWidth("None")) / 2) + 1, y + 1); - - graphics.setColor(Color.WHITE); - graphics.drawString("None", ((WIDTH - fm.stringWidth("None")) / 2), y); + panelComponent.getLines().add(new PanelComponent.Line("None", "")); } else { @@ -121,18 +94,10 @@ public class ClueScrollOverlay extends Overlay continue; } - String itemName = clueItem.getName(); - graphics.setColor(Color.BLACK); - graphics.drawString(itemName, ((WIDTH - fm.stringWidth(itemName)) / 2) + 1, y + 1); - - graphics.setColor(Color.WHITE); - graphics.drawString(itemName, ((WIDTH - fm.stringWidth(itemName)) / 2), y); - - //might eventually add a inventory/equipment check or item images here? - y += fm.getHeight() + SEPERATOR; + panelComponent.getLines().add(new PanelComponent.Line(clueItem.getName(), "")); } } - return new Dimension(WIDTH, height); + return panelComponent.render(graphics, parent); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java index b4d62a25b5..5702ed1d1c 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java @@ -30,6 +30,7 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.Polygon; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; @@ -79,13 +80,13 @@ public class DevToolsOverlay extends Overlay @Inject public DevToolsOverlay(@Nullable Client client, DevToolsPlugin plugin) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.client = client; this.plugin = plugin; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { Font font = plugin.getFont(); if (font != null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveOverlay.java index d6c8f1076e..8b5c02137a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fightcave/FightCaveOverlay.java @@ -29,6 +29,7 @@ import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Image; +import java.awt.Point; import java.awt.Rectangle; import java.io.IOException; import java.io.InputStream; @@ -59,13 +60,13 @@ public class FightCaveOverlay extends Overlay @Inject FightCaveOverlay(@Nullable Client client, FightCavePlugin plugin) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.client = client; this.plugin = plugin; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { JadAttack attack = plugin.getAttack(); Rectangle viewport = getViewportBounds(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingOverlay.java index 72ec2e4f51..a19ef78c00 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingOverlay.java @@ -26,8 +26,8 @@ package net.runelite.client.plugins.fishing; import java.awt.Color; import java.awt.Dimension; -import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import java.time.Duration; import java.time.Instant; import javax.annotation.Nullable; @@ -35,36 +35,28 @@ import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.PanelComponent; class FishingOverlay extends Overlay { - private static final int WIDTH = 140; - - private static final int TOP_BORDER = 2; - private static final int LEFT_BORDER = 2; - private static final int RIGHT_BORDER = 2; - private static final int BOTTOM_BORDER = 2; - private static final int SEPARATOR = 2; - - private static final Color BACKGROUND = new Color(Color.gray.getRed(), Color.gray.getGreen(), Color.gray.getBlue(), 127); private static final String FISHING_SPOT = "Fishing spot"; private final Client client; private final FishingPlugin plugin; private final FishingConfig config; + private final PanelComponent panelComponent = new PanelComponent(); @Inject public FishingOverlay(@Nullable Client client, FishingPlugin plugin, FishingConfig config) { - super(OverlayPosition.TOP_LEFT, OverlayPriority.LOW); + setPosition(OverlayPosition.TOP_LEFT); this.client = client; this.plugin = plugin; this.config = config; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { if (!config.enabled()) { @@ -86,50 +78,31 @@ class FishingOverlay extends Overlay return null; } - FontMetrics metrics = graphics.getFontMetrics(); - - int height = TOP_BORDER + (metrics.getHeight() * 3) + SEPARATOR * 3 + BOTTOM_BORDER; - int y = TOP_BORDER + metrics.getHeight(); - - graphics.setColor(BACKGROUND); - graphics.fillRect(0, 0, WIDTH, height); - + panelComponent.getLines().clear(); if (client.getLocalPlayer().getInteracting() != null && client.getLocalPlayer().getInteracting().getName().equals(FISHING_SPOT)) { - graphics.setColor(Color.green); - String str = "You are fishing"; - graphics.drawString(str, (WIDTH - metrics.stringWidth(str)) / 2, y); + panelComponent.setTitle("You are fishing"); + panelComponent.setTitleColor(Color.GREEN); } else { - graphics.setColor(Color.red); - String str = "You are NOT fishing"; - graphics.drawString(str, (WIDTH - metrics.stringWidth(str)) / 2, y); + panelComponent.setTitle("You are NOT fishing"); + panelComponent.setTitleColor(Color.RED); } - y += metrics.getHeight() + SEPARATOR; + panelComponent.getLines().add(new PanelComponent.Line( + "Caught fish:", + Integer.toString(session.getTotalFished()) + )); - graphics.setColor(Color.white); - graphics.drawString("Caught Fish:", LEFT_BORDER, y); - String totalFishedStr = Integer.toString(session.getTotalFished()); - graphics.drawString(totalFishedStr, WIDTH - RIGHT_BORDER - metrics.stringWidth(totalFishedStr), y); + panelComponent.getLines().add(new PanelComponent.Line( + "Fish/hr:", + session.getRecentFished() > 2 + ? Integer.toString(session.getPerHour()) + : "" + )); - y += metrics.getHeight() + SEPARATOR; - - graphics.drawString("Fish/hr:", LEFT_BORDER, y); - - String perHourStr; - if (session.getRecentFished() > 2) - { - perHourStr = Integer.toString(session.getPerHour()); - } - else - { - perHourStr = "~"; - } - graphics.drawString(perHourStr, WIDTH - RIGHT_BORDER - metrics.stringWidth(perHourStr), y); - - return new Dimension(WIDTH, height); + return panelComponent.render(graphics, parent); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java index 6001bad77e..14009ba3b5 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/fishing/FishingSpotOverlay.java @@ -28,6 +28,7 @@ import com.google.common.primitives.Ints; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; @@ -56,14 +57,14 @@ class FishingSpotOverlay extends Overlay @Inject public FishingSpotOverlay(RuneLite runelite, @Nullable Client client, FishingConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.runelite = runelite; this.client = client; this.config = config; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { if (!config.enabled()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java index d1cee9248e..effdab1c0d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java @@ -91,13 +91,13 @@ public class GroundItemsOverlay extends Overlay @Inject public GroundItemsOverlay(@Nullable Client client, GroundItemsConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.client = client; this.config = config; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, java.awt.Point parent) { Widget viewport = client.getViewportWidget(); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java index a7f57a4725..3c21d19536 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/idlenotifier/IdleNotifierPlugin.java @@ -86,7 +86,7 @@ public class IdleNotifierPlugin extends Plugin { return; } - + Player localPlayer = client.getLocalPlayer(); if (localPlayer != event.getActor()) { @@ -181,13 +181,14 @@ public class IdleNotifierPlugin extends Plugin ) public void checkIdle() { - if (!config.isEnabled() || client.getGameState() != GameState.LOGGED_IN) + Player local = client.getLocalPlayer(); + + if (!config.isEnabled() || client.getGameState() != GameState.LOGGED_IN || local == null) { return; } Duration waitDuration = Duration.ofMillis(config.getTimeout()); - Player local = client.getLocalPlayer(); if (notifyIdle && local.getAnimation() == IDLE && Instant.now().compareTo(lastAnimating.plus(waitDuration)) >= 0) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsOverlay.java index 89dc0beff3..7135b1a8da 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/implings/ImplingsOverlay.java @@ -1,26 +1,26 @@ -/* - * Copyright (c) 2017, Robin - * 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. +/* + * Copyright (c) 2017, Robin + * 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.implings; @@ -51,7 +51,7 @@ import net.runelite.client.ui.overlay.OverlayPosition; public class ImplingsOverlay extends Overlay { - // Impling spawns in PuroPuro. Not in NpcID. + // Impling spawns in PuroPuro. Not in NpcID. private static final int STATIC_SPAWN = 1618; private static final int DYNAMIC_SPAWN = 1633; @@ -63,14 +63,14 @@ public class ImplingsOverlay extends Overlay @Inject public ImplingsOverlay(RuneLite runelite, @Nullable Client client, ImplingsConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.runelite = runelite; this.client = client; this.config = config; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, java.awt.Point parent) { NPCQuery implingQuery = new NPCQuery().idEquals(Ints.toArray(ids)); NPC[] implings = runelite.runQuery(implingQuery); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java index c9cdf3a4dd..a9abcaada7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/instancemap/InstanceMapOverlay.java @@ -113,7 +113,7 @@ class InstanceMapOverlay extends Overlay @Inject InstanceMapOverlay(@Nullable Client client, InstanceMapConfig config, InstanceMapPlugin plugin) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.client = client; this.config = config; this.plugin = plugin; @@ -169,7 +169,7 @@ class InstanceMapOverlay extends Overlay } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, java.awt.Point parent) { if (!config.enabled() || !showMap) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/jewellerycount/JewelleryCountOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/jewellerycount/JewelleryCountOverlay.java index 183155b087..150877d203 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/jewellerycount/JewelleryCountOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/jewellerycount/JewelleryCountOverlay.java @@ -29,6 +29,7 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.Rectangle; import java.util.ArrayList; import java.util.Arrays; @@ -55,7 +56,7 @@ class JewelleryCountOverlay extends Overlay @Inject JewelleryCountOverlay(RuneLite runelite, JewelleryCountConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.runelite = runelite; this.client = runelite.getClient(); this.config = config; @@ -63,7 +64,7 @@ class JewelleryCountOverlay extends Overlay } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { if (!config.enabled()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java index 657e839e55..6a16e0fd2d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/mousehighlight/MouseHighlightOverlay.java @@ -26,37 +26,34 @@ package net.runelite.client.plugins.mousehighlight; import java.awt.Dimension; import java.awt.Graphics2D; +import java.awt.Point; import javax.annotation.Nullable; import javax.inject.Inject; import net.runelite.api.Client; import net.runelite.api.MenuEntry; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayRenderer; -import net.runelite.client.ui.overlay.tooltips.Tooltip; -import net.runelite.client.ui.overlay.tooltips.TooltipPriority; -import net.runelite.client.ui.overlay.tooltips.TooltipRenderer; +import net.runelite.client.ui.overlay.tooltip.Tooltip; +import net.runelite.client.ui.overlay.tooltip.TooltipManager; class MouseHighlightOverlay extends Overlay { - // Grabs the colour and name from a target string - // Player1 private final MouseHighlightConfig config; + private final TooltipManager tooltipManager; private final Client client; - private final TooltipRenderer tooltipRenderer; @Inject - MouseHighlightOverlay(@Nullable Client client, MouseHighlightConfig config, OverlayRenderer overlayRenderer) + MouseHighlightOverlay(@Nullable Client client, MouseHighlightConfig config, TooltipManager tooltipManager) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.client = client; this.config = config; - this.tooltipRenderer = overlayRenderer.getTooltipRenderer(); + this.tooltipManager = tooltipManager; this.setDrawOverBankScreen(true); } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point point) { if (!config.enabled()) { @@ -94,10 +91,7 @@ class MouseHighlightOverlay extends Overlay return null; } - Tooltip tooltip = new Tooltip(TooltipPriority.LOW, - option + " " + target); - tooltipRenderer.add(tooltip); - + tooltipManager.add(new Tooltip(option + " " + target)); return null; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java index 76d759c53b..0543bf0c05 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/opponentinfo/OpponentInfoOverlay.java @@ -28,18 +28,22 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics2D; -import net.runelite.api.Actor; -import net.runelite.api.Client; -import net.runelite.api.Player; -import net.runelite.client.ui.overlay.Overlay; -import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; +import java.awt.Point; +import java.awt.Rectangle; import java.text.DecimalFormat; import java.time.Duration; import java.time.Instant; import java.util.Map; import javax.annotation.Nullable; import javax.inject.Inject; +import net.runelite.api.Actor; +import net.runelite.api.Client; +import net.runelite.api.Player; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.BackgroundComponent; +import net.runelite.client.ui.overlay.components.TextComponent; class OpponentInfoOverlay extends Overlay { @@ -49,12 +53,10 @@ class OpponentInfoOverlay extends Overlay private static final int BOTTOM_BORDER = 2; private static final int BAR_WIDTH = 124; - private static final int BAR_HEIGHT = 20; + private static final int BAR_HEIGHT = 16; - private static final Color BACKGROUND = new Color(Color.gray.getRed(), Color.gray.getGreen(), Color.gray.getBlue(), 127); private static final Color HP_GREEN = new Color(0, 146, 54, 230); private static final Color HP_RED = new Color(102, 15, 16, 230); - private static final Duration WAIT = Duration.ofSeconds(3); private final Client client; @@ -69,7 +71,8 @@ class OpponentInfoOverlay extends Overlay @Inject OpponentInfoOverlay(@Nullable Client client, OpponentConfig config) { - super(OverlayPosition.TOP_LEFT, OverlayPriority.HIGH); + setPosition(OverlayPosition.TOP_LEFT); + setPriority(OverlayPriority.HIGH); this.client = client; this.config = config; } @@ -86,9 +89,9 @@ class OpponentInfoOverlay extends Overlay } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { - if (config.enabled() == false) + if (!config.enabled()) { return null; } @@ -107,27 +110,32 @@ class OpponentInfoOverlay extends Overlay { return null; //don't draw anything. } + FontMetrics fm = graphics.getFontMetrics(); int height = TOP_BORDER + fm.getHeight(); // opponent name if (lastRatio >= 0) { - height += 2 // between name and hp bar + height += 12 // between name and hp bar + BAR_HEIGHT; // bar } + height += BOTTOM_BORDER; - graphics.setColor(BACKGROUND); - graphics.fillRect(0, 0, WIDTH, height); + final BackgroundComponent backgroundComponent = new BackgroundComponent(); + backgroundComponent.setRectangle(new Rectangle(0, 0, WIDTH, height)); + backgroundComponent.render(graphics, parent); int x = (WIDTH - fm.stringWidth(opponentName)) / 2; - graphics.setColor(Color.white); - graphics.drawString(opponentName, x, fm.getHeight() + TOP_BORDER); + final TextComponent textComponent = new TextComponent(); + textComponent.setPosition(new Point(x, fm.getHeight() + TOP_BORDER)); + textComponent.setText(opponentName); + textComponent.render(graphics, parent); if (lastRatio >= 0) { int barWidth = (int) (lastRatio * (float) BAR_WIDTH); - int barY = TOP_BORDER + fm.getHeight() + 1; + int barY = TOP_BORDER + fm.getHeight() + 6; graphics.setColor(HP_GREEN); graphics.fillRect((WIDTH - BAR_WIDTH) / 2, barY, barWidth, BAR_HEIGHT); @@ -135,8 +143,6 @@ class OpponentInfoOverlay extends Overlay graphics.setColor(HP_RED); graphics.fillRect(((WIDTH - BAR_WIDTH) / 2) + barWidth, barY, BAR_WIDTH - barWidth, BAR_HEIGHT); - graphics.setColor(Color.white); - String str; if (lastMaxHealth != null) @@ -149,7 +155,10 @@ class OpponentInfoOverlay extends Overlay str = df.format(lastRatio * 100) + "%"; } - graphics.drawString(str, (WIDTH - fm.stringWidth(str)) / 2, barY + fm.getHeight()); + final TextComponent textComponent1 = new TextComponent(); + textComponent1.setText(str); + textComponent1.setPosition(new Point((WIDTH - fm.stringWidth(str)) / 2, barY + fm.getHeight())); + textComponent1.render(graphics, parent); } return new Dimension(WIDTH, height); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PestControlOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PestControlOverlay.java index 41e9d4a05f..956d001c37 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PestControlOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/pestcontrol/PestControlOverlay.java @@ -25,11 +25,16 @@ */ package net.runelite.client.plugins.pestcontrol; +import static net.runelite.client.plugins.pestcontrol.Portal.BLUE; +import static net.runelite.client.plugins.pestcontrol.Portal.PURPLE; +import static net.runelite.client.plugins.pestcontrol.Portal.RED; +import static net.runelite.client.plugins.pestcontrol.Portal.YELLOW; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.geom.Rectangle2D; import java.util.Arrays; import javax.inject.Inject; @@ -41,10 +46,6 @@ import net.runelite.api.queries.NPCQuery; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; import net.runelite.client.RuneLite; -import static net.runelite.client.plugins.pestcontrol.Portal.BLUE; -import static net.runelite.client.plugins.pestcontrol.Portal.PURPLE; -import static net.runelite.client.plugins.pestcontrol.Portal.RED; -import static net.runelite.client.plugins.pestcontrol.Portal.YELLOW; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayUtil; @@ -63,14 +64,14 @@ public class PestControlOverlay extends Overlay @Inject public PestControlOverlay(RuneLite runelite, PestControlPlugin plugin) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.runelite = runelite; this.client = runelite.getClient(); this.plugin = plugin; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point point) { // See if we are in a game or not if (client.getWidget(WidgetInfo.PESTCONTROL_BLUE_SHIELD) == null) diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayflick/PrayerFlickOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayflick/PrayerFlickOverlay.java index e2a40c8ba5..b7705be87a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/prayflick/PrayerFlickOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayflick/PrayerFlickOverlay.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.prayflick; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.geom.Rectangle2D; import java.time.Duration; import java.time.Instant; @@ -49,7 +50,7 @@ public class PrayerFlickOverlay extends Overlay @Inject public PrayerFlickOverlay(@Nullable Client client, PrayerFlickConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.client = client; this.config = config; } @@ -61,7 +62,7 @@ public class PrayerFlickOverlay extends Overlay } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point point) { if (!config.enabled() || !prayersActive)//If there are no prayers active we don't need to be flicking { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/BindNeckOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/BindNeckOverlay.java index 8d502677b0..656346421f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/BindNeckOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/BindNeckOverlay.java @@ -25,18 +25,19 @@ */ package net.runelite.client.plugins.runecraft; +import static net.runelite.api.ItemID.BINDING_NECKLACE; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.Rectangle; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import javax.inject.Inject; import net.runelite.api.Client; -import static net.runelite.api.ItemID.BINDING_NECKLACE; import net.runelite.api.Query; import net.runelite.api.queries.EquipmentItemQuery; import net.runelite.api.queries.InventoryItemQuery; @@ -58,7 +59,7 @@ public class BindNeckOverlay extends Overlay @Inject BindNeckOverlay(RuneLite runelite, RunecraftConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.runelite = runelite; this.client = runelite.getClient(); this.config = config; @@ -66,7 +67,7 @@ public class BindNeckOverlay extends Overlay } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { if (!config.showBindNeck()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftOverlay.java index f571a7836f..02bac9d917 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runecraft/RunecraftOverlay.java @@ -29,6 +29,7 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.Rectangle; import javax.inject.Inject; import net.runelite.api.Client; @@ -57,7 +58,7 @@ public class RunecraftOverlay extends Overlay @Inject RunecraftOverlay(RuneLite runelite, RunecraftConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.runelite = runelite; this.client = runelite.getClient(); this.config = config; @@ -65,7 +66,7 @@ public class RunecraftOverlay extends Overlay } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { if (!config.showPouch()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java index e8558a093c..39258cc50a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/runepouch/RunepouchOverlay.java @@ -40,11 +40,9 @@ import net.runelite.client.RuneLite; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayRenderer; import net.runelite.client.ui.overlay.OverlayUtil; -import net.runelite.client.ui.overlay.tooltips.Tooltip; -import net.runelite.client.ui.overlay.tooltips.TooltipPriority; -import net.runelite.client.ui.overlay.tooltips.TooltipRenderer; +import net.runelite.client.ui.overlay.tooltip.Tooltip; +import net.runelite.client.ui.overlay.tooltip.TooltipManager; public class RunepouchOverlay extends Overlay { @@ -62,21 +60,21 @@ public class RunepouchOverlay extends Overlay private final RuneLite runelite; private final Client client; private final RunepouchConfig config; - private final TooltipRenderer tooltipRenderer; + private final TooltipManager tooltipManager; @Inject - RunepouchOverlay(RuneLite runelite, RunepouchConfig config, OverlayRenderer overlayRenderer) + RunepouchOverlay(RuneLite runelite, RunepouchConfig config, TooltipManager tooltipManager) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); + this.tooltipManager = tooltipManager; this.runelite = runelite; this.client = runelite.getClient(); this.config = config; - this.tooltipRenderer = overlayRenderer.getTooltipRenderer(); this.setDrawOverBankScreen(true); } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, java.awt.Point point) { if (!config.enabled()) { @@ -145,9 +143,7 @@ public class RunepouchOverlay extends Overlay if (runePouch.getCanvasBounds().contains(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY())) { - String tooltipText = tooltipBuilder.toString(); - Tooltip tooltip = new Tooltip(TooltipPriority.HIGH, tooltipText); - tooltipRenderer.add(tooltip); + tooltipManager.add(new Tooltip(tooltipBuilder.toString())); } return null; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java index d11a31b326..bb90235bf9 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/slayer/SlayerOverlay.java @@ -24,14 +24,15 @@ */ package net.runelite.client.plugins.slayer; -import com.google.common.collect.ImmutableList; import static com.google.common.collect.ObjectArrays.concat; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.Rectangle; import java.util.Collection; import java.util.Set; @@ -86,7 +87,7 @@ class SlayerOverlay extends Overlay @Inject SlayerOverlay(RuneLite runelite, SlayerPlugin plugin, SlayerConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.runelite = runelite; this.client = runelite.getClient(); this.plugin = plugin; @@ -94,7 +95,7 @@ class SlayerOverlay extends Overlay } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { if (!config.enabled()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/specorb/SpecOrbOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/specorb/SpecOrbOverlay.java index 521bcff10d..6c5c107f8f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/specorb/SpecOrbOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/specorb/SpecOrbOverlay.java @@ -58,14 +58,14 @@ public class SpecOrbOverlay extends Overlay @Inject public SpecOrbOverlay(@Nullable Client client, SpecOrbConfig config, SpecOrbPlugin plugin) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.client = client; this.config = config; this.plugin = plugin; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, java.awt.Point point) { if (!config.enabled()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/volcanicmine/VolcanicMineOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/volcanicmine/VolcanicMineOverlay.java index 0d98e5ef02..e326466c0a 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/volcanicmine/VolcanicMineOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/volcanicmine/VolcanicMineOverlay.java @@ -72,14 +72,14 @@ public class VolcanicMineOverlay extends Overlay @Inject VolcanicMineOverlay(@Nullable Client client, VolcanicMinePlugin plugin, VolcanicMineConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.client = client; this.plugin = plugin; this.config = config; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, java.awt.Point point) { if (client == null || !plugin.getInside() || !config.enabled()) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java index db2903d47c..35fc920296 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/woodcutting/WoodcuttingOverlay.java @@ -26,8 +26,8 @@ package net.runelite.client.plugins.woodcutting; import java.awt.Color; import java.awt.Dimension; -import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import java.time.Duration; import java.time.Instant; import java.util.stream.IntStream; @@ -37,20 +37,10 @@ import static net.runelite.api.AnimationID.*; import net.runelite.api.Client; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.PanelComponent; class WoodcuttingOverlay extends Overlay { - private static final int WIDTH = 140; - - private static final int TOP_BORDER = 2; - private static final int LEFT_BORDER = 2; - private static final int RIGHT_BORDER = 2; - private static final int BOTTOM_BORDER = 2; - private static final int SEPARATOR = 2; - - private static final Color BACKGROUND = new Color(Color.gray.getRed(), Color.gray.getGreen(), Color.gray.getBlue(), 127); - private static final int[] animationIds = { WOODCUTTING_BRONZE, WOODCUTTING_IRON, WOODCUTTING_STEEL, WOODCUTTING_BLACK, @@ -61,18 +51,19 @@ class WoodcuttingOverlay extends Overlay private final Client client; private final WoodcuttingPlugin plugin; private final WoodcuttingConfig config; + private final PanelComponent panelComponent = new PanelComponent(); @Inject public WoodcuttingOverlay(@Nullable Client client, WoodcuttingPlugin plugin, WoodcuttingConfig config) { - super(OverlayPosition.TOP_LEFT, OverlayPriority.LOW); + setPosition(OverlayPosition.TOP_LEFT); this.client = client; this.plugin = plugin; this.config = config; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { if (!config.enabled()) { @@ -94,50 +85,32 @@ class WoodcuttingOverlay extends Overlay return null; } - FontMetrics metrics = graphics.getFontMetrics(); - - int height = TOP_BORDER + (metrics.getHeight() * 3) + SEPARATOR * 3 + BOTTOM_BORDER; - int y = TOP_BORDER + metrics.getHeight(); - - graphics.setColor(BACKGROUND); - graphics.fillRect(0, 0, WIDTH, height); + panelComponent.getLines().clear(); if (IntStream.of(animationIds).anyMatch(x -> x == client.getLocalPlayer().getAnimation())) { - graphics.setColor(Color.green); - String str = "You are woodcutting"; - graphics.drawString(str, (WIDTH - metrics.stringWidth(str)) / 2, y); + panelComponent.setTitle("You are woodcutting"); + panelComponent.setTitleColor(Color.GREEN); } else { - graphics.setColor(Color.red); - String str = "You are NOT woodcutting"; - graphics.drawString(str, (WIDTH - metrics.stringWidth(str)) / 2, y); + panelComponent.setTitle("You are NOT woodcutting"); + panelComponent.setTitleColor(Color.RED); } - y += metrics.getHeight() + SEPARATOR; + panelComponent.getLines().add(new PanelComponent.Line( + "Logs cut:", + Integer.toString(session.getTotalCut()) + )); - graphics.setColor(Color.white); - graphics.drawString("Logs cut:", LEFT_BORDER, y); - String totalCutStr = Integer.toString(session.getTotalCut()); - graphics.drawString(totalCutStr, WIDTH - RIGHT_BORDER - metrics.stringWidth(totalCutStr), y); + panelComponent.getLines().add(new PanelComponent.Line( + "Logs/hr:", + session.getRecentCut() > 2 + ? Integer.toString(session.getPerHour()) + : "" + )); - y += metrics.getHeight() + SEPARATOR; - - graphics.drawString("Logs/hr:", LEFT_BORDER, y); - - String perHourStr; - if (session.getRecentCut() > 2) - { - perHourStr = Integer.toString(session.getPerHour()); - } - else - { - perHourStr = "~"; - } - graphics.drawString(perHourStr, WIDTH - RIGHT_BORDER - metrics.stringWidth(perHourStr), y); - - return new Dimension(WIDTH, height); + return panelComponent.render(graphics, parent); } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java index 3c54a95208..000b25c254 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java @@ -75,14 +75,14 @@ public class XpGlobesOverlay extends Overlay @Inject public XpGlobesOverlay(@Nullable Client client, XpGlobesPlugin plugin, XpGlobesConfig config) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.client = client; this.plugin = plugin; this.config = config; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, java.awt.Point point) { // won't draw if not logged in or not enabled diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/zulrah/ZulrahOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/zulrah/ZulrahOverlay.java index c704c15f11..938de383b1 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/zulrah/ZulrahOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/zulrah/ZulrahOverlay.java @@ -74,13 +74,13 @@ public class ZulrahOverlay extends Overlay @Inject ZulrahOverlay(@Nullable Client client, ZulrahPlugin plugin) { - super(OverlayPosition.DYNAMIC); + setPosition(OverlayPosition.DYNAMIC); this.client = client; this.plugin = plugin; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, java.awt.Point point) { ZulrahInstance instance = plugin.getInstance(); diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java index e5441ac322..f94de86352 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java @@ -24,98 +24,14 @@ */ package net.runelite.client.ui.overlay; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import net.runelite.api.Client; -import net.runelite.api.GameState; -import net.runelite.api.widgets.WidgetInfo; +import lombok.Data; -public abstract class Overlay +@Data +public abstract class Overlay extends RenderableEntity { - private OverlayPosition position; // where to draw it - private OverlayPriority priority; // if multiple overlays exist in the same position, who wins - private Rectangle bounds; //screen bounds of overlay after OverlayRenderer decides location + private OverlayPosition position = OverlayPosition.TOP_LEFT; + private OverlayPriority priority = OverlayPriority.NONE; private boolean drawOverLoginScreen = false; private boolean drawOverBankScreen = false; private boolean drawOverClickToPlayScreen = false; - - public Overlay(OverlayPosition position) - { - this(position, OverlayPriority.NONE); - } - - public Overlay(OverlayPosition position, OverlayPriority priority) - { - this.position = position; - this.priority = priority; - } - - public OverlayPosition getPosition() - { - return position; - } - - public void setPosition(OverlayPosition position) - { - this.position = position; - } - - public OverlayPriority getPriority() - { - return priority; - } - - public void setPriority(OverlayPriority priority) - { - this.priority = priority; - } - - public abstract Dimension render(Graphics2D graphics); - - public Rectangle getBounds() - { - return bounds; - } - - public void storeBounds(Rectangle bounds) - { - this.bounds = bounds; - } - - public boolean shouldDraw(Client client) - { - if (client == null) - { - return false; - } - if (!drawOverLoginScreen && client.getGameState() != GameState.LOGGED_IN) - { - return false; - } - if (!drawOverClickToPlayScreen && client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN) != null) - { - return false; - } - if (!drawOverBankScreen && client.getWidget(WidgetInfo.BANK_INVENTORY_ITEMS_CONTAINER) != null) - { - return false; - } - return true; - } - - public void setDrawOverLoginScreen(boolean drawOverLoginScreen) - { - this.drawOverLoginScreen = drawOverLoginScreen; - } - - public void setDrawOverBankScreen(boolean drawOverBankScreen) - { - this.drawOverBankScreen = drawOverBankScreen; - } - - public void setDrawOverClickToPlayScreen(boolean drawOverClickToPlayScreen) - { - this.drawOverClickToPlayScreen = drawOverClickToPlayScreen; - } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPosition.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPosition.java index 300ef3507d..28b7d6fd11 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPosition.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPosition.java @@ -26,6 +26,10 @@ package net.runelite.client.ui.overlay; public enum OverlayPosition { + /** + * Overlay places itself where it wants + */ + DYNAMIC, /** * Place overlay in the top left most area possible */ @@ -35,7 +39,11 @@ public enum OverlayPosition */ TOP_RIGHT, /** - * Overlay places itself where it wants + * Place overlay in the bottom left most area possible */ - DYNAMIC; + BOTTOM_LEFT, + /** + * Place overlay in the bottom right most area possible + */ + BOTTOM_RIGHT; } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPriority.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPriority.java index fecaa01c20..87fc92d4db 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPriority.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPriority.java @@ -22,13 +22,12 @@ * (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; public enum OverlayPriority { - NONE, LOW, + NONE, MED, - HIGH; + HIGH } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java index b2d721d1ce..1da1f952e3 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java @@ -24,72 +24,231 @@ */ package net.runelite.client.ui.overlay; +import com.google.common.base.MoreObjects; +import com.google.common.eventbus.Subscribe; +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 javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.inject.Inject; +import javax.inject.Provider; import javax.inject.Singleton; import net.runelite.api.Client; -import net.runelite.client.config.RuneliteConfig; -import net.runelite.client.plugins.Plugin; +import net.runelite.api.GameState; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.events.GameStateChanged; +import net.runelite.client.events.PluginChanged; +import net.runelite.client.events.ResizeableChanged; import net.runelite.client.plugins.PluginManager; -import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.ui.overlay.infobox.InfoBoxOverlay; -import net.runelite.client.ui.overlay.tooltips.TooltipRenderer; +import net.runelite.client.ui.overlay.tooltip.TooltipOverlay; @Singleton public class OverlayRenderer { - private final Client client; - private final TooltipRenderer tooltipRenderer; - private final InfoBoxOverlay infoBoxOverlay; + private static final int BORDER_TOP = 25; + private static final int BORDER_LEFT = 5; + private static final int BORDER_RIGHT = 5; + private static final int BORDER_BOTTOM = 2; + private static final int PADDING = 2; @Inject PluginManager pluginManager; @Inject - public OverlayRenderer(@Nullable Client client, InfoBoxManager infoboxManager, RuneliteConfig config) + Provider clientProvider; + + @Inject + InfoBoxOverlay infoBoxOverlay; + + @Inject + TooltipOverlay tooltipOverlay; + + private final List overlays = new ArrayList<>(); + private final Rectangle chatboxBounds = new Rectangle(); + private BufferedImage surface; + private Graphics2D surfaceGraphics; + + @Subscribe + public void onResizableChanged(ResizeableChanged event) { - this.client = client; - tooltipRenderer = new TooltipRenderer(client, config); - infoBoxOverlay = new InfoBoxOverlay(client, tooltipRenderer, infoboxManager); + updateSurface(); } - public void render(BufferedImage clientBuffer) + @Subscribe + public void onGameStateChanged(GameStateChanged event) { - TopDownRendererLeft tdl = new TopDownRendererLeft(client); - TopDownRendererRight tdr = new TopDownRendererRight(client); - DynamicRenderer dr = new DynamicRenderer(client); - for (Plugin plugin : pluginManager.getPlugins()) + final Client client = clientProvider.get(); + + if (client == null) { - for (Overlay overlay : plugin.getOverlays()) - { - switch (overlay.getPosition()) - { - case TOP_RIGHT: - tdr.add(overlay); - break; - case TOP_LEFT: - tdl.add(overlay); - break; - case DYNAMIC: - dr.add(overlay); - break; - } - } + return; } - tdl.add(infoBoxOverlay); - - tdl.render(clientBuffer); - tdr.render(clientBuffer); - dr.render(clientBuffer); - - // tooltips are always rendered on top of other overlays - tooltipRenderer.render(clientBuffer); + if (event.getGameState().equals(GameState.LOGIN_SCREEN) || event.getGameState().equals(GameState.LOGGED_IN)) + { + updateSurface(); + } } - public TooltipRenderer getTooltipRenderer() + @Subscribe + public void onPluginChanged(PluginChanged event) { - return tooltipRenderer; + sortOverlays(); + } + + private void sortOverlays() + { + overlays.clear(); + overlays.addAll(Stream + .concat( + pluginManager.getPlugins() + .stream() + .flatMap(plugin -> plugin.getOverlays().stream()), + Stream.of(infoBoxOverlay, tooltipOverlay)) + .sorted((a, b) -> + { + if (a.getPosition() != b.getPosition()) + { + // This is so non-dynamic overlays render after dynamic + // overlays, which are generally in the scene + return a.getPosition().compareTo(b.getPosition()); + } + + // For dynamic overlays, higher priority means to + // draw *later* so it is on top. + // For non-dynamic overlays, higher priority means + // draw *first* so that they are closer to their + // defined position. + return a.getPosition() == OverlayPosition.DYNAMIC + ? a.getPriority().compareTo(b.getPriority()) + : b.getPriority().compareTo(a.getPriority()); + }) + .collect(Collectors.toList())); + } + + private void updateSurface() + { + final Client client = clientProvider.get(); + + if (client == null) + { + return; + } + + final Dimension size = client.getCanvas().getSize(); + final BufferedImage temp = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB); + final Graphics2D subGraphics = temp.createGraphics(); + subGraphics.setBackground(new Color(0, 0, 0, 0)); + OverlayUtil.setGraphicProperties(subGraphics); + + surface = temp; + + if (surfaceGraphics != null) + { + surfaceGraphics.dispose(); + } + + surfaceGraphics = subGraphics; + } + + public void render(Graphics2D graphics) + { + final Client client = clientProvider.get(); + + if (client == null || surface == null || overlays.isEmpty()) + { + return; + } + + final Widget chatbox = client.getWidget(WidgetInfo.CHATBOX); + + if (chatbox != null) + { + chatboxBounds.setBounds(chatbox.getBounds()); + } + + final Point topLeftPoint = new Point(); + topLeftPoint.move(BORDER_LEFT, BORDER_TOP); + final Point topRightPoint = new Point(); + topRightPoint.move(surface.getWidth() - BORDER_RIGHT, BORDER_TOP); + final Point bottomLeftPoint = new Point(); + bottomLeftPoint.move(BORDER_LEFT, chatboxBounds.y - BORDER_BOTTOM); + final Point bottomRightPoint = new Point(); + bottomRightPoint.move(chatboxBounds.x + chatboxBounds.width - BORDER_RIGHT, chatboxBounds.y - BORDER_BOTTOM); + + overlays.stream() + .filter(overlay -> shouldDrawOverlay(client, overlay)) + .forEach(overlay -> + { + final Point subPosition = new Point(); + + switch (overlay.getPosition()) + { + case BOTTOM_LEFT: + subPosition.setLocation(bottomLeftPoint); + break; + case BOTTOM_RIGHT: + subPosition.setLocation(bottomRightPoint); + break; + case TOP_LEFT: + subPosition.setLocation(topLeftPoint); + break; + case TOP_RIGHT: + subPosition.setLocation(topRightPoint); + break; + } + + if (overlay.getPosition().equals(OverlayPosition.DYNAMIC)) + { + overlay.render(graphics, new Point()); + } + else + { + surfaceGraphics.clearRect(0, 0, surface.getWidth(), surface.getHeight()); + + final Dimension dimension = MoreObjects.firstNonNull(overlay.render(surfaceGraphics, subPosition), new Dimension()); + if (dimension.width == 0 && dimension.height == 0) + { + return; + } + + final BufferedImage clippedImage = surface.getSubimage(0, 0, dimension.width, dimension.height); + + switch (overlay.getPosition()) + { + case BOTTOM_LEFT: + bottomLeftPoint.x += dimension.width + (dimension.width == 0 ? 0 : PADDING); + break; + case BOTTOM_RIGHT: + bottomRightPoint.x -= dimension.width - (dimension.width == 0 ? 0 : PADDING); + break; + case TOP_LEFT: + topLeftPoint.y += dimension.height + (dimension.height == 0 ? 0 : PADDING); + break; + case TOP_RIGHT: + topRightPoint.y += dimension.height + (dimension.height == 0 ? 0 : PADDING); + break; + } + + final Point transformed = OverlayUtil.transformPosition(overlay.getPosition(), dimension); + graphics.drawImage(clippedImage, subPosition.x + transformed.x, subPosition.y + transformed.y, null); + } + }); + } + + private boolean shouldDrawOverlay(Client client, Overlay overlay) + { + return client != null + && (overlay.isDrawOverLoginScreen() || client.getGameState() == GameState.LOGGED_IN) + && (overlay.isDrawOverClickToPlayScreen() || client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN) == null) + && (overlay.isDrawOverBankScreen() || client.getWidget(WidgetInfo.BANK_INVENTORY_ITEMS_CONTAINER) == null); } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayUtil.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayUtil.java index f84e622a87..739779a0ff 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayUtil.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayUtil.java @@ -26,6 +26,7 @@ package net.runelite.client.ui.overlay; import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics2D; @@ -33,6 +34,7 @@ import java.awt.Image; import java.awt.Paint; import java.awt.Polygon; import java.awt.RadialGradientPaint; +import java.awt.RenderingHints; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import net.runelite.api.Actor; @@ -316,4 +318,31 @@ public class OverlayUtil } } + public static void setGraphicProperties(Graphics2D graphics) + { + graphics.setFont(FontManager.getRunescapeFont()); + graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + } + + public static java.awt.Point transformPosition(OverlayPosition position, Dimension dimension) + { + final java.awt.Point result = new java.awt.Point(); + + switch (position) + { + case DYNAMIC: + case TOP_LEFT: + break; + case BOTTOM_LEFT: + result.y = result.y - dimension.height; + break; + case BOTTOM_RIGHT: + result.y = result.y - dimension.height; + case TOP_RIGHT: + result.x = result.x - dimension.width; + break; + } + + return result; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltips/TooltipPriority.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/RenderableEntity.java similarity index 81% rename from runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltips/TooltipPriority.java rename to runelite-client/src/main/java/net/runelite/client/ui/overlay/RenderableEntity.java index f63e4ceac0..35b702cf31 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltips/TooltipPriority.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/RenderableEntity.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Tyler + * Copyright (c) 2017, Tomas Slusny * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,11 +22,16 @@ * (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.tooltips; +package net.runelite.client.ui.overlay; -public enum TooltipPriority +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Point; + +public abstract class RenderableEntity { - LOW, - MED, - HIGH; + public Dimension render(Graphics2D graphics, Point parent) + { + return null; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/TopDownRendererRight.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/TopDownRendererRight.java deleted file mode 100644 index c1ed57350e..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/TopDownRendererRight.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (c) 2016-2017, Adam - * 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; - -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Rectangle; -import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.List; - -import net.runelite.api.Client; - -public class TopDownRendererRight implements Renderer -{ - private static final int BORDER_TOP = 0; - private static final int BORDER_RIGHT = 10; - private static final int PADDING = 10; - - private final Client client; - private final List overlays = new ArrayList<>(); - - public TopDownRendererRight(Client client) - { - this.client = client; - } - - public void add(Overlay overlay) - { - overlays.add(overlay); - } - - @Override - public void render(BufferedImage clientBuffer) - { - overlays.sort((o1, o2) -> o2.getPriority().compareTo(o1.getPriority())); - - int y = BORDER_TOP; - int clientWidth = client.getCanvas().getWidth(); - int clientHeight = client.getCanvas().getHeight(); - - for (Overlay overlay : overlays) - { - if (!overlay.shouldDraw(client)) - continue; - - BufferedImage image = new BufferedImage(clientWidth, clientHeight, BufferedImage.TYPE_INT_ARGB); - Graphics2D graphics = image.createGraphics(); - Renderer.setAntiAliasing(graphics); - Dimension dimension = overlay.render(graphics); - graphics.dispose(); - - if (dimension == null) - { - continue; - } - - image = image.getSubimage(0, 0, (int) dimension.getWidth(), (int) dimension.getHeight()); - - graphics = clientBuffer.createGraphics(); - graphics.drawImage(image, clientWidth - BORDER_RIGHT - (int) dimension.getWidth(), y, null); - graphics.dispose(); - - Rectangle bounds = new Rectangle(clientWidth - BORDER_RIGHT - (int) dimension.getWidth(), y, (int) dimension.getWidth(), (int) dimension.getHeight()); - overlay.storeBounds(bounds); - - y += dimension.getHeight() + PADDING; - } - } - -} diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/BackgroundComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/BackgroundComponent.java new file mode 100644 index 0000000000..ca952fa77a --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/BackgroundComponent.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017, Tomas Slusny + * 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.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Setter; +import net.runelite.client.ui.overlay.RenderableEntity; + +@NoArgsConstructor +@AllArgsConstructor +public class BackgroundComponent extends RenderableEntity +{ + private static final int BORDER_OFFSET = 2; + private static final Color BACKGROUND_COLOR = new Color(70, 61, 50, 156); + private static final Color OUTSIDE_STROKE_COLOR = new Color(56, 48, 35, 255); + private static final Color INSIDE_STROKE_COLOR = new Color(90, 82, 69, 255); + + @Setter + private Rectangle rectangle = new Rectangle(); + + @Override + public Dimension render(Graphics2D graphics, Point parent) + { + // Render background + graphics.setColor(BACKGROUND_COLOR); + graphics.fill(rectangle); + + // Render outside stroke + final Rectangle outsideStroke = new Rectangle(rectangle); + outsideStroke.grow(-BORDER_OFFSET / 2,- BORDER_OFFSET / 2); + graphics.setColor(OUTSIDE_STROKE_COLOR); + graphics.draw(outsideStroke); + + // Render inside stroke + final Rectangle insideStroke = new Rectangle(rectangle); + insideStroke.grow(-BORDER_OFFSET, -BORDER_OFFSET); + graphics.setColor(INSIDE_STROKE_COLOR); + graphics.draw(insideStroke); + return new Dimension(rectangle.getSize()); + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/TopDownRendererLeft.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/InfoBoxComponent.java similarity index 52% rename from runelite-client/src/main/java/net/runelite/client/ui/overlay/TopDownRendererLeft.java rename to runelite-client/src/main/java/net/runelite/client/ui/overlay/components/InfoBoxComponent.java index 8e40067b02..4672a57085 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/TopDownRendererLeft.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/InfoBoxComponent.java @@ -22,59 +22,61 @@ * (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; +package net.runelite.client.ui.overlay.components; +import java.awt.Color; import java.awt.Dimension; +import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.Rectangle; import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.List; -import net.runelite.api.Client; +import java.util.Objects; +import javax.annotation.Nullable; +import lombok.Setter; +import net.runelite.client.ui.overlay.RenderableEntity; -public class TopDownRendererLeft implements Renderer +public class InfoBoxComponent extends RenderableEntity { - private static final int BORDER_TOP = 25; - private static final int BORDER_LEFT = 10; - private static final int PADDING = 10; + private static final int BOX_SIZE = 35; + private static final int SEPARATOR = 2; - private final Client client; - private final List overlays = new ArrayList<>(); + @Setter + private String text; - public TopDownRendererLeft(Client client) - { - this.client = client; - } + @Setter + private Color color = Color.WHITE; - public void add(Overlay overlay) - { - overlays.add(overlay); - } + @Setter + private Point position = new Point(); + + @Setter + @Nullable + private BufferedImage image; @Override - public void render(BufferedImage clientBuffer) + public Dimension render(Graphics2D graphics, Point parent) { - overlays.sort((o1, o2) -> o2.getPriority().compareTo(o1.getPriority())); - int y = BORDER_TOP; + final FontMetrics metrics = graphics.getFontMetrics(); + final Rectangle bounds = new Rectangle(position.x, position.y, BOX_SIZE, BOX_SIZE); + final BackgroundComponent backgroundComponent = new BackgroundComponent(); + backgroundComponent.setRectangle(bounds); + backgroundComponent.render(graphics, parent); - for (Overlay overlay : overlays) + if (Objects.nonNull(image)) { - if (!overlay.shouldDraw(client)) - continue; - - BufferedImage image = clientBuffer.getSubimage(BORDER_LEFT, y, clientBuffer.getWidth() - BORDER_LEFT, clientBuffer.getHeight() - y); - Graphics2D graphics = image.createGraphics(); - Renderer.setAntiAliasing(graphics); - Dimension dimension = overlay.render(graphics); - graphics.dispose(); - - if (dimension == null) - continue; - - Rectangle bounds = new Rectangle(BORDER_LEFT, y, (int) dimension.getWidth(), (int) dimension.getHeight()); - overlay.storeBounds(bounds); - - y += dimension.getHeight() + PADDING; + graphics.drawImage(image, + position.x + (BOX_SIZE - image.getWidth()) / 2, + SEPARATOR, null); } + + final TextComponent textComponent = new TextComponent(); + textComponent.setColor(color); + textComponent.setText(text); + textComponent.setPosition(new Point( + position.x + ((BOX_SIZE - metrics.stringWidth(text)) / 2), + BOX_SIZE - SEPARATOR)); + textComponent.render(graphics, parent); + return new Dimension(BOX_SIZE, BOX_SIZE); } -} \ 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 new file mode 100644 index 0000000000..481aefc27c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2017, Tomas Slusny + * 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 com.google.common.base.Strings; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.Nullable; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; +import net.runelite.client.ui.overlay.RenderableEntity; + +public class PanelComponent extends RenderableEntity +{ + private static final int TOP_BORDER = 3; + private static final int LEFT_BORDER = 6; + private static final int RIGHT_BORDER = 6; + private static final int BOTTOM_BORDER = 6; + private static final int SEPARATOR = 2; + + @Data + @AllArgsConstructor + @RequiredArgsConstructor + public static class Line + { + private final String left; + private Color leftColor = Color.WHITE; + private final String right; + private Color rightColor = Color.WHITE; + } + + @Setter + @Nullable + private String title; + + @Setter + private Color titleColor = Color.WHITE; + + @Setter + private Point position = new Point(); + + @Getter + private List lines = new ArrayList<>(); + + @Setter + private int width = 140; + + @Override + public Dimension render(Graphics2D graphics, Point parent) + { + final Dimension dimension = new Dimension(); + final int elementNumber = (Strings.isNullOrEmpty(title) ? 0 : 1) + lines.size(); + int height = elementNumber == 0 ? 0 : + TOP_BORDER + (graphics.getFontMetrics().getHeight() * elementNumber) + + SEPARATOR * elementNumber + BOTTOM_BORDER; + dimension.setSize(width, height); + + if (dimension.height == 0) + { + return null; + } + + final FontMetrics metrics = graphics.getFontMetrics(); + + // Calculate panel dimensions + int y = position.y + TOP_BORDER + metrics.getHeight(); + + // Render background + final BackgroundComponent backgroundComponent = new BackgroundComponent(); + backgroundComponent.setRectangle(new Rectangle(position.x, position.y, dimension.width, dimension.height)); + backgroundComponent.render(graphics, parent); + + // Render title + if (!Strings.isNullOrEmpty(title)) + { + final TextComponent titleComponent = new TextComponent(); + titleComponent.setText(title); + titleComponent.setColor(titleColor); + titleComponent.setPosition(new Point(position.x + (width - metrics.stringWidth(title)) / 2, y)); + titleComponent.render(graphics, parent); + y += metrics.getHeight() + SEPARATOR; + } + + // Render all lines + for (final Line line : lines) + { + final TextComponent leftLineComponent = new TextComponent(); + leftLineComponent.setPosition(new Point(position.x + LEFT_BORDER, y)); + leftLineComponent.setText(line.getLeft()); + leftLineComponent.setColor(line.getLeftColor()); + leftLineComponent.render(graphics, parent); + + final TextComponent rightLineComponent = new TextComponent(); + rightLineComponent.setPosition(new Point(position.x + width - RIGHT_BORDER - metrics.stringWidth(line.getRight()), y)); + rightLineComponent.setText(line.getRight()); + rightLineComponent.setColor(line.getRightColor()); + rightLineComponent.render(graphics, parent); + y += metrics.getHeight() + SEPARATOR; + } + + return dimension; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/DynamicRenderer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java similarity index 61% rename from runelite-client/src/main/java/net/runelite/client/ui/overlay/DynamicRenderer.java rename to runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java index 8b79610520..83cc81db18 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/DynamicRenderer.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Adam + * Copyright (c) 2017, Tomas Slusny * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,42 +22,39 @@ * (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; +package net.runelite.client.ui.overlay.components; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; import java.awt.Graphics2D; -import java.awt.image.BufferedImage; -import java.util.ArrayList; -import java.util.List; -import net.runelite.api.Client; +import java.awt.Point; +import lombok.Setter; +import net.runelite.client.ui.overlay.RenderableEntity; -public class DynamicRenderer implements Renderer +public class TextComponent extends RenderableEntity { - private final Client client; - private final List overlays = new ArrayList<>(); + @Setter + private String text; - public DynamicRenderer(Client client) - { - this.client = client; - } + @Setter + private Point position = new Point(); - public void add(Overlay overlay) - { - overlays.add(overlay); - } + @Setter + private Color color = Color.WHITE; @Override - public void render(BufferedImage clientBuffer) + public Dimension render(Graphics2D graphics, Point parent) { - for (Overlay overlay : overlays) - { - if (!overlay.shouldDraw(client)) - continue; + // Draw shadow + graphics.setColor(Color.BLACK); + graphics.drawString(text, position.x + 1, position.y + 1); - Graphics2D graphics = clientBuffer.createGraphics(); - Renderer.setAntiAliasing(graphics); - overlay.render(graphics); - graphics.dispose(); - } + // Draw actual text + graphics.setColor(color); + graphics.drawString(text, position.x, position.y); + + final FontMetrics fontMetrics = graphics.getFontMetrics(); + return new Dimension(fontMetrics.stringWidth(text), fontMetrics.getHeight()); } - } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java new file mode 100644 index 0000000000..52310e6327 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TooltipComponent.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2016-2017, Adam + * 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.Color; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import lombok.Setter; +import net.runelite.client.ui.overlay.RenderableEntity; + +public class TooltipComponent extends RenderableEntity +{ + private static final Pattern COLOR_SPLIT = Pattern.compile("<\\/?col=?([^>]+)?>"); + private static final Pattern BR = Pattern.compile("
"); + private static final int OFFSET = 4; + + @Setter + private String text; + + @Setter + private Point position = new Point(); + + @Override + public Dimension render(Graphics2D graphics, Point parent) + { + // Tooltip size + final FontMetrics metrics = graphics.getFontMetrics(); + final int textDescent = metrics.getDescent(); + final int textHeight = graphics.getFontMetrics().getHeight(); + int tooltipWidth = 0; + int tooltipHeight = 0; + String[] lines = BR.split(text); + + for (String line : lines) + { + String lineClean = COLOR_SPLIT.matcher(line).replaceAll(""); + int textWidth = graphics.getFontMetrics().stringWidth(lineClean); + if (textWidth > tooltipWidth) + { + tooltipWidth = textWidth; + } + + tooltipHeight += textHeight; + } + + // Tooltip position + int x = position.x; + int y = position.y; + x = x - tooltipWidth - OFFSET * 2; + if (x < 0) + { + x = 0; + } + + y = y - tooltipHeight - OFFSET * 2; + if (y < 0) + { + y = 0; + } + + // Render tooltip - background + final Rectangle tooltipBackground = new Rectangle(x, y, + tooltipWidth + OFFSET * 2, tooltipHeight + OFFSET * 2); + final BackgroundComponent backgroundComponent = new BackgroundComponent(); + backgroundComponent.setRectangle(tooltipBackground); + backgroundComponent.render(graphics, parent); + graphics.setColor(Color.WHITE); + + // Render tooltip - text - line by line + int textX = x + OFFSET; + int textY = y + OFFSET; + int lineX; + Color nextColor = Color.WHITE; + for (int i = 0; i < lines.length; i++) + { + lineX = textX; + final String line = lines[i]; + final Matcher m = COLOR_SPLIT.matcher(line); + + int begin = 0; + while (m.find()) + { + // Draw text prior to color tag + String preText = line.substring(begin, m.start()); + final TextComponent textComponent = new TextComponent(); + textComponent.setText(preText); + textComponent.setPosition(new Point(lineX, textY + (i + 1) * textHeight - textDescent)); + textComponent.setColor(nextColor); + textComponent.render(graphics, parent); + + // Set color for next text part + if (m.group(1) == null) + { + // no color tag + nextColor = Color.WHITE; + } + else + { + // color tag + nextColor = Color.decode("#" + m.group(1)); + } + begin = m.end(); + lineX += metrics.stringWidth(preText); + } + + // Draw trailing text (after last tag) + final TextComponent textComponent = new TextComponent(); + textComponent.setText(line.substring(begin, line.length())); + textComponent.setPosition(new Point(lineX, textY + (i + 1) * textHeight - textDescent)); + textComponent.setColor(nextColor); + textComponent.render(graphics, parent); + } + + + return new Dimension(tooltipWidth + OFFSET * 2, tooltipHeight + OFFSET * 2); + } +} 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 36c7d2a32d..a536958549 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 @@ -25,42 +25,42 @@ */ package net.runelite.client.ui.overlay.infobox; -import java.awt.Color; +import com.google.common.base.Strings; import java.awt.Dimension; -import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.Rectangle; -import java.awt.image.BufferedImage; import java.util.List; +import javax.inject.Inject; +import javax.inject.Provider; import net.runelite.api.Client; -import net.runelite.api.Point; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; -import net.runelite.client.ui.overlay.OverlayPriority; -import net.runelite.client.ui.overlay.tooltips.Tooltip; -import net.runelite.client.ui.overlay.tooltips.TooltipPriority; -import net.runelite.client.ui.overlay.tooltips.TooltipRenderer; +import net.runelite.client.ui.overlay.OverlayUtil; +import net.runelite.client.ui.overlay.components.InfoBoxComponent; +import net.runelite.client.ui.overlay.tooltip.Tooltip; +import net.runelite.client.ui.overlay.tooltip.TooltipManager; public class InfoBoxOverlay extends Overlay { private static final int BOXSIZE = 35; private static final int SEPARATOR = 2; - private static final Color BACKGROUND = new Color(Color.gray.getRed(), Color.gray.getGreen(), Color.gray.getBlue(), 127); - private final Client client; - private final TooltipRenderer tooltipRenderer; private final InfoBoxManager infoboxManager; + private final TooltipManager tooltipManager; + private final Provider clientProvider; - public InfoBoxOverlay(Client client, TooltipRenderer tooltipRenderer, InfoBoxManager infoboxManager) + @Inject + public InfoBoxOverlay(InfoBoxManager infoboxManager, TooltipManager tooltipManager, Provider clientProvider) { - super(OverlayPosition.TOP_LEFT, OverlayPriority.LOW); - this.client = client; - this.tooltipRenderer = tooltipRenderer; + setPosition(OverlayPosition.BOTTOM_LEFT); + this.tooltipManager = tooltipManager; this.infoboxManager = infoboxManager; + this.clientProvider = clientProvider; } @Override - public Dimension render(Graphics2D graphics) + public Dimension render(Graphics2D graphics, Point parent) { List infoBoxes = infoboxManager.getInfoBoxes(); @@ -69,16 +69,9 @@ public class InfoBoxOverlay extends Overlay return null; } - FontMetrics metrics = graphics.getFontMetrics(); - int width = infoBoxes.size() * (BOXSIZE + SEPARATOR); - - Point mouse = client.getMouseCanvasPosition(); - int mouseX = mouse.getX(); - int mouseY = mouse.getY(); int x = 0; - Rectangle overlayBounds = this.getBounds(); for (InfoBox box : infoBoxes) { if (!box.render()) @@ -86,47 +79,29 @@ public class InfoBoxOverlay extends Overlay continue; } - graphics.setColor(BACKGROUND); - graphics.fillRect(x, 0, BOXSIZE, BOXSIZE); - graphics.setColor(Color.darkGray); - graphics.drawRect(x, 0, BOXSIZE, BOXSIZE); + final InfoBoxComponent infoBoxComponent = new InfoBoxComponent(); + infoBoxComponent.setColor(box.getTextColor()); + infoBoxComponent.setImage(box.getImage()); + infoBoxComponent.setText(box.getText()); + infoBoxComponent.setPosition(new Point(x, 0)); + final Dimension infoBoxBounds = infoBoxComponent.render(graphics, parent); - String str = box.getText(); - Color color = box.getTextColor(); - - BufferedImage image = box.getImage(); - if (image != null) + if (!Strings.isNullOrEmpty(box.getTooltip())) { - graphics.drawImage(image, x + (BOXSIZE - image.getWidth()) / 2, SEPARATOR, null); - } + final Rectangle intersectionRectangle = new Rectangle(infoBoxBounds); + intersectionRectangle.setLocation(parent); + intersectionRectangle.translate(x, 0); + final Point transformed = OverlayUtil.transformPosition(getPosition(), intersectionRectangle.getSize()); + intersectionRectangle.translate(transformed.x, transformed.y); - // text shaddow - graphics.setColor(Color.black); - graphics.drawString(str, x + ((BOXSIZE - metrics.stringWidth(str)) / 2) + 1, BOXSIZE - SEPARATOR + 1); + final Client client = clientProvider.get(); - graphics.setColor(color); - graphics.drawString(str, x + ((BOXSIZE - metrics.stringWidth(str)) / 2), BOXSIZE - SEPARATOR); - - if (overlayBounds == null) - { - x += BOXSIZE + SEPARATOR; - continue; - } - - String tooltipText = box.getTooltip(); - if (tooltipText == null || tooltipText.isEmpty()) - { - x += BOXSIZE + SEPARATOR; - continue; - } - - Rectangle infoboxBounds = new Rectangle((int) overlayBounds.getX() + x, (int) overlayBounds.getY(), BOXSIZE, BOXSIZE); - if (infoboxBounds.contains(mouseX, mouseY)) - { - Tooltip tooltip = new Tooltip(TooltipPriority.HIGH, - tooltipText); - tooltipRenderer.add(tooltip); + if (client != null && intersectionRectangle.contains(new Point(client.getMouseCanvasPosition().getX(), + client.getMouseCanvasPosition().getY()))) + { + tooltipManager.add(new Tooltip(box.getTooltip())); + } } x += BOXSIZE + SEPARATOR; @@ -134,5 +109,4 @@ public class InfoBoxOverlay extends Overlay return new Dimension(width, BOXSIZE); } - } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltips/Tooltip.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/Tooltip.java similarity index 76% rename from runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltips/Tooltip.java rename to runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/Tooltip.java index 459a700db4..09fb7e073b 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltips/Tooltip.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/Tooltip.java @@ -22,26 +22,19 @@ * (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.tooltips; +package net.runelite.client.ui.overlay.tooltip; +import java.awt.Point; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.RequiredArgsConstructor; + +@Data +@AllArgsConstructor +@RequiredArgsConstructor public class Tooltip { - private final TooltipPriority priority; // if multiple overlays exist in the same position, who wins - private final String tooltipText; - - public Tooltip(TooltipPriority priority, String tooltipText) - { - this.priority = priority; - this.tooltipText = tooltipText; - } - - public TooltipPriority getPriority() - { - return priority; - } - - public String getText() - { - return tooltipText; - } + private final String text; + private boolean followMouse = true; + private Point position = new Point(); } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Renderer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipManager.java similarity index 74% rename from runelite-client/src/main/java/net/runelite/client/ui/overlay/Renderer.java rename to runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipManager.java index 4c80d44d93..3d0f27a8fb 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Renderer.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Adam + * Copyright (c) 2017, Tomas Slusny * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -22,18 +22,28 @@ * (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; +package net.runelite.client.ui.overlay.tooltip; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.List; +import javax.inject.Singleton; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; -public interface Renderer +@Singleton +@Slf4j +public class TooltipManager { - void render(BufferedImage clientBuffer); + @Getter + private final List tooltips = new ArrayList<>(); - static void setAntiAliasing(Graphics2D graphics) + public void add(Tooltip tooltip) { - graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + tooltips.add(tooltip); + } + + public void clear() + { + tooltips.clear(); } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java new file mode 100644 index 0000000000..c27b7dc8de --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltip/TooltipOverlay.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2017, Tomas Slusny + * 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.tooltip; + +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Point; +import java.util.List; +import javax.inject.Inject; +import javax.inject.Provider; +import net.runelite.api.Client; +import net.runelite.client.ui.overlay.Overlay; +import net.runelite.client.ui.overlay.OverlayPosition; +import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.ui.overlay.components.TooltipComponent; + +public class TooltipOverlay extends Overlay +{ + private final TooltipManager tooltipManager; + private final Provider clientProvider; + + @Inject + public TooltipOverlay(TooltipManager tooltipManager, Provider clientProvider) + { + setPosition(OverlayPosition.DYNAMIC); + setPriority(OverlayPriority.HIGH); + this.tooltipManager = tooltipManager; + this.clientProvider = clientProvider; + } + + @Override + public Dimension render(Graphics2D graphics, Point parent) + { + List tooltips = tooltipManager.getTooltips(); + + if (tooltips.isEmpty()) + { + return null; + } + + for (Tooltip tooltip : tooltips) + { + final TooltipComponent tooltipComponent = new TooltipComponent(); + tooltipComponent.setText(tooltip.getText()); + + if (tooltip.isFollowMouse()) + { + final Client client = clientProvider.get(); + final net.runelite.api.Point mouseCanvasPosition = client != null + ? client.getMouseCanvasPosition() + : new net.runelite.api.Point(0, 0); + tooltipComponent.setPosition(new Point(mouseCanvasPosition.getX(), mouseCanvasPosition.getY())); + } + else + { + tooltipComponent.setPosition(tooltip.getPosition()); + } + + tooltipComponent.render(graphics, parent); + } + + tooltipManager.clear(); + return null; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltips/TooltipRenderer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltips/TooltipRenderer.java deleted file mode 100644 index acc038f681..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/tooltips/TooltipRenderer.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2017, Tyler - * 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.tooltips; - -import java.awt.Color; -import java.awt.FontMetrics; -import java.awt.Graphics2D; -import java.awt.image.BufferedImage; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import net.runelite.api.Client; -import net.runelite.api.Point; -import net.runelite.client.config.RuneliteConfig; -import net.runelite.client.ui.overlay.Renderer; - -public class TooltipRenderer implements Renderer -{ - private static final Pattern COLOR_SPLIT = Pattern.compile("<\\/?col=?([^>]+)?>"); - private static final Pattern BR = Pattern.compile("
"); - - private static final int BORDER_SIZE = 2; - private static final int JSWING_BORDER_RIGHT = 5; - private static final Color BACKGROUND_COLOR = new Color(Color.gray.getRed(), Color.gray.getGreen(), Color.gray.getBlue(), 150); - private static final Color BORDER_COLOR = Color.black; - private static final Color FONT_COLOR = Color.white; - - private final Client client; - private final RuneliteConfig config; - - private Tooltip tooltip; - - public TooltipRenderer(Client client, RuneliteConfig config) - { - this.client = client; - this.config = config; - } - - @Override - public void render(BufferedImage clientBuffer) - { - Point mousePos = client.getMouseCanvasPosition(); - Graphics2D graphics = clientBuffer.createGraphics(); - Renderer.setAntiAliasing(graphics); - drawTooltip(graphics, mousePos.getX(), mousePos.getY()); - graphics.dispose(); - - this.tooltip = null; - } - - public void add(Tooltip tooltip) - { - if (this.tooltip != null && tooltip.getPriority().compareTo(this.tooltip.getPriority()) < 0) - { - return; - } - - this.tooltip = tooltip; - } - - private void drawTooltip(Graphics2D graphics, int x, int y) - { - if (tooltip == null || tooltip.getText() == null || tooltip.getText().isEmpty()) - { - return; - } - - FontMetrics metrics = graphics.getFontMetrics(); - String tooltipText = tooltip.getText(); - int tooltipWidth = 0; - int tooltipHeight = 0; - int textHeight = metrics.getHeight(); - int textDescent = metrics.getDescent(); - - // Tooltip size - String[] lines = BR.split(tooltipText); - for (String line : lines) - { - String lineClean = COLOR_SPLIT.matcher(line).replaceAll(""); - int textWidth = metrics.stringWidth(lineClean); - if (textWidth > tooltipWidth) - { - tooltipWidth = textWidth; - } - - tooltipHeight += textHeight; - } - - // Position tooltip - if (config.tooltipLeft()) - { - x = x - tooltipWidth; - if (x < 0) - { - x = 0; - } - } - else - { - int clientWidth = client.getCanvas().getWidth(); - if (x + tooltipWidth + JSWING_BORDER_RIGHT > clientWidth) - { - x = clientWidth - tooltipWidth - JSWING_BORDER_RIGHT; - } - } - - y = y - tooltipHeight; - if (y < 0) - { - y = 0; - } - - // Render tooltip - background - graphics.setColor(BACKGROUND_COLOR); - graphics.fillRect(x, y, tooltipWidth + BORDER_SIZE * 2, tooltipHeight); - graphics.setColor(BORDER_COLOR); - graphics.drawRect(x, y, tooltipWidth + BORDER_SIZE * 2, tooltipHeight); - graphics.setColor(FONT_COLOR); - - // Render tooltip - text - line by line - int lineX; - Color nextColor = Color.WHITE; - for (int i = 0; i < lines.length; i++) - { - lineX = x; - String line = lines[i]; - Matcher m = COLOR_SPLIT.matcher(line); - - int begin = 0; - while (m.find()) - { - // Draw text prior to color tag - String preText = line.substring(begin, m.start()); - graphics.setColor(Color.BLACK); - graphics.drawString(preText, lineX + BORDER_SIZE + 1, y + (i + 1) * textHeight - textDescent + 1); // shadow - graphics.setColor(nextColor); - graphics.drawString(preText, lineX + BORDER_SIZE, y + (i + 1) * textHeight - textDescent); // text - - // Set color for next text part - if (m.group(1) == null) - { - // no color tag - nextColor = Color.WHITE; - } - else - { - // color tag - nextColor = Color.decode("#" + m.group(1)); - } - begin = m.end(); - lineX += metrics.stringWidth(preText); - } - // Draw trailing text (after last tag) - graphics.setColor(Color.BLACK); - graphics.drawString(line.substring(begin, line.length()), lineX + BORDER_SIZE + 1, y + (i + 1) * textHeight - textDescent + 1); - graphics.setColor(nextColor); - graphics.drawString(line.substring(begin, line.length()), lineX + BORDER_SIZE, y + (i + 1) * textHeight - textDescent); - } - } -}