From 1d7172c099a15816c5e7b9cd5911a2eef76da72f Mon Sep 17 00:00:00 2001 From: Max Weber Date: Wed, 16 Jun 2021 11:39:48 -0600 Subject: [PATCH] runelite-client: use menu entries for focusing world map points The previous way had usability issues since it would cover up the close button, consumed clicks for no reason on any icon, making it difficult to pan around the map when zoomed out, and had no tooltips. It previously also accessed widgets on the EDT, which is a threading issue. --- .../net/runelite/api/widgets/WidgetID.java | 1 + .../net/runelite/api/widgets/WidgetInfo.java | 1 + .../java/net/runelite/client/RuneLite.java | 1 + .../cluescrolls/ClueScrollWorldMapPoint.java | 1 + .../devtools/WorldMapRegionOverlay.java | 2 +- .../plugins/party/PartyWorldMapPoint.java | 1 + .../ui/overlay/worldmap/WorldMapOverlay.java | 101 +++++++++-- .../WorldMapOverlayMouseListener.java | 166 ------------------ .../ui/overlay/worldmap/WorldMapPoint.java | 14 +- 9 files changed, 98 insertions(+), 190 deletions(-) delete mode 100644 runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlayMouseListener.java diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java index af4a16ea25..c861e50e6d 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetID.java @@ -172,6 +172,7 @@ public class WidgetID { static final int MAPVIEW = 7; static final int OVERVIEW_MAP = 10; + static final int BOTTOM_BAR = 22; static final int SEARCH = 25; static final int SURFACE_SELECTOR = 33; static final int TOOLTIP = 41; diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java index 761b7fab6e..2227bb3c76 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java @@ -51,6 +51,7 @@ public enum WidgetInfo WORLD_MAP_VIEW(WidgetID.WORLD_MAP_GROUP_ID, WidgetID.WorldMap.MAPVIEW), WORLD_MAP_OVERVIEW_MAP(WidgetID.WORLD_MAP_GROUP_ID, WidgetID.WorldMap.OVERVIEW_MAP), + WORLD_MAP_BOTTOM_BAR(WidgetID.WORLD_MAP_GROUP_ID, WidgetID.WorldMap.BOTTOM_BAR), WORLD_MAP_SEARCH(WidgetID.WORLD_MAP_GROUP_ID, WidgetID.WorldMap.SEARCH), WORLD_MAP_SURFACE_SELECTOR(WidgetID.WORLD_MAP_GROUP_ID, WidgetID.WorldMap.SURFACE_SELECTOR), WORLD_MAP_TOOLTIP(WidgetID.WORLD_MAP_GROUP_ID, WidgetID.WorldMap.TOOLTIP), 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 42b57e6366..41c7fc8de3 100644 --- a/runelite-client/src/main/java/net/runelite/client/RuneLite.java +++ b/runelite-client/src/main/java/net/runelite/client/RuneLite.java @@ -326,6 +326,7 @@ public class RuneLite // Add core overlays WidgetOverlay.createOverlays(client).forEach(overlayManager::add); overlayManager.add(worldMapOverlay.get()); + eventBus.register(worldMapOverlay.get()); overlayManager.add(tooltipOverlay.get()); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollWorldMapPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollWorldMapPoint.java index 45fa1f874c..11b2dfc559 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollWorldMapPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/cluescrolls/ClueScrollWorldMapPoint.java @@ -51,6 +51,7 @@ class ClueScrollWorldMapPoint extends WorldMapPoint this.plugin = plugin; this.setSnapToEdge(true); this.setJumpOnClick(true); + this.setName("Clue Scroll"); this.setImage(clueScrollWorldImage); this.setImagePoint(clueScrollWorldImagePoint); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java index 8bfbf54398..0ae5cbafb6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WorldMapRegionOverlay.java @@ -79,7 +79,7 @@ class WorldMapRegionOverlay extends Overlay { RenderOverview ro = client.getRenderOverview(); Widget map = client.getWidget(WidgetInfo.WORLD_MAP_VIEW); - Float pixelsPerTile = ro.getWorldMapZoom(); + float pixelsPerTile = ro.getWorldMapZoom(); if (map == null) { diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java index f892560501..1c2bfd5b86 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/party/PartyWorldMapPoint.java @@ -45,6 +45,7 @@ class PartyWorldMapPoint extends WorldMapPoint this.member = member; this.setSnapToEdge(true); this.setJumpOnClick(true); + this.setName(member.getName()); this.setImagePoint(new Point( ARROW.getWidth() / 2, ARROW.getHeight())); diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java index d2e13ccad3..0c9a52b7e5 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlay.java @@ -25,33 +25,43 @@ package net.runelite.client.ui.overlay.worldmap; import com.google.common.base.Splitter; +import com.google.common.base.Strings; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.geom.Area; import java.awt.image.BufferedImage; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import net.runelite.api.Client; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; import net.runelite.api.Point; import net.runelite.api.RenderOverview; import net.runelite.api.coords.WorldPoint; +import net.runelite.api.events.MenuOptionClicked; +import net.runelite.api.widgets.JavaScriptCallback; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetID; import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.input.MouseManager; +import net.runelite.client.eventbus.Subscribe; import net.runelite.client.ui.FontManager; import net.runelite.client.ui.JagexColors; import net.runelite.client.ui.overlay.Overlay; import net.runelite.client.ui.overlay.OverlayLayer; import net.runelite.client.ui.overlay.OverlayPosition; import net.runelite.client.ui.overlay.OverlayPriority; +import net.runelite.client.util.ColorUtil; @Singleton public class WorldMapOverlay extends Overlay { + private static final String FOCUS_ON = "Focus on"; + private static final int TOOLTIP_OFFSET_HEIGHT = 25; private static final int TOOLTIP_OFFSET_WIDTH = 5; private static final int TOOLTIP_PADDING_HEIGHT = 1; @@ -63,12 +73,12 @@ public class WorldMapOverlay extends Overlay private final WorldMapPointManager worldMapPointManager; private final Client client; + private final List mapMenuEntries = new ArrayList<>(); + @Inject private WorldMapOverlay( Client client, - WorldMapPointManager worldMapPointManager, - MouseManager mouseManager, - WorldMapOverlayMouseListener worldMapOverlayMouseListener) + WorldMapPointManager worldMapPointManager) { this.client = client; this.worldMapPointManager = worldMapPointManager; @@ -76,7 +86,6 @@ public class WorldMapOverlay extends Overlay setPriority(OverlayPriority.HIGHEST); setLayer(OverlayLayer.MANUAL); drawAfterInterface(WidgetID.WORLD_MAP_GROUP_ID); - mouseManager.registerMouseListener(worldMapOverlayMouseListener); } @Override @@ -90,17 +99,44 @@ public class WorldMapOverlay extends Overlay } Widget widget = client.getWidget(WidgetInfo.WORLD_MAP_VIEW); - if (widget == null) + Widget bottomBar = client.getWidget(WidgetInfo.WORLD_MAP_BOTTOM_BAR); + if (widget == null || bottomBar == null) { return null; } + bottomBar.setOnTimerListener((JavaScriptCallback) ev -> + { + if (client.isMenuOpen() || mapMenuEntries.isEmpty()) + { + return; + } + + MenuEntry[] entries = client.getMenuEntries(); + int end = entries.length; + entries = Arrays.copyOf(entries, end + mapMenuEntries.size()); + for (int i = 0; i < mapMenuEntries.size(); i++) + { + entries[end + i] = mapMenuEntries.get(i); + } + client.setMenuEntries(entries); + }); + bottomBar.setHasListener(true); + final Rectangle worldMapRectangle = widget.getBounds(); final Area mapViewArea = getWorldMapClipArea(worldMapRectangle); final Rectangle canvasBounds = new Rectangle(0, 0, client.getCanvasWidth(), client.getCanvasHeight()); final Area canvasViewArea = getWorldMapClipArea(canvasBounds); Area currentClip = null; + Point mousePos = client.getMouseCanvasPosition(); + if (!canvasViewArea.contains(mousePos.getX(), mousePos.getY())) + { + mousePos = null; + } + + mapMenuEntries.clear(); + WorldMapPoint tooltipPoint = null; for (WorldMapPoint worldPoint : points) @@ -111,10 +147,8 @@ public class WorldMapOverlay extends Overlay if (image != null && point != null) { Point drawPoint = mapWorldPointToGraphicsPoint(point); - if (drawPoint == null) { - worldPoint.setClickbox(null); continue; } @@ -183,15 +217,40 @@ public class WorldMapOverlay extends Overlay graphics.drawImage(image, drawX, drawY, null); Rectangle clickbox = new Rectangle(drawX, drawY, image.getWidth(), image.getHeight()); - worldPoint.setClickbox(clickbox); - - if (worldPoint.isTooltipVisible()) + if (mousePos != null && clickbox.contains(mousePos.getX(), mousePos.getY())) { - tooltipPoint = worldPoint; + if (!Strings.isNullOrEmpty(worldPoint.getTooltip())) + { + tooltipPoint = worldPoint; + } + + if (worldPoint.isJumpOnClick()) + { + assert worldPoint.getName() != null; + + WorldPoint target = worldPoint.getTarget(); + if (target == null) + { + target = worldPoint.getWorldPoint(); + } + + MenuEntry entry = new MenuEntry(); + entry.setType(MenuAction.RUNELITE.getId()); + entry.setOption(FOCUS_ON); + entry.setTarget(ColorUtil.wrapWithColorTag(worldPoint.getName(), JagexColors.MENU_TARGET)); + entry.setIdentifier(target.getPlane() << 28 | target.getX() << 14 | target.getY()); + mapMenuEntries.add(entry); + } } } } + final Widget rsTooltip = client.getWidget(WidgetInfo.WORLD_MAP_TOOLTIP); + if (rsTooltip != null) + { + rsTooltip.setHidden(tooltipPoint != null); + } + if (tooltipPoint != null) { drawTooltip(graphics, tooltipPoint); @@ -200,8 +259,24 @@ public class WorldMapOverlay extends Overlay return null; } + @Subscribe + private void onMenuOptionClicked(MenuOptionClicked ev) + { + if (ev.getMenuAction() == MenuAction.RUNELITE && FOCUS_ON.equals(ev.getMenuOption())) + { + int pxy = ev.getId(); + WorldPoint wp = new WorldPoint( + pxy >> 14 & 0x3fff, + pxy & 0x3fff, + pxy >> 28); + + client.getRenderOverview().setWorldMapPositionTarget(wp); + } + } + /** * Get the screen coordinates for a WorldPoint on the world map + * * @param worldPoint WorldPoint to get screen coordinates of * @return Point of screen coordinates of the center of the world point */ @@ -214,7 +289,7 @@ public class WorldMapOverlay extends Overlay return null; } - Float pixelsPerTile = ro.getWorldMapZoom(); + float pixelsPerTile = ro.getWorldMapZoom(); Widget map = client.getWidget(WidgetInfo.WORLD_MAP_VIEW); if (map != null) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlayMouseListener.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlayMouseListener.java deleted file mode 100644 index 71af9a55dc..0000000000 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapOverlayMouseListener.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2018, Morgan Lewis - * 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.worldmap; - -import java.awt.Rectangle; -import java.awt.event.MouseEvent; -import java.util.List; -import javax.inject.Inject; -import javax.inject.Singleton; -import javax.swing.SwingUtilities; -import net.runelite.api.Client; -import net.runelite.api.Point; -import net.runelite.api.RenderOverview; -import net.runelite.api.coords.WorldPoint; -import net.runelite.api.widgets.Widget; -import net.runelite.api.widgets.WidgetInfo; -import net.runelite.client.input.MouseAdapter; - -@Singleton -public class WorldMapOverlayMouseListener extends MouseAdapter -{ - private final Client client; - private final WorldMapPointManager worldMapPointManager; - private WorldMapPoint tooltipPoint = null; - - @Inject - private WorldMapOverlayMouseListener(Client client, WorldMapPointManager worldMapPointManager) - { - this.client = client; - this.worldMapPointManager = worldMapPointManager; - } - - @Override - public MouseEvent mousePressed(MouseEvent e) - { - final List worldMapPoints = worldMapPointManager.getWorldMapPoints(); - - if (SwingUtilities.isLeftMouseButton(e) && !worldMapPoints.isEmpty()) - { - Point mousePos = client.getMouseCanvasPosition(); - final Widget view = client.getWidget(WidgetInfo.WORLD_MAP_VIEW); - - if (view == null) - { - return e; - } - - for (WorldMapPoint worldMapPoint : worldMapPoints) - { - Rectangle clickbox = worldMapPoint.getClickbox(); - if (clickbox != null && clickbox.contains(mousePos.getX(), mousePos.getY())) - { - if (worldMapPoint.isJumpOnClick()) - { - // jump map to target, or position of point - WorldPoint target = worldMapPoint.getTarget(); - if (target == null) - { - target = worldMapPoint.getWorldPoint(); - } - RenderOverview renderOverview = client.getRenderOverview(); - renderOverview.setWorldMapPositionTarget(target); - } - e.consume(); - return worldMapPoint.onClick(e); - } - } - } - return e; - } - - @Override - public MouseEvent mouseMoved(MouseEvent mouseEvent) - { - final List worldMapPoints = worldMapPointManager.getWorldMapPoints(); - - if (worldMapPoints.isEmpty()) - { - return mouseEvent; - } - - final Point mousePos = client.getMouseCanvasPosition(); - final Widget view = client.getWidget(WidgetInfo.WORLD_MAP_VIEW); - - if (view == null) - { - return mouseEvent; - } - - final Rectangle worldMapDisplay = view.getBounds(); - - if (worldMapDisplay == null || !worldMapDisplay.contains(mousePos.getX(), mousePos.getY())) - { - if (tooltipPoint != null) - { - tooltipPoint.setTooltipVisible(false); - tooltipPoint = null; - final Widget rsTooltip = client.getWidget(WidgetInfo.WORLD_MAP_TOOLTIP); - if (rsTooltip != null) - { - rsTooltip.setHidden(false); - } - } - return mouseEvent; - } - - if (tooltipPoint != null) - { - if (tooltipPoint.getClickbox() != null - && tooltipPoint.getClickbox().contains(mousePos.getX(), mousePos.getY())) - { - return mouseEvent; - } - else - { - tooltipPoint.setTooltipVisible(false); - tooltipPoint = null; - final Widget rsTooltip = client.getWidget(WidgetInfo.WORLD_MAP_TOOLTIP); - if (rsTooltip != null) - { - rsTooltip.setHidden(false); - } - } - } - - for (WorldMapPoint worldMapPoint : worldMapPointManager.getWorldMapPoints()) - { - if (worldMapPoint.getClickbox() != null - && worldMapPoint.getClickbox().contains(mousePos.getX(), mousePos.getY()) - && worldMapPoint.getTooltip() != null) - { - worldMapPoint.setTooltipVisible(true); - tooltipPoint = worldMapPoint; - final Widget rsTooltip = client.getWidget(WidgetInfo.WORLD_MAP_TOOLTIP); - if (rsTooltip != null) - { - rsTooltip.setHidden(true); - } - return mouseEvent; - } - } - return mouseEvent; - } -} diff --git a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapPoint.java b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapPoint.java index 836bcd1ef5..f12fd10214 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapPoint.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/overlay/worldmap/WorldMapPoint.java @@ -24,8 +24,6 @@ */ package net.runelite.client.ui.overlay.worldmap; -import java.awt.Rectangle; -import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import javax.annotation.Nullable; import lombok.Data; @@ -53,8 +51,6 @@ public class WorldMapPoint */ private Point imagePoint; - private Rectangle clickbox; - private boolean snapToEdge; private boolean currentlyEdgeSnapped; @@ -64,7 +60,10 @@ public class WorldMapPoint */ private boolean jumpOnClick; - private boolean tooltipVisible; + /** + * Name in menu option when {@link #jumpOnClick} is set + */ + private String name; private String tooltip; @@ -74,11 +73,6 @@ public class WorldMapPoint this.image = image; } - public MouseEvent onClick(MouseEvent e) - { - return e; - } - public void onEdgeSnap() { }