infobox: add support for multiple infobox groups

Co-authored-by: Ron Young <admin@ryoung.io>
This commit is contained in:
Adam
2020-09-21 17:10:42 -04:00
committed by Adam
parent 6df3016bb5
commit 908c6b4fe4
13 changed files with 383 additions and 35 deletions

View File

@@ -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());
} }

View File

@@ -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()
{ {

View File

@@ -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();
}
} }

View File

@@ -45,4 +45,10 @@ class TimerTimer extends Timer
{ {
return timer; return timer;
} }
@Override
public String getName()
{
return timer.name();
}
} }

View File

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

View File

@@ -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());
} }

View File

@@ -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();
}
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -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()
{ {

View File

@@ -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()
{ {