From 6b278d48a5aa3e2d0737e47e876f87ece2f5196c Mon Sep 17 00:00:00 2001 From: Max Weber Date: Fri, 15 Jun 2018 06:09:57 -0600 Subject: [PATCH] Add API to create new widgets --- .../main/java/net/runelite/api/ScriptID.java | 8 ++ .../java/net/runelite/api/WidgetType.java | 30 +++++++ .../java/net/runelite/api/widgets/Widget.java | 86 +++++++++++++++++++ .../devtools/WidgetInfoTableModel.java | 8 +- .../net/runelite/mixins/RSWidgetMixin.java | 58 +++++++++++++ runelite-scripts/scripts/null.rs2asm | 37 ++++++++ .../java/net/runelite/rs/api/RSClient.java | 9 ++ .../java/net/runelite/rs/api/RSWidget.java | 51 +++++++++++ 8 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 runelite-api/src/main/java/net/runelite/api/WidgetType.java create mode 100644 runelite-scripts/scripts/null.rs2asm diff --git a/runelite-api/src/main/java/net/runelite/api/ScriptID.java b/runelite-api/src/main/java/net/runelite/api/ScriptID.java index 08b48cdc0d..ce33b5f98e 100644 --- a/runelite-api/src/main/java/net/runelite/api/ScriptID.java +++ b/runelite-api/src/main/java/net/runelite/api/ScriptID.java @@ -52,4 +52,12 @@ public final class ScriptID * */ public static final int RUNELITE_CHATBOX_INPUT_INIT = 10001; + + /** + * Does nothing + * + * This is used to eat events when you want a menu action attached to it + * because you need an op listener attached to it for it to work + */ + public static final int NULL = 10003; } diff --git a/runelite-api/src/main/java/net/runelite/api/WidgetType.java b/runelite-api/src/main/java/net/runelite/api/WidgetType.java new file mode 100644 index 0000000000..67cb44c590 --- /dev/null +++ b/runelite-api/src/main/java/net/runelite/api/WidgetType.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2018 Abex + * 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.api; + +public final class WidgetType +{ + public static final int GRAPHIC = 5; +} 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 0b296d3e61..15ead6cad1 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 @@ -267,6 +267,11 @@ public interface Widget */ void setHidden(boolean hidden); + /** + * The index of this widget in it's parent's children array + */ + int getIndex(); + /** * Gets the location the widget is being drawn on the canvas. *

@@ -354,14 +359,46 @@ public interface Widget */ boolean contains(Point point); + /** + * Gets the amount of pixels the widget is scrolled in the X axis + */ int getScrollX(); + /** + * Sets the amount of pixels the widget is scrolled in the X axis + */ void setScrollX(int scrollX); + /** + * Gets the amount of pixels the widget is scrolled in the Y axis + */ int getScrollY(); + /** + * sets the amount of pixels the widget is scrolled in the Y axis + */ void setScrollY(int scrollY); + /** + * Gets the size of the widget's viewport in the X axis + */ + int getScrollWidth(); + + /** + * Sets the size of the widget's viewport in the X axis + */ + void setScrollWidth(int width); + + /** + * Gets the size of the widget's viewport in the Y axis + */ + int getScrollHeight(); + + /** + * Sets the size of the widget's viewport in the Y axis + */ + void setScrollHeight(int height); + /** * Gets the original x-axis coordinate. * @@ -452,4 +489,53 @@ public interface Widget * @return the actions */ String[] getActions(); + + /** + * Creates a dynamic widget child + * + * @param index the index of the new widget in the children list or -1 to append to the back + * @param type the type of the widget + */ + Widget createChild(int index, int type); + + /** + * Creates a menu action on the widget + * + * @param index The index of the menu + * @param action The string to be displayed next to the widget's name in the context menu + */ + void setAction(int index, String action); + + /** + * Sets a script to be ran when the a menu action is clicked. + * hasListener must be true for this to take effect + * + * @param args A ScriptID, then the args for the script + */ + void setOnOpListener(Object ...args); + + /** + * If this widget has any listeners on it + */ + boolean hasListener(); + + /** + * Sets if the widget has any listeners. This should be called whenever a setXListener function is called + */ + void setHasListener(boolean hasListener); + + /** + * This is true if the widget is from an if3 interface, or is dynamically created + */ + boolean isIf3(); + + /** + * Recomputes this widget's x/y/w/h, excluding scroll + */ + void revalidate(); + + /** + * Recomputes this widget's group's x/y/w/h including scroll + */ + void revalidateScroll(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java index 0c26c71dcf..79a261dfff 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/devtools/WidgetInfoTableModel.java @@ -134,12 +134,16 @@ public class WidgetInfoTableModel extends AbstractTableModel out.add(new WidgetField<>("RelativeY", Widget::getRelativeY, Widget::setRelativeY, Integer.class)); out.add(new WidgetField<>("CanvasLocation", Widget::getCanvasLocation)); out.add(new WidgetField<>("Bounds", Widget::getBounds)); - out.add(new WidgetField<>("ScrollX", Widget::getScrollX)); - out.add(new WidgetField<>("ScrollY", Widget::getScrollY)); + out.add(new WidgetField<>("ScrollX", Widget::getScrollX, Widget::setScrollX, Integer.class)); + out.add(new WidgetField<>("ScrollY", Widget::getScrollY, Widget::setScrollY, Integer.class)); + out.add(new WidgetField<>("ScrollWidth", Widget::getScrollWidth, Widget::setScrollWidth, Integer.class)); + out.add(new WidgetField<>("ScrollHeight", Widget::getScrollHeight, Widget::setScrollHeight, Integer.class)); out.add(new WidgetField<>("OriginalX", Widget::getOriginalX)); out.add(new WidgetField<>("OriginalY", Widget::getOriginalY)); out.add(new WidgetField<>("PaddingX", Widget::getPaddingX)); out.add(new WidgetField<>("PaddingY", Widget::getPaddingY)); + out.add(new WidgetField<>("IsIf3", Widget::isIf3)); + out.add(new WidgetField<>("HasListener", Widget::hasListener, Widget::setHasListener, Boolean.class)); return out; } diff --git a/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java b/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java index a4d2dc8cc8..3b197f10ed 100644 --- a/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java +++ b/runelite-mixins/src/main/java/net/runelite/mixins/RSWidgetMixin.java @@ -477,4 +477,62 @@ public abstract class RSWidgetMixin implements RSWidget WidgetPositioned widgetPositioned = new WidgetPositioned(); client.getCallbacks().postDeferred(widgetPositioned); } + + @Inject + @Override + public Widget createChild(int index, int type) + { + RSWidget w = client.createWidget(); + w.setType(type); + w.setParentId(getId()); + w.setId(getId()); + w.setIsIf3(true); + + RSWidget[] siblings = getChildren(); + + if (index < 0) + { + if (siblings == null) + { + index = 0; + } + else + { + index = siblings.length; + } + } + + if (siblings == null) + { + siblings = new RSWidget[index + 1]; + setChildren(siblings); + } + else if (siblings.length <= index) + { + RSWidget[] newSiblings = new RSWidget[index + 1]; + System.arraycopy(siblings, 0, newSiblings, 0, siblings.length); + siblings = newSiblings; + setChildren(siblings); + } + + siblings[index] = w; + w.setIndex(index); + + return w; + } + + @Inject + @Override + public void revalidate() + { + client.revalidateWidget(this); + } + + @Inject + @Override + public void revalidateScroll() + { + client.revalidateWidget(this); + client.revalidateWidgetScroll(client.getWidgets()[TO_GROUP(this.getId())], this, false); + } } diff --git a/runelite-scripts/scripts/null.rs2asm b/runelite-scripts/scripts/null.rs2asm new file mode 100644 index 0000000000..81afec5354 --- /dev/null +++ b/runelite-scripts/scripts/null.rs2asm @@ -0,0 +1,37 @@ +; Copyright (c) 2018 Abex +; 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. + +;; +; Does nothing +; +; This is used to eat events when you want a menu action attached to it +; because you need an op listener attached to it for it to work +;; + +.id 10003 +.int_stack_count 0 +.string_stack_count 0 +.int_var_count 0 +.string_var_count 0 + +return diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java index 5c64dd89ec..9748ce4ec4 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSClient.java @@ -648,4 +648,13 @@ public interface RSClient extends RSGameEngine, Client RSItem getLastItemDespawn(); void setLastItemDespawn(RSItem lastItemDespawn); + + @Construct + RSWidget createWidget(); + + @Import("revalidateWidget") + void revalidateWidget(Widget w); + + @Import("revalidateWidgetScroll") + void revalidateWidgetScroll(Widget[] group, Widget w, boolean postEvent); } diff --git a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java index 53bfa46cfd..36d9ed69fe 100644 --- a/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java +++ b/runescape-api/src/main/java/net/runelite/rs/api/RSWidget.java @@ -36,6 +36,9 @@ public interface RSWidget extends Widget @Override RSWidget[] getChildren(); + @Import("children") + void setChildren(RSWidget[] children); + @Import("id") @Override int getId(); @@ -46,9 +49,15 @@ public interface RSWidget extends Widget void setRenderY(int y); + @Import("id") + void setId(int id); + @Import("parentId") int getRSParentId(); + @Import("parentId") + void setParentId(int id); + @Import("clickMask") int getClickMask(); @@ -141,6 +150,9 @@ public interface RSWidget extends Widget @Import("index") int getIndex(); + @Import("index") + void setIndex(int index); + @Import("rotationX") int getRotationX(); @@ -182,6 +194,22 @@ public interface RSWidget extends Widget @Override void setScrollY(int scrollY); + @Import("scrollWidth") + @Override + int getScrollWidth(); + + @Import("scrollWidth") + @Override + void setScrollWidth(int width); + + @Import("scrollHeight") + @Override + int getScrollHeight(); + + @Import("scrollHeight") + @Override + void setScrollHeight(int height); + @Import("spriteId") @Override int getSpriteId(); @@ -250,4 +278,27 @@ public interface RSWidget extends Widget void setPaddingY(int paddingY); void broadcastHidden(boolean hidden); + + @Import("onOpListener") + @Override + void setOnOpListener(Object ...args); + + @Import("setAction") + @Override + void setAction(int idx, String action); + + @Import("isIf3") + @Override + boolean isIf3(); + + @Import("isIf3") + void setIsIf3(boolean isIf3); + + @Import("hasListener") + @Override + boolean hasListener(); + + @Import("hasListener") + @Override + void setHasListener(boolean hasListener); }