diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java index 98b2c9a73b..81e25192ed 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerCreationOverlay.java @@ -42,9 +42,10 @@ class ScreenMarkerCreationOverlay extends Overlay private ScreenMarkerCreationOverlay(final ScreenMarkerPlugin plugin) { this.plugin = plugin; - setPosition(OverlayPosition.DETACHED); + setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.ABOVE_WIDGETS); setPriority(OverlayPriority.HIGH); + setMovable(true); } @Override diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerOverlay.java index c991f58f2e..5341f75af8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerOverlay.java @@ -45,9 +45,10 @@ public class ScreenMarkerOverlay extends Overlay { this.marker = marker; this.screenMarkerRenderable = new ScreenMarkerRenderable(); - setPosition(OverlayPosition.DETACHED); + setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.ALWAYS_ON_TOP); setPriority(OverlayPriority.HIGH); + setMovable(true); setResizable(true); setMinimumSize(16); setResettable(false); diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerWidgetHighlightOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerWidgetHighlightOverlay.java index 718ea93903..9868b0f322 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerWidgetHighlightOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/screenmarkers/ScreenMarkerWidgetHighlightOverlay.java @@ -51,9 +51,10 @@ class ScreenMarkerWidgetHighlightOverlay extends Overlay { this.plugin = plugin; this.client = client; - setPosition(OverlayPosition.DETACHED); + setPosition(OverlayPosition.DYNAMIC); setLayer(OverlayLayer.ABOVE_WIDGETS); setPriority(OverlayPriority.HIGH); + setMovable(true); } @Override 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 dd36bf167e..a63dca7d2d 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 @@ -64,12 +64,25 @@ public abstract class Overlay implements LayoutableRenderableEntity @Setter(AccessLevel.PROTECTED) private boolean dragTargetable; + /** + * Whether this overlay can be moved with alt + */ + @Setter(AccessLevel.PROTECTED) + private boolean movable = true; + + /** + * Whether this overlay can be moved to a snap corner + * and have its preferredPosition changed + */ + @Setter(AccessLevel.PROTECTED) + private boolean snappable = true; + protected Overlay() { plugin = null; } - protected Overlay(Plugin plugin) + protected Overlay(@Nullable Plugin plugin) { this.plugin = plugin; } @@ -161,4 +174,25 @@ public abstract class Overlay implements LayoutableRenderableEntity public void revalidate() { } + + public void setPosition(OverlayPosition position) + { + this.position = position; + + switch (position) + { + case TOOLTIP: + case DYNAMIC: + movable = false; + snappable = false; + break; + case DETACHED: + movable = true; + snappable = false; + break; + default: + movable = true; + snappable = true; + } + } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java index 5811f98936..4ad59bf541 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayManager.java @@ -313,21 +313,29 @@ public class OverlayManager private void loadOverlay(final Overlay overlay) { final Point location = loadOverlayLocation(overlay); - overlay.setPreferredLocation(location); final Dimension size = loadOverlaySize(overlay); - overlay.setPreferredSize(size); final OverlayPosition position = loadOverlayPosition(overlay); - if (position != null) + + if (overlay.isMovable()) { - if (overlay.getPosition() != OverlayPosition.DYNAMIC && overlay.getPosition() != OverlayPosition.TOOLTIP) - { - overlay.setPreferredPosition(position); - } - else - { - log.info("Resetting preferred position of dynamic overlay {}", overlay.getClass().getSimpleName()); - saveOverlayPosition(overlay); - } + overlay.setPreferredLocation(location); + } + else + { + log.info("Resetting preferred location of non-movable overlay {} (class {})", overlay.getName(), overlay.getClass().getName()); + saveOverlayLocation(overlay); + } + + overlay.setPreferredSize(size); + + if (overlay.isSnappable()) + { + overlay.setPreferredPosition(position); + } + else + { + log.info("Resetting preferred position of non-snappable overlay {} (class {})", overlay.getName(), overlay.getClass().getName()); + saveOverlayPosition(overlay); } } diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPosition.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPosition.java index 14edc0dd05..9464c87520 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPosition.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/OverlayPosition.java @@ -28,7 +28,9 @@ public enum OverlayPosition { /** * Not attached anywhere, but still movable + * Deprecated. Use DYNAMIC and setMovable(true) */ + @Deprecated DETACHED, /** * Overlay places itself where it wants 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 9cd09225ee..2217a8d3ec 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 @@ -256,7 +256,7 @@ public class OverlayRenderer extends MouseAdapter OverlayUtil.setGraphicProperties(graphics); // Draw snap corners - if (inOverlayDraggingMode && layer == OverlayLayer.UNDER_WIDGETS && currentManagedOverlay != null && currentManagedOverlay.getPosition() != OverlayPosition.DETACHED) + if (inOverlayDraggingMode && layer == OverlayLayer.UNDER_WIDGETS && currentManagedOverlay != null && currentManagedOverlay.isSnappable()) { final OverlayBounds translatedSnapCorners = snapCorners.translated( -SNAP_CORNER_SIZE.width, @@ -288,102 +288,87 @@ public class OverlayRenderer extends MouseAdapter for (Overlay overlay : overlays) { final OverlayPosition overlayPosition = getCorrectedOverlayPosition(overlay); + final Rectangle bounds = overlay.getBounds(); + final Dimension dimension = bounds.getSize(); + final Point preferredLocation = overlay.getPreferredLocation(); + Point location; + Rectangle snapCorner = null; - if (overlayPosition == OverlayPosition.DYNAMIC || overlayPosition == OverlayPosition.TOOLTIP) + // If the final position is not modified, layout it + if (overlayPosition != OverlayPosition.DYNAMIC && overlayPosition != OverlayPosition.TOOLTIP + && overlayPosition != OverlayPosition.DETACHED && preferredLocation == null) { - safeRender(client, overlay, layer, graphics, new Point()); - - // Restore graphics2d properties - graphics.setTransform(transform); - graphics.setStroke(stroke); - graphics.setComposite(composite); - graphics.setPaint(paint); - graphics.setRenderingHints(renderingHints); - graphics.setBackground(background); + snapCorner = snapCorners.forPosition(overlayPosition); + final Point translation = OverlayUtil.transformPosition(overlayPosition, dimension); // offset from corner + // Target x/y to draw the overlay + int destX = snapCorner.x + translation.x; + int destY = snapCorner.y + translation.y; + // Clamp the target position to ensure it is on screen or within parent bounds + location = clampOverlayLocation(destX, destY, dimension.width, dimension.height, overlay); } else { - final Rectangle bounds = overlay.getBounds(); - final Dimension dimension = bounds.getSize(); - final Point preferredLocation = overlay.getPreferredLocation(); - Point location; - Rectangle snapCorner = null; + location = preferredLocation != null ? preferredLocation : bounds.getLocation(); - // If the final position is not modified, layout it - if (overlayPosition != OverlayPosition.DETACHED && (preferredLocation == null || overlay.getPreferredPosition() != null)) + // Clamp the overlay position to ensure it is on screen or within parent bounds + location = clampOverlayLocation(location.x, location.y, dimension.width, dimension.height, overlay); + } + + if (overlay.getPreferredSize() != null) + { + bounds.setSize(overlay.getPreferredSize()); + } + + safeRender(client, overlay, layer, graphics, location); + + // Adjust snap corner based on where the overlay was drawn + if (snapCorner != null && bounds.width + bounds.height > 0) + { + OverlayUtil.shiftSnapCorner(overlayPosition, snapCorner, bounds, PADDING); + } + + // Restore graphics2d properties prior to drawing bounds + graphics.setTransform(transform); + graphics.setStroke(stroke); + graphics.setComposite(composite); + graphics.setPaint(paint); + graphics.setRenderingHints(renderingHints); + graphics.setBackground(background); + + if (!bounds.isEmpty()) + { + if (inOverlayManagingMode) { - snapCorner = snapCorners.forPosition(overlayPosition); - final Point translation = OverlayUtil.transformPosition(overlayPosition, dimension); // offset from corner - // Target x/y to draw the overlay - int destX = snapCorner.x + translation.x; - int destY = snapCorner.y + translation.y; - // Clamp the target position to ensure it is on screen or within parent bounds - location = clampOverlayLocation(destX, destY, dimension.width, dimension.height, overlay); - } - else - { - location = preferredLocation != null ? preferredLocation : bounds.getLocation(); - - // Clamp the overlay position to ensure it is on screen or within parent bounds - location = clampOverlayLocation(location.x, location.y, dimension.width, dimension.height, overlay); - } - - if (overlay.getPreferredSize() != null) - { - bounds.setSize(overlay.getPreferredSize()); - } - - safeRender(client, overlay, layer, graphics, location); - - // Adjust snap corner based on where the overlay was drawn - if (snapCorner != null && bounds.width + bounds.height > 0) - { - OverlayUtil.shiftSnapCorner(overlayPosition, snapCorner, bounds, PADDING); - } - - // Restore graphics2d properties prior to drawing bounds - graphics.setTransform(transform); - graphics.setStroke(stroke); - graphics.setComposite(composite); - graphics.setPaint(paint); - graphics.setRenderingHints(renderingHints); - graphics.setBackground(background); - - if (!bounds.isEmpty()) - { - if (inOverlayManagingMode) + Color boundsColor; + if (inOverlayResizingMode && currentManagedOverlay == overlay) { - Color boundsColor; - if (inOverlayResizingMode && currentManagedOverlay == overlay) - { - boundsColor = MOVING_OVERLAY_RESIZING_COLOR; - } - else if (inOverlayDraggingMode && currentManagedOverlay == overlay) - { - boundsColor = MOVING_OVERLAY_ACTIVE_COLOR; - } - else if (inOverlayDraggingMode && overlay.isDragTargetable() && currentManagedOverlay.isDragTargetable() - && currentManagedOverlay.getBounds().intersects(bounds)) - { - boundsColor = MOVING_OVERLAY_TARGET_COLOR; - assert currentManagedOverlay != overlay; - dragTargetOverlay = overlay; - } - else - { - boundsColor = MOVING_OVERLAY_COLOR; - } - - graphics.setColor(boundsColor); - graphics.draw(bounds); - graphics.setPaint(paint); + boundsColor = MOVING_OVERLAY_RESIZING_COLOR; + } + else if (inOverlayDraggingMode && currentManagedOverlay == overlay) + { + boundsColor = MOVING_OVERLAY_ACTIVE_COLOR; + } + else if (inOverlayDraggingMode && overlay.isDragTargetable() && currentManagedOverlay.isDragTargetable() + && currentManagedOverlay.getBounds().intersects(bounds)) + { + boundsColor = MOVING_OVERLAY_TARGET_COLOR; + assert currentManagedOverlay != overlay; + dragTargetOverlay = overlay; + } + else + { + boundsColor = MOVING_OVERLAY_COLOR; } - if (!client.isMenuOpen() && !client.getSpellSelected() && bounds.contains(mouse)) - { - hoveredOverlay = overlay; - overlay.onMouseOver(); - } + graphics.setColor(boundsColor); + graphics.draw(bounds); + graphics.setPaint(paint); + } + + if (!client.isMenuOpen() && !client.getSpellSelected() && bounds.contains(mouse)) + { + hoveredOverlay = overlay; + overlay.onMouseOver(); } } } @@ -511,7 +496,7 @@ public class OverlayRenderer extends MouseAdapter // ABOVE_SCENE overlays aren't managed .filter(c -> layerOrder.contains(c.getLayer())) // never allow moving dynamic or tooltip overlays - .filter(c -> c.getPosition() != OverlayPosition.DYNAMIC && c.getPosition() != OverlayPosition.TOOLTIP) + .filter(Overlay::isMovable) .sorted( Comparator.comparingInt(c -> layerOrder.indexOf(c.getLayer())) .thenComparing(OverlayManager.OVERLAY_COMPARATOR) @@ -686,8 +671,8 @@ public class OverlayRenderer extends MouseAdapter } } - // Check if the overlay is over a snapcorner and move it if so, unless it is a detached overlay - if (currentManagedOverlay.getPosition() != OverlayPosition.DETACHED && inOverlayDraggingMode) + // Check if the overlay is over a snapcorner and snap it if so + if (currentManagedOverlay.isSnappable() && inOverlayDraggingMode) { final OverlayBounds snapCorners = this.emptySnapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height); 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 b0a0067964..5d2080dcbd 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 @@ -43,14 +43,14 @@ public class WidgetOverlay extends Overlay { return Arrays.asList( // classic resizable - new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_CHATBOX_PARENT, OverlayPosition.DETACHED, OverlayPriority.HIGH), - new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_CHATBOX_PARENT, OverlayPosition.DETACHED, OverlayPriority.HIGH), - new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_INVENTORY_PARENT, OverlayPosition.DETACHED), + new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_CHATBOX_PARENT, OverlayPosition.DYNAMIC, OverlayPriority.HIGH), + new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_CHATBOX_PARENT, OverlayPosition.DYNAMIC, OverlayPriority.HIGH), + new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_INVENTORY_PARENT, OverlayPosition.DYNAMIC), new WidgetOverlay(client, WidgetInfo.RESIZABLE_MINIMAP_WIDGET, OverlayPosition.CANVAS_TOP_RIGHT, OverlayPriority.MED), // modern resizable - new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_TABS1, OverlayPosition.DETACHED), - new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_TABS2, OverlayPosition.DETACHED), - new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_INVENTORY_PARENT, OverlayPosition.DETACHED), + new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_TABS1, OverlayPosition.DYNAMIC), + new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_TABS2, OverlayPosition.DYNAMIC), + new WidgetOverlay(client, WidgetInfo.RESIZABLE_VIEWPORT_BOTTOM_LINE_INVENTORY_PARENT, OverlayPosition.DYNAMIC), new WidgetOverlay(client, WidgetInfo.RESIZABLE_MINIMAP_STONES_WIDGET, OverlayPosition.CANVAS_TOP_RIGHT, OverlayPriority.MED), // The client forces the oxygen bar below the xp tracker, so set its priority lower new WidgetOverlay(client, WidgetInfo.FOSSIL_ISLAND_OXYGENBAR, OverlayPosition.TOP_CENTER, OverlayPriority.HIGH), @@ -84,7 +84,7 @@ public class WidgetOverlay extends Overlay new WidgetOverlay(client, WidgetInfo.TEMPOROSS_STATUS_INDICATOR, OverlayPosition.TOP_LEFT), new WidgetOverlay(client, WidgetInfo.BA_HEAL_TEAMMATES, OverlayPosition.BOTTOM_LEFT), new WidgetOverlay(client, WidgetInfo.BA_TEAM, OverlayPosition.TOP_RIGHT), - new WidgetOverlay(client, WidgetInfo.PVP_WILDERNESS_SKULL_CONTAINER, OverlayPosition.DETACHED) + new WidgetOverlay(client, WidgetInfo.PVP_WILDERNESS_SKULL_CONTAINER, OverlayPosition.DYNAMIC) ); } @@ -105,6 +105,8 @@ public class WidgetOverlay extends Overlay setPriority(overlayPriority); setLayer(OverlayLayer.UNDER_WIDGETS); setPosition(overlayPosition); + setMovable(true); + setSnappable(true); // It's almost possible to drawAfterInterface(widgetInfo.getGroupId()) here, but that fires // *after* the native components are drawn, which is too late. }