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.BOTTOM_LEFT;
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_RIGHT;
@@ -39,7 +40,7 @@ import static net.runelite.client.ui.overlay.OverlayPosition.TOP_RIGHT;
@Value
class OverlayBounds
{
private final Rectangle topLeft, topRight, bottomLeft, bottomRight, aboveChatboxRight;
private final Rectangle topLeft, topRight, bottomLeft, bottomRight, aboveChatboxRight, canvasTopRight;
OverlayBounds(OverlayBounds other)
{
@@ -48,6 +49,7 @@ class OverlayBounds
bottomLeft = new Rectangle(other.bottomLeft);
bottomRight = new Rectangle(other.bottomRight);
aboveChatboxRight = new Rectangle(other.aboveChatboxRight);
canvasTopRight = new Rectangle(other.canvasTopRight);
}
OverlayBounds translated(final int x, final int y)
@@ -57,6 +59,7 @@ class OverlayBounds
translated.getBottomLeft().translate(0, y);
translated.getBottomRight().translate(x, y);
translated.getAboveChatboxRight().translate(x, y);
translated.getCanvasTopRight().translate(x, 0);
return translated;
}
@@ -74,6 +77,8 @@ class OverlayBounds
return bottomRight;
case ABOVE_CHATBOX_RIGHT:
return aboveChatboxRight;
case CANVAS_TOP_RIGHT:
return canvasTopRight;
default:
throw new IllegalArgumentException();
}
@@ -101,6 +106,10 @@ class OverlayBounds
{
return ABOVE_CHATBOX_RIGHT;
}
else if (bounds == canvasTopRight)
{
return CANVAS_TOP_RIGHT;
}
else
{
throw new IllegalArgumentException();
@@ -109,6 +118,6 @@ class OverlayBounds
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,
/**
* Place overlay in the top left most area possible
* Place overlay in the top left viewport area
*/
TOP_LEFT,
/**
* Place overlay in the top right most area possible
* Place overlay in the top right viewport area
*/
TOP_RIGHT,
/**
* Place overlay in the bottom left most area possible
* Place overlay in the bottom left viewport area
*/
BOTTOM_LEFT,
/**
* Place overlay in the bottom right most area possible
* Place overlay in the bottom right viewport area
*/
BOTTOM_RIGHT,
/**
* Place overlay directly above right most area of chatbox possible
* Place overlay directly above right side of chatbox
*/
ABOVE_CHATBOX_RIGHT,
/**
* Place overlay in the top right most area possible
*/
CANVAS_TOP_RIGHT,
/**
* Tooltip overlay
*/
TOOLTIP;
TOOLTIP
}

View File

@@ -52,13 +52,8 @@ import net.runelite.client.ui.FontManager;
@Singleton
public class OverlayRenderer extends MouseListener implements KeyListener
{
private static final int BORDER_LEFT_RESIZABLE = 5;
private static final int BORDER_TOP_RESIZABLE = 20;
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 BORDER = 5;
private static final int BORDER_TOP = BORDER + 15;
private static final int PADDING = 2;
private static final Dimension SNAP_CORNER_SIZE = new Dimension(80, 80);
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
private Rectangle viewportBounds;
private Rectangle chatboxBounds;
private int viewportOffset;
private boolean chatboxHidden;
private boolean isResizeable;
private OverlayBounds snapCorners;
@@ -155,12 +151,21 @@ public class OverlayRenderer extends MouseListener implements KeyListener
overlayPosition = overlay.getPreferredPosition();
}
if (overlayPosition == OverlayPosition.ABOVE_CHATBOX_RIGHT && !isResizeable)
if (!isResizeable)
{
// 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.
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)
@@ -421,43 +426,55 @@ public class OverlayRenderer extends MouseListener implements KeyListener
changed = true;
}
final boolean viewportOffsetChanged = client.getViewportXOffset() != viewportOffset;
if (viewportOffsetChanged)
{
viewportOffset = client.getViewportXOffset();
changed = true;
}
return changed;
}
private OverlayBounds buildSnapCorners()
{
final Point topLeftPoint = new Point(
isResizeable ? BORDER_LEFT_RESIZABLE : BORDER_LEFT_FIXED,
isResizeable ? BORDER_TOP_RESIZABLE : BORDER_TOP_FIXED);
viewportOffset + BORDER,
viewportOffset + BORDER_TOP);
final Point topRightPoint = new Point(
viewportBounds.x + viewportBounds.width - BORDER_RIGHT,
BORDER_TOP_FIXED);
viewportOffset + viewportBounds.width - BORDER,
viewportOffset + BORDER);
final Point bottomLeftPoint = new Point(
isResizeable ? BORDER_LEFT_RESIZABLE : BORDER_LEFT_FIXED,
viewportBounds.y + viewportBounds.height - BORDER_BOTTOM);
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);
topLeftPoint.x,
viewportOffset + viewportBounds.height - BORDER);
// Check to see if chat box is minimized
if (isResizeable && chatboxHidden)
{
rightChatboxPoint.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(
new Rectangle(topLeftPoint, SNAP_CORNER_SIZE),
new Rectangle(topRightPoint, SNAP_CORNER_SIZE),
new Rectangle(bottomLeftPoint, 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:
result.y += dimension.height + (dimension.height == 0 ? 0 : padding);
break;
case CANVAS_TOP_RIGHT:
case TOP_RIGHT:
result.y += dimension.height + (dimension.height == 0 ? 0 : padding);
break;
@@ -232,6 +233,7 @@ public class OverlayUtil
case ABOVE_CHATBOX_RIGHT:
result.y = result.y - dimension.height;
// FALLTHROUGH
case CANVAS_TOP_RIGHT:
case TOP_RIGHT:
result.x = result.x - dimension.width;
break;

View File

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