From 70a2e41db0187cba6ab3fcd08e7d71c74ed63ecd Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 12 Dec 2020 16:15:17 -0500 Subject: [PATCH] Allow overlay renderer to restrict overlay parent bounds This removes the hack of double setting the widget position in WidgetOverlay, which was required to override the overlay renderers clamping code in both overlay drag and in overlay rendering. --- .../runelite/client/ui/overlay/Overlay.java | 11 ++++ .../client/ui/overlay/OverlayRenderer.java | 57 +++++++++++++------ .../client/ui/overlay/WidgetOverlay.java | 54 ++++++------------ 3 files changed, 69 insertions(+), 53 deletions(-) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java index 303b423a6a..405fe28080 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/Overlay.java @@ -97,4 +97,15 @@ public abstract class Overlay implements LayoutableRenderableEntity { return false; } + + /** + * Get the parent bounds for overlay dragging. The overlay will + * not be allowed to be moved outside of the parent bounds. + * @return + */ + @Nullable + public Rectangle getParentBounds() + { + return null; + } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java index d2a4e135a2..6b6c01add2 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayRenderer.java @@ -246,11 +246,14 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener } else { - final Point location = overlay.getBounds().getLocation(); - final Dimension dimension = overlay.getBounds().getSize(); + final Rectangle bounds = overlay.getBounds(); + final Point location = bounds.getLocation(); + final Dimension dimension = bounds.getSize(); + + final Point preferredLocation = overlay.getPreferredLocation(); // If the final position is not modified, layout it - if (overlayPosition != OverlayPosition.DETACHED && (overlay.getPreferredLocation() == null || overlay.getPreferredPosition() != null)) + if (overlayPosition != OverlayPosition.DETACHED && (preferredLocation == null || overlay.getPreferredPosition() != null)) { final Rectangle snapCorner = snapCorners.forPosition(overlayPosition); final Point translation = OverlayUtil.transformPosition(overlayPosition, dimension); @@ -260,21 +263,18 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener } else { - final Point preferredLocation = overlay.getPreferredLocation(); - if (preferredLocation != null) { location.setLocation(preferredLocation); } - final Dimension realDimensions = client.getRealDimensions(); - location.x = Ints.constrainToRange(location.x, 0, Math.max(0, realDimensions.width - dimension.width)); - location.y = Ints.constrainToRange(location.y, 0, Math.max(0, realDimensions.height - dimension.height)); + // Clamp the overlay position to ensure it is on screen or within parent bounds + clampOverlayLocation(location, dimension.width, dimension.height, overlay); } if (overlay.getPreferredSize() != null) { - overlay.getBounds().setSize(overlay.getPreferredSize()); + bounds.setSize(overlay.getPreferredSize()); } safeRender(client, overlay, layer, graphics, location); @@ -287,8 +287,6 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener graphics.setRenderingHints(renderingHints); graphics.setBackground(background); - final Rectangle bounds = overlay.getBounds(); - if (!bounds.isEmpty()) { if (inOverlayManagingMode) @@ -583,12 +581,14 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener } else if (inOverlayDraggingMode) { - final Dimension realDimension = client.getRealDimensions(); - p.translate(-overlayOffset.x, -overlayOffset.y); - p.x = Ints.constrainToRange(p.x, 0, Math.max(0, realDimension.width - currentManagedOverlay.getBounds().width)); - p.y = Ints.constrainToRange(p.y, 0, Math.max(0, realDimension.height - currentManagedOverlay.getBounds().height)); + Point overlayPosition = new Point(p); + overlayPosition.translate(-overlayOffset.x, -overlayOffset.y); // adjust by mouse offset to get overlay position + + // Clamp drag to parent component + final Rectangle overlayBounds = currentManagedOverlay.getBounds(); + clampOverlayLocation(overlayPosition, overlayBounds.width, overlayBounds.height, currentManagedOverlay); currentManagedOverlay.setPreferredPosition(null); - currentManagedOverlay.setPreferredLocation(p); + currentManagedOverlay.setPreferredLocation(overlayPosition); } else { @@ -887,4 +887,29 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener return entries; } + + /** + * Adjust the given overlay position to be within its parent's bounds. + * + * @param overlayPosition the overlay position, which is modified in place + * @param overlayWidth + * @param overlayHeight + * @param overlay the overlay + */ + private void clampOverlayLocation(Point overlayPosition, int overlayWidth, int overlayHeight, Overlay overlay) + { + Rectangle parentBounds = overlay.getParentBounds(); + if (parentBounds == null || parentBounds.isEmpty()) + { + // If no bounds are set, use the full client bounds + Dimension dim = client.getRealDimensions(); + parentBounds = new Rectangle(0, 0, dim.width, dim.height); + } + + // Constrain overlay position to be within the parent bounds + overlayPosition.x = Ints.constrainToRange(overlayPosition.x, parentBounds.x, + Math.max(parentBounds.x, parentBounds.width - overlayWidth)); + overlayPosition.y = Ints.constrainToRange(overlayPosition.y, parentBounds.y, + Math.max(parentBounds.y, parentBounds.height - overlayHeight)); + } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java index 468f195519..d5f57d6590 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/WidgetOverlay.java @@ -88,32 +88,10 @@ public class WidgetOverlay extends Overlay return Objects.toString(widgetInfo); } - @Override - public Rectangle getBounds() - { - final Rectangle bounds = super.getBounds(); - final Rectangle parent = getParentBounds(client.getWidget(widgetInfo)); - - if (parent.isEmpty()) - { - return bounds; - } - - int x = bounds.x; - int y = bounds.y; - x = Math.max(parent.x, x); - y = Math.max(parent.y, y); - x = Math.min((int)parent.getMaxX() - bounds.width, x); - y = Math.min((int)parent.getMaxY() - bounds.height, y); - bounds.setLocation(x, y); - return bounds; - } - @Override public Dimension render(Graphics2D graphics) { final Widget widget = client.getWidget(widgetInfo); - final Rectangle bounds = super.getBounds(); final Rectangle parent = getParentBounds(widget); if (parent.isEmpty()) @@ -121,15 +99,8 @@ public class WidgetOverlay extends Overlay return null; } - int x = bounds.x; - int y = bounds.y; - x = Math.max(parent.x, x); - y = Math.max(parent.y, y); - x = Math.min((int)parent.getMaxX() - bounds.width, x); - y = Math.min((int)parent.getMaxY() - bounds.height, y); - bounds.setLocation(x, y); - widget.setOriginalX(0); - widget.setOriginalY(0); + final Rectangle bounds = getBounds(); + // The widget relative pos is relative to the parent widget.setRelativeX(bounds.x - parent.x); widget.setRelativeY(bounds.y - parent.y); return new Dimension(widget.getWidth(), widget.getHeight()); @@ -137,11 +108,6 @@ public class WidgetOverlay extends Overlay private Rectangle getParentBounds(final Widget widget) { - if (!client.isClientThread()) - { - return parentBounds; - } - if (widget == null || widget.isHidden()) { parentBounds.setBounds(new Rectangle()); @@ -157,13 +123,27 @@ public class WidgetOverlay extends Overlay } else { - bounds = new Rectangle(parent.getCanvasLocation().getX(), parent.getCanvasLocation().getY(), parent.getWidth(), parent.getHeight()); + bounds = parent.getBounds(); } parentBounds.setBounds(bounds); return bounds; } + @Override + public Rectangle getParentBounds() + { + if (!client.isClientThread()) + { + // During overlay drag this is called on the EDT, so we just + // cache and reuse the last known parent bounds. + return parentBounds; + } + + final Widget widget = client.getWidget(widgetInfo); + return getParentBounds(widget); + } + private static class XpTrackerWidgetOverlay extends WidgetOverlay { private XpTrackerWidgetOverlay(Client client, WidgetInfo widgetInfo, OverlayPosition overlayPosition)