WidgetInspector: Add widget picker
This commit is contained in:
@@ -1564,6 +1564,7 @@ public final class SpriteID
|
|||||||
public static final int MOBILE_FUNCTION_MODE_DISABLED = 1624;
|
public static final int MOBILE_FUNCTION_MODE_DISABLED = 1624;
|
||||||
public static final int MOBILE_YELLOW_TOUCH_ANIMATION_1 = 1625;
|
public static final int MOBILE_YELLOW_TOUCH_ANIMATION_1 = 1625;
|
||||||
public static final int MOBILE_YELLOW_TOUCH_ANIMATION_2 = 1626;
|
public static final int MOBILE_YELLOW_TOUCH_ANIMATION_2 = 1626;
|
||||||
|
public static final int MOBILE_FINGER_ON_INTERFACE = 1653;
|
||||||
/* Unmapped: 1627~1701 */
|
/* Unmapped: 1627~1701 */
|
||||||
public static final int BUTTON_FRIENDS = 1702;
|
public static final int BUTTON_FRIENDS = 1702;
|
||||||
public static final int BUTTON_IGNORES = 1703;
|
public static final int BUTTON_IGNORES = 1703;
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ import java.awt.geom.Rectangle2D;
|
|||||||
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 lombok.Getter;
|
|
||||||
import lombok.Setter;
|
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
import net.runelite.api.Constants;
|
import net.runelite.api.Constants;
|
||||||
import net.runelite.api.DecorativeObject;
|
import net.runelite.api.DecorativeObject;
|
||||||
@@ -72,9 +70,6 @@ import net.runelite.client.ui.overlay.tooltip.TooltipManager;
|
|||||||
@Singleton
|
@Singleton
|
||||||
class DevToolsOverlay extends Overlay
|
class DevToolsOverlay extends Overlay
|
||||||
{
|
{
|
||||||
private static final int ITEM_EMPTY = 6512;
|
|
||||||
private static final int ITEM_FILLED = 20594;
|
|
||||||
|
|
||||||
private static final Font FONT = FontManager.getRunescapeFont().deriveFont(Font.BOLD, 16);
|
private static final Font FONT = FontManager.getRunescapeFont().deriveFont(Font.BOLD, 16);
|
||||||
private static final Color RED = new Color(221, 44, 0);
|
private static final Color RED = new Color(221, 44, 0);
|
||||||
private static final Color GREEN = new Color(0, 200, 83);
|
private static final Color GREEN = new Color(0, 200, 83);
|
||||||
@@ -92,13 +87,6 @@ class DevToolsOverlay extends Overlay
|
|||||||
private final DevToolsPlugin plugin;
|
private final DevToolsPlugin plugin;
|
||||||
private final TooltipManager toolTipManager;
|
private final TooltipManager toolTipManager;
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
private Widget widget;
|
|
||||||
|
|
||||||
@Setter
|
|
||||||
private int itemIndex = -1;
|
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private DevToolsOverlay(Client client, DevToolsPlugin plugin, TooltipManager toolTipManager)
|
private DevToolsOverlay(Client client, DevToolsPlugin plugin, TooltipManager toolTipManager)
|
||||||
{
|
{
|
||||||
@@ -145,8 +133,6 @@ class DevToolsOverlay extends Overlay
|
|||||||
renderGraphicsObjects(graphics);
|
renderGraphicsObjects(graphics);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderWidgets(graphics);
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -430,70 +416,6 @@ class DevToolsOverlay extends Overlay
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void renderWidgets(Graphics2D graphics)
|
|
||||||
{
|
|
||||||
if (widget == null || widget.isHidden())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle childBounds = widget.getBounds();
|
|
||||||
graphics.setColor(CYAN);
|
|
||||||
graphics.draw(childBounds);
|
|
||||||
|
|
||||||
if (itemIndex == -1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (widget.getItemId() != ITEM_EMPTY
|
|
||||||
&& widget.getItemId() != ITEM_FILLED)
|
|
||||||
{
|
|
||||||
Rectangle componentBounds = widget.getBounds();
|
|
||||||
|
|
||||||
graphics.setColor(ORANGE);
|
|
||||||
graphics.draw(componentBounds);
|
|
||||||
|
|
||||||
renderWidgetText(graphics, componentBounds, widget.getItemId(), YELLOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
WidgetItem widgetItem = widget.getWidgetItem(itemIndex);
|
|
||||||
if (widgetItem == null
|
|
||||||
|| widgetItem.getId() < 0
|
|
||||||
|| widgetItem.getId() == ITEM_EMPTY
|
|
||||||
|| widgetItem.getId() == ITEM_FILLED)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle itemBounds = widgetItem.getCanvasBounds();
|
|
||||||
|
|
||||||
graphics.setColor(ORANGE);
|
|
||||||
graphics.draw(itemBounds);
|
|
||||||
|
|
||||||
renderWidgetText(graphics, itemBounds, widgetItem.getId(), YELLOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderWidgetText(Graphics2D graphics, Rectangle bounds, int itemId, Color color)
|
|
||||||
{
|
|
||||||
if (itemId == -1)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String text = itemId + "";
|
|
||||||
FontMetrics fm = graphics.getFontMetrics();
|
|
||||||
Rectangle2D textBounds = fm.getStringBounds(text, graphics);
|
|
||||||
|
|
||||||
int textX = (int) (bounds.getX() + (bounds.getWidth() / 2) - (textBounds.getWidth() / 2));
|
|
||||||
int textY = (int) (bounds.getY() + (bounds.getHeight() / 2) + (textBounds.getHeight() / 2));
|
|
||||||
|
|
||||||
graphics.setColor(Color.BLACK);
|
|
||||||
graphics.drawString(text, textX + 1, textY + 1);
|
|
||||||
graphics.setColor(color);
|
|
||||||
graphics.drawString(text, textX, textY);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void renderPlayerWireframe(Graphics2D graphics, Player player, Color color)
|
private void renderPlayerWireframe(Graphics2D graphics, Player player, Color color)
|
||||||
{
|
{
|
||||||
Polygon[] polys = player.getPolygons();
|
Polygon[] polys = player.getPolygons();
|
||||||
|
|||||||
@@ -27,13 +27,20 @@
|
|||||||
package net.runelite.client.plugins.devtools;
|
package net.runelite.client.plugins.devtools;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import com.google.inject.Provider;
|
||||||
|
import com.google.inject.Singleton;
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Color;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.event.WindowAdapter;
|
import java.awt.event.WindowAdapter;
|
||||||
import java.awt.event.WindowEvent;
|
import java.awt.event.WindowEvent;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Enumeration;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Stack;
|
||||||
|
import java.util.stream.Stream;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.JCheckBox;
|
import javax.swing.JCheckBox;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
@@ -45,31 +52,68 @@ import javax.swing.JTree;
|
|||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.tree.DefaultMutableTreeNode;
|
import javax.swing.tree.DefaultMutableTreeNode;
|
||||||
import javax.swing.tree.DefaultTreeModel;
|
import javax.swing.tree.DefaultTreeModel;
|
||||||
|
import javax.swing.tree.TreePath;
|
||||||
|
import lombok.Getter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.api.Client;
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.MenuAction;
|
||||||
|
import net.runelite.api.MenuEntry;
|
||||||
|
import net.runelite.api.SpriteID;
|
||||||
import net.runelite.api.events.ConfigChanged;
|
import net.runelite.api.events.ConfigChanged;
|
||||||
|
import net.runelite.api.events.MenuEntryAdded;
|
||||||
|
import net.runelite.api.events.MenuOptionClicked;
|
||||||
|
import net.runelite.api.widgets.JavaScriptCallback;
|
||||||
import net.runelite.api.widgets.Widget;
|
import net.runelite.api.widgets.Widget;
|
||||||
|
import net.runelite.api.widgets.WidgetConfig;
|
||||||
import net.runelite.api.widgets.WidgetInfo;
|
import net.runelite.api.widgets.WidgetInfo;
|
||||||
import net.runelite.api.widgets.WidgetItem;
|
import net.runelite.api.widgets.WidgetItem;
|
||||||
|
import net.runelite.api.widgets.WidgetType;
|
||||||
import net.runelite.client.callback.ClientThread;
|
import net.runelite.client.callback.ClientThread;
|
||||||
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.ui.ClientUI;
|
import net.runelite.client.ui.ClientUI;
|
||||||
|
import net.runelite.client.ui.overlay.OverlayManager;
|
||||||
|
import net.runelite.client.util.ColorUtil;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@Singleton
|
||||||
class WidgetInspector extends JFrame
|
class WidgetInspector extends JFrame
|
||||||
{
|
{
|
||||||
|
private static final Map<Integer, WidgetInfo> widgetIdMap = new HashMap<>();
|
||||||
|
|
||||||
|
static final Color SELECTED_WIDGET_COLOR = Color.CYAN;
|
||||||
|
private static final float SELECTED_WIDGET_HUE;
|
||||||
|
|
||||||
|
static
|
||||||
|
{
|
||||||
|
float[] hsb = new float[3];
|
||||||
|
Color.RGBtoHSB(SELECTED_WIDGET_COLOR.getRed(), SELECTED_WIDGET_COLOR.getGreen(), SELECTED_WIDGET_COLOR.getBlue(), hsb);
|
||||||
|
SELECTED_WIDGET_HUE = hsb[0];
|
||||||
|
}
|
||||||
|
|
||||||
private final Client client;
|
private final Client client;
|
||||||
private final ClientThread clientThread;
|
private final ClientThread clientThread;
|
||||||
private final DevToolsConfig config;
|
private final DevToolsConfig config;
|
||||||
private final DevToolsOverlay overlay;
|
private final Provider<WidgetInspectorOverlay> overlay;
|
||||||
private final DevToolsPlugin plugin;
|
private final OverlayManager overlayManager;
|
||||||
|
|
||||||
private final JTree widgetTree;
|
private final JTree widgetTree;
|
||||||
private final WidgetInfoTableModel infoTableModel;
|
private final WidgetInfoTableModel infoTableModel;
|
||||||
private final JCheckBox alwaysOnTop;
|
private final JCheckBox alwaysOnTop;
|
||||||
|
private final JCheckBox hideHidden;
|
||||||
|
|
||||||
private static final Map<Integer, WidgetInfo> widgetIdMap = new HashMap<>();
|
private DefaultMutableTreeNode root;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private Widget selectedWidget;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private int selectedItem;
|
||||||
|
|
||||||
|
private Widget picker = null;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
private boolean pickerSelected = false;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
private WidgetInspector(
|
private WidgetInspector(
|
||||||
@@ -77,16 +121,17 @@ class WidgetInspector extends JFrame
|
|||||||
ClientThread clientThread,
|
ClientThread clientThread,
|
||||||
WidgetInfoTableModel infoTableModel,
|
WidgetInfoTableModel infoTableModel,
|
||||||
DevToolsConfig config,
|
DevToolsConfig config,
|
||||||
|
DevToolsPlugin plugin,
|
||||||
EventBus eventBus,
|
EventBus eventBus,
|
||||||
DevToolsOverlay overlay,
|
Provider<WidgetInspectorOverlay> overlay,
|
||||||
DevToolsPlugin plugin)
|
OverlayManager overlayManager)
|
||||||
{
|
{
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.clientThread = clientThread;
|
this.clientThread = clientThread;
|
||||||
this.infoTableModel = infoTableModel;
|
this.infoTableModel = infoTableModel;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.overlay = overlay;
|
this.overlay = overlay;
|
||||||
this.plugin = plugin;
|
this.overlayManager = overlayManager;
|
||||||
|
|
||||||
eventBus.register(this);
|
eventBus.register(this);
|
||||||
|
|
||||||
@@ -116,16 +161,12 @@ class WidgetInspector extends JFrame
|
|||||||
{
|
{
|
||||||
WidgetTreeNode node = (WidgetTreeNode) selected;
|
WidgetTreeNode node = (WidgetTreeNode) selected;
|
||||||
Widget widget = node.getWidget();
|
Widget widget = node.getWidget();
|
||||||
overlay.setWidget(widget);
|
setSelectedWidget(widget, -1, false);
|
||||||
overlay.setItemIndex(widget.getItemId());
|
|
||||||
refreshInfo();
|
|
||||||
log.debug("Set widget to {} and item index to {}", widget, widget.getItemId());
|
|
||||||
}
|
}
|
||||||
else if (selected instanceof WidgetItemNode)
|
else if (selected instanceof WidgetItemNode)
|
||||||
{
|
{
|
||||||
WidgetItemNode node = (WidgetItemNode) selected;
|
WidgetItemNode node = (WidgetItemNode) selected;
|
||||||
overlay.setItemIndex(node.getWidgetItem().getIndex());
|
setSelectedWidget(node.getWidgetItem().getWidget(), node.getWidgetItem().getIndex(), false);
|
||||||
log.debug("Set item index to {}", node.getWidgetItem().getIndex());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -151,15 +192,20 @@ class WidgetInspector extends JFrame
|
|||||||
onConfigChanged(null);
|
onConfigChanged(null);
|
||||||
bottomPanel.add(alwaysOnTop);
|
bottomPanel.add(alwaysOnTop);
|
||||||
|
|
||||||
|
hideHidden = new JCheckBox("Hide hidden");
|
||||||
|
hideHidden.setSelected(true);
|
||||||
|
hideHidden.addItemListener(ev -> refreshWidgets());
|
||||||
|
bottomPanel.add(hideHidden);
|
||||||
|
|
||||||
final JButton revalidateWidget = new JButton("Revalidate");
|
final JButton revalidateWidget = new JButton("Revalidate");
|
||||||
revalidateWidget.addActionListener(ev -> clientThread.invokeLater(() ->
|
revalidateWidget.addActionListener(ev -> clientThread.invokeLater(() ->
|
||||||
{
|
{
|
||||||
if (overlay.getWidget() == null)
|
if (selectedWidget == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
overlay.getWidget().revalidate();
|
selectedWidget.revalidate();
|
||||||
}));
|
}));
|
||||||
bottomPanel.add(revalidateWidget);
|
bottomPanel.add(revalidateWidget);
|
||||||
|
|
||||||
@@ -182,10 +228,13 @@ class WidgetInspector extends JFrame
|
|||||||
clientThread.invokeLater(() ->
|
clientThread.invokeLater(() ->
|
||||||
{
|
{
|
||||||
Widget[] rootWidgets = client.getWidgetRoots();
|
Widget[] rootWidgets = client.getWidgetRoots();
|
||||||
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
|
root = new DefaultMutableTreeNode();
|
||||||
|
|
||||||
overlay.setWidget(null);
|
Widget wasSelectedWidget = selectedWidget;
|
||||||
overlay.setItemIndex(-1);
|
int wasSelectedItem = selectedItem;
|
||||||
|
|
||||||
|
selectedWidget = null;
|
||||||
|
selectedItem = -1;
|
||||||
|
|
||||||
for (Widget widget : rootWidgets)
|
for (Widget widget : rootWidgets)
|
||||||
{
|
{
|
||||||
@@ -198,17 +247,15 @@ class WidgetInspector extends JFrame
|
|||||||
|
|
||||||
SwingUtilities.invokeLater(() ->
|
SwingUtilities.invokeLater(() ->
|
||||||
{
|
{
|
||||||
overlay.setWidget(null);
|
|
||||||
overlay.setItemIndex(-1);
|
|
||||||
refreshInfo();
|
|
||||||
widgetTree.setModel(new DefaultTreeModel(root));
|
widgetTree.setModel(new DefaultTreeModel(root));
|
||||||
|
setSelectedWidget(wasSelectedWidget, wasSelectedItem, true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private DefaultMutableTreeNode addWidget(String type, Widget widget)
|
private DefaultMutableTreeNode addWidget(String type, Widget widget)
|
||||||
{
|
{
|
||||||
if (widget == null || widget.isHidden())
|
if (widget == null || (hideHidden.isSelected() && widget.isHidden()))
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -271,9 +318,70 @@ class WidgetInspector extends JFrame
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void refreshInfo()
|
private void setSelectedWidget(Widget widget, int item, boolean updateTree)
|
||||||
{
|
{
|
||||||
infoTableModel.setWidget(overlay.getWidget());
|
infoTableModel.setWidget(widget);
|
||||||
|
|
||||||
|
if (this.selectedWidget == widget && this.selectedItem == item)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedWidget = widget;
|
||||||
|
this.selectedItem = item;
|
||||||
|
|
||||||
|
if (root == null || !updateTree)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clientThread.invoke(() ->
|
||||||
|
{
|
||||||
|
Stack<Widget> treePath = new Stack<>();
|
||||||
|
for (Widget w = widget; w != null; w = w.getParent())
|
||||||
|
{
|
||||||
|
treePath.push(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultMutableTreeNode node = root;
|
||||||
|
deeper:
|
||||||
|
for (; !treePath.empty(); )
|
||||||
|
{
|
||||||
|
Widget w = treePath.pop();
|
||||||
|
for (Enumeration<?> it = node.children(); it.hasMoreElements(); )
|
||||||
|
{
|
||||||
|
WidgetTreeNode inner = (WidgetTreeNode) it.nextElement();
|
||||||
|
if (inner.getWidget().getId() == w.getId() && inner.getWidget().getIndex() == w.getIndex())
|
||||||
|
{
|
||||||
|
node = inner;
|
||||||
|
continue deeper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedItem != -1)
|
||||||
|
{
|
||||||
|
for (Enumeration<?> it = node.children(); it.hasMoreElements(); )
|
||||||
|
{
|
||||||
|
Object wiw = it.nextElement();
|
||||||
|
if (wiw instanceof WidgetItemNode)
|
||||||
|
{
|
||||||
|
WidgetItemNode inner = (WidgetItemNode) wiw;
|
||||||
|
if (inner.getWidgetItem().getIndex() == selectedItem)
|
||||||
|
{
|
||||||
|
node = inner;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final DefaultMutableTreeNode fnode = node;
|
||||||
|
SwingUtilities.invokeLater(() ->
|
||||||
|
{
|
||||||
|
widgetTree.getSelectionModel().clearSelection();
|
||||||
|
widgetTree.getSelectionModel().addSelectionPath(new TreePath(fnode.getPath()));
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static WidgetInfo getWidgetInfo(int packedId)
|
static WidgetInfo getWidgetInfo(int packedId)
|
||||||
@@ -297,12 +405,177 @@ class WidgetInspector extends JFrame
|
|||||||
setVisible(true);
|
setVisible(true);
|
||||||
toFront();
|
toFront();
|
||||||
repaint();
|
repaint();
|
||||||
|
overlayManager.add(this.overlay.get());
|
||||||
|
clientThread.invokeLater(this::addPickerWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void close()
|
public void close()
|
||||||
{
|
{
|
||||||
overlay.setWidget(null);
|
overlayManager.remove(this.overlay.get());
|
||||||
overlay.setItemIndex(-1);
|
clientThread.invokeLater(this::removePickerWidget);
|
||||||
|
setSelectedWidget(null, -1, false);
|
||||||
setVisible(false);
|
setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void removePickerWidget()
|
||||||
|
{
|
||||||
|
if (picker == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget parent = picker.getParent();
|
||||||
|
if (parent == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget[] children = parent.getChildren();
|
||||||
|
if (children == null || children.length <= picker.getIndex() || children[picker.getIndex()] != picker)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
children[picker.getIndex()] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPickerWidget()
|
||||||
|
{
|
||||||
|
removePickerWidget();
|
||||||
|
|
||||||
|
int x = 10, y = 2;
|
||||||
|
Widget parent = client.getWidget(WidgetInfo.MINIMAP_ORBS);
|
||||||
|
if (parent == null)
|
||||||
|
{
|
||||||
|
Widget[] roots = client.getWidgetRoots();
|
||||||
|
|
||||||
|
parent = Stream.of(roots)
|
||||||
|
.filter(w -> w.getType() == WidgetType.LAYER && w.getContentType() == 0 && !w.isSelfHidden())
|
||||||
|
.sorted(Comparator.comparing((Widget w) -> w.getRelativeX() + w.getRelativeY())
|
||||||
|
.reversed()
|
||||||
|
.thenComparing(Widget::getId)
|
||||||
|
.reversed())
|
||||||
|
.findFirst().get();
|
||||||
|
x = 4;
|
||||||
|
y = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
picker = parent.createChild(-1, WidgetType.GRAPHIC);
|
||||||
|
|
||||||
|
log.info("Picker is {}.{} [{}]", WidgetInfo.TO_GROUP(picker.getId()), WidgetInfo.TO_CHILD(picker.getId()), picker.getIndex());
|
||||||
|
|
||||||
|
picker.setSpriteId(SpriteID.MOBILE_FINGER_ON_INTERFACE);
|
||||||
|
picker.setOriginalWidth(15);
|
||||||
|
picker.setOriginalHeight(17);
|
||||||
|
picker.setOriginalX(x);
|
||||||
|
picker.setOriginalY(y);
|
||||||
|
picker.revalidate();
|
||||||
|
picker.setTargetVerb("Select");
|
||||||
|
picker.setName("Pick");
|
||||||
|
picker.setClickMask(WidgetConfig.USE_WIDGET | WidgetConfig.USE_ITEM);
|
||||||
|
picker.setNoClickThrough(true);
|
||||||
|
picker.setOnTargetEnterListener((JavaScriptCallback) ev ->
|
||||||
|
{
|
||||||
|
pickerSelected = true;
|
||||||
|
picker.setOpacity(30);
|
||||||
|
client.setAllWidgetsAreOpTargetable(true);
|
||||||
|
});
|
||||||
|
picker.setOnTargetLeaveListener((JavaScriptCallback) ev -> onPickerDeselect());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onPickerDeselect()
|
||||||
|
{
|
||||||
|
client.setAllWidgetsAreOpTargetable(false);
|
||||||
|
picker.setOpacity(0);
|
||||||
|
pickerSelected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onMenuOptionClicked(MenuOptionClicked ev)
|
||||||
|
{
|
||||||
|
if (!pickerSelected)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
onPickerDeselect();
|
||||||
|
client.setSpellSelected(false);
|
||||||
|
ev.consume();
|
||||||
|
|
||||||
|
Object target = getWidgetOrWidgetItemForMenuOption(ev.getMenuAction().getId(), ev.getActionParam(), ev.getWidgetId());
|
||||||
|
if (target == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (target instanceof WidgetItem)
|
||||||
|
{
|
||||||
|
WidgetItem iw = (WidgetItem) target;
|
||||||
|
setSelectedWidget(iw.getWidget(), iw.getIndex(), true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
setSelectedWidget((Widget) target, -1, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Subscribe
|
||||||
|
private void onMenuEntryAdded(MenuEntryAdded event)
|
||||||
|
{
|
||||||
|
if (!pickerSelected)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuEntry[] menuEntries = client.getMenuEntries();
|
||||||
|
|
||||||
|
for (int i = 0; i < menuEntries.length; i++)
|
||||||
|
{
|
||||||
|
MenuEntry entry = menuEntries[i];
|
||||||
|
if (entry.getType() != MenuAction.ITEM_USE_ON_WIDGET.getId()
|
||||||
|
&& entry.getType() != MenuAction.SPELL_CAST_ON_WIDGET.getId())
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String name = WidgetInfo.TO_GROUP(entry.getParam1()) + "." + WidgetInfo.TO_CHILD(entry.getParam1());
|
||||||
|
|
||||||
|
if (entry.getParam0() != -1)
|
||||||
|
{
|
||||||
|
name += " [" + entry.getParam0() + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
Color color = colorForWidget(i, menuEntries.length);
|
||||||
|
|
||||||
|
entry.setTarget(ColorUtil.wrapWithColorTag(name, color));
|
||||||
|
}
|
||||||
|
|
||||||
|
client.setMenuEntries(menuEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
Color colorForWidget(int index, int length)
|
||||||
|
{
|
||||||
|
float h = SELECTED_WIDGET_HUE + .1f + (.8f / length) * index;
|
||||||
|
|
||||||
|
return Color.getHSBColor(h, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object getWidgetOrWidgetItemForMenuOption(int type, int param0, int param1)
|
||||||
|
{
|
||||||
|
if (type == MenuAction.SPELL_CAST_ON_WIDGET.getId())
|
||||||
|
{
|
||||||
|
Widget w = client.getWidget(WidgetInfo.TO_GROUP(param1), WidgetInfo.TO_CHILD(param1));
|
||||||
|
if (param0 != -1)
|
||||||
|
{
|
||||||
|
w = w.getChild(param0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
else if (type == MenuAction.ITEM_USE_ON_WIDGET.getId())
|
||||||
|
{
|
||||||
|
Widget w = client.getWidget(WidgetInfo.TO_GROUP(param1), WidgetInfo.TO_CHILD(param1));
|
||||||
|
return w.getWidgetItem(param0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Abex
|
||||||
|
* Copyright (c) 2017, Kronos <https://github.com/KronosDesign>
|
||||||
|
* Copyright (c) 2017, 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.plugins.devtools;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.geom.Rectangle2D;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
import net.runelite.api.Client;
|
||||||
|
import net.runelite.api.MenuEntry;
|
||||||
|
import net.runelite.api.widgets.Widget;
|
||||||
|
import net.runelite.api.widgets.WidgetItem;
|
||||||
|
import net.runelite.client.ui.overlay.Overlay;
|
||||||
|
import net.runelite.client.ui.overlay.OverlayLayer;
|
||||||
|
import net.runelite.client.ui.overlay.OverlayPosition;
|
||||||
|
import net.runelite.client.ui.overlay.OverlayPriority;
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
public class WidgetInspectorOverlay extends Overlay
|
||||||
|
{
|
||||||
|
private final Client client;
|
||||||
|
private final WidgetInspector inspector;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public WidgetInspectorOverlay(
|
||||||
|
Client client,
|
||||||
|
WidgetInspector inspector
|
||||||
|
)
|
||||||
|
{
|
||||||
|
this.client = client;
|
||||||
|
this.inspector = inspector;
|
||||||
|
|
||||||
|
setPosition(OverlayPosition.DYNAMIC);
|
||||||
|
setLayer(OverlayLayer.ABOVE_WIDGETS);
|
||||||
|
setPriority(OverlayPriority.HIGHEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension render(Graphics2D g)
|
||||||
|
{
|
||||||
|
Widget w = inspector.getSelectedWidget();
|
||||||
|
if (w != null)
|
||||||
|
{
|
||||||
|
Object wiw = w;
|
||||||
|
if (inspector.getSelectedItem() != -1)
|
||||||
|
{
|
||||||
|
wiw = w.getWidgetItem(inspector.getSelectedItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
renderWiw(g, wiw, WidgetInspector.SELECTED_WIDGET_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inspector.isPickerSelected())
|
||||||
|
{
|
||||||
|
boolean menuOpen = client.isMenuOpen();
|
||||||
|
|
||||||
|
MenuEntry[] entries = client.getMenuEntries();
|
||||||
|
for (int i = menuOpen ? 0 : entries.length - 1; i < entries.length; i++)
|
||||||
|
{
|
||||||
|
MenuEntry e = entries[i];
|
||||||
|
|
||||||
|
Object wiw = inspector.getWidgetOrWidgetItemForMenuOption(e.getType(), e.getParam0(), e.getParam1());
|
||||||
|
if (wiw == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color color = inspector.colorForWidget(i, entries.length);
|
||||||
|
renderWiw(g, wiw, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderWiw(Graphics2D g, Object wiw, Color color)
|
||||||
|
{
|
||||||
|
g.setColor(color);
|
||||||
|
|
||||||
|
if (wiw instanceof WidgetItem)
|
||||||
|
{
|
||||||
|
WidgetItem wi = (WidgetItem) wiw;
|
||||||
|
Rectangle bounds = wi.getCanvasBounds();
|
||||||
|
g.draw(bounds);
|
||||||
|
|
||||||
|
String text = wi.getId() + "";
|
||||||
|
FontMetrics fm = g.getFontMetrics();
|
||||||
|
Rectangle2D textBounds = fm.getStringBounds(text, g);
|
||||||
|
|
||||||
|
int textX = (int) (bounds.getX() + (bounds.getWidth() / 2) - (textBounds.getWidth() / 2));
|
||||||
|
int textY = (int) (bounds.getY() + (bounds.getHeight() / 2) + (textBounds.getHeight() / 2));
|
||||||
|
|
||||||
|
g.setColor(Color.BLACK);
|
||||||
|
g.drawString(text, textX + 1, textY + 1);
|
||||||
|
g.setColor(Color.ORANGE);
|
||||||
|
g.drawString(text, textX, textY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Widget w = (Widget) wiw;
|
||||||
|
g.draw(w.getBounds());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user