Merge remote-tracking branch 'runelite/master'

This commit is contained in:
Owain van Brakel
2020-04-18 23:38:58 +02:00
32 changed files with 812 additions and 280 deletions

View File

@@ -27,10 +27,12 @@ package net.runelite.client;
import io.reactivex.rxjava3.schedulers.Schedulers;
import java.time.temporal.ChronoUnit;
import java.util.UUID;
import java.util.concurrent.Future;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.ClientShutdown;
import net.runelite.client.task.Schedule;
@Singleton
@@ -38,15 +40,23 @@ import net.runelite.client.task.Schedule;
public class ClientSessionManager
{
private final SessionClient sessionClient;
private final ClientThread clientThread;
private UUID sessionId;
@Inject
ClientSessionManager(ClientThread clientThread)
ClientSessionManager(EventBus eventBus)
{
this.sessionClient = new SessionClient();
this.clientThread = clientThread;
eventBus.subscribe(ClientShutdown.class, this, (e) ->
{
Future<Void> f = shutdown();
if (f != null)
{
e.waitFor(f);
}
sessionId = null;
});
}
void start()
@@ -54,7 +64,8 @@ public class ClientSessionManager
sessionClient.openSession()
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.single())
.subscribe(this::setUuid, this::error);
.doOnError(this::error)
.subscribe(this::setUuid);
}
@Schedule(period = 10, unit = ChronoUnit.MINUTES, asynchronous = true)
@@ -73,18 +84,15 @@ public class ClientSessionManager
.subscribe();
}
public void shutdown()
private Future<Void> shutdown()
{
if (sessionId != null)
{
sessionClient.delete(sessionId)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.single())
.doOnError(this::error)
.subscribe();
return sessionClient.delete(sessionId)
.toFuture();
sessionId = null;
}
return null;
}
private void setUuid(UUID uuid)

View File

@@ -469,7 +469,7 @@ public class RuneLite
// Initialize UI
RuneLiteSplashScreen.stage(.80, "Initialize UI");
clientUI.init(this);
clientUI.init();
// Initialize Discord service
discordService.init();
@@ -599,13 +599,6 @@ public class RuneLite
}
}
public void shutdown()
{
clientSessionManager.shutdown();
discordService.close();
groups.close();
}
private static class ConfigFileConverter implements ValueConverter<File>
{
@Override

View File

@@ -371,18 +371,6 @@ public interface RuneLiteConfig extends Config
return false;
}
@ConfigItem(
keyName = "infoBoxWrap",
name = "Infobox wrap count",
description = "Configures the amount of infoboxes shown before wrapping",
position = 29,
titleSection = "infoboxTitle"
)
default int infoBoxWrap()
{
return 4;
}
@ConfigItem(
keyName = "infoBoxSize",
name = "Infobox size",

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2020 Abex
* 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.events;
import java.time.Duration;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.events.Event;
@Value
@Slf4j
public class ClientShutdown implements Event
{
private Queue<Future<?>> tasks = new ConcurrentLinkedQueue<>();
public void waitFor(Future<?> future)
{
tasks.add(future);
}
public void waitForAllConsumers(Duration totalTimeout)
{
long deadline = System.nanoTime() + totalTimeout.toNanos();
for (Future<?> task; (task = tasks.poll()) != null; )
{
long timeout = deadline - System.nanoTime();
if (timeout < 0)
{
log.warn("Timed out waiting for task completion");
return;
}
try
{
task.get(timeout, TimeUnit.NANOSECONDS);
}
catch (ThreadDeath d)
{
throw d;
}
catch (Throwable t)
{
log.warn("Error during shutdown: ", t);
}
}
}
}

View File

@@ -49,25 +49,52 @@ public class KeyManager
public void processKeyPressed(KeyEvent keyEvent)
{
if (keyEvent.isConsumed())
{
return;
}
for (KeyListener keyListener : keyListeners)
{
keyListener.keyPressed(keyEvent);
if (keyEvent.isConsumed())
{
break;
}
}
}
public void processKeyReleased(KeyEvent keyEvent)
{
if (keyEvent.isConsumed())
{
return;
}
for (KeyListener keyListener : keyListeners)
{
keyListener.keyReleased(keyEvent);
if (keyEvent.isConsumed())
{
break;
}
}
}
public void processKeyTyped(KeyEvent keyEvent)
{
if (keyEvent.isConsumed())
{
return;
}
for (KeyListener keyListener : keyListeners)
{
keyListener.keyTyped(keyEvent);
if (keyEvent.isConsumed())
{
break;
}
}
}
}

View File

@@ -82,30 +82,57 @@ public class MouseManager
public MouseEvent processMousePressed(MouseEvent mouseEvent)
{
if (mouseEvent.isConsumed())
{
return mouseEvent;
}
checkExtraMouseButtons(mouseEvent);
for (MouseListener mouseListener : mouseListeners)
{
mouseEvent = mouseListener.mousePressed(mouseEvent);
if (mouseEvent.isConsumed())
{
break;
}
}
return mouseEvent;
}
public MouseEvent processMouseReleased(MouseEvent mouseEvent)
{
if (mouseEvent.isConsumed())
{
return mouseEvent;
}
checkExtraMouseButtons(mouseEvent);
for (MouseListener mouseListener : mouseListeners)
{
mouseEvent = mouseListener.mouseReleased(mouseEvent);
if (mouseEvent.isConsumed())
{
break;
}
}
return mouseEvent;
}
public MouseEvent processMouseClicked(MouseEvent mouseEvent)
{
if (mouseEvent.isConsumed())
{
return mouseEvent;
}
checkExtraMouseButtons(mouseEvent);
for (MouseListener mouseListener : mouseListeners)
{
mouseEvent = mouseListener.mouseClicked(mouseEvent);
if (mouseEvent.isConsumed())
{
break;
}
}
return mouseEvent;
}
@@ -123,45 +150,90 @@ public class MouseManager
public MouseEvent processMouseEntered(MouseEvent mouseEvent)
{
if (mouseEvent.isConsumed())
{
return mouseEvent;
}
for (MouseListener mouseListener : mouseListeners)
{
mouseEvent = mouseListener.mouseEntered(mouseEvent);
if (mouseEvent.isConsumed())
{
break;
}
}
return mouseEvent;
}
public MouseEvent processMouseExited(MouseEvent mouseEvent)
{
if (mouseEvent.isConsumed())
{
return mouseEvent;
}
for (MouseListener mouseListener : mouseListeners)
{
mouseEvent = mouseListener.mouseExited(mouseEvent);
if (mouseEvent.isConsumed())
{
break;
}
}
return mouseEvent;
}
public MouseEvent processMouseDragged(MouseEvent mouseEvent)
{
if (mouseEvent.isConsumed())
{
return mouseEvent;
}
for (MouseListener mouseListener : mouseListeners)
{
mouseEvent = mouseListener.mouseDragged(mouseEvent);
if (mouseEvent.isConsumed())
{
break;
}
}
return mouseEvent;
}
public MouseEvent processMouseMoved(MouseEvent mouseEvent)
{
if (mouseEvent.isConsumed())
{
return mouseEvent;
}
for (MouseListener mouseListener : mouseListeners)
{
mouseEvent = mouseListener.mouseMoved(mouseEvent);
if (mouseEvent.isConsumed())
{
break;
}
}
return mouseEvent;
}
public MouseWheelEvent processMouseWheelMoved(MouseWheelEvent mouseWheelEvent)
{
if (mouseWheelEvent.isConsumed())
{
return mouseWheelEvent;
}
for (MouseWheelListener mouseWheelListener : mouseWheelListeners)
{
mouseWheelEvent = mouseWheelListener.mouseWheelMoved(mouseWheelEvent);
if (mouseWheelEvent.isConsumed())
{
break;
}
}
return mouseWheelEvent;
}

View File

@@ -44,10 +44,13 @@ import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.Window;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.Duration;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Provider;
@@ -72,7 +75,6 @@ import net.runelite.api.Point;
import net.runelite.api.events.GameStateChanged;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.RuneLite;
import net.runelite.client.RuneLiteProperties;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
@@ -80,6 +82,7 @@ import net.runelite.client.config.ExpandResizeType;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.config.WarningOnExit;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.ClientShutdown;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.events.NavigationButtonAdded;
import net.runelite.client.events.NavigationButtonRemoved;
@@ -131,6 +134,7 @@ public class ClientUI
private final Applet client;
private final ConfigManager configManager;
private final Provider<ClientThread> clientThreadProvider;
private final EventBus eventBus;
private final CardLayout cardLayout = new CardLayout();
private final Rectangle sidebarButtonPosition = new Rectangle();
private boolean withTitleBar;
@@ -144,6 +148,7 @@ public class ClientUI
private NavigationButton sidebarNavigationButton;
private JButton sidebarNavigationJButton;
private Dimension lastClientSize;
private Cursor defaultCursor;
private Field opacityField;
private Field peerField;
private Method setOpacityMethod;
@@ -164,6 +169,7 @@ public class ClientUI
this.client = client;
this.configManager = configManager;
this.clientThreadProvider = clientThreadProvider;
this.eventBus = eventbus;
eventbus.subscribe(ConfigChanged.class, this, this::onConfigChanged);
eventbus.subscribe(NavigationButtonAdded.class, this, this::onNavigationButtonAdded);
@@ -313,11 +319,8 @@ public class ClientUI
/**
* Initialize UI.
*
* @param runelite runelite instance that will be shut down on exit
* @throws Exception exception that can occur during creation of the UI
*/
public void init(final RuneLite runelite) throws Exception
public void init() throws Exception
{
SwingUtilities.invokeAndWait(() ->
{
@@ -335,14 +338,36 @@ public class ClientUI
frame.setLocationRelativeTo(frame.getOwner());
frame.setResizable(true);
SwingUtil.addGracefulExitCallback(frame,
() ->
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent event)
{
saveClientBoundsConfig();
runelite.shutdown();
},
this::showWarningOnExit
);
int result = JOptionPane.OK_OPTION;
if (showWarningOnExit())
{
try
{
result = JOptionPane.showConfirmDialog(
frame,
"Are you sure you want to exit?", "Exit",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);
}
catch (Exception e)
{
log.warn("Unexpected exception occurred while check for confirm required", e);
}
}
if (result == JOptionPane.OK_OPTION)
{
shutdownClient();
}
}
});
container = new JPanel();
container.setLayout(new BoxLayout(container, BoxLayout.X_AXIS));
@@ -550,7 +575,7 @@ public class ClientUI
SwingUtilities.invokeLater(() -> JOptionPane.showMessageDialog(frame,
"OpenOSRS has not yet been updated to work with the latest\n"
+ "game update, it will work with reduced functionality until then.",
"RuneLite is outdated", INFORMATION_MESSAGE));
"OpenOSRS is outdated", INFORMATION_MESSAGE));
}
}
@@ -569,6 +594,45 @@ public class ClientUI
return false;
}
private void shutdownClient()
{
saveClientBoundsConfig();
ClientShutdown csev = new ClientShutdown();
eventBus.post(ClientShutdown.class, csev);
new Thread(() ->
{
csev.waitForAllConsumers(Duration.ofSeconds(10));
if (client != null)
{
// The client can call System.exit when it's done shutting down
// if it doesn't though, we want to exit anyway, so race it
int clientShutdownWaitMS;
if (client instanceof Client)
{
((Client) client).stopNow();
clientShutdownWaitMS = 1000;
}
else
{
// it will continue rendering for about 4 seconds before attempting shutdown if its vanilla
client.stop();
frame.setVisible(false);
clientShutdownWaitMS = 6000;
}
try
{
Thread.sleep(clientShutdownWaitMS);
}
catch (InterruptedException ignored)
{
}
}
System.exit(0);
}, "OpenOSRS Shutdown").start();
}
/**
* Paint this component to target graphics
*
@@ -654,7 +718,27 @@ public class ClientUI
}
/**
* Changes cursor for client window. Requires ${@link ClientUI#init(RuneLite)} to be called first.
* Returns current cursor set on game container
*
* @return awt cursor
*/
public Cursor getCurrentCursor()
{
return container.getCursor();
}
/**
* Returns current custom cursor or default system cursor if cursor is not set
*
* @return awt cursor
*/
public Cursor getDefaultCursor()
{
return defaultCursor != null ? defaultCursor : Cursor.getDefaultCursor();
}
/**
* Changes cursor for client window. Requires ${@link ClientUI#init()} to be called first.
* FIXME: This is working properly only on Windows, Linux and Mac are displaying cursor incorrectly
*
* @param image cursor image
@@ -669,7 +753,18 @@ public class ClientUI
final java.awt.Point hotspot = new java.awt.Point(0, 0);
final Cursor cursorAwt = Toolkit.getDefaultToolkit().createCustomCursor(image, hotspot, name);
container.setCursor(cursorAwt);
defaultCursor = cursorAwt;
setCursor(cursorAwt);
}
/**
* Changes cursor for client window. Requires ${@link ClientUI#init()} to be called first.
*
* @param cursor awt cursor
*/
public void setCursor(final Cursor cursor)
{
container.setCursor(cursor);
}
/**
@@ -684,6 +779,7 @@ public class ClientUI
return;
}
defaultCursor = null;
container.setCursor(Cursor.getDefaultCursor());
}

View File

@@ -128,6 +128,12 @@ public class FlatTextField extends JPanel
setBackground(color, true);
}
@Override
public boolean requestFocusInWindow()
{
return textField.requestFocusInWindow();
}
public void setBackground(Color color, boolean saveColor)
{
if (color == null)

View File

@@ -49,6 +49,7 @@ public abstract class Overlay implements LayoutableRenderableEntity
private OverlayPriority priority = OverlayPriority.NONE;
private OverlayLayer layer = OverlayLayer.UNDER_WIDGETS;
private final List<OverlayMenuEntry> menuEntries = new ArrayList<>();
private boolean resizable;
protected Overlay()
{

View File

@@ -261,7 +261,7 @@ public class OverlayManager
saveOverlay(overlay);
}
private synchronized void rebuildOverlayLayers()
synchronized void rebuildOverlayLayers()
{
for (OverlayLayer l : OverlayLayer.values())
{

View File

@@ -0,0 +1,96 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* 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.Dimension;
import java.awt.Graphics2D;
import lombok.Getter;
import lombok.Setter;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.overlay.components.ComponentConstants;
import net.runelite.client.ui.overlay.components.PanelComponent;
@Getter
@Setter
public abstract class OverlayPanel extends Overlay
{
protected final PanelComponent panelComponent = new PanelComponent();
/**
* Enables/disables automatic clearing of {@link this#getPanelComponent()} children after rendering (enabled by default)
*/
private boolean clearChildren = true;
/**
* Enables/disables automatic font size changes based on panel component size relative to default panel component size.
*/
private boolean dynamicFont = false;
protected OverlayPanel()
{
super();
setResizable(true);
}
protected OverlayPanel(Plugin plugin)
{
super(plugin);
setResizable(true);
}
@Override
public Dimension render(final Graphics2D graphics)
{
final Dimension oldSize = panelComponent.getPreferredSize();
if (getPreferredSize() != null)
{
panelComponent.setPreferredSize(getPreferredSize());
if (dynamicFont)
{
if (getPreferredSize().width >= ComponentConstants.STANDARD_WIDTH * 1.3)
{
graphics.setFont(FontManager.getRunescapeBoldFont());
}
else if (getPreferredSize().width <= ComponentConstants.STANDARD_WIDTH * 0.8)
{
graphics.setFont(FontManager.getRunescapeSmallFont());
}
}
}
final Dimension dimension = panelComponent.render(graphics);
if (clearChildren)
{
panelComponent.getChildren().clear();
}
panelComponent.setPreferredSize(oldSize);
return dimension;
}
}

View File

@@ -25,8 +25,10 @@
package net.runelite.client.ui.overlay;
import com.google.common.base.MoreObjects;
import com.google.common.primitives.Ints;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Paint;
@@ -60,6 +62,7 @@ import net.runelite.client.input.KeyListener;
import net.runelite.client.input.KeyManager;
import net.runelite.client.input.MouseAdapter;
import net.runelite.client.input.MouseManager;
import net.runelite.client.ui.ClientUI;
import net.runelite.client.ui.JagexColors;
import net.runelite.client.util.ColorUtil;
import net.runelite.client.util.MiscUtils;
@@ -71,21 +74,29 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
private static final int BORDER = 5;
private static final int BORDER_TOP = BORDER + 15;
private static final int PADDING = 2;
private static final int MIN_OVERLAY_SIZE = 32;
private static final int OVERLAY_RESIZE_TOLERANCE = 5;
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 Color MOVING_OVERLAY_RESIZING_COLOR = new Color(255, 0, 255, 200);
private final Client client;
private final OverlayManager overlayManager;
private final RuneLiteConfig runeLiteConfig;
private final ClientUI clientUI;
// Overlay movement variables
private final Point overlayOffset = new Point();
private final Point mousePosition = new Point();
private Overlay movedOverlay;
private Overlay currentManagedOverlay;
private Rectangle currentManagedBounds;
private boolean inOverlayManagingMode;
private boolean inOverlayResizingMode;
private boolean inOverlayDraggingMode;
private boolean inMenuEntryMode;
private boolean startedMovingOverlay;
private MenuEntry[] menuEntries;
// Overlay state validation
@@ -106,11 +117,13 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
final RuneLiteConfig runeLiteConfig,
final MouseManager mouseManager,
final KeyManager keyManager,
final EventBus eventbus)
final EventBus eventbus,
final ClientUI clientUI)
{
this.client = client;
this.overlayManager = overlayManager;
this.runeLiteConfig = runeLiteConfig;
this.clientUI = clientUI;
keyManager.registerKeyListener(this);
mouseManager.registerMouseListener(this);
@@ -123,7 +136,8 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
{
if (!event.isFocused())
{
inOverlayDraggingMode = false;
inOverlayManagingMode = false;
resetOverlayManagementMode();
inMenuEntryMode = false;
menuEntries = null;
}
@@ -202,7 +216,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
OverlayUtil.setGraphicProperties(graphics);
// Draw snap corners
if (layer == OverlayLayer.UNDER_WIDGETS && movedOverlay != null && movedOverlay.getPosition() != OverlayPosition.DETACHED)
if (inOverlayDraggingMode && layer == OverlayLayer.UNDER_WIDGETS && currentManagedOverlay != null && currentManagedOverlay.getPosition() != OverlayPosition.DETACHED)
{
final OverlayBounds translatedSnapCorners = snapCorners.translated(
-SNAP_CORNER_SIZE.width,
@@ -294,12 +308,19 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
if (!bounds.isEmpty())
{
if (inOverlayDraggingMode)
if (inOverlayManagingMode)
{
final Color previous = graphics.getColor();
graphics.setColor(movedOverlay == overlay ? MOVING_OVERLAY_ACTIVE_COLOR : MOVING_OVERLAY_COLOR);
if (inOverlayResizingMode && currentManagedOverlay == overlay)
{
graphics.setColor(MOVING_OVERLAY_RESIZING_COLOR);
}
else
{
graphics.setColor(inOverlayDraggingMode && currentManagedOverlay == overlay ? MOVING_OVERLAY_ACTIVE_COLOR : MOVING_OVERLAY_COLOR);
}
graphics.draw(bounds);
graphics.setColor(previous);
graphics.setPaint(paint);
}
if (!client.isMenuOpen() && !client.isSpellSelected() && bounds.contains(mouse))
@@ -319,7 +340,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
@Override
public MouseEvent mousePressed(MouseEvent mouseEvent)
{
if (!inOverlayDraggingMode)
if (!inOverlayManagingMode)
{
return mouseEvent;
}
@@ -327,71 +348,205 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
final Point mousePoint = mouseEvent.getPoint();
mousePosition.setLocation(mousePoint);
synchronized (overlayManager)
if (currentManagedOverlay == null)
{
for (Overlay overlay : overlayManager.getOverlays())
return mouseEvent;
}
if (SwingUtilities.isRightMouseButton(mouseEvent))
{
overlayManager.resetOverlay(currentManagedOverlay);
}
else if (SwingUtilities.isLeftMouseButton(mouseEvent))
{
final Point offset = new Point(mousePoint.x, mousePoint.y);
offset.translate(-currentManagedOverlay.getBounds().x, -currentManagedOverlay.getBounds().y);
overlayOffset.setLocation(offset);
inOverlayResizingMode = currentManagedOverlay != null && currentManagedOverlay.isResizable() && clientUI.getCurrentCursor() != clientUI.getDefaultCursor();
inOverlayDraggingMode = !inOverlayResizingMode;
startedMovingOverlay = true;
currentManagedBounds = new Rectangle(currentManagedOverlay.getBounds());
}
else
{
return mouseEvent;
}
mouseEvent.consume();
return mouseEvent;
}
@Override
public MouseEvent mouseMoved(MouseEvent mouseEvent)
{
if (!inOverlayManagingMode)
{
return mouseEvent;
}
final Point mousePoint = mouseEvent.getPoint();
mousePosition.setLocation(mousePoint);
if (!inOverlayResizingMode && !inOverlayDraggingMode)
{
currentManagedOverlay = null;
synchronized (overlayManager)
{
final OverlayPosition overlayPosition = getCorrectedOverlayPosition(overlay);
if (overlayPosition == OverlayPosition.DYNAMIC || overlayPosition == OverlayPosition.TOOLTIP)
for (Overlay overlay : overlayManager.getOverlays())
{
continue;
}
if (overlay.getBounds().contains(mousePoint))
{
if (SwingUtilities.isRightMouseButton(mouseEvent))
final Rectangle bounds = overlay.getBounds();
if (bounds.contains(mousePoint))
{
overlayManager.resetOverlay(overlay);
currentManagedOverlay = overlay;
break;
}
else
{
final Point offset = new Point(mousePoint.x, mousePoint.y);
offset.translate(-overlay.getBounds().x, -overlay.getBounds().y);
overlayOffset.setLocation(offset);
mousePoint.translate(-offset.x, -offset.y);
movedOverlay = overlay;
movedOverlay.setPreferredPosition(null);
movedOverlay.setPreferredLocation(mousePoint);
overlayManager.saveOverlay(movedOverlay);
}
mouseEvent.consume();
break;
}
}
}
if (currentManagedOverlay == null || !currentManagedOverlay.isResizable())
{
clientUI.setCursor(clientUI.getDefaultCursor());
return mouseEvent;
}
final Rectangle toleranceRect = new Rectangle(currentManagedOverlay.getBounds());
toleranceRect.grow(-OVERLAY_RESIZE_TOLERANCE, -OVERLAY_RESIZE_TOLERANCE);
final int outcode = toleranceRect.outcode(mouseEvent.getPoint());
switch (outcode)
{
case Rectangle.OUT_TOP:
clientUI.setCursor(Cursor.getPredefinedCursor(Cursor.N_RESIZE_CURSOR));
break;
case Rectangle.OUT_TOP | Rectangle.OUT_LEFT:
clientUI.setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
break;
case Rectangle.OUT_LEFT:
clientUI.setCursor(Cursor.getPredefinedCursor(Cursor.W_RESIZE_CURSOR));
break;
case Rectangle.OUT_LEFT | Rectangle.OUT_BOTTOM:
clientUI.setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
break;
case Rectangle.OUT_BOTTOM:
clientUI.setCursor(Cursor.getPredefinedCursor(Cursor.S_RESIZE_CURSOR));
break;
case Rectangle.OUT_BOTTOM | Rectangle.OUT_RIGHT:
clientUI.setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
break;
case Rectangle.OUT_RIGHT:
clientUI.setCursor(Cursor.getPredefinedCursor(Cursor.E_RESIZE_CURSOR));
break;
case Rectangle.OUT_RIGHT | Rectangle.OUT_TOP:
clientUI.setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
break;
default:
// center
clientUI.setCursor(clientUI.getDefaultCursor());
}
return mouseEvent;
}
@Override
public MouseEvent mouseDragged(MouseEvent mouseEvent)
{
if (!inOverlayDraggingMode)
if (!inOverlayManagingMode)
{
return mouseEvent;
}
final Point p = mouseEvent.getPoint();
mousePosition.setLocation(p);
if (currentManagedOverlay == null)
{
return mouseEvent;
}
final Point mousePoint = mouseEvent.getPoint();
mousePosition.setLocation(mousePoint);
final Rectangle canvasRect = new Rectangle(client.getRealDimensions());
if (!canvasRect.contains(mousePoint))
if (!canvasRect.contains(p))
{
return mouseEvent;
}
if (movedOverlay != null)
if (inOverlayResizingMode)
{
final Rectangle r = currentManagedBounds;
final int dx = p.x - r.x;
final int dy = p.y - r.y;
switch (clientUI.getCurrentCursor().getType())
{
case Cursor.N_RESIZE_CURSOR:
int height = r.height - dy;
r.setRect(r.x, r.y + dy, r.width, height);
break;
case Cursor.NW_RESIZE_CURSOR:
int width = r.width - dx;
height = r.height - dy;
r.setRect(r.x + dx, r.y + dy, width, height);
break;
case Cursor.W_RESIZE_CURSOR:
width = r.width - dx;
r.setRect(r.x + dx, r.y, width, r.height);
break;
case Cursor.SW_RESIZE_CURSOR:
width = r.width - dx;
height = dy;
r.setRect(r.x + dx, r.y, width, height);
break;
case Cursor.S_RESIZE_CURSOR:
height = dy;
r.setRect(r.x, r.y, r.width, height);
break;
case Cursor.SE_RESIZE_CURSOR:
width = dx;
height = dy;
r.setRect(r.x, r.y, width, height);
break;
case Cursor.E_RESIZE_CURSOR:
width = dx;
r.setRect(r.x, r.y, width, r.height);
break;
case Cursor.NE_RESIZE_CURSOR:
width = dx;
height = r.height - dy;
r.setRect(r.x, r.y + dy, width, height);
break;
default:
// center
}
currentManagedOverlay.setPreferredSize(new Dimension(Math.max(MIN_OVERLAY_SIZE, currentManagedBounds.width), Math.max(MIN_OVERLAY_SIZE, currentManagedBounds.height)));
if (currentManagedOverlay.getPreferredLocation() != null)
{
currentManagedOverlay.setPreferredLocation(currentManagedBounds.getLocation());
}
}
else if (inOverlayDraggingMode)
{
final Dimension realDimension = client.getRealDimensions();
mousePoint.translate(-overlayOffset.x, -overlayOffset.y);
mousePoint.x = MiscUtils.clamp(mousePoint.x, 0, Math.max(0, realDimension.width - movedOverlay.getBounds().width));
mousePoint.y = MiscUtils.clamp(mousePoint.y, 0, Math.max(0, realDimension.height - movedOverlay.getBounds().height));
movedOverlay.setPreferredPosition(null);
movedOverlay.setPreferredLocation(mousePoint);
mouseEvent.consume();
p.translate(-overlayOffset.x, -overlayOffset.y);
p.x = Ints.constrainToRange(p.x, 0, Math.max(0, realDimension.width - currentManagedOverlay.getBounds().width));
p.y = Ints.constrainToRange(p.y, 0, Math.max(0, realDimension.height - currentManagedOverlay.getBounds().height));
currentManagedOverlay.setPreferredPosition(null);
currentManagedOverlay.setPreferredLocation(p);
}
else
{
return mouseEvent;
}
if (startedMovingOverlay)
{
// Move currently moved overlay to correct layer
overlayManager.rebuildOverlayLayers();
startedMovingOverlay = false;
}
return mouseEvent;
@@ -400,39 +555,40 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
@Override
public MouseEvent mouseReleased(MouseEvent mouseEvent)
{
if (movedOverlay != null)
if (!inOverlayManagingMode || currentManagedOverlay == null || (!inOverlayDraggingMode && !inOverlayResizingMode))
{
mousePosition.setLocation(-1, -1);
// do not snapcorner detached overlays
if (movedOverlay.getPosition() != OverlayPosition.DETACHED)
{
final OverlayBounds snapCorners = this.snapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height);
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;
}
}
}
overlayManager.saveOverlay(movedOverlay);
movedOverlay = null;
mouseEvent.consume();
return mouseEvent;
}
mousePosition.setLocation(-1, -1);
// do not snapcorner detached overlays
if (currentManagedOverlay.getPosition() != OverlayPosition.DETACHED && inOverlayDraggingMode)
{
final OverlayBounds snapCorners = this.snapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height);
for (Rectangle snapCorner : snapCorners.getBounds())
{
if (snapCorner.contains(mouseEvent.getPoint()))
{
OverlayPosition position = snapCorners.fromBounds(snapCorner);
if (position == currentManagedOverlay.getPosition())
{
// overlay moves back to default position
position = null;
}
currentManagedOverlay.setPreferredPosition(position);
currentManagedOverlay.setPreferredLocation(null); // from dragging
break;
}
}
}
overlayManager.saveOverlay(currentManagedOverlay);
resetOverlayManagementMode();
mouseEvent.consume();
return mouseEvent;
}
@@ -446,7 +602,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
{
if (e.isAltDown())
{
inOverlayDraggingMode = true;
inOverlayManagingMode = true;
}
if (e.isShiftDown() && runeLiteConfig.menuEntryShift())
@@ -460,7 +616,8 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
{
if (!e.isAltDown())
{
inOverlayDraggingMode = false;
inOverlayManagingMode = false;
resetOverlayManagementMode();
}
if (!e.isShiftDown())
@@ -546,6 +703,15 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
return overlayPosition;
}
private void resetOverlayManagementMode()
{
inOverlayResizingMode = false;
inOverlayDraggingMode = false;
currentManagedOverlay = null;
currentManagedBounds = null;
clientUI.setCursor(clientUI.getDefaultCursor());
}
private boolean shouldInvalidateBounds()
{
final Widget chatbox = client.getWidget(WidgetInfo.CHATBOX);

View File

@@ -45,6 +45,7 @@ public class PanelComponent implements LayoutableRenderableEntity
private Point preferredLocation = new Point();
@Setter
@Getter
private Dimension preferredSize = new Dimension(ComponentConstants.STANDARD_WIDTH, 0);
@Setter
@@ -58,7 +59,7 @@ public class PanelComponent implements LayoutableRenderableEntity
private ComponentOrientation orientation = ComponentOrientation.VERTICAL;
@Setter
private int wrapping = -1;
private boolean wrap = false;
@Setter
private Rectangle border = new Rectangle(
@@ -114,12 +115,23 @@ public class PanelComponent implements LayoutableRenderableEntity
int totalWidth = 0;
// Render all children
for (int i = 0; i < children.size(); i++)
for (final LayoutableRenderableEntity child : children)
{
final LayoutableRenderableEntity child = children.get(i);
// Correctly propagate child dimensions based on orientation and wrapping
if (!wrap)
{
switch (orientation)
{
case VERTICAL:
child.setPreferredSize(new Dimension(childPreferredSize.width, 0));
break;
case HORIZONTAL:
child.setPreferredSize(new Dimension(0, childPreferredSize.height));
break;
}
}
child.setPreferredLocation(new Point(x, y));
child.setPreferredSize(childPreferredSize);
final Dimension childDimension = child.render(graphics);
switch (orientation)
@@ -140,28 +152,38 @@ public class PanelComponent implements LayoutableRenderableEntity
totalWidth = Math.max(totalWidth, width);
totalHeight = Math.max(totalHeight, height);
if (wrapping > 0 && i < children.size() - 1 && (i + 1) % wrapping == 0)
if (!wrap)
{
switch (orientation)
continue;
}
switch (orientation)
{
case VERTICAL:
{
case VERTICAL:
if (childPreferredSize.height > 0 && height >= childPreferredSize.height)
{
height = 0;
y = baseY;
int diff = childDimension.width + gap.x;
x += diff;
width += diff;
break;
}
case HORIZONTAL:
break;
}
case HORIZONTAL:
{
if (childPreferredSize.width > 0 && width >= childPreferredSize.width)
{
width = 0;
x = baseX;
int diff = childDimension.height + gap.y;
y += diff;
height += diff;
break;
}
break;
}
}
}

View File

@@ -36,19 +36,20 @@ import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.api.Client;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayPanel;
import net.runelite.client.ui.overlay.OverlayPosition;
import net.runelite.client.ui.overlay.components.ComponentOrientation;
import net.runelite.client.ui.overlay.components.InfoBoxComponent;
import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity;
import net.runelite.client.ui.overlay.components.PanelComponent;
import net.runelite.client.ui.overlay.tooltip.Tooltip;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
@Singleton
public class InfoBoxOverlay extends Overlay
public class InfoBoxOverlay extends OverlayPanel
{
private final PanelComponent panelComponent = new PanelComponent();
private static final int GAP = 1;
private static final int DEFAULT_WRAP_COUNT = 4;
private final InfoBoxManager infoboxManager;
private final TooltipManager tooltipManager;
private final Client client;
@@ -66,10 +67,12 @@ public class InfoBoxOverlay extends Overlay
this.client = client;
this.config = config;
setPosition(OverlayPosition.TOP_LEFT);
setClearChildren(false);
panelComponent.setWrap(true);
panelComponent.setBackgroundColor(null);
panelComponent.setBorder(new Rectangle());
panelComponent.setGap(new Point(1, 1));
panelComponent.setGap(new Point(GAP, GAP));
}
@Override
@@ -82,12 +85,12 @@ public class InfoBoxOverlay extends Overlay
return null;
}
panelComponent.getChildren().clear();
panelComponent.setWrapping(config.infoBoxWrap());
// Set preferred size to the size of DEFAULT_WRAP_COUNT infoboxes, including the padding - which is applied
// to the last infobox prior to wrapping too.
panelComponent.setPreferredSize(new Dimension(DEFAULT_WRAP_COUNT * (config.infoBoxSize() + GAP), DEFAULT_WRAP_COUNT * (config.infoBoxSize() + GAP)));
panelComponent.setOrientation(config.infoBoxVertical()
? ComponentOrientation.VERTICAL
: ComponentOrientation.HORIZONTAL);
panelComponent.setPreferredSize(new Dimension(config.infoBoxSize(), config.infoBoxSize()));
for (InfoBox box : infoBoxes)
{
@@ -107,10 +110,11 @@ public class InfoBoxOverlay extends Overlay
}
infoBoxComponent.setImage(box.getScaledImage());
infoBoxComponent.setTooltip(box.getTooltip());
infoBoxComponent.setPreferredSize(new Dimension(config.infoBoxSize(), config.infoBoxSize()));
panelComponent.getChildren().add(infoBoxComponent);
}
final Dimension dimension = panelComponent.render(graphics);
final Dimension dimension = super.render(graphics);
// Handle tooltips
final Point mouse = new Point(client.getMouseCanvasPosition().getX(), client.getMouseCanvasPosition().getY());
@@ -135,6 +139,7 @@ public class InfoBoxOverlay extends Overlay
}
}
panelComponent.getChildren().clear();
return dimension;
}
}

View File

@@ -24,27 +24,14 @@
*/
package net.runelite.client.ui.overlay.tooltip;
import com.google.common.base.Strings;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.Getter;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.eventbus.Subscribe;
import net.runelite.client.events.ConfigChanged;
@Singleton
public class TooltipManager
{
private final ConfigManager configManager;
@Inject
private TooltipManager(final ConfigManager configManager)
{
this.configManager = configManager;
}
@Getter
private final List<Tooltip> tooltips = new ArrayList<>();
@@ -62,17 +49,4 @@ public class TooltipManager
{
tooltips.clear();
}
@Subscribe
public void onConfigChanged(final ConfigChanged event)
{
// Temporary fix for resetting repositioned tooltip overlay
// TODO: Remove this eventually
if (event.getGroup().equals("runelite") &&
event.getKey().equals("TooltipOverlay_preferredLocation") &&
!Strings.isNullOrEmpty(event.getNewValue()))
{
configManager.unsetConfiguration(event.getGroup(), event.getKey());
}
}
}

View File

@@ -5,6 +5,8 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Future;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.AccessLevel;
@@ -12,6 +14,8 @@ import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.client.RuneLite;
import net.runelite.client.config.OpenOSRSConfig;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.ClientShutdown;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.ui.RuneLiteSplashScreen;
import org.jgroups.Address;
@@ -38,7 +42,7 @@ public class Groups extends ReceiverAdapter
private final PublishSubject<Message> messageObjectSubject = PublishSubject.create();
@Inject
public Groups(OpenOSRSConfig openOSRSConfig) throws Exception
public Groups(OpenOSRSConfig openOSRSConfig, EventBus eventBus) throws Exception
{
this.openOSRSConfig = openOSRSConfig;
@@ -47,6 +51,11 @@ public class Groups extends ReceiverAdapter
.setReceiver(this)
.setDiscardOwnMessages(true)
.connect("openosrs");
eventBus.subscribe(ClientShutdown.class, this, (e) -> {
Future<Void> f = close();
e.waitFor(f);
});
}
public void broadcastSring(String command)
@@ -134,10 +143,22 @@ public class Groups extends ReceiverAdapter
{
messageObjectSubject.onNext(message);
}
}
public void close()
private CompletableFuture<Void> close()
{
channel.close();
CompletableFuture<Void> future = new CompletableFuture<>();
try
{
channel.close();
future.complete(null);
}
catch (Exception ex)
{
future.completeExceptionally(ex);
}
return future;
}
}

View File

@@ -41,22 +41,18 @@ import java.awt.Toolkit;
import java.awt.TrayIcon;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import java.util.Enumeration;
import java.util.concurrent.Callable;
import java.util.function.BiConsumer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.swing.ButtonModel;
import javax.swing.AbstractButton;
import javax.swing.ButtonModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
@@ -67,7 +63,6 @@ import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import static javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE;
import javax.swing.border.Border;
import javax.swing.border.CompoundBorder;
import javax.swing.border.EmptyBorder;
@@ -214,48 +209,6 @@ public class SwingUtil
return trayIcon;
}
/**
* Add graceful exit callback.
*
* @param frame the frame
* @param callback the callback
* @param confirmRequired the confirm required
*/
public static void addGracefulExitCallback(@Nonnull final JFrame frame, @Nonnull final Runnable callback, @Nonnull final Callable<Boolean> confirmRequired)
{
frame.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent event)
{
int result = JOptionPane.OK_OPTION;
try
{
if (confirmRequired.call())
{
result = JOptionPane.showConfirmDialog(
frame,
"Are you sure you want to exit?", "Exit",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);
}
}
catch (Exception e)
{
log.warn("Unexpected exception occurred while check for confirm required", e);
}
if (result == JOptionPane.OK_OPTION)
{
callback.run();
System.exit(0);
}
}
});
}
/**
* Create swing button from navigation button.
*

View File

@@ -83,7 +83,7 @@ public class WeaponMap
StyleMap.put(ItemID.BLACK_SWORD, WeaponStyle.MELEE);
StyleMap.put(ItemID.BLACK_WARHAMMER, WeaponStyle.MELEE);
StyleMap.put(ItemID.BLADE_OF_SAELDOR, WeaponStyle.MELEE);
StyleMap.put(ItemID.BLADE_OF_SAELDOR_I, WeaponStyle.MELEE);
StyleMap.put(ItemID.BLADE_OF_SAELDOR_C, WeaponStyle.MELEE);
StyleMap.put(ItemID.BLADE_OF_SAELDOR_INACTIVE, WeaponStyle.MELEE);
StyleMap.put(ItemID.BLESSED_AXE, WeaponStyle.MELEE);
StyleMap.put(ItemID.BLUE_FLOWERS, WeaponStyle.MELEE);

View File

@@ -8706,6 +8706,14 @@
20621,
20622
],
"tangleroot": [
20661,
24555,
24557,
24559,
24561,
24563
],
"rift guardian": [
20665,
20667,