diff --git a/runelite-client/src/main/java/net/runelite/client/RuneLite.java b/runelite-client/src/main/java/net/runelite/client/RuneLite.java index dc28b8fbe1..28b253dcd1 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -56,6 +56,7 @@ import net.runelite.client.ui.ClientUI; import net.runelite.client.ui.DrawManager; import net.runelite.client.ui.TitleToolbar; import net.runelite.client.ui.overlay.OverlayRenderer; +import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import org.slf4j.LoggerFactory; import org.slf4j.MDC; @@ -120,6 +121,9 @@ public class RuneLite @Inject private ClanManager clanManager; + @Inject + private InfoBoxManager infoBoxManager; + Client client; public static void main(String[] args) throws Exception @@ -214,6 +218,7 @@ public class RuneLite eventBus.register(commandManager); eventBus.register(pluginManager); eventBus.register(clanManager); + eventBus.register(infoBoxManager); if (this.client != null) { diff --git a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java index d582ad81d8..43081bba9a 100644 --- a/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java +++ b/runelite-client/src/main/java/net/runelite/client/config/RuneLiteConfig.java @@ -221,4 +221,15 @@ public interface RuneLiteConfig extends Config { return 4; } + + @ConfigItem( + keyName = "infoBoxSize", + name = "Infobox size (px)", + description = "Configures the size of each infobox in pixels", + position = 34 + ) + default int infoBoxSize() + { + return 35; + } } \ No newline at end of file diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerCounter.java b/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerCounter.java index 07a2bdea97..c2793674be 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerCounter.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/prayer/PrayerCounter.java @@ -24,9 +24,7 @@ */ package net.runelite.client.plugins.prayer; -import java.awt.image.BufferedImage; import lombok.Getter; -import lombok.Setter; import net.runelite.client.plugins.Plugin; import net.runelite.client.ui.overlay.infobox.Counter; @@ -35,9 +33,6 @@ public class PrayerCounter extends Counter @Getter private final PrayerType prayerType; - @Setter - private BufferedImage image; - PrayerCounter(Plugin plugin, PrayerType prayerType) { super(null, plugin, ""); @@ -55,10 +50,4 @@ public class PrayerCounter extends Counter { return prayerType.getDescription(); } - - @Override - public BufferedImage getImage() - { - return image; - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerRenderable.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerRenderable.java index 32b74630d1..0d44e01345 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerRenderable.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerRenderable.java @@ -27,6 +27,7 @@ package net.runelite.client.plugins.screenmarkers; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.Stroke; import lombok.AccessLevel; import lombok.Getter; @@ -36,6 +37,10 @@ import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity; public class ScreenMarkerRenderable implements LayoutableRenderableEntity { @Getter(AccessLevel.PACKAGE) + @Setter + private Point preferredLocation; + @Getter(AccessLevel.PACKAGE) + @Setter private Dimension preferredSize; @Getter(AccessLevel.PACKAGE) @Setter(AccessLevel.PACKAGE) @@ -69,10 +74,4 @@ public class ScreenMarkerRenderable implements LayoutableRenderableEntity graphics.drawRect(offset, offset, width - thickness, height - thickness); return preferredSize; } - - @Override - public void setPreferredSize(Dimension preferredSize) - { - this.preferredSize = preferredSize; - } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java index 24db80a9ee..51c1e242ec 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/xpglobes/XpGlobesOverlay.java @@ -231,7 +231,7 @@ public class XpGlobesOverlay extends Overlay String skillCurrentXp = decimalFormat.format(mouseOverSkill.getCurrentXp()); xpTooltip.getChildren().clear(); - graphics.translate(x, y); + xpTooltip.setPreferredLocation(new java.awt.Point(x, y)); xpTooltip.setPreferredSize(new Dimension(TOOLTIP_RECT_SIZE_X, 0)); xpTooltip.getChildren().add(LineComponent.builder() @@ -286,6 +286,5 @@ public class XpGlobesOverlay extends Overlay } xpTooltip.render(graphics); - graphics.translate(-x, -y); } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ImageComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ImageComponent.java index 4eef508b39..05ddc35395 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ImageComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ImageComponent.java @@ -26,15 +26,17 @@ package net.runelite.client.ui.overlay.components; import java.awt.Dimension; import java.awt.Graphics2D; +import java.awt.Point; import java.awt.image.BufferedImage; -import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; import lombok.Setter; -@AllArgsConstructor +@RequiredArgsConstructor @Setter public class ImageComponent implements LayoutableRenderableEntity { - private BufferedImage image; + private final BufferedImage image; + private Point preferredLocation = new Point(); @Override public Dimension render(Graphics2D graphics) @@ -44,7 +46,7 @@ public class ImageComponent implements LayoutableRenderableEntity return null; } - graphics.drawImage(image, 0, -graphics.getFontMetrics().getHeight(), null); + graphics.drawImage(image, preferredLocation.x, preferredLocation.y, null); return new Dimension(image.getWidth(), image.getHeight()); } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/InfoBoxComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/InfoBoxComponent.java index 0414dd1b3a..ca6c55d3be 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/InfoBoxComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/InfoBoxComponent.java @@ -28,49 +28,80 @@ import java.awt.Color; 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.awt.image.BufferedImage; -import java.util.Objects; +import lombok.Getter; import lombok.Setter; -import net.runelite.client.ui.overlay.RenderableEntity; +import net.runelite.client.ui.FontManager; @Setter -public class InfoBoxComponent implements RenderableEntity +public class InfoBoxComponent implements LayoutableRenderableEntity { - private static final int BOX_SIZE = 35; - private static final int SEPARATOR = 2; + private static final int SEPARATOR = 3; + private static final int DEFAULT_SIZE = 32; + + @Getter + private String tooltip; + + @Getter + private Point preferredLocation = new Point(); + + @Setter + private Dimension preferredSize = new Dimension(DEFAULT_SIZE, DEFAULT_SIZE); private String text; private Color color = Color.WHITE; private Color backgroundColor = ComponentConstants.STANDARD_BACKGROUND_COLOR; - private Point position = new Point(); - private BufferedImage image; + private Image image; @Override public Dimension render(Graphics2D graphics) { + if (image == null) + { + return new Dimension(); + } + + graphics.setFont(getSize() < DEFAULT_SIZE ? FontManager.getRunescapeSmallFont() : FontManager.getRunescapeFont()); + graphics.translate(preferredLocation.x, preferredLocation.y); + + // Calculate dimensions final FontMetrics metrics = graphics.getFontMetrics(); - final Rectangle bounds = new Rectangle(position.x, position.y, BOX_SIZE, BOX_SIZE); + final int size = getSize(); + final Rectangle bounds = new Rectangle(size, size); + + // Render background final BackgroundComponent backgroundComponent = new BackgroundComponent(); backgroundComponent.setBackgroundColor(backgroundColor); backgroundComponent.setRectangle(bounds); backgroundComponent.render(graphics); - if (Objects.nonNull(image)) - { - graphics.drawImage(image, - position.x + (BOX_SIZE - image.getWidth()) / 2, - position.y + (BOX_SIZE - image.getHeight()) / 2, null); - } + // Render image + graphics.drawImage( + image, + (size - image.getWidth(null)) / 2, + (size - image.getHeight(null)) / 2, + null); + // Render caption final TextComponent textComponent = new TextComponent(); textComponent.setColor(color); textComponent.setText(text); - textComponent.setPosition(new Point( - position.x + ((BOX_SIZE - metrics.stringWidth(text)) / 2), - position.y + BOX_SIZE - SEPARATOR)); + textComponent.setPosition(new Point(((size - metrics.stringWidth(text)) / 2), size - SEPARATOR)); textComponent.render(graphics); - return new Dimension(BOX_SIZE, BOX_SIZE); + + graphics.translate(-preferredLocation.x, -preferredLocation.y); + return bounds.getSize(); + } + + public Dimension getPreferredSize() + { + return new Dimension(getSize(), getSize()); + } + + private int getSize() + { + return Math.max(preferredSize.width, preferredSize.height); } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LayoutableRenderableEntity.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LayoutableRenderableEntity.java index b717f58706..ba7f1e7717 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LayoutableRenderableEntity.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LayoutableRenderableEntity.java @@ -25,9 +25,11 @@ package net.runelite.client.ui.overlay.components; import java.awt.Dimension; +import java.awt.Point; import net.runelite.client.ui.overlay.RenderableEntity; public interface LayoutableRenderableEntity extends RenderableEntity { + void setPreferredLocation(Point position); void setPreferredSize(Dimension dimension); } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java index ea0ff656f6..a76d20f3d6 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/LineComponent.java @@ -47,19 +47,23 @@ public class LineComponent implements LayoutableRenderableEntity @Builder.Default private Color rightColor = Color.WHITE; + @Builder.Default + private Point preferredLocation = new Point(); + @Builder.Default private Dimension preferredSize = new Dimension(ComponentConstants.STANDARD_WIDTH, 0); @Override public Dimension render(Graphics2D graphics) { + graphics.translate(preferredLocation.x, preferredLocation.y); // Prevent NPEs final String left = MoreObjects.firstNonNull(this.left, ""); final String right = MoreObjects.firstNonNull(this.right, ""); final FontMetrics metrics = graphics.getFontMetrics(); int x = 0; - int y = 0; + int y = metrics.getHeight(); final int leftFullWidth = getLineWidth(left, metrics); final int rightFullWidth = getLineWidth(right, metrics); @@ -108,7 +112,8 @@ public class LineComponent implements LayoutableRenderableEntity y += metrics.getHeight(); } - return new Dimension(preferredSize.width, y); + graphics.translate(-preferredLocation.x, -preferredLocation.y); + return new Dimension(preferredSize.width, y - metrics.getHeight()); } final TextComponent leftLineComponent = new TextComponent(); @@ -124,7 +129,8 @@ public class LineComponent implements LayoutableRenderableEntity rightLineComponent.render(graphics); y += metrics.getHeight(); - return new Dimension(preferredSize.width, y); + graphics.translate(-preferredLocation.x, -preferredLocation.y); + return new Dimension(preferredSize.width, y - metrics.getHeight()); } private static int getLineWidth(final String line, final FontMetrics metrics) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java index 2c7a09cafa..974ec37240 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/PanelComponent.java @@ -26,12 +26,12 @@ 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.ArrayList; import java.util.List; +import javax.annotation.Nullable; import lombok.Getter; import lombok.Setter; @@ -44,8 +44,12 @@ public class PanelComponent implements LayoutableRenderableEntity } @Setter + @Nullable private Color backgroundColor = ComponentConstants.STANDARD_BACKGROUND_COLOR; + @Setter + private Point preferredLocation = new Point(); + @Setter private Dimension preferredSize = new Dimension(ComponentConstants.STANDARD_WIDTH, 0); @@ -55,6 +59,9 @@ public class PanelComponent implements LayoutableRenderableEntity @Setter private Orientation orientation = Orientation.VERTICAL; + @Setter + private int wrapping = -1; + @Setter private Rectangle border = new Rectangle( ComponentConstants.STANDARD_BORDER, @@ -75,21 +82,25 @@ public class PanelComponent implements LayoutableRenderableEntity return null; } - final FontMetrics metrics = graphics.getFontMetrics(); + graphics.translate(preferredLocation.x, preferredLocation.y); - // Render background + // Calculate panel dimension final Dimension dimension = new Dimension( border.x + childDimensions.width + border.width, border.y + childDimensions.height + border.height); - final BackgroundComponent backgroundComponent = new BackgroundComponent(); - backgroundComponent.setRectangle(new Rectangle(dimension)); - backgroundComponent.setBackgroundColor(backgroundColor); - backgroundComponent.render(graphics); + // Render background + if (backgroundColor != null) + { + final BackgroundComponent backgroundComponent = new BackgroundComponent(); + backgroundComponent.setRectangle(new Rectangle(dimension)); + backgroundComponent.setBackgroundColor(backgroundColor); + backgroundComponent.render(graphics); + } // Offset children final int baseX = border.x; - final int baseY = border.y + metrics.getHeight(); + final int baseY = border.y; int width = 0; int height = 0; int x = baseX; @@ -100,13 +111,17 @@ public class PanelComponent implements LayoutableRenderableEntity preferredSize.width - border.x - border.width, preferredSize.height - border.y - border.height); + // Calculate max width/height for infoboxes + int totalHeight = 0; + int totalWidth = 0; + // Render all children - for (final LayoutableRenderableEntity child : children) + for (int i = 0; i < children.size(); i ++) { + final LayoutableRenderableEntity child = children.get(i); + child.setPreferredLocation(new Point(x, y)); child.setPreferredSize(childPreferredSize); - graphics.translate(x, y); final Dimension childDimension = child.render(graphics); - graphics.translate(-x, -y); switch (orientation) { @@ -121,15 +136,45 @@ public class PanelComponent implements LayoutableRenderableEntity height = Math.max(height, childDimension.height); break; } + + // Calculate total size + totalWidth = Math.max(totalWidth, width); + totalHeight = Math.max(totalHeight, height); + + if (wrapping > 0 && i < children.size() - 1 && (i + 1) % wrapping == 0) + { + switch (orientation) + { + case VERTICAL: + { + height = 0; + y = baseY; + int diff = childDimension.width + gap.x; + x += diff; + width += diff; + break; + } + case HORIZONTAL: + { + width = 0; + x = baseX; + int diff = childDimension.height + gap.y; + y += diff; + height += diff; + break; + } + } + } } // Remove last child gap - width -= gap.x; - height -= gap.y; + totalWidth -= gap.x; + totalHeight -= gap.y; // Cache children bounds - childDimensions.setSize(width, height); + childDimensions.setSize(totalWidth, totalHeight); + graphics.translate(-preferredLocation.x, -preferredLocation.y); return dimension; } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java index dc61f9c4ec..d60e25bf69 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/ProgressBarComponent.java @@ -50,15 +50,17 @@ public class ProgressBarComponent implements LayoutableRenderableEntity private Color foregroundColor = new Color(82, 161, 82); private Color backgroundColor = new Color(255, 255, 255, 127); private Color fontColor = Color.WHITE; + private Point preferredLocation = new Point(); private Dimension preferredSize = new Dimension(ComponentConstants.STANDARD_WIDTH, 16); @Override public Dimension render(Graphics2D graphics) { + graphics.translate(preferredLocation.x, preferredLocation.y); final FontMetrics metrics = graphics.getFontMetrics(); final int barX = 0; - final int barY = -metrics.getHeight(); + final int barY = 0; final long span = maximum - minimum; final double currentValue = value - minimum; @@ -92,6 +94,7 @@ public class ProgressBarComponent implements LayoutableRenderableEntity textComponent.setText(textToWrite); textComponent.render(graphics); + graphics.translate(-preferredLocation.x, -preferredLocation.y); return new Dimension(width, height); } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TitleComponent.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TitleComponent.java index 6cc2341916..d808fa8d6b 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TitleComponent.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/components/TitleComponent.java @@ -41,18 +41,23 @@ public class TitleComponent implements LayoutableRenderableEntity @Builder.Default private Color color = Color.WHITE; + @Builder.Default + private Point preferredLocation = new Point(); + @Builder.Default private Dimension preferredSize = new Dimension(ComponentConstants.STANDARD_WIDTH, 0); @Override public Dimension render(Graphics2D graphics) { + graphics.translate(preferredLocation.x, preferredLocation.y); final FontMetrics metrics = graphics.getFontMetrics(); final TextComponent titleComponent = new TextComponent(); titleComponent.setText(text); titleComponent.setColor(color); - titleComponent.setPosition(new Point((preferredSize.width - metrics.stringWidth(text)) / 2, 0)); + titleComponent.setPosition(new Point((preferredSize.width - metrics.stringWidth(text)) / 2, metrics.getHeight())); final Dimension dimension = titleComponent.render(graphics); + graphics.translate(-preferredLocation.x, -preferredLocation.y); return new Dimension(Math.min(preferredSize.width, dimension.width), dimension.height); } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBox.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBox.java index a3668a7ed9..fc498d3635 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBox.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBox.java @@ -25,36 +25,39 @@ package net.runelite.client.ui.overlay.infobox; import java.awt.Color; -import java.awt.image.BufferedImage; +import java.awt.Image; import lombok.Getter; import lombok.Setter; import net.runelite.client.plugins.Plugin; public abstract class InfoBox { - private final BufferedImage image; - @Getter private final Plugin plugin; + @Getter + @Setter + private Image image; + + @Getter + @Setter + private Image scaledImage; + @Getter @Setter private InfoBoxPriority priority; + @Getter + @Setter private String tooltip; - public InfoBox(BufferedImage image, Plugin plugin) + public InfoBox(Image image, Plugin plugin) { - this.image = image; this.plugin = plugin; + setImage(image); setPriority(InfoBoxPriority.NONE); } - public BufferedImage getImage() - { - return image; - } - public abstract String getText(); public abstract Color getTextColor(); @@ -68,14 +71,4 @@ public abstract class InfoBox { return false; } - - public String getTooltip() - { - return tooltip; - } - - public void setTooltip(String tooltip) - { - this.tooltip = tooltip; - } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxManager.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxManager.java index e07bc84832..0e9919af12 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxManager.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxManager.java @@ -26,13 +26,20 @@ package net.runelite.client.ui.overlay.infobox; import com.google.common.base.Preconditions; import com.google.common.collect.ComparisonChain; +import com.google.common.eventbus.Subscribe; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.function.Predicate; +import javax.inject.Inject; import javax.inject.Singleton; import lombok.extern.slf4j.Slf4j; +import net.runelite.api.events.ConfigChanged; +import net.runelite.client.config.RuneLiteConfig; import net.runelite.client.plugins.PluginDescriptor; @Singleton @@ -40,13 +47,30 @@ import net.runelite.client.plugins.PluginDescriptor; public class InfoBoxManager { private final List infoBoxes = new ArrayList<>(); + private final RuneLiteConfig runeLiteConfig; + + @Inject + private InfoBoxManager(final RuneLiteConfig runeLiteConfig) + { + this.runeLiteConfig = runeLiteConfig; + } + + @Subscribe + public void onConfigChanged(ConfigChanged event) + { + if (event.getGroup().equals("runelite") && event.getKey().equals("infoBoxSize")) + { + infoBoxes.forEach(this::updateInfoBoxImage); + } + } public void addInfoBox(InfoBox infoBox) { Preconditions.checkNotNull(infoBox); log.debug("Adding InfoBox {}", infoBox); - infoBoxes.add(infoBox); + updateInfoBoxImage(infoBox); + infoBoxes.add(infoBox); refreshInfoBoxes(); } @@ -92,6 +116,43 @@ public class InfoBoxManager } } + private void updateInfoBoxImage(final InfoBox infoBox) + { + if (infoBox.getImage() == null) + { + return; + } + + // Set scaled InfoBox image + final Image image = infoBox.getImage(); + Image resultImage = image; + final double width = image.getWidth(null); + final double height = image.getHeight(null); + final double size = Math.max(2, runeLiteConfig.infoBoxSize()); // Limit size to 2 as that is minimum size not causing breakage + + if (size < width || size < height) + { + final double scalex = size / width; + final double scaley = size / height; + + if (scalex == 1 && scaley == 1) + { + return; + } + + final double scale = Math.min(scalex, scaley); + final int newWidth = (int) (width * scale); + final int newHeight = (int) (height * scale); + final BufferedImage scaledImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_ARGB); + final Graphics g = scaledImage.createGraphics(); + g.drawImage(image, 0, 0, newWidth, newHeight, null); + g.dispose(); + resultImage = scaledImage; + } + + infoBox.setScaledImage(resultImage); + } + private void refreshInfoBoxes() { Collections.sort(infoBoxes, (b1, b2) -> ComparisonChain diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java index 7005b32afe..40f2315380 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/infobox/InfoBoxOverlay.java @@ -39,15 +39,14 @@ import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayUtil; import net.runelite.client.ui.overlay.components.InfoBoxComponent; +import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity; +import net.runelite.client.ui.overlay.components.PanelComponent; 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 int TOTAL_BOXSIZE = BOXSIZE + SEPARATOR; - + private final PanelComponent panelComponent = new PanelComponent(); private final InfoBoxManager infoboxManager; private final TooltipManager tooltipManager; private final Provider clientProvider; @@ -65,108 +64,73 @@ public class InfoBoxOverlay extends Overlay this.clientProvider = clientProvider; this.config = config; setPosition(OverlayPosition.TOP_LEFT); + + panelComponent.setBackgroundColor(null); + panelComponent.setBorder(new Rectangle()); + panelComponent.setGap(new Point(1, 1)); } @Override public Dimension render(Graphics2D graphics) { - List infoBoxes = infoboxManager.getInfoBoxes(); + final List infoBoxes = infoboxManager.getInfoBoxes(); if (infoBoxes.isEmpty()) { return null; } - int wrap = config.infoBoxWrap(); - int infoBoxCount = infoBoxes.size(); - boolean vertical = config.infoBoxVertical(); + panelComponent.getChildren().clear(); + panelComponent.setWrapping(config.infoBoxWrap()); + panelComponent.setOrientation(config.infoBoxVertical() + ? PanelComponent.Orientation.VERTICAL + : PanelComponent.Orientation.HORIZONTAL); + panelComponent.setPreferredSize(new Dimension(config.infoBoxSize(), config.infoBoxSize())); - int width, height; - if (!vertical) + infoBoxes.forEach(box -> { - width = getWidth(infoBoxCount, wrap); - height = getHeight(infoBoxCount, wrap); - } - else - { - width = getHeight(infoBoxCount, wrap); - height = getWidth(infoBoxCount, wrap); - } - - int x = 0; - int y = 0; - - for (InfoBox box : infoBoxes) - { - if (!box.render()) - { - continue; - } - - final InfoBoxComponent infoBoxComponent = new InfoBoxComponent(); infoBoxComponent.setColor(box.getTextColor()); - infoBoxComponent.setImage(box.getImage()); + infoBoxComponent.setImage(box.getScaledImage()); infoBoxComponent.setText(box.getText()); - infoBoxComponent.setPosition(new Point(x, y)); - final Dimension infoBoxBounds = infoBoxComponent.render(graphics); + infoBoxComponent.setTooltip(box.getTooltip()); + panelComponent.getChildren().add(infoBoxComponent); + }); - if (!Strings.isNullOrEmpty(box.getTooltip())) + final Dimension dimension = panelComponent.render(graphics); + final Client client = clientProvider.get(); + + // Handle tooltips + if (client != null) + { + final Point mouse = new Point(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY()); + + for (final LayoutableRenderableEntity child : panelComponent.getChildren()) { - final Rectangle intersectionRectangle = new Rectangle(infoBoxBounds); - intersectionRectangle.setLocation(getBounds().getLocation()); - intersectionRectangle.translate(x, y); - final Point transformed = OverlayUtil.transformPosition(getPosition(), intersectionRectangle.getSize()); - intersectionRectangle.translate(transformed.x, transformed.y); + if (child instanceof InfoBoxComponent) + { + final InfoBoxComponent component = (InfoBoxComponent) child; - final Client client = clientProvider.get(); + if (!Strings.isNullOrEmpty(component.getTooltip())) + { + final Rectangle intersectionRectangle = new Rectangle(component.getPreferredLocation(), component.getPreferredSize()); - if (client != null && intersectionRectangle.contains(new Point(client.getMouseCanvasPosition().getX(), - client.getMouseCanvasPosition().getY()))) - { - tooltipManager.add(new Tooltip(box.getTooltip())); - } - } + // Move the intersection based on overlay position + intersectionRectangle.translate(getBounds().x, getBounds().y); - // Determine which axis to reset/increase - if (vertical) - { - // Reset y if newbox reaches height limit - if (y + TOTAL_BOXSIZE < height) - { - y += TOTAL_BOXSIZE; - } - else - { - y = 0; - x += TOTAL_BOXSIZE; - } - } - else - { - // Reset x if newbox reaches width limit - if (x + TOTAL_BOXSIZE < width) - { - x += TOTAL_BOXSIZE; - } - else - { - x = 0; - y += TOTAL_BOXSIZE; + // Move the intersection based on overlay "orientation" + final Point transformed = OverlayUtil.transformPosition(getPosition(), intersectionRectangle.getSize()); + intersectionRectangle.translate(transformed.x, transformed.y); + + if (intersectionRectangle.contains(mouse)) + { + tooltipManager.add(new Tooltip(component.getTooltip())); + } + } } } } - return new Dimension(width, height); - } - - private static int getHeight(int infoBoxCount, int maxRow) - { - return maxRow == 0 ? TOTAL_BOXSIZE : (int) Math.ceil((double)infoBoxCount / maxRow) * TOTAL_BOXSIZE; - } - - private static int getWidth(int infoBoxCount, int maxRow) - { - return maxRow == 0 ? infoBoxCount * TOTAL_BOXSIZE : (maxRow > infoBoxCount ? infoBoxCount : maxRow) * TOTAL_BOXSIZE; + return dimension; } }