From 39f9cfbe70b00d9a45d8c5187c7570536f8d7297 Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 5 Aug 2017 14:11:05 -0400 Subject: [PATCH] runelite-api: fix widget children lookup logic Also update dev tools panel widget tree to use show all widgets children, and start from the root widgets. Thanks to @rsbmatt for his assistance in explaining the logic --- .../main/java/net/runelite/api/Client.java | 34 ++-- .../java/net/runelite/api/widgets/Widget.java | 103 ++++++---- .../net/runelite/api/widgets/WidgetInfo.java | 10 + .../client/plugins/devtools/DevTools.java | 36 +--- .../plugins/devtools/DevToolsOverlay.java | 46 ++--- .../plugins/devtools/DevToolsPanel.java | 187 +++++++++--------- .../plugins/devtools/WidgetItemNode.java | 51 +++++ .../plugins/devtools/WidgetTreeNode.java | 54 +++++ .../main/java/net/runelite/rs/api/Client.java | 11 +- 9 files changed, 330 insertions(+), 202 deletions(-) create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetItemNode.java create mode 100644 runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetTreeNode.java diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index 8711ec33f4..5008c40646 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -26,6 +26,7 @@ package net.runelite.api; import java.awt.Canvas; import java.util.Arrays; +import java.util.Objects; import net.runelite.api.widgets.Widget; import net.runelite.api.widgets.WidgetInfo; import net.runelite.rs.api.ItemComposition; @@ -213,13 +214,14 @@ public class Client return client.getBaseY(); } - public Widget[][] getWidgets() + public Widget[] getWidgetRoots() { - return Arrays.stream(client.getWidgets()) - .map(parent -> parent != null ? Arrays.stream(parent) - .map(child -> child != null ? new Widget(this, child) : null) - .toArray(Widget[]::new) : null - ).toArray(Widget[][]::new); + int topGroup = client.getWidgetRoot(); + return Arrays.stream(client.getWidgets()[topGroup]) + .filter(Objects::nonNull) + .filter(w -> w.getParentId() == -1) // is a root + .map(w -> new Widget(this, w)) + .toArray(Widget[]::new); } public Widget getWidget(WidgetInfo widget) @@ -230,6 +232,21 @@ public class Client return getWidget(groupId, childId); } + public Widget[] getGroup(int groupId) + { + net.runelite.rs.api.Widget[][] widgets = client.getWidgets(); + + if (widgets == null || groupId < 0 || groupId >= widgets.length) + { + return null; + } + + return Arrays.stream(widgets[groupId]) + .filter(Objects::nonNull) + .map(w -> new Widget(this, w)) + .toArray(Widget[]::new); + } + public Widget getWidget(int groupId, int childId) { net.runelite.rs.api.Widget[][] widgets = client.getWidgets(); @@ -258,11 +275,6 @@ public class Client return client.getWidgetPositionsY(); } - public boolean[] getValidInterfaces() - { - return client.getValidInterfaces(); - } - public String[] getPlayerOptions() { return client.getPlayerOptions(); diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java b/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java index 5ff159ff96..e438e29cf2 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/Widget.java @@ -26,13 +26,17 @@ package net.runelite.api.widgets; import java.awt.Rectangle; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.Objects; import net.runelite.api.Client; import net.runelite.api.Node; import net.runelite.api.Point; import net.runelite.api.WidgetNode; import net.runelite.api.XHashTable; +import static net.runelite.api.widgets.WidgetInfo.TO_CHILD; +import static net.runelite.api.widgets.WidgetInfo.TO_GROUP; public class Widget { @@ -70,7 +74,7 @@ public class Widget return null; } - return client.getWidget(id >>> 16, id & 0xFFFF); + return client.getWidget(TO_GROUP(id), TO_CHILD(id)); } public int getParentId() @@ -81,7 +85,7 @@ public class Widget return parentId; } - int i = getId() >>> 16; + int i = TO_GROUP(getId()); XHashTable componentTable = client.getComponentTable(); for (Node node : componentTable.getNodes()) { @@ -96,6 +100,70 @@ public class Widget return -1; } + public Widget getChild(int index) + { + net.runelite.rs.api.Widget[] widgets = widget.getChildren(); + + if (widgets == null || widgets[index] == null) + { + return null; + } + + return new Widget(client, widgets[index]); + } + + public Widget[] getDynamicChildren() + { + net.runelite.rs.api.Widget[] children = widget.getChildren(); + + if (children == null) + { + return new Widget[0]; + } + + return Arrays.stream(children) + .filter(Objects::nonNull) + .filter(w -> w.getParentId() == getId()) + .map(w -> new Widget(client, w)) + .toArray(Widget[]::new); + } + + public Widget[] getStaticChildren() + { + return Arrays.stream(client.getGroup(TO_GROUP(getId()))) + .filter(Objects::nonNull) + .filter(w -> w.getParentId() == getId()) + .toArray(Widget[]::new); + } + + public Widget[] getNestedChildren() + { + XHashTable componentTable = client.getComponentTable(); + int group = -1; + + // XXX can actually use hashtable lookup instead of table + // iteration here... + for (Node node : componentTable.getNodes()) + { + WidgetNode wn = (WidgetNode) node; + + if (wn.getHash() == getId()) + { + group = wn.getId(); + break; + } + } + + if (group == -1) + { + return new Widget[0]; + } + + return Arrays.stream(client.getGroup(group)) + .filter(w -> w.getParentId() == getId()) + .toArray(Widget[]::new); + } + private int getRelativeX() { return widget.getRelativeX(); @@ -264,37 +332,6 @@ public class Widget return widget.getPaddingY(); } - public Widget[] getChildren() - { - net.runelite.rs.api.Widget[] widgets = widget.getChildren(); - - if (widgets == null) - { - return null; - } - - Widget[] children = new Widget[widgets.length]; - - for (int i = 0; i < widgets.length; ++i) - { - children[i] = getChild(i); - } - - return children; - } - - public Widget getChild(int index) - { - net.runelite.rs.api.Widget[] widgets = widget.getChildren(); - - if (widgets == null || widgets[index] == null) - { - return null; - } - - return new Widget(client, widgets[index]); - } - public int getItemId() { return widget.getItemId(); diff --git a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java index e846dc396b..3e3201dc7e 100644 --- a/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java +++ b/runelite-api/src/main/java/net/runelite/api/widgets/WidgetInfo.java @@ -89,4 +89,14 @@ public enum WidgetInfo return childId; } + public static int TO_GROUP(int id) + { + return id >>> 16; + } + + public static int TO_CHILD(int id) + { + return id & 0xFFFF; + } + } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevTools.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevTools.java index 104e1d55b0..5d85c4f2f6 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevTools.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevTools.java @@ -28,6 +28,7 @@ import java.awt.Font; import java.awt.GraphicsEnvironment; import javax.imageio.ImageIO; import javax.swing.ImageIcon; +import net.runelite.api.widgets.Widget; import net.runelite.client.RuneLite; import net.runelite.client.plugins.Plugin; @@ -51,9 +52,8 @@ public class DevTools extends Plugin private boolean toggleDecor; private boolean toggleInventory; - private int widgetParent = -1; - private int widgetChild = -1; - private int widgetItem = -1; + Widget currentWidget; + int itemIndex = -1; private Font font; @@ -171,34 +171,4 @@ public class DevTools extends Plugin return toggleInventory; } - void setWidgetParent(int id) - { - widgetParent = id; - } - - void setWidgetChild(int id) - { - widgetChild = id; - } - - void setWidgetItem(int id) - { - widgetItem = id; - } - - int getWidgetParent() - { - return widgetParent; - } - - int getWidgetChild() - { - return widgetChild; - } - - int getWidgetItem() - { - return widgetItem; - } - } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java index 6dcb2538cb..d56c13de0d 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsOverlay.java @@ -324,37 +324,15 @@ public class DevToolsOverlay extends Overlay public void renderWidgets(Graphics2D graphics) { - int parentID = plugin.getWidgetParent(); - int childID = plugin.getWidgetChild(); - int itemIndex = plugin.getWidgetItem(); + Widget widget = plugin.currentWidget; + int itemIndex = plugin.itemIndex; - if (parentID == -1) + if (widget == null || widget.isHidden()) { return; } - Widget widgetParent = client.getWidget(parentID, 0); - if (widgetParent == null || widgetParent.isHidden()) - { - return; - } - - Rectangle parentBounds = widgetParent.getBounds(); - graphics.setColor(YELLOW); - graphics.draw(parentBounds); - - if (childID == -1) - { - return; - } - - Widget widgetChild = client.getWidget(parentID, childID); - if (widgetChild == null || widgetChild.isHidden()) - { - return; - } - - Rectangle childBounds = widgetChild.getBounds(); + Rectangle childBounds = widget.getBounds(); graphics.setColor(CYAN); graphics.draw(childBounds); @@ -363,21 +341,21 @@ public class DevToolsOverlay extends Overlay return; } - Widget childComponent = widgetChild.getChild(itemIndex); - if (childComponent != null && !childComponent.isHidden() - && childComponent.getItemId() != ITEM_EMPTY - && childComponent.getItemId() != ITEM_FILLED) + if (widget.getItemId() != ITEM_EMPTY + && widget.getItemId() != ITEM_FILLED) { - Rectangle componentBounds = childComponent.getBounds(); + Rectangle componentBounds = widget.getBounds(); graphics.setColor(ORANGE); graphics.draw(componentBounds); - renderWidgetText(graphics, componentBounds, childComponent.getItemId(), YELLOW); + renderWidgetText(graphics, componentBounds, widget.getItemId(), YELLOW); } - WidgetItem widgetItem = widgetChild.getWidgetItem(itemIndex); - if (widgetItem == null) + WidgetItem widgetItem = widget.getWidgetItem(itemIndex); + if (widgetItem == null + || widgetItem.getId() == ITEM_EMPTY + || widgetItem.getId() == ITEM_FILLED) { return; } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java index ac258febef..193ebf1af8 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/DevToolsPanel.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2017, Kronos + * Copyright (c) 2017, Adam * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -33,14 +34,18 @@ import javax.swing.tree.DefaultTreeModel; import net.runelite.api.Client; import net.runelite.api.widgets.Widget; +import static net.runelite.api.widgets.WidgetInfo.TO_CHILD; +import static net.runelite.api.widgets.WidgetInfo.TO_GROUP; import net.runelite.api.widgets.WidgetItem; import net.runelite.client.RuneLite; -import static net.runelite.client.plugins.devtools.DevToolsOverlay.ITEM_EMPTY; -import static net.runelite.client.plugins.devtools.DevToolsOverlay.ITEM_FILLED; import net.runelite.client.ui.PluginPanel; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class DevToolsPanel extends PluginPanel { + private static final Logger logger = LoggerFactory.getLogger(DevToolsPanel.class); + private final EmptyBorder PADDING_BORDER = new EmptyBorder(3, 3, 3, 3); private final Client client = RuneLite.getClient(); @@ -66,8 +71,6 @@ public class DevToolsPanel extends PluginPanel private DevTools plugin; - private DefaultMutableTreeNode widgetListRoot = new DefaultMutableTreeNode(); - private final SettingsTracker settingsTracker = new SettingsTracker(client); public DevToolsPanel(DevTools plugin) @@ -170,16 +173,27 @@ public class DevToolsPanel extends PluginPanel JPanel container = new JPanel(); container.setLayout(new BorderLayout()); - JTree tree = new JTree(widgetListRoot); + JTree tree = new JTree(new DefaultMutableTreeNode()); tree.setRootVisible(false); tree.setShowsRootHandles(true); tree.getSelectionModel().addTreeSelectionListener(e -> { - Object[] path = e.getPath().getPath(); - plugin.setWidgetParent(Integer.parseInt(path[1].toString())); - plugin.setWidgetChild((path.length > 2) ? Integer.parseInt(path[2].toString()) : -1); - plugin.setWidgetItem((path.length > 3) ? Integer.parseInt(path[3].toString()) : -1); - setWidgetInfo(); + Object selected = tree.getLastSelectedPathComponent(); + if (selected instanceof WidgetTreeNode) + { + WidgetTreeNode node = (WidgetTreeNode) selected; + Widget widget = node.getWidget(); + plugin.currentWidget = widget; + plugin.itemIndex = widget.getItemId(); + setWidgetInfo(widget); + logger.debug("Set widget to {} and item index to {}", widget, widget.getItemId()); + } + else if (selected instanceof WidgetItemNode) + { + WidgetItemNode node = (WidgetItemNode) selected; + plugin.itemIndex = node.getWidgetItem().getIndex(); + logger.debug("Set item index to {}", plugin.itemIndex); + } }); JScrollPane scrollPane = new JScrollPane(tree); @@ -189,8 +203,8 @@ public class DevToolsPanel extends PluginPanel JButton refreshWidgetsBtn = new JButton("Refresh Widgets"); refreshWidgetsBtn.addActionListener(e -> { - refreshWidgets(); - tree.setModel(new DefaultTreeModel(widgetListRoot)); + DefaultMutableTreeNode root = refreshWidgets(); + tree.setModel(new DefaultTreeModel(root)); }); JPanel btnContainer = new JPanel(); @@ -225,18 +239,8 @@ public class DevToolsPanel extends PluginPanel return container; } - private void setWidgetInfo() + private void setWidgetInfo(Widget widget) { - int parent = plugin.getWidgetParent(); - int child = plugin.getWidgetChild(); - - if (parent == -1) - { - return; - } - - Widget widget = client.getWidget(parent, (child == -1) ? 0 : child); - if (widget == null) { return; @@ -247,8 +251,9 @@ public class DevToolsPanel extends PluginPanel nameLbl.setText("Name: " + widget.getName().trim()); modelLbl.setText("Model ID: " + widget.getModelId()); textureLbl.setText("Sprite ID: " + widget.getSpriteId()); - typeLbl.setText("Type: " + widget.getType()); - contentTypeLbl.setText("Content Type: " + widget.getContentType()); + typeLbl.setText("Type: " + widget.getType() + + " Parent " + (widget.getParentId() == -1 ? -1 : TO_GROUP(widget.getParentId()) + "." + TO_CHILD(widget.getParentId()))); + contentTypeLbl.setText("Content Type: " + widget.getContentType() + " Hidden " + widget.isHidden()); } private void highlightButton(JButton button) @@ -263,83 +268,89 @@ public class DevToolsPanel extends PluginPanel } } - private void refreshWidgets() + private DefaultMutableTreeNode refreshWidgets() { - Widget[][] widgets = client.getWidgets(); - boolean[] validInterfaces = client.getValidInterfaces(); + Widget[] rootWidgets = client.getWidgetRoots(); DefaultMutableTreeNode root = new DefaultMutableTreeNode(); - plugin.setWidgetParent(-1); - plugin.setWidgetChild(-1); - plugin.setWidgetItem(-1); + plugin.currentWidget = null; + plugin.itemIndex = -1; - int idx = -1; - - for (Widget[] children : widgets) + for (Widget widget : rootWidgets) { - ++idx; - - if (!validInterfaces[idx]) + DefaultMutableTreeNode childNode = addWidget("R", widget); + if (childNode != null) { - continue; + root.add(childNode); } + } - if (children == null) + return root; + } + + private DefaultMutableTreeNode addWidget(String type, Widget widget) + { + if (widget == null || widget.isHidden()) + { + return null; + } + + DefaultMutableTreeNode node = new WidgetTreeNode(type, widget); + + Widget[] childComponents = widget.getDynamicChildren(); + if (childComponents != null) + { + for (Widget component : childComponents) { - continue; - } - - DefaultMutableTreeNode parent = new DefaultMutableTreeNode(idx); - root.add(parent); - - for (Widget widgetChild : children) - { - if (widgetChild == null || widgetChild.isHidden()) + DefaultMutableTreeNode childNode = addWidget("D", component); + if (childNode != null) { - continue; - } - - DefaultMutableTreeNode child = new DefaultMutableTreeNode(widgetChild.getId() & 0xFFFF); - parent.add(child); - - Widget[] childComponents = widgetChild.getChildren(); - if (childComponents != null) - { - int index = -1; - for (Widget component : childComponents) - { - index++; - if (component == null || component.isHidden() - || component.getItemId() == ITEM_EMPTY - || component.getItemId() == ITEM_FILLED) - { - continue; - } - - child.add(new DefaultMutableTreeNode(index)); - } - } - - Collection items = widgetChild.getWidgetItems(); - if (items == null) - { - continue; - } - - for (WidgetItem item : items) - { - - if (item == null) - { - continue; - } - - child.add(new DefaultMutableTreeNode(item.getIndex())); + node.add(childNode); } } } - widgetListRoot = root; + childComponents = widget.getStaticChildren(); + if (childComponents != null) + { + for (Widget component : childComponents) + { + DefaultMutableTreeNode childNode = addWidget("S", component); + if (childNode != null) + { + node.add(childNode); + } + } + } + + childComponents = widget.getNestedChildren(); + if (childComponents != null) + { + for (Widget component : childComponents) + { + DefaultMutableTreeNode childNode = addWidget("N", component); + if (childNode != null) + { + node.add(childNode); + } + } + } + + Collection items = widget.getWidgetItems(); + if (items != null) + { + for (WidgetItem item : items) + { + if (item == null) + { + continue; + } + + node.add(new WidgetItemNode(item)); + } + } + + return node; } } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetItemNode.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetItemNode.java new file mode 100644 index 0000000000..2c640c1de6 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetItemNode.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017, Adam + * 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 javax.swing.tree.DefaultMutableTreeNode; +import net.runelite.api.widgets.WidgetItem; + +class WidgetItemNode extends DefaultMutableTreeNode +{ + private final WidgetItem widgetItem; + + public WidgetItemNode(WidgetItem widgetItem) + { + super(widgetItem); + this.widgetItem = widgetItem; + } + + public WidgetItem getWidgetItem() + { + return widgetItem; + } + + @Override + public String toString() + { + return "I " + widgetItem.getIndex(); + } + +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetTreeNode.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetTreeNode.java new file mode 100644 index 0000000000..7ff7d4262c --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetTreeNode.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017, Adam + * 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 javax.swing.tree.DefaultMutableTreeNode; +import net.runelite.api.widgets.Widget; +import static net.runelite.api.widgets.WidgetInfo.TO_CHILD; +import static net.runelite.api.widgets.WidgetInfo.TO_GROUP; + +class WidgetTreeNode extends DefaultMutableTreeNode +{ + private final String type; + + public WidgetTreeNode(String type, Widget widget) + { + super(widget); + this.type = type; + } + + public Widget getWidget() + { + return (Widget) getUserObject(); + } + + @Override + public String toString() + { + Widget widget = getWidget(); + int id = widget.getId(); + return type + " " + TO_GROUP(id) + "." + TO_CHILD(id); + } +} diff --git a/runescape-api/src/main/java/net/runelite/rs/api/Client.java b/runescape-api/src/main/java/net/runelite/rs/api/Client.java index d04a6afa03..c15caf1450 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/Client.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/Client.java @@ -172,9 +172,6 @@ public interface Client extends GameEngine @Import("viewportWidth") int getViewportWidth(); - @Import("validInterfaces") - boolean[] getValidInterfaces(); - @Import("isResized") boolean isResized(); @@ -234,4 +231,12 @@ public interface Client extends GameEngine @Import(value = "chatCycle", setter = true) void setChatCycle(int value); + + /** + * Get the widget top group. widgets[topGroup] contains widgets with + * parentId -1, which are the widget roots. + * @return + */ + @Import("widgetRoot") + int getWidgetRoot(); }