Merge pull request #246 from deathbeam/plugin-ui-update

Make overlay UI reusable and look native
This commit is contained in:
Adam
2017-12-13 18:39:08 -05:00
committed by GitHub
47 changed files with 1073 additions and 948 deletions

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Tyler <https://github.com/tylerthardy>
* Copyright (c) 2017, Tomas Slusny <slusnucky@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,11 +22,14 @@
* (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.events;
public enum TooltipPriority
import lombok.Data;
import net.runelite.client.plugins.Plugin;
@Data
public class PluginChanged
{
LOW,
MED,
HIGH;
private final Plugin plugin;
private final boolean loaded;
}

View File

@@ -44,6 +44,7 @@ import javax.inject.Singleton;
import javax.swing.SwingUtilities;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.RuneLite;
import net.runelite.client.events.PluginChanged;
import net.runelite.client.task.Schedule;
import net.runelite.client.task.ScheduledMethod;
import net.runelite.client.task.Scheduler;
@@ -167,6 +168,7 @@ public class PluginManager
log.debug("Plugin {} is now running", plugin.getClass().getSimpleName());
eventBus.register(plugin);
eventBus.post(new PluginChanged(plugin, true));
schedule(plugin);
}
catch (InterruptedException | InvocationTargetException ex)
@@ -181,6 +183,7 @@ public class PluginManager
{
unschedule(plugin);
eventBus.unregister(plugin);
eventBus.post(new PluginChanged(plugin, false));
// plugins always stop in the event thread
SwingUtilities.invokeAndWait(() ->

View File

@@ -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())
{

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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)

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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())
{

View File

@@ -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();

View File

@@ -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)
{

View File

@@ -1,26 +1,26 @@
/*
* Copyright (c) 2017, Robin <robin.weymans@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/*
* Copyright (c) 2017, Robin <robin.weymans@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.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);

View File

@@ -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)
{

View File

@@ -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())
{

View File

@@ -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
// <col=ffffff>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;
}
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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
{

View File

@@ -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())
{

View File

@@ -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())
{

View File

@@ -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;
}

View File

@@ -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())
{

View File

@@ -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())
{

View File

@@ -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())
{

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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();

View File

@@ -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;
}
}

View File

@@ -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;
}

View File

@@ -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
}

View File

@@ -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<Client> clientProvider;
@Inject
InfoBoxOverlay infoBoxOverlay;
@Inject
TooltipOverlay tooltipOverlay;
private final List<Overlay> 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);
}
}

View File

@@ -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;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* Copyright (c) 2017, Tomas Slusny <slusnucky@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,16 +24,14 @@
*/
package net.runelite.client.ui.overlay;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.Point;
public interface Renderer
public abstract class RenderableEntity
{
void render(BufferedImage clientBuffer);
static void setAntiAliasing(Graphics2D graphics)
public Dimension render(Graphics2D graphics, Point parent)
{
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
return null;
}
}

View File

@@ -1,93 +0,0 @@
/*
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 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<Overlay> 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;
}
}
}

View File

@@ -0,0 +1,69 @@
/*
* Copyright (c) 2017, Tomas Slusny <slusnucky@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.ui.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());
}
}

View File

@@ -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<Overlay> 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);
}
}
}

View File

@@ -0,0 +1,134 @@
/*
* Copyright (c) 2017, Tomas Slusny <slusnucky@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.ui.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<Line> 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;
}
}

View File

@@ -0,0 +1,60 @@
/*
* Copyright (c) 2017, Tomas Slusny <slusnucky@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.ui.overlay.components;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import lombok.Setter;
import net.runelite.client.ui.overlay.RenderableEntity;
public class TextComponent extends RenderableEntity
{
@Setter
private String text;
@Setter
private Point position = new Point();
@Setter
private Color color = Color.WHITE;
@Override
public Dimension render(Graphics2D graphics, Point parent)
{
// Draw shadow
graphics.setColor(Color.BLACK);
graphics.drawString(text, position.x + 1, position.y + 1);
// 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());
}
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright (c) 2016-2017, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 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("</br>");
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);
}
}

View File

@@ -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<Client> clientProvider;
public InfoBoxOverlay(Client client, TooltipRenderer tooltipRenderer, InfoBoxManager infoboxManager)
@Inject
public InfoBoxOverlay(InfoBoxManager infoboxManager, TooltipManager tooltipManager, Provider<Client> 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<InfoBox> 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);
}
}

View File

@@ -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();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, Adam <Adam@sigterm.info>
* Copyright (c) 2017, Tomas Slusny <slusnucky@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -22,42 +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.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import net.runelite.api.Client;
import javax.inject.Singleton;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
public class DynamicRenderer implements Renderer
@Singleton
@Slf4j
public class TooltipManager
{
private final Client client;
private final List<Overlay> overlays = new ArrayList<>();
@Getter
private final List<Tooltip> tooltips = new ArrayList<>();
public DynamicRenderer(Client client)
public void add(Tooltip tooltip)
{
this.client = client;
tooltips.add(tooltip);
}
public void add(Overlay overlay)
public void clear()
{
overlays.add(overlay);
tooltips.clear();
}
@Override
public void render(BufferedImage clientBuffer)
{
for (Overlay overlay : overlays)
{
if (!overlay.shouldDraw(client))
continue;
Graphics2D graphics = clientBuffer.createGraphics();
Renderer.setAntiAliasing(graphics);
overlay.render(graphics);
graphics.dispose();
}
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright (c) 2017, Tomas Slusny <slusnucky@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.ui.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<Client> clientProvider;
@Inject
public TooltipOverlay(TooltipManager tooltipManager, Provider<Client> clientProvider)
{
setPosition(OverlayPosition.DYNAMIC);
setPriority(OverlayPriority.HIGH);
this.tooltipManager = tooltipManager;
this.clientProvider = clientProvider;
}
@Override
public Dimension render(Graphics2D graphics, Point parent)
{
List<Tooltip> 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;
}
}

View File

@@ -1,181 +0,0 @@
/*
* Copyright (c) 2017, Tyler <https://github.com/tylerthardy>
* 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("</br>");
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);
}
}
}