infobox: add support for multiple infobox groups
Co-authored-by: Ron Young <admin@ryoung.io>
This commit is contained in:
@@ -79,7 +79,6 @@ import net.runelite.client.ui.overlay.OverlayManager;
|
|||||||
import net.runelite.client.ui.overlay.OverlayRenderer;
|
import net.runelite.client.ui.overlay.OverlayRenderer;
|
||||||
import net.runelite.client.ui.overlay.WidgetOverlay;
|
import net.runelite.client.ui.overlay.WidgetOverlay;
|
||||||
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||||
import net.runelite.client.ui.overlay.infobox.InfoBoxOverlay;
|
|
||||||
import net.runelite.client.ui.overlay.tooltip.TooltipOverlay;
|
import net.runelite.client.ui.overlay.tooltip.TooltipOverlay;
|
||||||
import net.runelite.client.ui.overlay.worldmap.WorldMapOverlay;
|
import net.runelite.client.ui.overlay.worldmap.WorldMapOverlay;
|
||||||
import net.runelite.client.ws.PartyService;
|
import net.runelite.client.ws.PartyService;
|
||||||
@@ -134,7 +133,7 @@ public class RuneLite
|
|||||||
private ClientUI clientUI;
|
private ClientUI clientUI;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private InfoBoxManager infoBoxManager;
|
private Provider<InfoBoxManager> infoBoxManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private OverlayManager overlayManager;
|
private OverlayManager overlayManager;
|
||||||
@@ -160,9 +159,6 @@ public class RuneLite
|
|||||||
@Inject
|
@Inject
|
||||||
private Provider<CommandManager> commandManager;
|
private Provider<CommandManager> commandManager;
|
||||||
|
|
||||||
@Inject
|
|
||||||
private Provider<InfoBoxOverlay> infoBoxOverlay;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private Provider<TooltipOverlay> tooltipOverlay;
|
private Provider<TooltipOverlay> tooltipOverlay;
|
||||||
|
|
||||||
@@ -367,7 +363,6 @@ public class RuneLite
|
|||||||
eventBus.register(externalPluginManager);
|
eventBus.register(externalPluginManager);
|
||||||
eventBus.register(overlayManager);
|
eventBus.register(overlayManager);
|
||||||
eventBus.register(drawManager);
|
eventBus.register(drawManager);
|
||||||
eventBus.register(infoBoxManager);
|
|
||||||
eventBus.register(configManager);
|
eventBus.register(configManager);
|
||||||
eventBus.register(discordService);
|
eventBus.register(discordService);
|
||||||
|
|
||||||
@@ -376,6 +371,7 @@ public class RuneLite
|
|||||||
// Initialize chat colors
|
// Initialize chat colors
|
||||||
chatMessageManager.get().loadColors();
|
chatMessageManager.get().loadColors();
|
||||||
|
|
||||||
|
eventBus.register(infoBoxManager.get());
|
||||||
eventBus.register(partyService.get());
|
eventBus.register(partyService.get());
|
||||||
eventBus.register(overlayRenderer.get());
|
eventBus.register(overlayRenderer.get());
|
||||||
eventBus.register(friendsChatManager.get());
|
eventBus.register(friendsChatManager.get());
|
||||||
@@ -386,11 +382,9 @@ public class RuneLite
|
|||||||
eventBus.register(lootManager.get());
|
eventBus.register(lootManager.get());
|
||||||
eventBus.register(chatboxPanelManager.get());
|
eventBus.register(chatboxPanelManager.get());
|
||||||
eventBus.register(hooks.get());
|
eventBus.register(hooks.get());
|
||||||
eventBus.register(infoBoxOverlay.get());
|
|
||||||
|
|
||||||
// Add core overlays
|
// Add core overlays
|
||||||
WidgetOverlay.createOverlays(client).forEach(overlayManager::add);
|
WidgetOverlay.createOverlays(client).forEach(overlayManager::add);
|
||||||
overlayManager.add(infoBoxOverlay.get());
|
|
||||||
overlayManager.add(worldMapOverlay.get());
|
overlayManager.add(worldMapOverlay.get());
|
||||||
overlayManager.add(tooltipOverlay.get());
|
overlayManager.add(tooltipOverlay.get());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -334,7 +334,8 @@ public interface RuneLiteConfig extends Config
|
|||||||
name = "Display infoboxes vertically",
|
name = "Display infoboxes vertically",
|
||||||
description = "Toggles the infoboxes to display vertically",
|
description = "Toggles the infoboxes to display vertically",
|
||||||
position = 40,
|
position = 40,
|
||||||
section = overlaySettings
|
section = overlaySettings,
|
||||||
|
hidden = true
|
||||||
)
|
)
|
||||||
default boolean infoBoxVertical()
|
default boolean infoBoxVertical()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -89,4 +89,10 @@ public class BoostIndicator extends InfoBox
|
|||||||
{
|
{
|
||||||
return config.displayInfoboxes() && plugin.canShowBoosts() && plugin.getSkillsToDisplay().contains(getSkill());
|
return config.displayInfoboxes() && plugin.canShowBoosts() && plugin.getSkillsToDisplay().contains(getSkill());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return "Boost " + skill.getName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,4 +45,10 @@ class TimerTimer extends Timer
|
|||||||
{
|
{
|
||||||
return timer;
|
return timer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return timer.name();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import java.awt.Rectangle;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import lombok.AccessLevel;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import net.runelite.client.plugins.Plugin;
|
import net.runelite.client.plugins.Plugin;
|
||||||
@@ -52,6 +53,13 @@ public abstract class Overlay implements LayoutableRenderableEntity
|
|||||||
private boolean resizable;
|
private boolean resizable;
|
||||||
private boolean resettable = true;
|
private boolean resettable = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether this overlay can be dragged onto other overlays & have
|
||||||
|
* other overlays dragged onto it.
|
||||||
|
*/
|
||||||
|
@Setter(AccessLevel.PROTECTED)
|
||||||
|
private boolean dragTargetable;
|
||||||
|
|
||||||
protected Overlay()
|
protected Overlay()
|
||||||
{
|
{
|
||||||
plugin = null;
|
plugin = null;
|
||||||
@@ -64,6 +72,7 @@ public abstract class Overlay implements LayoutableRenderableEntity
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Overlay name, used for saving the overlay, needs to be unique
|
* Overlay name, used for saving the overlay, needs to be unique
|
||||||
|
*
|
||||||
* @return overlay name
|
* @return overlay name
|
||||||
*/
|
*/
|
||||||
public String getName()
|
public String getName()
|
||||||
@@ -74,4 +83,17 @@ public abstract class Overlay implements LayoutableRenderableEntity
|
|||||||
public void onMouseOver()
|
public void onMouseOver()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when an overlay is dragged onto this, if dragTargetable is true.
|
||||||
|
* Return true to consume the mouse event and prevent the other
|
||||||
|
* overlay from being moved
|
||||||
|
*
|
||||||
|
* @param other the overlay being dragged
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public boolean onDrag(Overlay other)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
private static final Color SNAP_CORNER_ACTIVE_COLOR = new Color(0, 255, 0, 100);
|
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_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_ACTIVE_COLOR = new Color(255, 255, 0, 200);
|
||||||
|
private static final Color MOVING_OVERLAY_TARGET_COLOR = Color.RED;
|
||||||
private static final Color MOVING_OVERLAY_RESIZING_COLOR = new Color(255, 0, 255, 200);
|
private static final Color MOVING_OVERLAY_RESIZING_COLOR = new Color(255, 0, 255, 200);
|
||||||
private final Client client;
|
private final Client client;
|
||||||
private final OverlayManager overlayManager;
|
private final OverlayManager overlayManager;
|
||||||
@@ -87,6 +88,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
private final Point overlayOffset = new Point();
|
private final Point overlayOffset = new Point();
|
||||||
private final Point mousePosition = new Point();
|
private final Point mousePosition = new Point();
|
||||||
private Overlay currentManagedOverlay;
|
private Overlay currentManagedOverlay;
|
||||||
|
private Overlay dragTargetOverlay;
|
||||||
private Rectangle currentManagedBounds;
|
private Rectangle currentManagedBounds;
|
||||||
private boolean inOverlayManagingMode;
|
private boolean inOverlayManagingMode;
|
||||||
private boolean inOverlayResizingMode;
|
private boolean inOverlayResizingMode;
|
||||||
@@ -292,15 +294,28 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
{
|
{
|
||||||
if (inOverlayManagingMode)
|
if (inOverlayManagingMode)
|
||||||
{
|
{
|
||||||
|
Color boundsColor;
|
||||||
if (inOverlayResizingMode && currentManagedOverlay == overlay)
|
if (inOverlayResizingMode && currentManagedOverlay == overlay)
|
||||||
{
|
{
|
||||||
graphics.setColor(MOVING_OVERLAY_RESIZING_COLOR);
|
boundsColor = MOVING_OVERLAY_RESIZING_COLOR;
|
||||||
|
}
|
||||||
|
else if (inOverlayDraggingMode && currentManagedOverlay == overlay)
|
||||||
|
{
|
||||||
|
boundsColor = MOVING_OVERLAY_ACTIVE_COLOR;
|
||||||
|
}
|
||||||
|
else if (inOverlayDraggingMode && overlay.isDragTargetable() && currentManagedOverlay.isDragTargetable()
|
||||||
|
&& currentManagedOverlay.getBounds().intersects(bounds))
|
||||||
|
{
|
||||||
|
boundsColor = MOVING_OVERLAY_TARGET_COLOR;
|
||||||
|
assert currentManagedOverlay != overlay;
|
||||||
|
dragTargetOverlay = overlay;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
graphics.setColor(inOverlayDraggingMode && currentManagedOverlay == overlay ? MOVING_OVERLAY_ACTIVE_COLOR : MOVING_OVERLAY_COLOR);
|
boundsColor = MOVING_OVERLAY_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
graphics.setColor(boundsColor);
|
||||||
graphics.draw(bounds);
|
graphics.draw(bounds);
|
||||||
graphics.setPaint(paint);
|
graphics.setPaint(paint);
|
||||||
}
|
}
|
||||||
@@ -457,6 +472,12 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
return mouseEvent;
|
return mouseEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dragTargetOverlay != null && !currentManagedOverlay.getBounds().intersects(dragTargetOverlay.getBounds()))
|
||||||
|
{
|
||||||
|
// No longer over drag target
|
||||||
|
dragTargetOverlay = null;
|
||||||
|
}
|
||||||
|
|
||||||
final Rectangle canvasRect = new Rectangle(client.getRealDimensions());
|
final Rectangle canvasRect = new Rectangle(client.getRealDimensions());
|
||||||
|
|
||||||
if (!canvasRect.contains(p))
|
if (!canvasRect.contains(p))
|
||||||
@@ -584,7 +605,17 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
|
|
||||||
mousePosition.setLocation(-1, -1);
|
mousePosition.setLocation(-1, -1);
|
||||||
|
|
||||||
// do not snapcorner detached overlays
|
if (dragTargetOverlay != null)
|
||||||
|
{
|
||||||
|
if (dragTargetOverlay.onDrag(currentManagedOverlay))
|
||||||
|
{
|
||||||
|
mouseEvent.consume();
|
||||||
|
resetOverlayManagementMode();
|
||||||
|
return mouseEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the overlay is over a snapcorner and move it if so, unless it is a detached overlay
|
||||||
if (currentManagedOverlay.getPosition() != OverlayPosition.DETACHED && inOverlayDraggingMode)
|
if (currentManagedOverlay.getPosition() != OverlayPosition.DETACHED && inOverlayDraggingMode)
|
||||||
{
|
{
|
||||||
final OverlayBounds snapCorners = this.snapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height);
|
final OverlayBounds snapCorners = this.snapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height);
|
||||||
@@ -720,6 +751,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
|
|||||||
inOverlayResizingMode = false;
|
inOverlayResizingMode = false;
|
||||||
inOverlayDraggingMode = false;
|
inOverlayDraggingMode = false;
|
||||||
currentManagedOverlay = null;
|
currentManagedOverlay = null;
|
||||||
|
dragTargetOverlay = null;
|
||||||
currentManagedBounds = null;
|
currentManagedBounds = null;
|
||||||
clientUI.setCursor(clientUI.getDefaultCursor());
|
clientUI.setCursor(clientUI.getDefaultCursor());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,4 +81,11 @@ public abstract class InfoBox
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
// Use a combination of plugin name and infobox implementation name to try and make each infobox as unique
|
||||||
|
// as possible by default
|
||||||
|
return plugin.getClass().getSimpleName() + "_" + getClass().getSimpleName();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,33 +25,76 @@
|
|||||||
package net.runelite.client.ui.overlay.infobox;
|
package net.runelite.client.ui.overlay.infobox;
|
||||||
|
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ComparisonChain;
|
import com.google.common.collect.ComparisonChain;
|
||||||
import java.awt.Graphics;
|
import java.awt.Graphics;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.MenuAction;
|
||||||
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.config.RuneLiteConfig;
|
import net.runelite.client.config.RuneLiteConfig;
|
||||||
|
import net.runelite.client.eventbus.EventBus;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
import net.runelite.client.events.ConfigChanged;
|
import net.runelite.client.events.ConfigChanged;
|
||||||
|
import net.runelite.client.events.InfoBoxMenuClicked;
|
||||||
|
import net.runelite.client.ui.overlay.OverlayManager;
|
||||||
|
import net.runelite.client.ui.overlay.OverlayMenuEntry;
|
||||||
|
import net.runelite.client.ui.overlay.components.ComponentOrientation;
|
||||||
|
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
|
||||||
import net.runelite.client.util.AsyncBufferedImage;
|
import net.runelite.client.util.AsyncBufferedImage;
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class InfoBoxManager
|
public class InfoBoxManager
|
||||||
{
|
{
|
||||||
private final List<InfoBox> infoBoxes = new CopyOnWriteArrayList<>();
|
private static final String INFOBOXLAYER_KEY = "infoboxlayer";
|
||||||
|
private static final String INFOBOXOVERLAY_KEY = "infoboxoverlay";
|
||||||
|
private static final String INFOBOXOVERLAY_ORIENTATION_PREFIX = "orient_";
|
||||||
|
private static final String DEFAULT_LAYER = "InfoBoxOverlay";
|
||||||
|
|
||||||
|
private static final String DETACH = "Detach";
|
||||||
|
private static final String FLIP = "Flip";
|
||||||
|
private static final String DELETE = "Delete";
|
||||||
|
|
||||||
|
private static final OverlayMenuEntry DETACH_ME = new OverlayMenuEntry(MenuAction.RUNELITE_INFOBOX, DETACH, "InfoBox");
|
||||||
|
private static final OverlayMenuEntry FLIP_ME = new OverlayMenuEntry(MenuAction.RUNELITE_INFOBOX, FLIP, "InfoBox Group");
|
||||||
|
private static final OverlayMenuEntry DELETE_ME = new OverlayMenuEntry(MenuAction.RUNELITE_INFOBOX, DELETE, "InfoBox Group");
|
||||||
|
|
||||||
|
private final Map<String, InfoBoxOverlay> layers = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final RuneLiteConfig runeLiteConfig;
|
private final RuneLiteConfig runeLiteConfig;
|
||||||
|
private final TooltipManager tooltipManager;
|
||||||
|
private final Client client;
|
||||||
|
private final EventBus eventBus;
|
||||||
|
private final OverlayManager overlayManager;
|
||||||
|
private final ConfigManager configManager;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private InfoBoxManager(final RuneLiteConfig runeLiteConfig)
|
private InfoBoxManager(
|
||||||
|
final RuneLiteConfig runeLiteConfig,
|
||||||
|
final TooltipManager tooltipManager,
|
||||||
|
final Client client,
|
||||||
|
final EventBus eventBus,
|
||||||
|
final OverlayManager overlayManager,
|
||||||
|
final ConfigManager configManager)
|
||||||
{
|
{
|
||||||
this.runeLiteConfig = runeLiteConfig;
|
this.runeLiteConfig = runeLiteConfig;
|
||||||
|
this.tooltipManager = tooltipManager;
|
||||||
|
this.client = client;
|
||||||
|
this.eventBus = eventBus;
|
||||||
|
this.overlayManager = overlayManager;
|
||||||
|
this.configManager = configManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -59,7 +102,33 @@ public class InfoBoxManager
|
|||||||
{
|
{
|
||||||
if (event.getGroup().equals("runelite") && event.getKey().equals("infoBoxSize"))
|
if (event.getGroup().equals("runelite") && event.getKey().equals("infoBoxSize"))
|
||||||
{
|
{
|
||||||
infoBoxes.forEach(this::updateInfoBoxImage);
|
layers.values().forEach(l -> l.getInfoBoxes().forEach(this::updateInfoBoxImage));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
public void onInfoBoxMenuClicked(InfoBoxMenuClicked event)
|
||||||
|
{
|
||||||
|
if (DETACH.equals(event.getEntry().getOption()))
|
||||||
|
{
|
||||||
|
// The layer name doesn't matter as long as it is unique
|
||||||
|
splitInfobox(event.getInfoBox().getName() + "_" + System.currentTimeMillis(), event.getInfoBox());
|
||||||
|
}
|
||||||
|
else if (FLIP.equals(event.getEntry().getOption()))
|
||||||
|
{
|
||||||
|
InfoBoxOverlay infoBoxOverlay = layers.get(getLayer(event.getInfoBox()));
|
||||||
|
ComponentOrientation newOrientation = infoBoxOverlay.flip();
|
||||||
|
setOrientation(infoBoxOverlay.getName(), newOrientation);
|
||||||
|
}
|
||||||
|
else if (DELETE.equals(event.getEntry().getOption()))
|
||||||
|
{
|
||||||
|
// This is just a merge into the default layer
|
||||||
|
InfoBoxOverlay source = layers.get(getLayer(event.getInfoBox()));
|
||||||
|
InfoBoxOverlay dest = layers.computeIfAbsent(DEFAULT_LAYER, this::makeOverlay);
|
||||||
|
if (source != dest)
|
||||||
|
{
|
||||||
|
mergeInfoBoxes(source, dest);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,14 +139,25 @@ public class InfoBoxManager
|
|||||||
|
|
||||||
updateInfoBoxImage(infoBox);
|
updateInfoBoxImage(infoBox);
|
||||||
|
|
||||||
|
String layerName = getLayer(infoBox);
|
||||||
|
InfoBoxOverlay overlay = layers.computeIfAbsent(layerName, this::makeOverlay);
|
||||||
|
List<OverlayMenuEntry> menuEntries = infoBox.getMenuEntries();
|
||||||
|
menuEntries.add(DETACH_ME);
|
||||||
|
menuEntries.add(FLIP_ME);
|
||||||
|
if (!layerName.equals(DEFAULT_LAYER))
|
||||||
|
{
|
||||||
|
// Non default-group infoboxes have a delete option to delete the group
|
||||||
|
menuEntries.add(DELETE_ME);
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
int idx = findInsertionIndex(infoBoxes, infoBox, (b1, b2) -> ComparisonChain
|
int idx = findInsertionIndex(overlay.getInfoBoxes(), infoBox, (b1, b2) -> ComparisonChain
|
||||||
.start()
|
.start()
|
||||||
.compare(b1.getPriority(), b2.getPriority())
|
.compare(b1.getPriority(), b2.getPriority())
|
||||||
.compare(b1.getPlugin().getName(), b2.getPlugin().getName())
|
.compare(b1.getPlugin().getName(), b2.getPlugin().getName())
|
||||||
.result());
|
.result());
|
||||||
infoBoxes.add(idx, infoBox);
|
overlay.getInfoBoxes().add(idx, infoBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferedImage image = infoBox.getImage();
|
BufferedImage image = infoBox.getImage();
|
||||||
@@ -91,28 +171,40 @@ public class InfoBoxManager
|
|||||||
|
|
||||||
public synchronized void removeInfoBox(InfoBox infoBox)
|
public synchronized void removeInfoBox(InfoBox infoBox)
|
||||||
{
|
{
|
||||||
if (infoBoxes.remove(infoBox))
|
if (infoBox == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layers.get(getLayer(infoBox)).getInfoBoxes().remove(infoBox))
|
||||||
{
|
{
|
||||||
log.debug("Removed InfoBox {}", infoBox);
|
log.debug("Removed InfoBox {}", infoBox);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infoBox.getMenuEntries().remove(DETACH_ME);
|
||||||
|
infoBox.getMenuEntries().remove(FLIP_ME);
|
||||||
|
infoBox.getMenuEntries().remove(DELETE_ME);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void removeIf(Predicate<InfoBox> filter)
|
public synchronized void removeIf(Predicate<InfoBox> filter)
|
||||||
{
|
{
|
||||||
if (infoBoxes.removeIf(filter))
|
for (InfoBoxOverlay overlay : layers.values())
|
||||||
{
|
{
|
||||||
log.debug("Removed InfoBoxes for filter {}", filter);
|
if (overlay.getInfoBoxes().removeIf(filter))
|
||||||
|
{
|
||||||
|
log.debug("Removed InfoBoxes for filter {} from {}", filter, overlay);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<InfoBox> getInfoBoxes()
|
public List<InfoBox> getInfoBoxes()
|
||||||
{
|
{
|
||||||
return Collections.unmodifiableList(infoBoxes);
|
return layers.values().stream().map(InfoBoxOverlay::getInfoBoxes).flatMap(Collection::stream).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void cull()
|
public synchronized void cull()
|
||||||
{
|
{
|
||||||
infoBoxes.removeIf(InfoBox::cull);
|
layers.values().forEach(l -> l.getInfoBoxes().removeIf(InfoBox::cull));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateInfoBoxImage(final InfoBox infoBox)
|
public void updateInfoBoxImage(final InfoBox infoBox)
|
||||||
@@ -152,6 +244,140 @@ public class InfoBoxManager
|
|||||||
infoBox.setScaledImage(resultImage);
|
infoBox.setScaledImage(resultImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private InfoBoxOverlay makeOverlay(String name)
|
||||||
|
{
|
||||||
|
ComponentOrientation orientation = getOrientation(name);
|
||||||
|
if (orientation == null)
|
||||||
|
{
|
||||||
|
if (name.equals(DEFAULT_LAYER))
|
||||||
|
{
|
||||||
|
// Fall back to old orientation config option
|
||||||
|
orientation = runeLiteConfig.infoBoxVertical() ? ComponentOrientation.VERTICAL : ComponentOrientation.HORIZONTAL;
|
||||||
|
setOrientation(name, orientation);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Default infobox orientation
|
||||||
|
orientation = ComponentOrientation.HORIZONTAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoBoxOverlay infoBoxOverlay = new InfoBoxOverlay(
|
||||||
|
this,
|
||||||
|
tooltipManager,
|
||||||
|
client,
|
||||||
|
runeLiteConfig,
|
||||||
|
eventBus,
|
||||||
|
name,
|
||||||
|
orientation);
|
||||||
|
overlayManager.add(infoBoxOverlay);
|
||||||
|
eventBus.register(infoBoxOverlay);
|
||||||
|
return infoBoxOverlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeOverlay(InfoBoxOverlay overlay)
|
||||||
|
{
|
||||||
|
unsetOrientation(overlay.getName());
|
||||||
|
eventBus.unregister(overlay);
|
||||||
|
overlayManager.remove(overlay);
|
||||||
|
layers.remove(overlay.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void splitInfobox(String newLayer, InfoBox infoBox)
|
||||||
|
{
|
||||||
|
String layer = getLayer(infoBox);
|
||||||
|
InfoBoxOverlay oldOverlay = layers.get(layer);
|
||||||
|
// Find all infoboxes with the same name, as they are all within the same group and so move at once.
|
||||||
|
Collection<InfoBox> filtered = oldOverlay.getInfoBoxes().stream()
|
||||||
|
.filter(i -> i.getName().equals(infoBox.getName())).collect(Collectors.toList());
|
||||||
|
|
||||||
|
oldOverlay.getInfoBoxes().removeAll(filtered);
|
||||||
|
if (oldOverlay.getInfoBoxes().isEmpty())
|
||||||
|
{
|
||||||
|
log.debug("Deleted layer: {}", oldOverlay.getName());
|
||||||
|
removeOverlay(oldOverlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoBoxOverlay newOverlay = layers.computeIfAbsent(newLayer, this::makeOverlay);
|
||||||
|
newOverlay.getInfoBoxes().addAll(filtered);
|
||||||
|
|
||||||
|
// Adjust config for new infoboxes
|
||||||
|
for (InfoBox i : filtered)
|
||||||
|
{
|
||||||
|
setLayer(i, newLayer);
|
||||||
|
|
||||||
|
if (!i.getMenuEntries().contains(DELETE_ME))
|
||||||
|
{
|
||||||
|
i.getMenuEntries().add(DELETE_ME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Moving infobox named {} (layer {}) to layer {}: {} boxes", infoBox.getName(), layer, newLayer, filtered.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void mergeInfoBoxes(InfoBoxOverlay source, InfoBoxOverlay dest)
|
||||||
|
{
|
||||||
|
Collection<InfoBox> infoBoxesToMove = source.getInfoBoxes();
|
||||||
|
boolean isDefault = dest.getName().equals(DEFAULT_LAYER);
|
||||||
|
|
||||||
|
log.debug("Merging InfoBoxes from {} into {} ({} boxes)", source.getName(), dest.getName(), infoBoxesToMove.size());
|
||||||
|
|
||||||
|
for (InfoBox infoBox : infoBoxesToMove)
|
||||||
|
{
|
||||||
|
setLayer(infoBox, dest.getName());
|
||||||
|
|
||||||
|
if (isDefault)
|
||||||
|
{
|
||||||
|
infoBox.getMenuEntries().remove(DELETE_ME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.getInfoBoxes().addAll(infoBoxesToMove);
|
||||||
|
source.getInfoBoxes().clear();
|
||||||
|
|
||||||
|
// remove source
|
||||||
|
removeOverlay(source);
|
||||||
|
log.debug("Deleted layer: {}", source.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getLayer(InfoBox infoBox)
|
||||||
|
{
|
||||||
|
String name = configManager.getConfiguration(INFOBOXLAYER_KEY, infoBox.getName());
|
||||||
|
if (Strings.isNullOrEmpty(name))
|
||||||
|
{
|
||||||
|
return DEFAULT_LAYER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLayer(InfoBox infoBox, String layer)
|
||||||
|
{
|
||||||
|
if (layer.equals(DEFAULT_LAYER))
|
||||||
|
{
|
||||||
|
configManager.unsetConfiguration(INFOBOXLAYER_KEY, infoBox.getName());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
configManager.setConfiguration(INFOBOXLAYER_KEY, infoBox.getName(), layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ComponentOrientation getOrientation(String name)
|
||||||
|
{
|
||||||
|
return configManager.getConfiguration(INFOBOXOVERLAY_KEY, INFOBOXOVERLAY_ORIENTATION_PREFIX + name, ComponentOrientation.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOrientation(String name, ComponentOrientation orientation)
|
||||||
|
{
|
||||||
|
configManager.setConfiguration(INFOBOXOVERLAY_KEY, INFOBOXOVERLAY_ORIENTATION_PREFIX + name, orientation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unsetOrientation(String name)
|
||||||
|
{
|
||||||
|
configManager.unsetConfiguration(INFOBOXOVERLAY_KEY, INFOBOXOVERLAY_ORIENTATION_PREFIX + name);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find insertion point for the given key into the given sorted list. If key already exists in the list,
|
* Find insertion point for the given key into the given sorted list. If key already exists in the list,
|
||||||
* return the index after the last occurrence.
|
* return the index after the last occurrence.
|
||||||
|
|||||||
@@ -33,8 +33,9 @@ import java.awt.Point;
|
|||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.inject.Inject;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import javax.inject.Singleton;
|
import lombok.Getter;
|
||||||
|
import lombok.NonNull;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.MenuAction;
|
import net.runelite.api.MenuAction;
|
||||||
import net.runelite.api.events.MenuOptionClicked;
|
import net.runelite.api.events.MenuOptionClicked;
|
||||||
@@ -42,6 +43,7 @@ import net.runelite.client.config.RuneLiteConfig;
|
|||||||
import net.runelite.client.eventbus.EventBus;
|
import net.runelite.client.eventbus.EventBus;
|
||||||
import net.runelite.client.eventbus.Subscribe;
|
import net.runelite.client.eventbus.Subscribe;
|
||||||
import net.runelite.client.events.InfoBoxMenuClicked;
|
import net.runelite.client.events.InfoBoxMenuClicked;
|
||||||
|
import net.runelite.client.ui.overlay.Overlay;
|
||||||
import net.runelite.client.ui.overlay.OverlayMenuEntry;
|
import net.runelite.client.ui.overlay.OverlayMenuEntry;
|
||||||
import net.runelite.client.ui.overlay.OverlayPanel;
|
import net.runelite.client.ui.overlay.OverlayPanel;
|
||||||
import net.runelite.client.ui.overlay.OverlayPosition;
|
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||||
@@ -51,7 +53,6 @@ import net.runelite.client.ui.overlay.components.LayoutableRenderableEntity;
|
|||||||
import net.runelite.client.ui.overlay.tooltip.Tooltip;
|
import net.runelite.client.ui.overlay.tooltip.Tooltip;
|
||||||
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
|
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
|
||||||
|
|
||||||
@Singleton
|
|
||||||
public class InfoBoxOverlay extends OverlayPanel
|
public class InfoBoxOverlay extends OverlayPanel
|
||||||
{
|
{
|
||||||
private static final int GAP = 1;
|
private static final int GAP = 1;
|
||||||
@@ -62,24 +63,33 @@ public class InfoBoxOverlay extends OverlayPanel
|
|||||||
private final Client client;
|
private final Client client;
|
||||||
private final RuneLiteConfig config;
|
private final RuneLiteConfig config;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
|
private final String name;
|
||||||
|
private ComponentOrientation orientation;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private final List<InfoBox> infoBoxes = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
private InfoBoxComponent hoveredComponent;
|
private InfoBoxComponent hoveredComponent;
|
||||||
|
|
||||||
@Inject
|
InfoBoxOverlay(
|
||||||
private InfoBoxOverlay(
|
|
||||||
InfoBoxManager infoboxManager,
|
InfoBoxManager infoboxManager,
|
||||||
TooltipManager tooltipManager,
|
TooltipManager tooltipManager,
|
||||||
Client client,
|
Client client,
|
||||||
RuneLiteConfig config,
|
RuneLiteConfig config,
|
||||||
EventBus eventBus)
|
EventBus eventBus,
|
||||||
|
String name,
|
||||||
|
@NonNull ComponentOrientation orientation)
|
||||||
{
|
{
|
||||||
this.tooltipManager = tooltipManager;
|
this.tooltipManager = tooltipManager;
|
||||||
this.infoboxManager = infoboxManager;
|
this.infoboxManager = infoboxManager;
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.eventBus = eventBus;
|
this.eventBus = eventBus;
|
||||||
|
this.name = name;
|
||||||
|
this.orientation = orientation;
|
||||||
setPosition(OverlayPosition.TOP_LEFT);
|
setPosition(OverlayPosition.TOP_LEFT);
|
||||||
setClearChildren(false);
|
setClearChildren(false);
|
||||||
|
setDragTargetable(true);
|
||||||
|
|
||||||
panelComponent.setWrap(true);
|
panelComponent.setWrap(true);
|
||||||
panelComponent.setBackgroundColor(null);
|
panelComponent.setBackgroundColor(null);
|
||||||
@@ -87,11 +97,15 @@ public class InfoBoxOverlay extends OverlayPanel
|
|||||||
panelComponent.setGap(new Point(GAP, GAP));
|
panelComponent.setGap(new Point(GAP, GAP));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Dimension render(Graphics2D graphics)
|
public Dimension render(Graphics2D graphics)
|
||||||
{
|
{
|
||||||
final List<InfoBox> infoBoxes = infoboxManager.getInfoBoxes();
|
|
||||||
|
|
||||||
final boolean menuOpen = client.isMenuOpen();
|
final boolean menuOpen = client.isMenuOpen();
|
||||||
if (!menuOpen)
|
if (!menuOpen)
|
||||||
{
|
{
|
||||||
@@ -106,9 +120,7 @@ public class InfoBoxOverlay extends OverlayPanel
|
|||||||
// Set preferred size to the size of DEFAULT_WRAP_COUNT infoboxes, including the padding - which is applied
|
// 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.
|
// 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.setPreferredSize(new Dimension(DEFAULT_WRAP_COUNT * (config.infoBoxSize() + GAP), DEFAULT_WRAP_COUNT * (config.infoBoxSize() + GAP)));
|
||||||
panelComponent.setOrientation(config.infoBoxVertical()
|
panelComponent.setOrientation(orientation);
|
||||||
? ComponentOrientation.VERTICAL
|
|
||||||
: ComponentOrientation.HORIZONTAL);
|
|
||||||
|
|
||||||
for (InfoBox box : infoBoxes)
|
for (InfoBox box : infoBoxes)
|
||||||
{
|
{
|
||||||
@@ -177,7 +189,7 @@ public class InfoBoxOverlay extends OverlayPanel
|
|||||||
@Subscribe
|
@Subscribe
|
||||||
public void onMenuOptionClicked(MenuOptionClicked menuOptionClicked)
|
public void onMenuOptionClicked(MenuOptionClicked menuOptionClicked)
|
||||||
{
|
{
|
||||||
if (menuOptionClicked.getMenuAction() != MenuAction.RUNELITE_INFOBOX)
|
if (menuOptionClicked.getMenuAction() != MenuAction.RUNELITE_INFOBOX || hoveredComponent == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -192,4 +204,21 @@ public class InfoBoxOverlay extends OverlayPanel
|
|||||||
eventBus.post(new InfoBoxMenuClicked(overlayMenuEntry, infoBox));
|
eventBus.post(new InfoBoxMenuClicked(overlayMenuEntry, infoBox));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onDrag(Overlay source)
|
||||||
|
{
|
||||||
|
if (!(source instanceof InfoBoxOverlay))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
infoboxManager.mergeInfoBoxes((InfoBoxOverlay) source, this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComponentOrientation flip()
|
||||||
|
{
|
||||||
|
return orientation = orientation == ComponentOrientation.HORIZONTAL ? ComponentOrientation.VERTICAL : ComponentOrientation.HORIZONTAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import net.runelite.api.events.ChatMessage;
|
|||||||
import net.runelite.client.Notifier;
|
import net.runelite.client.Notifier;
|
||||||
import net.runelite.client.config.RuneLiteConfig;
|
import net.runelite.client.config.RuneLiteConfig;
|
||||||
import net.runelite.client.ui.overlay.OverlayManager;
|
import net.runelite.client.ui.overlay.OverlayManager;
|
||||||
|
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@@ -91,6 +92,10 @@ public class ItemChargePluginTest
|
|||||||
@Bind
|
@Bind
|
||||||
private Notifier notifier;
|
private Notifier notifier;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private InfoBoxManager infoBoxManager;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
@Bind
|
@Bind
|
||||||
private ItemChargeConfig config;
|
private ItemChargeConfig config;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import net.runelite.client.Notifier;
|
|||||||
import net.runelite.client.config.ChatColorConfig;
|
import net.runelite.client.config.ChatColorConfig;
|
||||||
import net.runelite.client.config.RuneLiteConfig;
|
import net.runelite.client.config.RuneLiteConfig;
|
||||||
import net.runelite.client.ui.overlay.OverlayManager;
|
import net.runelite.client.ui.overlay.OverlayManager;
|
||||||
|
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||||
import net.runelite.client.util.ImageCapture;
|
import net.runelite.client.util.ImageCapture;
|
||||||
import net.runelite.client.ws.PartyService;
|
import net.runelite.client.ws.PartyService;
|
||||||
import net.runelite.http.api.chat.ChatClient;
|
import net.runelite.http.api.chat.ChatClient;
|
||||||
@@ -85,6 +86,10 @@ public class RaidsPluginTest
|
|||||||
@Inject
|
@Inject
|
||||||
RaidsPlugin raidsPlugin;
|
RaidsPlugin raidsPlugin;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private InfoBoxManager infoBoxManager;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
@Bind
|
@Bind
|
||||||
private PartyService partyService;
|
private PartyService partyService;
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import net.runelite.client.config.RuneLiteConfig;
|
|||||||
import net.runelite.client.ui.ClientUI;
|
import net.runelite.client.ui.ClientUI;
|
||||||
import net.runelite.client.ui.DrawManager;
|
import net.runelite.client.ui.DrawManager;
|
||||||
import net.runelite.client.ui.overlay.OverlayManager;
|
import net.runelite.client.ui.overlay.OverlayManager;
|
||||||
|
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -105,6 +106,10 @@ public class ScreenshotPluginTest
|
|||||||
@Bind
|
@Bind
|
||||||
private OverlayManager overlayManager;
|
private OverlayManager overlayManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private InfoBoxManager infoBoxManager;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before()
|
public void before()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import java.util.Arrays;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.client.config.ConfigManager;
|
||||||
import net.runelite.client.config.RuneLiteConfig;
|
import net.runelite.client.config.RuneLiteConfig;
|
||||||
import net.runelite.client.plugins.Plugin;
|
import net.runelite.client.plugins.Plugin;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -53,6 +55,14 @@ public class InfoBoxManagerTest
|
|||||||
@Bind
|
@Bind
|
||||||
private RuneLiteConfig runeLiteConfig;
|
private RuneLiteConfig runeLiteConfig;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private ConfigManager configManager;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
@Bind
|
||||||
|
private Client client;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before()
|
public void before()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user