diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java index 60b984f66d..3d6fae9bd7 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsConfig.java @@ -26,6 +26,7 @@ package net.runelite.client.plugins.grounditems; import java.awt.Color; +import net.runelite.client.config.Alpha; import net.runelite.client.config.Config; import net.runelite.client.config.ConfigGroup; import net.runelite.client.config.ConfigItem; @@ -57,6 +58,7 @@ public interface GroundItemsConfig extends Config position = 2, parent = "colorsStub" ) + @Alpha default Color defaultColor() { return Color.WHITE; @@ -69,6 +71,7 @@ public interface GroundItemsConfig extends Config position = 3, parent = "colorsStub" ) + @Alpha default Color highlightedColor() { return Color.decode("#AA00FF"); @@ -81,6 +84,7 @@ public interface GroundItemsConfig extends Config position = 4, parent = "colorsStub" ) + @Alpha default Color hiddenColor() { return Color.GRAY; @@ -319,6 +323,7 @@ public interface GroundItemsConfig extends Config position = 23, parent = "lowValueStub" ) + @Alpha default Color lowValueColor() { return Color.decode("#66B2FF"); @@ -366,6 +371,7 @@ public interface GroundItemsConfig extends Config position = 27, parent = "mediumValueStub" ) + @Alpha default Color mediumValueColor() { return Color.decode("#99FF99"); @@ -413,6 +419,7 @@ public interface GroundItemsConfig extends Config position = 31, parent = "highValueStub" ) + @Alpha default Color highValueColor() { return Color.decode("#FF9600"); @@ -460,6 +467,7 @@ public interface GroundItemsConfig extends Config position = 35, parent = "insaneValueStub" ) + @Alpha default Color insaneValueColor() { return Color.decode("#FF66B2"); @@ -618,4 +626,16 @@ public interface GroundItemsConfig extends Config { return false; } + + @Alpha + @ConfigItem( + keyName = "bordercolor", + name = "Border color", + description = "Change the border color", + position = 49 + ) + default Color bordercolor() + { + return new Color(0, 0, 0, 150); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java index cc192e334b..f9ce93dad6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsOverlay.java @@ -109,8 +109,6 @@ public class GroundItemsOverlay extends Overlay { return null; } - - final FontMetrics fm = graphics.getFontMetrics(); final Player player = client.getLocalPlayer(); if (player == null || client.getViewportWidget() == null) @@ -118,6 +116,8 @@ public class GroundItemsOverlay extends Overlay return null; } + final FontMetrics fm = graphics.getFontMetrics(); + offsetMap.clear(); final LocalPoint localLocation = player.getLocalLocation(); final Point mousePos = client.getMouseCanvasPosition(); @@ -376,7 +376,8 @@ public class GroundItemsOverlay extends Overlay if (config.toggleOutline()) { - graphics.setColor(Color.BLACK); + final Color bordercolor = config.bordercolor(); + graphics.setColor(bordercolor); graphics.drawString(itemString, textX + 1, textY + 1); graphics.drawString(itemString, textX - 1, textY - 1); graphics.drawString(itemString, textX - 1, textY + 1); @@ -388,7 +389,6 @@ public class GroundItemsOverlay extends Overlay textComponent.setPosition(new java.awt.Point(textX, textY)); textComponent.render(graphics); } - return null; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java index 41c24e5c0a..0754a4616f 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/grounditems/GroundItemsPlugin.java @@ -124,6 +124,7 @@ public class GroundItemsPlugin extends Plugin private static final int EXAMINE_ITEM = MenuAction.EXAMINE_ITEM_GROUND.getId(); private static final int WALK = MenuAction.WALK.getId(); + @Getter(AccessLevel.PACKAGE) @Setter(AccessLevel.PACKAGE) private Map.Entry textBoxBounds; diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java index 98532a8d7c..fba19f5013 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TextComponent.java @@ -24,11 +24,15 @@ */ package net.runelite.client.ui.overlay.components; +import java.awt.AlphaComposite; import java.awt.Color; +import java.awt.Composite; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Point; +import java.awt.Shape; +import java.awt.font.GlyphVector; import java.util.regex.Pattern; import lombok.Setter; import net.runelite.client.ui.overlay.RenderableEntity; @@ -43,6 +47,7 @@ public class TextComponent implements RenderableEntity private String text; private Point position = new Point(); private Color color = Color.WHITE; + private Color borderColor = Color.BLACK; public static String textWithoutColTags(String text) { @@ -64,28 +69,43 @@ public class TextComponent implements RenderableEntity final String textWithoutCol = textWithoutColTags(textSplitOnCol); final String colColor = textSplitOnCol.substring(textSplitOnCol.indexOf("=") + 1, textSplitOnCol.indexOf(">")); - // shadow - graphics.setColor(Color.BLACK); - graphics.drawString(textWithoutCol, x + 1, position.y + 1); - - // actual text - graphics.setColor(Color.decode("#" + colColor)); - graphics.drawString(textWithoutCol, x, position.y); + renderText(graphics, x, position.y, textWithoutCol, Color.decode("#" + colColor), borderColor); x += fontMetrics.stringWidth(textWithoutCol); } } else { - // shadow - graphics.setColor(Color.BLACK); - graphics.drawString(text, position.x + 1, position.y + 1); - - // actual text - graphics.setColor(color); - graphics.drawString(text, position.x, position.y); + renderText(graphics, position.x, position.y, text, color, borderColor); } - return new Dimension(fontMetrics.stringWidth(text), fontMetrics.getHeight()); } + + private void renderText(Graphics2D graphics, int x, int y, String text, Color color, Color border) + { + // remember previous composite + Composite originalComposite = graphics.getComposite(); + + // create a vector of the text + GlyphVector vector = graphics.getFont().createGlyphVector(graphics.getFontRenderContext(), text); + + // compute the text shape + Shape stroke = vector.getOutline(x + 1, y + 1); + Shape shape = vector.getOutline(x, y); + + // draw text border + graphics.setColor(border); + graphics.fill(stroke); + + // replace the pixels instead of overlaying + graphics.setComposite(AlphaComposite.Src); + + // draw actual text + graphics.setColor(color); + graphics.fill(shape); + + // reset composite to original + graphics.setComposite(originalComposite); + } + } diff --git a/runelite-client/src/test/java/net/runelite/client/ui/overlay/components/TextComponentTest.java b/runelite-client/src/test/java/net/runelite/client/ui/overlay/components/TextComponentTest.java index 45c859a4a7..f1677daa4b 100644 --- a/runelite-client/src/test/java/net/runelite/client/ui/overlay/components/TextComponentTest.java +++ b/runelite-client/src/test/java/net/runelite/client/ui/overlay/components/TextComponentTest.java @@ -25,33 +25,24 @@ package net.runelite.client.ui.overlay.components; import java.awt.Color; -import java.awt.FontMetrics; import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.junit.runner.RunWith; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.eq; -import org.mockito.Mock; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import org.mockito.runners.MockitoJUnitRunner; -@RunWith(MockitoJUnitRunner.class) public class TextComponentTest { - @Mock private Graphics2D graphics; - + private BufferedImage dest; + @Before public void before() { - when(graphics.getFontMetrics()).thenReturn(mock(FontMetrics.class)); + dest = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); + graphics = (Graphics2D) dest.getGraphics(); } - + @Test public void testRender() { @@ -59,29 +50,29 @@ public class TextComponentTest textComponent.setText("test"); textComponent.setColor(Color.RED); textComponent.render(graphics); - verify(graphics, times(2)).drawString(eq("test"), anyInt(), anyInt()); - verify(graphics, atLeastOnce()).setColor(Color.RED); } - + @Test public void testRender2() { TextComponent textComponent = new TextComponent(); textComponent.setText("test"); textComponent.render(graphics); - verify(graphics, times(2)).drawString(eq("test"), anyInt(), anyInt()); - verify(graphics, atLeastOnce()).setColor(Color.BLUE); } - + @Test public void testRender3() { TextComponent textComponent = new TextComponent(); textComponent.setText("test test"); textComponent.render(graphics); - verify(graphics, atLeastOnce()).drawString(eq("test"), anyInt(), anyInt()); - verify(graphics, atLeastOnce()).drawString(eq(" test"), anyInt(), anyInt()); - verify(graphics, atLeastOnce()).setColor(Color.BLUE); - verify(graphics, atLeastOnce()).setColor(Color.GREEN); } + + @After + public void after() + { + graphics.dispose(); + dest.flush(); + } + }