Merge pull request #989 from deathbeam/movable-overlays

Add support for movable overlays
This commit is contained in:
Adam
2018-03-22 21:22:18 -04:00
committed by GitHub
7 changed files with 633 additions and 135 deletions

View File

@@ -331,6 +331,8 @@ public interface Client extends GameEngine
Dimension getStretchedDimensions();
Dimension getRealDimensions();
/**
* Changes world. Works only on login screen
* @param world world

View File

@@ -24,10 +24,12 @@
*/
package net.runelite.client.config;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.eventbus.EventBus;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -244,6 +246,16 @@ public class ConfigManager
return properties.getProperty(groupName + "." + key);
}
public <T> T getConfiguration(String groupName, String key, Class<T> clazz)
{
String value = getConfiguration(groupName, key);
if (!Strings.isNullOrEmpty(value))
{
return (T) stringToObject(value, clazz);
}
return null;
}
public void setConfiguration(String groupName, String key, String value)
{
log.debug("Setting configuration value for {}.{} to {}", groupName, key, value);
@@ -289,6 +301,11 @@ public class ConfigManager
eventBus.post(configChanged);
}
public void setConfiguration(String groupName, String key, Object value)
{
setConfiguration(groupName, key, objectToString(value));
}
public void unsetConfiguration(String groupName, String key)
{
log.debug("Unsetting configuration value for {}.{}", groupName, key);
@@ -420,6 +437,13 @@ public class ConfigManager
int height = Integer.parseInt(splitStr[1]);
return new Dimension(width, height);
}
if (type == Point.class)
{
String[] splitStr = str.split(":");
int width = Integer.parseInt(splitStr[0]);
int height = Integer.parseInt(splitStr[1]);
return new Point(width, height);
}
if (type.isEnum())
{
return Enum.valueOf((Class<? extends Enum>) type, str);
@@ -442,6 +466,11 @@ public class ConfigManager
Dimension d = (Dimension) object;
return d.width + "x" + d.height;
}
if (object instanceof Point)
{
Point p = (Point) object;
return p.x + ":" + p.y;
}
return object.toString();
}
}

View File

@@ -24,11 +24,16 @@
*/
package net.runelite.client.ui.overlay;
import java.awt.Point;
import java.awt.Rectangle;
import lombok.Data;
@Data
public abstract class Overlay implements RenderableEntity
{
private Point preferredLocation;
private OverlayPosition preferredPosition;
private Rectangle bounds = new Rectangle();
private OverlayPosition position = OverlayPosition.TOP_LEFT;
private OverlayPriority priority = OverlayPriority.NONE;
private OverlayLayer layer = OverlayLayer.UNDER_WIDGETS;

View File

@@ -0,0 +1,104 @@
/*
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* 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;
import java.awt.Rectangle;
import java.util.Arrays;
import java.util.Collection;
import lombok.AllArgsConstructor;
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.TOP_LEFT;
import static net.runelite.client.ui.overlay.OverlayPosition.TOP_RIGHT;
@AllArgsConstructor
@Value
class OverlayBounds
{
private final Rectangle topLeft, topRight, bottomLeft, bottomRight, aboveChatboxRight;
OverlayBounds(OverlayBounds other)
{
topLeft = new Rectangle(other.topLeft);
topRight = new Rectangle(other.topRight);
bottomLeft = new Rectangle(other.bottomLeft);
bottomRight = new Rectangle(other.bottomRight);
aboveChatboxRight = new Rectangle(other.aboveChatboxRight);
}
Rectangle forPosition(OverlayPosition overlayPosition)
{
switch (overlayPosition)
{
case TOP_LEFT:
return topLeft;
case TOP_RIGHT:
return topRight;
case BOTTOM_LEFT:
return bottomLeft;
case BOTTOM_RIGHT:
return bottomRight;
case ABOVE_CHATBOX_RIGHT:
return aboveChatboxRight;
default:
throw new IllegalArgumentException();
}
}
OverlayPosition fromBounds(Rectangle bounds)
{
if (bounds == topLeft)
{
return TOP_LEFT;
}
else if (bounds == topRight)
{
return TOP_RIGHT;
}
else if (bounds == bottomLeft)
{
return BOTTOM_LEFT;
}
else if (bounds == bottomRight)
{
return BOTTOM_RIGHT;
}
else if (bounds == aboveChatboxRight)
{
return ABOVE_CHATBOX_RIGHT;
}
else
{
throw new IllegalArgumentException();
}
}
Collection<Rectangle> getBounds()
{
return Arrays.asList(topLeft, topRight, bottomLeft, bottomRight, aboveChatboxRight);
}
}

View File

@@ -31,6 +31,8 @@ import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.List;
import java.util.Objects;
@@ -42,21 +44,28 @@ import java.util.stream.Stream;
import javax.inject.Inject;
import javax.inject.Provider;
import javax.inject.Singleton;
import javax.swing.SwingUtilities;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.events.ResizeableChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.events.PluginChanged;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.KeyManager;
import net.runelite.client.input.MouseListener;
import net.runelite.client.input.MouseManager;
import net.runelite.client.plugins.PluginManager;
import net.runelite.client.ui.overlay.infobox.InfoBoxOverlay;
import net.runelite.client.ui.overlay.tooltip.TooltipOverlay;
@Singleton
@Slf4j
public class OverlayRenderer
public class OverlayRenderer extends MouseListener implements KeyListener
{
private static final int BORDER_LEFT_RESIZABLE = 5;
private static final int BORDER_TOP_RESIZABLE = 20;
@@ -66,29 +75,56 @@ public class OverlayRenderer
private static final int BORDER_RIGHT = 2;
private static final int BORDER_BOTTOM = 2;
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);
private static final Color SNAP_CORNER_ACTIVE_COLOR = new Color(0, 255, 0, 100);
private static final Color MOVING_OVERLAY_COLOR = new Color(255, 255, 0, 100);
private static final Color MOVING_OVERLAY_ACTIVE_COLOR = new Color(255, 255, 0, 200);
private static final String OVERLAY_CONFIG_PREFERRED_LOCATION = "_preferredLocation";
private static final String OVERLAY_CONFIG_PREFERRED_POSITION = "_preferredPosition";
private final PluginManager pluginManager;
private final Provider<Client> clientProvider;
private final InfoBoxOverlay infoBoxOverlay;
private final ConfigManager configManager;
private final TooltipOverlay tooltipOverlay;
private final List<Overlay> allOverlays = new CopyOnWriteArrayList<>();
private final List<Overlay> overlaysAboveScene = new CopyOnWriteArrayList<>(),
overlaysUnderWidgets = new CopyOnWriteArrayList<>(),
overlaysAboveWidgets = new CopyOnWriteArrayList<>(),
overlaysOnTop = new CopyOnWriteArrayList<>();
private final ConcurrentLinkedQueue<Consumer<BufferedImage>> screenshotRequests = new ConcurrentLinkedQueue<>();
private final String runeliteGroupName = RuneLiteConfig.class.getAnnotation(ConfigGroup.class).keyName();
// Overlay movement variables
private final Point overlayOffset = new Point();
private final Point mousePosition = new Point();
private Overlay movedOverlay;
private boolean inOverlayDraggingMode;
// Overlay state validation
private Rectangle viewportBounds;
private boolean chatboxHidden;
private boolean isResizeable;
private OverlayBounds snapCorners;
@Inject
PluginManager pluginManager;
@Inject
Provider<Client> clientProvider;
@Inject
InfoBoxOverlay infoBoxOverlay;
@Inject
TooltipOverlay tooltipOverlay;
private final List<Overlay> overlays = new CopyOnWriteArrayList<>();
private BufferedImage surface;
private Graphics2D surfaceGraphics;
private ConcurrentLinkedQueue<Consumer<BufferedImage>> screenshotRequests = new ConcurrentLinkedQueue<>();
@Subscribe
public void onResizableChanged(ResizeableChanged event)
private OverlayRenderer(
final Provider<Client> clientProvider,
final PluginManager pluginManager,
final MouseManager mouseManager,
final KeyManager keyManager,
final TooltipOverlay tooltipOverlay,
final InfoBoxOverlay infoBoxOverlay,
final ConfigManager configManager)
{
updateSurface();
this.clientProvider = clientProvider;
this.pluginManager = pluginManager;
this.tooltipOverlay = tooltipOverlay;
this.infoBoxOverlay = infoBoxOverlay;
this.configManager = configManager;
keyManager.registerKeyListener(this);
mouseManager.registerMouseListener(this);
}
@Subscribe
@@ -101,32 +137,101 @@ public class OverlayRenderer
return;
}
if (event.getGameState().equals(GameState.LOGIN_SCREEN) || event.getGameState().equals(GameState.LOGGED_IN))
if (event.getGameState().equals(GameState.LOGGED_IN))
{
refreshPlugins();
updateSurface();
rebuildOverlays();
}
}
@Subscribe
public void onPluginChanged(PluginChanged event)
{
refreshPlugins();
rebuildOverlays();
}
private void refreshPlugins()
private List<Overlay> getOverlaysForLayer(OverlayLayer layer)
{
overlays.clear();
overlays.addAll(Stream
switch (layer)
{
case ABOVE_SCENE:
return overlaysAboveScene;
case UNDER_WIDGETS:
return overlaysUnderWidgets;
case ABOVE_WIDGETS:
return overlaysAboveWidgets;
case ALWAYS_ON_TOP:
return overlaysOnTop;
default:
throw new IllegalStateException();
}
}
private void rebuildOverlays()
{
List<Overlay> overlays = Stream
.concat(
pluginManager.getPlugins()
.stream()
.filter(plugin -> pluginManager.isPluginEnabled(plugin))
.filter(pluginManager::isPluginEnabled)
.flatMap(plugin -> plugin.getOverlays().stream()),
Stream.of(infoBoxOverlay, tooltipOverlay))
.filter(Objects::nonNull)
.collect(Collectors.toList()));
.collect(Collectors.toList());
sortOverlays(overlays);
allOverlays.clear();
allOverlays.addAll(overlays);
final Client client = clientProvider.get();
for (final Overlay overlay : overlays)
{
final Point location = loadOverlayLocation(overlay);
if (location != null
&& client.getCanvas() != null
&& !client.getCanvas().contains(location))
{
overlay.setPreferredLocation(null);
saveOverlayLocation(overlay);
}
else
{
overlay.setPreferredLocation(location);
}
final OverlayPosition position = loadOverlayPosition(overlay);
overlay.setPreferredPosition(position);
}
rebuildOverlayLayers();
}
private void rebuildOverlayLayers()
{
overlaysAboveScene.clear();
overlaysUnderWidgets.clear();
overlaysAboveWidgets.clear();
overlaysOnTop.clear();
for (final Overlay overlay : allOverlays)
{
OverlayLayer layer = overlay.getLayer();
if (overlay.getPreferredLocation() != null && overlay.getPreferredPosition() == null)
{
// When UNDER_WIDGET overlays are in preferred locations, move to
// ABOVE_WIDGETS so that it can draw over interfaces
if (layer == OverlayLayer.UNDER_WIDGETS)
{
layer = OverlayLayer.ABOVE_WIDGETS;
}
}
List<Overlay> overlayLayer = getOverlaysForLayer(layer);
overlayLayer.add(overlay);
}
}
static void sortOverlays(List<Overlay> overlays)
@@ -151,89 +256,54 @@ public class OverlayRenderer
});
}
private void updateSurface()
public void render(Graphics2D graphics, final OverlayLayer layer)
{
final Client client = clientProvider.get();
List<Overlay> overlays = getOverlaysForLayer(layer);
if (client == null)
if (client == null
|| overlays.isEmpty()
|| client.getViewportWidget() == null
|| client.getGameState() != GameState.LOGGED_IN
|| client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN) != null)
{
return;
}
final Dimension size = client.getCanvas().getSize();
final BufferedImage temp = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D subGraphics = temp.createGraphics();
subGraphics.setBackground(new Color(0, 0, 0, 0));
OverlayUtil.setGraphicProperties(subGraphics);
surface = temp;
if (surfaceGraphics != null)
if (shouldInvalidateOverlays())
{
surfaceGraphics.dispose();
snapCorners = buildSnapCorners();
}
surfaceGraphics = subGraphics;
}
public void render(Graphics2D graphics, OverlayLayer layer)
{
final Client client = clientProvider.get();
if (client == null || surface == null || overlays.isEmpty())
{
return;
}
if (client.getGameState() != GameState.LOGGED_IN)
{
return;
}
if (client.getWidget(WidgetInfo.LOGIN_CLICK_TO_PLAY_SCREEN) != null)
{
return;
}
final boolean isResizeable = client.isResized();
final Widget viewport = client.getViewportWidget();
final Rectangle bounds = viewport != null
? new Rectangle(viewport.getBounds())
: new Rectangle(0, 0, surface.getWidth(), surface.getHeight());
final Widget chatbox = client.getWidget(WidgetInfo.CHATBOX_MESSAGES);
final Rectangle chatboxBounds = chatbox != null
? chatbox.getBounds() : new Rectangle(0, bounds.height, 519, 165);
// Create copy of snap corners because overlays will modify them
OverlayBounds snapCorners = new OverlayBounds(this.snapCorners);
OverlayUtil.setGraphicProperties(graphics);
final Point topLeftPoint = new Point();
topLeftPoint.move(
isResizeable ? BORDER_LEFT_RESIZABLE : BORDER_LEFT_FIXED,
isResizeable ? BORDER_TOP_RESIZABLE : BORDER_TOP_FIXED);
final Point topRightPoint = new Point();
topRightPoint.move(bounds.x + bounds.width - BORDER_RIGHT, BORDER_TOP_FIXED);
final Point bottomLeftPoint = new Point();
bottomLeftPoint.move(isResizeable ? BORDER_LEFT_RESIZABLE : BORDER_LEFT_FIXED, bounds.y + bounds.height - BORDER_BOTTOM);
final Point bottomRightPoint = new Point();
bottomRightPoint.move(bounds.x + bounds.width - BORDER_RIGHT, bounds.y + bounds.height - BORDER_BOTTOM);
final Point rightChatboxPoint = new Point();
rightChatboxPoint.move(bounds.x + chatboxBounds.width - BORDER_RIGHT, bounds.y + bounds.height - BORDER_BOTTOM);
//check to see if Chatbox is minimized
if (chatbox != null && isResizeable && chatbox.isHidden())
// Draw snap corners
if (layer == OverlayLayer.UNDER_WIDGETS && movedOverlay != null)
{
rightChatboxPoint.y += chatboxBounds.height;
bottomLeftPoint.y += chatboxBounds.height;
final OverlayBounds translatedSnapCorners = translateSnapCorners(snapCorners);
final Color previous = graphics.getColor();
for (final Rectangle corner : translatedSnapCorners.getBounds())
{
graphics.setColor(corner.contains(mousePosition) ? SNAP_CORNER_ACTIVE_COLOR : SNAP_CORNER_COLOR);
graphics.fill(corner);
}
graphics.setColor(previous);
}
for (Overlay overlay : overlays)
{
if (overlay.getLayer() != layer)
OverlayPosition overlayPosition = overlay.getPosition();
if (overlay.getPreferredPosition() != null)
{
continue;
overlayPosition = overlay.getPreferredPosition();
}
OverlayPosition overlayPosition = overlay.getPosition();
if (overlayPosition == OverlayPosition.ABOVE_CHATBOX_RIGHT && !client.isResized())
{
// On fixed mode, ABOVE_CHATBOX_RIGHT is in the same location as
@@ -241,25 +311,6 @@ public class OverlayRenderer
// drawing over each other.
overlayPosition = OverlayPosition.BOTTOM_RIGHT;
}
final Point subPosition = new Point();
switch (overlayPosition)
{
case BOTTOM_LEFT:
subPosition.setLocation(bottomLeftPoint);
break;
case BOTTOM_RIGHT:
subPosition.setLocation(bottomRightPoint);
break;
case TOP_LEFT:
subPosition.setLocation(topLeftPoint);
break;
case TOP_RIGHT:
subPosition.setLocation(topRightPoint);
break;
case ABOVE_CHATBOX_RIGHT:
subPosition.setLocation(rightChatboxPoint);
break;
}
if (overlayPosition == OverlayPosition.DYNAMIC || overlayPosition == OverlayPosition.TOOLTIP)
{
@@ -267,48 +318,313 @@ public class OverlayRenderer
}
else
{
final Dimension dimension = MoreObjects.firstNonNull(safeRender(overlay, surfaceGraphics, subPosition), new Dimension());
if (dimension.width == 0 && dimension.height == 0)
final Point location = overlay.getBounds().getLocation();
final Dimension dimension = overlay.getBounds().getSize();
// If the final position is not modified, layout it
if (overlay.getPreferredLocation() == null || overlay.getPreferredPosition() != null)
{
final Rectangle snapCorner = snapCorners.forPosition(overlayPosition);
final Point translation = OverlayUtil.transformPosition(overlayPosition, dimension);
location.setLocation(snapCorner.getX() + translation.x, snapCorner.getY() + translation.y);
final Point padding = OverlayUtil.padPosition(overlayPosition, dimension, PADDING);
snapCorner.translate(padding.x, padding.y);
}
else
{
location.setLocation(overlay.getPreferredLocation());
}
final Dimension overlayDimension = MoreObjects.firstNonNull(
safeRender(overlay, graphics, location),
new Dimension());
overlay.setBounds(new Rectangle(location, overlayDimension));
if (overlayDimension.width == 0 && overlayDimension.height == 0)
{
continue;
}
final BufferedImage clippedImage = surface.getSubimage(0, 0, dimension.width, dimension.height);
switch (overlayPosition)
if (inOverlayDraggingMode)
{
case BOTTOM_LEFT:
bottomLeftPoint.x += dimension.width + (dimension.width == 0 ? 0 : PADDING);
break;
case BOTTOM_RIGHT:
bottomRightPoint.x -= dimension.width + (dimension.width == 0 ? 0 : PADDING);
break;
case TOP_LEFT:
topLeftPoint.y += dimension.height + (dimension.height == 0 ? 0 : PADDING);
break;
case TOP_RIGHT:
topRightPoint.y += dimension.height + (dimension.height == 0 ? 0 : PADDING);
break;
case ABOVE_CHATBOX_RIGHT:
rightChatboxPoint.y -= dimension.height + (dimension.height == 0 ? 0 : PADDING);
break;
final Color previous = graphics.getColor();
graphics.setColor(movedOverlay == overlay ? MOVING_OVERLAY_ACTIVE_COLOR : MOVING_OVERLAY_COLOR);
graphics.drawRect(location.x, location.y, dimension.width - 1, dimension.height - 1);
graphics.setColor(previous);
}
}
}
}
@Override
public MouseEvent mousePressed(MouseEvent mouseEvent)
{
if (!inOverlayDraggingMode)
{
return mouseEvent;
}
final Point mousePoint = mouseEvent.getPoint();
mousePosition.setLocation(mousePoint);
for (Overlay overlay : allOverlays)
{
if (overlay.getBounds().contains(mousePoint))
{
if (SwingUtilities.isRightMouseButton(mouseEvent))
{
overlay.setPreferredLocation(null);
overlay.setPreferredPosition(null);
rebuildOverlayLayers();
}
else
{
mousePoint.translate(-overlay.getBounds().x, -overlay.getBounds().y);
overlayOffset.setLocation(mousePoint);
movedOverlay = overlay;
}
final Point transformed = OverlayUtil.transformPosition(overlayPosition, dimension);
graphics.drawImage(clippedImage, subPosition.x + transformed.x, subPosition.y + transformed.y, null);
surfaceGraphics.clearRect(0, 0, (int) dimension.getWidth(), (int) dimension.getHeight());
mouseEvent.consume();
break;
}
}
return mouseEvent;
}
@Override
public MouseEvent mouseDragged(MouseEvent mouseEvent)
{
if (!inOverlayDraggingMode)
{
return mouseEvent;
}
final Client client = clientProvider.get();
if (client == null)
{
return mouseEvent;
}
final Point mousePoint = mouseEvent.getPoint();
mousePosition.setLocation(mousePoint);
final Rectangle canvasRect = new Rectangle(client.getRealDimensions());
if (!canvasRect.contains(mousePoint))
{
return mouseEvent;
}
if (movedOverlay != null)
{
mousePoint.translate(-overlayOffset.x, -overlayOffset.y);
movedOverlay.setPreferredPosition(null);
movedOverlay.setPreferredLocation(mousePoint);
rebuildOverlayLayers();
mouseEvent.consume();
}
return mouseEvent;
}
@Override
public MouseEvent mouseReleased(MouseEvent mouseEvent)
{
if (movedOverlay != null)
{
mousePosition.setLocation(-1, -1);
final OverlayBounds snapCorners = translateSnapCorners(buildSnapCorners());
for (Rectangle snapCorner : snapCorners.getBounds())
{
if (snapCorner.contains(mouseEvent.getPoint()))
{
OverlayPosition position = snapCorners.fromBounds(snapCorner);
if (position == movedOverlay.getPosition())
{
// overlay moves back to default position
position = null;
}
movedOverlay.setPreferredPosition(position);
movedOverlay.setPreferredLocation(null); // from dragging
break;
}
}
saveOverlayPosition(movedOverlay);
saveOverlayLocation(movedOverlay);
rebuildOverlayLayers();
movedOverlay = null;
mouseEvent.consume();
}
return mouseEvent;
}
@Override
public void keyTyped(KeyEvent e)
{
}
@Override
public void keyPressed(KeyEvent e)
{
if (e.isAltDown())
{
inOverlayDraggingMode = true;
}
}
@Override
public void keyReleased(KeyEvent e)
{
if (!e.isAltDown())
{
inOverlayDraggingMode = false;
}
}
private Dimension safeRender(RenderableEntity entity, Graphics2D graphics, Point point)
{
final Graphics2D subGraphics = (Graphics2D) graphics.create();
subGraphics.translate(point.x, point.y);
final Dimension dimension = entity.render(subGraphics, point);
subGraphics.dispose();
return dimension;
}
private boolean shouldInvalidateOverlays()
{
final Client client = clientProvider.get();
final Widget widget = client.getWidget(WidgetInfo.CHATBOX_MESSAGES);
final boolean resizeableChanged = isResizeable != client.isResized();
if (resizeableChanged)
{
isResizeable = client.isResized();
return true;
}
final boolean chatboxHiddenChanged = chatboxHidden != (widget != null && widget.isHidden());
if (chatboxHiddenChanged)
{
chatboxHidden = widget != null && widget.isHidden();
return true;
}
final boolean viewportChanged = !client.getViewportWidget().getBounds().equals(viewportBounds);
if (viewportChanged)
{
viewportBounds = client.getViewportWidget().getBounds();
return true;
}
return false;
}
private OverlayBounds buildSnapCorners()
{
final Client client = clientProvider.get();
final Rectangle bounds = viewportBounds != null
? viewportBounds
: new Rectangle(0, 0, client.getCanvas().getWidth(), client.getCanvas().getHeight());
final Widget chatbox = client.getWidget(WidgetInfo.CHATBOX_MESSAGES);
final Rectangle chatboxBounds = chatbox != null
? chatbox.getBounds() : new Rectangle(0, bounds.height, 519, 165);
final Point topLeftPoint = new Point(
isResizeable ? BORDER_LEFT_RESIZABLE : BORDER_LEFT_FIXED,
isResizeable ? BORDER_TOP_RESIZABLE : BORDER_TOP_FIXED);
final Point topRightPoint = new Point(bounds.x + bounds.width - BORDER_RIGHT, BORDER_TOP_FIXED);
final Point bottomLeftPoint = new Point(isResizeable ? BORDER_LEFT_RESIZABLE : BORDER_LEFT_FIXED, bounds.y + bounds.height - BORDER_BOTTOM);
final Point bottomRightPoint = new Point(bounds.x + bounds.width - BORDER_RIGHT, bounds.y + bounds.height - BORDER_BOTTOM);
final Point rightChatboxPoint = new Point(bounds.x + chatboxBounds.width - BORDER_RIGHT, bounds.y + bounds.height - BORDER_BOTTOM);
// Check to see if chat box is minimized
if (chatbox != null && isResizeable && chatboxHidden)
{
rightChatboxPoint.y += chatboxBounds.height;
bottomLeftPoint.y += chatboxBounds.height;
}
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));
}
private OverlayBounds translateSnapCorners(OverlayBounds snapCorners)
{
return new OverlayBounds(
snapCorners.getTopLeft(),
translate(snapCorners.getTopRight(), -SNAP_CORNER_SIZE.width, 0),
translate(snapCorners.getBottomLeft(), 0, -SNAP_CORNER_SIZE.height),
translate(snapCorners.getBottomRight(), -SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height),
translate(snapCorners.getAboveChatboxRight(), -SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height));
}
private static Rectangle translate(Rectangle rectangle, int dx, int dy)
{
rectangle.translate(dx, dy);
return rectangle;
}
private void saveOverlayLocation(final Overlay overlay)
{
final String key = overlay.getClass().getSimpleName() + OVERLAY_CONFIG_PREFERRED_LOCATION;
if (overlay.getPreferredLocation() != null)
{
configManager.setConfiguration(
runeliteGroupName,
key,
overlay.getPreferredLocation());
}
else
{
configManager.unsetConfiguration(
runeliteGroupName,
key);
}
}
private void saveOverlayPosition(final Overlay overlay)
{
final String key = overlay.getClass().getSimpleName() + OVERLAY_CONFIG_PREFERRED_POSITION;
if (overlay.getPreferredPosition() != null)
{
configManager.setConfiguration(
runeliteGroupName,
key,
overlay.getPreferredPosition());
}
else
{
configManager.unsetConfiguration(
runeliteGroupName,
key);
}
}
private Point loadOverlayLocation(final Overlay overlay)
{
final String key = overlay.getClass().getSimpleName() + OVERLAY_CONFIG_PREFERRED_LOCATION;
return configManager.getConfiguration(runeliteGroupName, key, Point.class);
}
private OverlayPosition loadOverlayPosition(final Overlay overlay)
{
final String locationKey = overlay.getClass().getSimpleName() + OVERLAY_CONFIG_PREFERRED_POSITION;
return configManager.getConfiguration(runeliteGroupName, locationKey, OverlayPosition.class);
}
public void provideScreenshot(BufferedImage image)
{
Consumer<BufferedImage> consumer;

View File

@@ -137,6 +137,35 @@ public class OverlayUtil
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
public static java.awt.Point padPosition(OverlayPosition position, Dimension dimension, final int padding)
{
final java.awt.Point result = new java.awt.Point();
switch (position)
{
case DYNAMIC:
case TOOLTIP:
break;
case BOTTOM_LEFT:
result.x += dimension.width + (dimension.width == 0 ? 0 : padding);
break;
case BOTTOM_RIGHT:
result.x -= dimension.width + (dimension.width == 0 ? 0 : padding);
break;
case TOP_LEFT:
result.y += dimension.height + (dimension.height == 0 ? 0 : padding);
break;
case TOP_RIGHT:
result.y += dimension.height + (dimension.height == 0 ? 0 : padding);
break;
case ABOVE_CHATBOX_RIGHT:
result.y -= dimension.height + (dimension.height == 0 ? 0 : padding);
break;
}
return result;
}
public static java.awt.Point transformPosition(OverlayPosition position, Dimension dimension)
{
final java.awt.Point result = new java.awt.Point();
@@ -144,6 +173,7 @@ public class OverlayUtil
switch (position)
{
case DYNAMIC:
case TOOLTIP:
case TOP_LEFT:
break;
case BOTTOM_LEFT:

View File

@@ -85,6 +85,18 @@ public abstract class StretchedFixedModeMixin implements RSClient
cachedStretchedDimensions = null;
}
@Inject
@Override
public Dimension getRealDimensions()
{
if (isStretchedEnabled() && !isResized())
{
return Constants.GAME_FIXED_SIZE;
}
return getCanvas().getSize();
}
@Inject
@Override
public Dimension getStretchedDimensions()