Make RuneScape widgets layoutable

Instead of making RuneScape widgets detached, make them layoutable

- Add new snap corner CANVAS_TOP_RIGHT that is basically minimap
position
- Make WidgetOverlay use standard overlay layouting
- Adjust paddings in the OverlayRenderer to match game more closely

Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
This commit is contained in:
Tomas Slusny
2018-08-22 19:14:58 +02:00
parent 0a17590c2a
commit 428832bcf9
5 changed files with 98 additions and 99 deletions

View File

@@ -32,6 +32,7 @@ import lombok.Value;
import static net.runelite.client.ui.overlay.OverlayPosition.ABOVE_CHATBOX_RIGHT; import static net.runelite.client.ui.overlay.OverlayPosition.ABOVE_CHATBOX_RIGHT;
import static net.runelite.client.ui.overlay.OverlayPosition.BOTTOM_LEFT; import static net.runelite.client.ui.overlay.OverlayPosition.BOTTOM_LEFT;
import static net.runelite.client.ui.overlay.OverlayPosition.BOTTOM_RIGHT; import static net.runelite.client.ui.overlay.OverlayPosition.BOTTOM_RIGHT;
import static net.runelite.client.ui.overlay.OverlayPosition.CANVAS_TOP_RIGHT;
import static net.runelite.client.ui.overlay.OverlayPosition.TOP_LEFT; import static net.runelite.client.ui.overlay.OverlayPosition.TOP_LEFT;
import static net.runelite.client.ui.overlay.OverlayPosition.TOP_RIGHT; import static net.runelite.client.ui.overlay.OverlayPosition.TOP_RIGHT;
@@ -39,7 +40,7 @@ import static net.runelite.client.ui.overlay.OverlayPosition.TOP_RIGHT;
@Value @Value
class OverlayBounds class OverlayBounds
{ {
private final Rectangle topLeft, topRight, bottomLeft, bottomRight, aboveChatboxRight; private final Rectangle topLeft, topRight, bottomLeft, bottomRight, aboveChatboxRight, canvasTopRight;
OverlayBounds(OverlayBounds other) OverlayBounds(OverlayBounds other)
{ {
@@ -48,6 +49,7 @@ class OverlayBounds
bottomLeft = new Rectangle(other.bottomLeft); bottomLeft = new Rectangle(other.bottomLeft);
bottomRight = new Rectangle(other.bottomRight); bottomRight = new Rectangle(other.bottomRight);
aboveChatboxRight = new Rectangle(other.aboveChatboxRight); aboveChatboxRight = new Rectangle(other.aboveChatboxRight);
canvasTopRight = new Rectangle(other.canvasTopRight);
} }
OverlayBounds translated(final int x, final int y) OverlayBounds translated(final int x, final int y)
@@ -57,6 +59,7 @@ class OverlayBounds
translated.getBottomLeft().translate(0, y); translated.getBottomLeft().translate(0, y);
translated.getBottomRight().translate(x, y); translated.getBottomRight().translate(x, y);
translated.getAboveChatboxRight().translate(x, y); translated.getAboveChatboxRight().translate(x, y);
translated.getCanvasTopRight().translate(x, 0);
return translated; return translated;
} }
@@ -74,6 +77,8 @@ class OverlayBounds
return bottomRight; return bottomRight;
case ABOVE_CHATBOX_RIGHT: case ABOVE_CHATBOX_RIGHT:
return aboveChatboxRight; return aboveChatboxRight;
case CANVAS_TOP_RIGHT:
return canvasTopRight;
default: default:
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
@@ -101,6 +106,10 @@ class OverlayBounds
{ {
return ABOVE_CHATBOX_RIGHT; return ABOVE_CHATBOX_RIGHT;
} }
else if (bounds == canvasTopRight)
{
return CANVAS_TOP_RIGHT;
}
else else
{ {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
@@ -109,6 +118,6 @@ class OverlayBounds
Collection<Rectangle> getBounds() Collection<Rectangle> getBounds()
{ {
return Arrays.asList(topLeft, topRight, bottomLeft, bottomRight, aboveChatboxRight); return Arrays.asList(topLeft, topRight, bottomLeft, bottomRight, aboveChatboxRight, canvasTopRight);
} }
} }

View File

@@ -35,27 +35,31 @@ public enum OverlayPosition
*/ */
DYNAMIC, DYNAMIC,
/** /**
* Place overlay in the top left most area possible * Place overlay in the top left viewport area
*/ */
TOP_LEFT, TOP_LEFT,
/** /**
* Place overlay in the top right most area possible * Place overlay in the top right viewport area
*/ */
TOP_RIGHT, TOP_RIGHT,
/** /**
* Place overlay in the bottom left most area possible * Place overlay in the bottom left viewport area
*/ */
BOTTOM_LEFT, BOTTOM_LEFT,
/** /**
* Place overlay in the bottom right most area possible * Place overlay in the bottom right viewport area
*/ */
BOTTOM_RIGHT, BOTTOM_RIGHT,
/** /**
* Place overlay directly above right most area of chatbox possible * Place overlay directly above right side of chatbox
*/ */
ABOVE_CHATBOX_RIGHT, ABOVE_CHATBOX_RIGHT,
/**
* Place overlay in the top right most area possible
*/
CANVAS_TOP_RIGHT,
/** /**
* Tooltip overlay * Tooltip overlay
*/ */
TOOLTIP; TOOLTIP
} }

View File

@@ -52,13 +52,8 @@ import net.runelite.client.ui.FontManager;
@Singleton @Singleton
public class OverlayRenderer extends MouseListener implements KeyListener public class OverlayRenderer extends MouseListener implements KeyListener
{ {
private static final int BORDER_LEFT_RESIZABLE = 5; private static final int BORDER = 5;
private static final int BORDER_TOP_RESIZABLE = 20; private static final int BORDER_TOP = BORDER + 15;
private static final int FRAME_OFFSET = 4;
private static final int BORDER_LEFT_FIXED = BORDER_LEFT_RESIZABLE + FRAME_OFFSET;
private static final int BORDER_TOP_FIXED = BORDER_TOP_RESIZABLE + FRAME_OFFSET;
private static final int BORDER_RIGHT = 2;
private static final int BORDER_BOTTOM = 2;
private static final int PADDING = 2; private static final int PADDING = 2;
private static final Dimension SNAP_CORNER_SIZE = new Dimension(80, 80); private static final Dimension SNAP_CORNER_SIZE = new Dimension(80, 80);
private static final Color SNAP_CORNER_COLOR = new Color(0, 255, 255, 50); private static final Color SNAP_CORNER_COLOR = new Color(0, 255, 255, 50);
@@ -78,6 +73,7 @@ public class OverlayRenderer extends MouseListener implements KeyListener
// Overlay state validation // Overlay state validation
private Rectangle viewportBounds; private Rectangle viewportBounds;
private Rectangle chatboxBounds; private Rectangle chatboxBounds;
private int viewportOffset;
private boolean chatboxHidden; private boolean chatboxHidden;
private boolean isResizeable; private boolean isResizeable;
private OverlayBounds snapCorners; private OverlayBounds snapCorners;
@@ -155,12 +151,21 @@ public class OverlayRenderer extends MouseListener implements KeyListener
overlayPosition = overlay.getPreferredPosition(); overlayPosition = overlay.getPreferredPosition();
} }
if (overlayPosition == OverlayPosition.ABOVE_CHATBOX_RIGHT && !isResizeable) if (!isResizeable)
{ {
// On fixed mode, ABOVE_CHATBOX_RIGHT is in the same location as // On fixed mode, ABOVE_CHATBOX_RIGHT is in the same location as
// BOTTOM_RIGHT. Just use BOTTOM_RIGHT to prevent overlays from // BOTTOM_RIGHT and CANVAST_TOP_RIGHT is same as TOP_RIGHT.
// Just use BOTTOM_RIGHT and TOP_RIGHT to prevent overlays from
// drawing over each other. // drawing over each other.
overlayPosition = OverlayPosition.BOTTOM_RIGHT; switch (overlayPosition)
{
case CANVAS_TOP_RIGHT:
overlayPosition = OverlayPosition.TOP_RIGHT;
break;
case ABOVE_CHATBOX_RIGHT:
overlayPosition = OverlayPosition.BOTTOM_RIGHT;
break;
}
} }
if (overlayPosition == OverlayPosition.DYNAMIC || overlayPosition == OverlayPosition.TOOLTIP) if (overlayPosition == OverlayPosition.DYNAMIC || overlayPosition == OverlayPosition.TOOLTIP)
@@ -421,43 +426,55 @@ public class OverlayRenderer extends MouseListener implements KeyListener
changed = true; changed = true;
} }
final boolean viewportOffsetChanged = client.getViewportXOffset() != viewportOffset;
if (viewportOffsetChanged)
{
viewportOffset = client.getViewportXOffset();
changed = true;
}
return changed; return changed;
} }
private OverlayBounds buildSnapCorners() private OverlayBounds buildSnapCorners()
{ {
final Point topLeftPoint = new Point( final Point topLeftPoint = new Point(
isResizeable ? BORDER_LEFT_RESIZABLE : BORDER_LEFT_FIXED, viewportOffset + BORDER,
isResizeable ? BORDER_TOP_RESIZABLE : BORDER_TOP_FIXED); viewportOffset + BORDER_TOP);
final Point topRightPoint = new Point( final Point topRightPoint = new Point(
viewportBounds.x + viewportBounds.width - BORDER_RIGHT, viewportOffset + viewportBounds.width - BORDER,
BORDER_TOP_FIXED); viewportOffset + BORDER);
final Point bottomLeftPoint = new Point( final Point bottomLeftPoint = new Point(
isResizeable ? BORDER_LEFT_RESIZABLE : BORDER_LEFT_FIXED, topLeftPoint.x,
viewportBounds.y + viewportBounds.height - BORDER_BOTTOM); viewportOffset + viewportBounds.height - BORDER);
final Point bottomRightPoint = new Point(
viewportBounds.x + viewportBounds.width - BORDER_RIGHT,
viewportBounds.y + viewportBounds.height - BORDER_BOTTOM);
final Point rightChatboxPoint = new Point(
viewportBounds.x + chatboxBounds.width - BORDER_RIGHT,
viewportBounds.y + viewportBounds.height - BORDER_BOTTOM);
// Check to see if chat box is minimized // Check to see if chat box is minimized
if (isResizeable && chatboxHidden) if (isResizeable && chatboxHidden)
{ {
rightChatboxPoint.y += chatboxBounds.height;
bottomLeftPoint.y += chatboxBounds.height; bottomLeftPoint.y += chatboxBounds.height;
} }
final Point bottomRightPoint = new Point(
topRightPoint.x,
bottomLeftPoint.y);
final Point rightChatboxPoint = isResizeable ? new Point(
viewportOffset + chatboxBounds.width - BORDER,
bottomLeftPoint.y) : bottomRightPoint;
final Point canvasTopRightPoint = isResizeable ? new Point(
client.getCanvas().getWidth(),
0) : topRightPoint;
return new OverlayBounds( return new OverlayBounds(
new Rectangle(topLeftPoint, SNAP_CORNER_SIZE), new Rectangle(topLeftPoint, SNAP_CORNER_SIZE),
new Rectangle(topRightPoint, SNAP_CORNER_SIZE), new Rectangle(topRightPoint, SNAP_CORNER_SIZE),
new Rectangle(bottomLeftPoint, SNAP_CORNER_SIZE), new Rectangle(bottomLeftPoint, SNAP_CORNER_SIZE),
new Rectangle(bottomRightPoint, SNAP_CORNER_SIZE), new Rectangle(bottomRightPoint, SNAP_CORNER_SIZE),
new Rectangle(rightChatboxPoint, SNAP_CORNER_SIZE)); new Rectangle(rightChatboxPoint, SNAP_CORNER_SIZE),
new Rectangle(canvasTopRightPoint, SNAP_CORNER_SIZE));
} }
} }

View File

@@ -204,6 +204,7 @@ public class OverlayUtil
case TOP_LEFT: case TOP_LEFT:
result.y += dimension.height + (dimension.height == 0 ? 0 : padding); result.y += dimension.height + (dimension.height == 0 ? 0 : padding);
break; break;
case CANVAS_TOP_RIGHT:
case TOP_RIGHT: case TOP_RIGHT:
result.y += dimension.height + (dimension.height == 0 ? 0 : padding); result.y += dimension.height + (dimension.height == 0 ? 0 : padding);
break; break;
@@ -232,6 +233,7 @@ public class OverlayUtil
case ABOVE_CHATBOX_RIGHT: case ABOVE_CHATBOX_RIGHT:
result.y = result.y - dimension.height; result.y = result.y - dimension.height;
// FALLTHROUGH // FALLTHROUGH
case CANVAS_TOP_RIGHT:
case TOP_RIGHT: case TOP_RIGHT:
result.x = result.x - dimension.width; result.x = result.x - dimension.width;
break; break;

View File

@@ -24,10 +24,11 @@
*/ */
package net.runelite.client.ui.overlay; package net.runelite.client.ui.overlay;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableMap;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -37,29 +38,29 @@ import net.runelite.api.widgets.WidgetInfo;
public class WidgetOverlay extends Overlay public class WidgetOverlay extends Overlay
{ {
private static final Set<WidgetInfo> WIDGETS = ImmutableSet.of( private static final Map<WidgetInfo, OverlayPosition> WIDGETS = ImmutableMap
WidgetInfo.RESIZABLE_MINIMAP_WIDGET, .<WidgetInfo, OverlayPosition>builder()
WidgetInfo.RESIZABLE_MINIMAP_STONES_WIDGET, .put(WidgetInfo.FOSSIL_ISLAND_OXYGENBAR, OverlayPosition.TOP_LEFT)
WidgetInfo.EXPERIENCE_TRACKER_WIDGET, .put(WidgetInfo.EXPERIENCE_TRACKER_WIDGET, OverlayPosition.TOP_RIGHT)
WidgetInfo.FOSSIL_ISLAND_OXYGENBAR .put(WidgetInfo.RESIZABLE_MINIMAP_WIDGET, OverlayPosition.CANVAS_TOP_RIGHT)
); .put(WidgetInfo.RESIZABLE_MINIMAP_STONES_WIDGET, OverlayPosition.CANVAS_TOP_RIGHT)
.build();
public static Set<WidgetOverlay> createOverlays(final Client client) public static Set<WidgetOverlay> createOverlays(final Client client)
{ {
return WIDGETS.stream().map(w -> new WidgetOverlay(client, w)).collect(Collectors.toSet()); return WIDGETS.entrySet().stream().map(w -> new WidgetOverlay(client, w.getKey(), w.getValue())).collect(Collectors.toSet());
} }
private final Client client; private final Client client;
private final WidgetInfo widgetInfo; private final WidgetInfo widgetInfo;
private Integer toRestoreX;
private Integer toRestoreY;
private WidgetOverlay(final Client client, final WidgetInfo widgetInfo) private WidgetOverlay(final Client client, final WidgetInfo widgetInfo, final OverlayPosition overlayPosition)
{ {
this.client = client; this.client = client;
this.widgetInfo = widgetInfo; this.widgetInfo = widgetInfo;
setPriority(OverlayPriority.HIGHEST);
setLayer(OverlayLayer.UNDER_WIDGETS); setLayer(OverlayLayer.UNDER_WIDGETS);
setPosition(OverlayPosition.DETACHED); setPosition(overlayPosition);
} }
@Override @Override
@@ -68,73 +69,39 @@ public class WidgetOverlay extends Overlay
return Objects.toString(widgetInfo); return Objects.toString(widgetInfo);
} }
@Override
public Rectangle getBounds()
{
final Widget widget = client.getWidget(widgetInfo);
if (widget != null && !widget.isHidden())
{
return new Rectangle(
widget.getOriginalX() + widget.getRelativeX(),
widget.getOriginalY() + widget.getRelativeY(),
widget.getWidth(), widget.getHeight());
}
return new Rectangle();
}
@Override @Override
public Dimension render(Graphics2D graphics) public Dimension render(Graphics2D graphics)
{ {
final Widget widget = client.getWidget(widgetInfo); final Widget widget = client.getWidget(widgetInfo);
if (widget == null || widget.isHidden()) if (widget == null || widget.isHidden())
{ {
return null; return null;
} }
if (getPreferredLocation() == null)
{
if (toRestoreX != null)
{
widget.setRelativeX(toRestoreX);
toRestoreX = null;
}
if (toRestoreY != null)
{
widget.setRelativeY(toRestoreY);
toRestoreY = null;
}
return null;
}
final Rectangle bounds = getBounds(); final Rectangle bounds = getBounds();
int x = getPreferredLocation().x - widget.getOriginalX(); final Rectangle parent = getParentBounds(widget);
int y = getPreferredLocation().y - widget.getOriginalY(); int x = bounds.x;
x = Math.max(0, x); int y = bounds.y;
y = Math.max(0, 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.setRelativeX(0);
widget.setRelativeX(bounds.x - parent.x);
widget.setRelativeY(bounds.y - parent.y);
return new Dimension(widget.getWidth(), widget.getHeight());
}
private Rectangle getParentBounds(final Widget widget)
{
final Widget parent = widget.getParent(); final Widget parent = widget.getParent();
final Dimension dimensions = parent == null ? client.getRealDimensions() : new Dimension(parent.getWidth(), parent.getHeight()); if (parent == null)
x = Math.min(dimensions.width - bounds.width, x);
y = Math.min(dimensions.height - bounds.height, y);
if (toRestoreX == null)
{ {
toRestoreX = widget.getRelativeX(); return new Rectangle(client.getRealDimensions());
} }
if (toRestoreY == null) return new Rectangle(parent.getCanvasLocation().getX(), parent.getCanvasLocation().getY(), parent.getWidth(), parent.getHeight());
{
toRestoreY = widget.getRelativeY();
}
widget.setRelativeX(x);
widget.setRelativeY(y);
return null;
} }
} }