client: add support for menu options on infoboxes

This commit is contained in:
Adam
2020-06-16 21:06:53 -04:00
committed by Adam
parent 1b7dadeb68
commit 48357f9329
9 changed files with 129 additions and 22 deletions

View File

@@ -277,6 +277,10 @@ public enum MenuAction
* a player and have its identifier set to a player index. * a player and have its identifier set to a player index.
*/ */
RUNELITE_PLAYER(1503), RUNELITE_PLAYER(1503),
/**
* Menu action for InfoBox menu entries
*/
RUNELITE_INFOBOX(1504),
/** /**
* Menu action triggered when the id is not defined in this class. * Menu action triggered when the id is not defined in this class.

View File

@@ -361,6 +361,7 @@ 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);

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2020, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.events;
import lombok.Value;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.infobox.InfoBox;
@Value
public class InfoBoxMenuClicked
{
private OverlayMenuEntry entry;
private InfoBox infoBox;
}

View File

@@ -33,9 +33,11 @@ import javax.inject.Inject;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JPanel; import javax.swing.JPanel;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.MenuAction;
import net.runelite.client.Notifier; import net.runelite.client.Notifier;
import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.ColorScheme;
import net.runelite.client.ui.PluginPanel; import net.runelite.client.ui.PluginPanel;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.infobox.Counter; import net.runelite.client.ui.overlay.infobox.Counter;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager; import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.util.ImageUtil; import net.runelite.client.util.ImageUtil;
@@ -166,7 +168,12 @@ class DevToolsPanel extends PluginPanel
}); });
final JButton newInfoboxBtn = new JButton("Infobox"); final JButton newInfoboxBtn = new JButton("Infobox");
newInfoboxBtn.addActionListener(e -> infoBoxManager.addInfoBox(new Counter(ImageUtil.getResourceStreamFromClass(getClass(), "devtools_icon.png"), plugin, 42))); newInfoboxBtn.addActionListener(e ->
{
Counter counter = new Counter(ImageUtil.getResourceStreamFromClass(getClass(), "devtools_icon.png"), plugin, 42);
counter.getMenuEntries().add(new OverlayMenuEntry(MenuAction.RUNELITE_INFOBOX, "Test", "DevTools"));
infoBoxManager.addInfoBox(counter);
});
container.add(newInfoboxBtn); container.add(newInfoboxBtn);
final JButton clearInfoboxBtn = new JButton("Clear Infobox"); final JButton clearInfoboxBtn = new JButton("Clear Infobox");

View File

@@ -33,7 +33,6 @@ import java.util.Comparator;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.function.Predicate; import java.util.function.Predicate;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
@@ -136,7 +135,8 @@ public class OverlayManager
@Subscribe @Subscribe
public void onMenuOptionClicked(MenuOptionClicked event) public void onMenuOptionClicked(MenuOptionClicked event)
{ {
if (event.getMenuAction() != MenuAction.RUNELITE_OVERLAY) MenuAction menuAction = event.getMenuAction();
if (menuAction != MenuAction.RUNELITE_OVERLAY && menuAction != MenuAction.RUNELITE_OVERLAY_CONFIG)
{ {
return; return;
} }
@@ -147,12 +147,13 @@ public class OverlayManager
if (overlay != null) if (overlay != null)
{ {
List<OverlayMenuEntry> menuEntries = overlay.getMenuEntries(); List<OverlayMenuEntry> menuEntries = overlay.getMenuEntries();
Optional<OverlayMenuEntry> optionalOverlayMenuEntry = menuEntries.stream() OverlayMenuEntry overlayMenuEntry = menuEntries.stream()
.filter(me -> me.getOption().equals(event.getMenuOption())) .filter(me -> me.getOption().equals(event.getMenuOption()))
.findAny(); .findAny()
if (optionalOverlayMenuEntry.isPresent()) .orElse(null);
if (overlayMenuEntry != null)
{ {
eventBus.post(new OverlayMenuClicked(optionalOverlayMenuEntry.get(), overlay)); eventBus.post(new OverlayMenuClicked(overlayMenuEntry, overlay));
} }
} }
} }

View File

@@ -46,7 +46,6 @@ import javax.swing.SwingUtilities;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.GameState; import net.runelite.api.GameState;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry; import net.runelite.api.MenuEntry;
import net.runelite.api.events.BeforeRender; import net.runelite.api.events.BeforeRender;
import net.runelite.api.events.ClientTick; import net.runelite.api.events.ClientTick;
@@ -807,7 +806,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
final MenuEntry entry = new MenuEntry(); final MenuEntry entry = new MenuEntry();
entry.setOption(overlayMenuEntry.getOption()); entry.setOption(overlayMenuEntry.getOption());
entry.setTarget(ColorUtil.wrapWithColorTag(overlayMenuEntry.getTarget(), JagexColors.MENU_TARGET)); entry.setTarget(ColorUtil.wrapWithColorTag(overlayMenuEntry.getTarget(), JagexColors.MENU_TARGET));
entry.setType(MenuAction.RUNELITE_OVERLAY.getId()); entry.setType(overlayMenuEntry.getMenuAction().getId());
entry.setIdentifier(overlayManager.getOverlays().indexOf(overlay)); // overlay id entry.setIdentifier(overlayManager.getOverlays().indexOf(overlay)); // overlay id
entries[i] = entry; entries[i] = entry;

View File

@@ -35,6 +35,7 @@ import java.awt.image.BufferedImage;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import net.runelite.client.ui.FontManager; import net.runelite.client.ui.FontManager;
import net.runelite.client.ui.overlay.infobox.InfoBox;
@Setter @Setter
public class InfoBoxComponent implements LayoutableRenderableEntity public class InfoBoxComponent implements LayoutableRenderableEntity
@@ -54,6 +55,8 @@ public class InfoBoxComponent implements LayoutableRenderableEntity
private Color color = Color.WHITE; private Color color = Color.WHITE;
private Color backgroundColor = ComponentConstants.STANDARD_BACKGROUND_COLOR; private Color backgroundColor = ComponentConstants.STANDARD_BACKGROUND_COLOR;
private BufferedImage image; private BufferedImage image;
@Getter
private InfoBox infoBox;
@Override @Override
public Dimension render(Graphics2D graphics) public Dimension render(Graphics2D graphics)

View File

@@ -26,11 +26,14 @@ package net.runelite.client.ui.overlay.infobox;
import java.awt.Color; import java.awt.Color;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import lombok.AccessLevel; 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;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
public abstract class InfoBox public abstract class InfoBox
{ {
@@ -54,6 +57,10 @@ public abstract class InfoBox
@Setter @Setter
private String tooltip; private String tooltip;
@Getter
@Setter
private List<OverlayMenuEntry> menuEntries = new ArrayList<>();
public InfoBox(BufferedImage image, @Nonnull Plugin plugin) public InfoBox(BufferedImage image, @Nonnull Plugin plugin)
{ {
this.plugin = plugin; this.plugin = plugin;

View File

@@ -31,11 +31,18 @@ import java.awt.Dimension;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Point; import java.awt.Point;
import java.awt.Rectangle; import java.awt.Rectangle;
import java.util.Collections;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
import net.runelite.api.Client; import net.runelite.api.Client;
import net.runelite.api.MenuAction;
import net.runelite.api.events.MenuOptionClicked;
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.events.InfoBoxMenuClicked;
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;
import net.runelite.client.ui.overlay.components.ComponentOrientation; import net.runelite.client.ui.overlay.components.ComponentOrientation;
@@ -54,18 +61,23 @@ public class InfoBoxOverlay extends OverlayPanel
private final TooltipManager tooltipManager; private final TooltipManager tooltipManager;
private final Client client; private final Client client;
private final RuneLiteConfig config; private final RuneLiteConfig config;
private final EventBus eventBus;
private InfoBoxComponent hoveredComponent;
@Inject @Inject
private InfoBoxOverlay( private InfoBoxOverlay(
InfoBoxManager infoboxManager, InfoBoxManager infoboxManager,
TooltipManager tooltipManager, TooltipManager tooltipManager,
Client client, Client client,
RuneLiteConfig config) RuneLiteConfig config,
EventBus eventBus)
{ {
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;
setPosition(OverlayPosition.TOP_LEFT); setPosition(OverlayPosition.TOP_LEFT);
setClearChildren(false); setClearChildren(false);
@@ -80,6 +92,12 @@ public class InfoBoxOverlay extends OverlayPanel
{ {
final List<InfoBox> infoBoxes = infoboxManager.getInfoBoxes(); final List<InfoBox> infoBoxes = infoboxManager.getInfoBoxes();
final boolean menuOpen = client.isMenuOpen();
if (!menuOpen)
{
hoveredComponent = null;
}
if (infoBoxes.isEmpty()) if (infoBoxes.isEmpty())
{ {
return null; return null;
@@ -112,6 +130,7 @@ public class InfoBoxOverlay extends OverlayPanel
infoBoxComponent.setTooltip(box.getTooltip()); infoBoxComponent.setTooltip(box.getTooltip());
infoBoxComponent.setPreferredSize(new Dimension(config.infoBoxSize(), config.infoBoxSize())); infoBoxComponent.setPreferredSize(new Dimension(config.infoBoxSize(), config.infoBoxSize()));
infoBoxComponent.setBackgroundColor(config.overlayBackgroundColor()); infoBoxComponent.setBackgroundColor(config.overlayBackgroundColor());
infoBoxComponent.setInfoBox(box);
panelComponent.getChildren().add(infoBoxComponent); panelComponent.getChildren().add(infoBoxComponent);
} }
@@ -122,25 +141,55 @@ public class InfoBoxOverlay extends OverlayPanel
for (final LayoutableRenderableEntity child : panelComponent.getChildren()) for (final LayoutableRenderableEntity child : panelComponent.getChildren())
{ {
if (child instanceof InfoBoxComponent) final InfoBoxComponent component = (InfoBoxComponent) child;
// Create intersection rectangle
final Rectangle intersectionRectangle = new Rectangle(component.getBounds());
intersectionRectangle.translate(getBounds().x, getBounds().y);
if (intersectionRectangle.contains(mouse))
{ {
final InfoBoxComponent component = (InfoBoxComponent) child; final String tooltip = component.getTooltip();
if (!Strings.isNullOrEmpty(tooltip))
if (!Strings.isNullOrEmpty(component.getTooltip()))
{ {
// Create intersection rectangle tooltipManager.add(new Tooltip(tooltip));
final Rectangle intersectionRectangle = new Rectangle(component.getBounds());
intersectionRectangle.translate(getBounds().x, getBounds().y);
if (intersectionRectangle.contains(mouse))
{
tooltipManager.add(new Tooltip(component.getTooltip()));
}
} }
if (!menuOpen)
{
hoveredComponent = component;
}
break;
} }
} }
panelComponent.getChildren().clear(); panelComponent.getChildren().clear();
return dimension; return dimension;
} }
@Override
public List<OverlayMenuEntry> getMenuEntries()
{
// we dynamically build the menu options based on which infobox is hovered
return hoveredComponent == null ? Collections.emptyList() : hoveredComponent.getInfoBox().getMenuEntries();
}
@Subscribe
public void onMenuOptionClicked(MenuOptionClicked menuOptionClicked)
{
if (menuOptionClicked.getMenuAction() != MenuAction.RUNELITE_INFOBOX)
{
return;
}
InfoBox infoBox = hoveredComponent.getInfoBox();
OverlayMenuEntry overlayMenuEntry = infoBox.getMenuEntries().stream()
.filter(me -> me.getOption().equals(menuOptionClicked.getMenuOption()))
.findAny()
.orElse(null);
if (overlayMenuEntry != null)
{
eventBus.post(new InfoBoxMenuClicked(overlayMenuEntry, infoBox));
}
}
} }