|
|
|
|
@@ -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;
|
|
|
|
|
|