Merge pull request #638 from Abextm/widget-listeners
Move widget inspector into it's own window
This commit is contained in:
@@ -78,8 +78,19 @@ public interface Widget
|
||||
|
||||
void setSpriteId(int spriteId);
|
||||
|
||||
/**
|
||||
* @return True if this widget or any of it's parents are hidden
|
||||
*/
|
||||
boolean isHidden();
|
||||
|
||||
/**
|
||||
* @return True if this widget, regardless of it's parent's state
|
||||
*/
|
||||
boolean isSelfHidden();
|
||||
|
||||
/**
|
||||
* Sets if this element is hidden as returned by isSelfHidden()
|
||||
*/
|
||||
void setHidden(boolean hidden);
|
||||
|
||||
Point getCanvasLocation();
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.client.plugins.devtools;
|
||||
|
||||
import net.runelite.client.config.ConfigGroup;
|
||||
import net.runelite.client.config.ConfigItem;
|
||||
|
||||
@ConfigGroup(
|
||||
keyName = "devtools",
|
||||
name = "Dev Tools",
|
||||
description = "Configuration for developer tools"
|
||||
)
|
||||
public interface DevToolsConfig
|
||||
{
|
||||
@ConfigItem(
|
||||
keyName = "inspectorAlwaysOnTop",
|
||||
name = "",
|
||||
description = "",
|
||||
hidden = true
|
||||
)
|
||||
default boolean inspectorAlwaysOnTop()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@ConfigItem(
|
||||
keyName = "inspectorAlwaysOnTop",
|
||||
name = "",
|
||||
description = ""
|
||||
)
|
||||
void inspectorAlwaysOnTop(boolean value);
|
||||
}
|
||||
@@ -25,88 +25,46 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.devtools;
|
||||
|
||||
|
||||
import static net.runelite.api.widgets.WidgetInfo.TO_CHILD;
|
||||
import static net.runelite.api.widgets.WidgetInfo.TO_GROUP;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.GridLayout;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Inject;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetItem;
|
||||
import net.runelite.client.ui.PluginPanel;
|
||||
|
||||
@Slf4j
|
||||
public class DevToolsPanel extends PluginPanel
|
||||
{
|
||||
private JButton renderPlayersBtn = new JButton();
|
||||
private JButton renderNpcsBtn = new JButton();
|
||||
private JButton renderGroundItemsBtn = new JButton();
|
||||
private JButton renderGroundObjectsBtn = new JButton();
|
||||
private JButton renderGameObjectsBtn = new JButton();
|
||||
private JButton renderWallsBtn = new JButton();
|
||||
private JButton renderDecorBtn = new JButton();
|
||||
private JButton renderInventoryBtn = new JButton();
|
||||
private JButton renderProjectilesBtn = new JButton();
|
||||
private JPanel boundsDebugPanel = new JPanel();
|
||||
private JButton renderLocationBtn = new JButton();
|
||||
|
||||
private JLabel textLbl = new JLabel();
|
||||
private JLabel textColorLbl = new JLabel();
|
||||
private JLabel nameLbl = new JLabel();
|
||||
private JLabel modelLbl = new JLabel();
|
||||
private JLabel textureLbl = new JLabel();
|
||||
private JLabel typeLbl = new JLabel();
|
||||
private JLabel contentTypeLbl = new JLabel();
|
||||
private JButton editWidgetBtn = new JButton();
|
||||
|
||||
private JPanel borderedWrap = null;
|
||||
private JPanel widgetTreeContainer = null;
|
||||
private WidgetEditPanel editWidgetPanel = null;
|
||||
private boolean editActive = false;
|
||||
|
||||
private final Client client;
|
||||
private final DevToolsPlugin plugin;
|
||||
|
||||
private final SettingsTracker settingsTracker;
|
||||
|
||||
private WidgetInspector widgetInspector;
|
||||
|
||||
@Inject
|
||||
public DevToolsPanel(Client client, DevToolsPlugin plugin)
|
||||
public DevToolsPanel(Client client, DevToolsPlugin plugin, WidgetInspector widgetInspector)
|
||||
{
|
||||
super();
|
||||
this.client = client;
|
||||
this.plugin = plugin;
|
||||
this.widgetInspector = widgetInspector;
|
||||
|
||||
settingsTracker = new SettingsTracker(client);
|
||||
borderedWrap = new JPanel();
|
||||
borderedWrap.setLayout(new BorderLayout(0, 3));
|
||||
borderedWrap.add(createOptionsPanel(), BorderLayout.NORTH);
|
||||
borderedWrap.add(createWidgetTreePanel(), BorderLayout.CENTER);
|
||||
add(borderedWrap);
|
||||
add(createOptionsPanel());
|
||||
}
|
||||
|
||||
private JPanel createOptionsPanel()
|
||||
{
|
||||
JPanel container = new JPanel();
|
||||
container.setLayout(new GridLayout(7, 2, 3, 3));
|
||||
final JPanel container = new JPanel();
|
||||
container.setLayout(new GridLayout(0, 2, 3, 3));
|
||||
|
||||
renderPlayersBtn = new JButton("Players");
|
||||
final JButton renderPlayersBtn = new JButton("Players");
|
||||
renderPlayersBtn.addActionListener(e ->
|
||||
{
|
||||
highlightButton(renderPlayersBtn);
|
||||
@@ -114,7 +72,7 @@ public class DevToolsPanel extends PluginPanel
|
||||
});
|
||||
container.add(renderPlayersBtn);
|
||||
|
||||
renderNpcsBtn = new JButton("NPCs");
|
||||
final JButton renderNpcsBtn = new JButton("NPCs");
|
||||
renderNpcsBtn.addActionListener(e ->
|
||||
{
|
||||
highlightButton(renderNpcsBtn);
|
||||
@@ -122,7 +80,7 @@ public class DevToolsPanel extends PluginPanel
|
||||
});
|
||||
container.add(renderNpcsBtn);
|
||||
|
||||
renderGroundItemsBtn = new JButton("Ground Items");
|
||||
final JButton renderGroundItemsBtn = new JButton("Ground Items");
|
||||
renderGroundItemsBtn.addActionListener(e ->
|
||||
{
|
||||
highlightButton(renderGroundItemsBtn);
|
||||
@@ -130,7 +88,7 @@ public class DevToolsPanel extends PluginPanel
|
||||
});
|
||||
container.add(renderGroundItemsBtn);
|
||||
|
||||
renderGroundObjectsBtn = new JButton("Ground Objects");
|
||||
final JButton renderGroundObjectsBtn = new JButton("Ground Objects");
|
||||
renderGroundObjectsBtn.addActionListener(e ->
|
||||
{
|
||||
highlightButton(renderGroundObjectsBtn);
|
||||
@@ -138,7 +96,7 @@ public class DevToolsPanel extends PluginPanel
|
||||
});
|
||||
container.add(renderGroundObjectsBtn);
|
||||
|
||||
renderGameObjectsBtn = new JButton("Game Objects");
|
||||
final JButton renderGameObjectsBtn = new JButton("Game Objects");
|
||||
renderGameObjectsBtn.addActionListener(e ->
|
||||
{
|
||||
highlightButton(renderGameObjectsBtn);
|
||||
@@ -146,7 +104,7 @@ public class DevToolsPanel extends PluginPanel
|
||||
});
|
||||
container.add(renderGameObjectsBtn);
|
||||
|
||||
renderWallsBtn = new JButton("Walls");
|
||||
final JButton renderWallsBtn = new JButton("Walls");
|
||||
renderWallsBtn.addActionListener(e ->
|
||||
{
|
||||
highlightButton(renderWallsBtn);
|
||||
@@ -154,7 +112,7 @@ public class DevToolsPanel extends PluginPanel
|
||||
});
|
||||
container.add(renderWallsBtn);
|
||||
|
||||
renderDecorBtn = new JButton("Decorations");
|
||||
final JButton renderDecorBtn = new JButton("Decorations");
|
||||
renderDecorBtn.addActionListener(e ->
|
||||
{
|
||||
highlightButton(renderDecorBtn);
|
||||
@@ -162,7 +120,7 @@ public class DevToolsPanel extends PluginPanel
|
||||
});
|
||||
container.add(renderDecorBtn);
|
||||
|
||||
renderInventoryBtn = new JButton("Inventory");
|
||||
final JButton renderInventoryBtn = new JButton("Inventory");
|
||||
renderInventoryBtn.addActionListener(e ->
|
||||
{
|
||||
highlightButton(renderInventoryBtn);
|
||||
@@ -170,7 +128,7 @@ public class DevToolsPanel extends PluginPanel
|
||||
});
|
||||
container.add(renderInventoryBtn);
|
||||
|
||||
renderProjectilesBtn = new JButton("Projectiles");
|
||||
final JButton renderProjectilesBtn = new JButton("Projectiles");
|
||||
renderProjectilesBtn.addActionListener(e ->
|
||||
{
|
||||
highlightButton(renderProjectilesBtn);
|
||||
@@ -178,18 +136,18 @@ public class DevToolsPanel extends PluginPanel
|
||||
});
|
||||
container.add(renderProjectilesBtn);
|
||||
|
||||
boundsDebugPanel = createBoundsDebugMultiButton();
|
||||
final JPanel boundsDebugPanel = createBoundsDebugMultiButton();
|
||||
container.add(boundsDebugPanel);
|
||||
|
||||
JButton settingsSnapshotBtn = new JButton("Get Settings");
|
||||
final JButton settingsSnapshotBtn = new JButton("Get Settings");
|
||||
settingsSnapshotBtn.addActionListener(settingsTracker::snapshot);
|
||||
container.add(settingsSnapshotBtn);
|
||||
|
||||
JButton settingsClearBtn = new JButton("Clear Settings");
|
||||
final JButton settingsClearBtn = new JButton("Clear Settings");
|
||||
settingsClearBtn.addActionListener(settingsTracker::clear);
|
||||
container.add(settingsClearBtn);
|
||||
|
||||
renderLocationBtn = new JButton("Location");
|
||||
final JButton renderLocationBtn = new JButton("Location");
|
||||
renderLocationBtn.addActionListener(e ->
|
||||
{
|
||||
highlightButton(renderLocationBtn);
|
||||
@@ -197,6 +155,15 @@ public class DevToolsPanel extends PluginPanel
|
||||
});
|
||||
container.add(renderLocationBtn);
|
||||
|
||||
final JButton widgetInspectorBtn = new JButton("Inspector");
|
||||
widgetInspectorBtn.addActionListener(e ->
|
||||
{
|
||||
widgetInspector.setVisible(true);
|
||||
widgetInspector.toFront();
|
||||
widgetInspector.repaint();
|
||||
});
|
||||
container.add(widgetInspectorBtn);
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
@@ -267,150 +234,6 @@ public class DevToolsPanel extends PluginPanel
|
||||
return buttonPanel;
|
||||
}
|
||||
|
||||
private void editWidget(Widget w)
|
||||
{
|
||||
if (editWidgetPanel == null)
|
||||
{
|
||||
editWidgetPanel = new WidgetEditPanel(this, w);
|
||||
}
|
||||
else
|
||||
{
|
||||
editWidgetPanel.setWidget(w);
|
||||
}
|
||||
|
||||
widgetTreeContainer.setVisible(false);
|
||||
this.borderedWrap.remove(widgetTreeContainer);
|
||||
this.borderedWrap.add(editWidgetPanel, BorderLayout.CENTER);
|
||||
editWidgetPanel.validate();
|
||||
editWidgetPanel.setVisible(true);
|
||||
editWidgetPanel.repaint();
|
||||
editActive = true;
|
||||
}
|
||||
|
||||
public void cancelEdit()
|
||||
{
|
||||
if (!editActive)
|
||||
return;
|
||||
|
||||
editWidgetPanel.setVisible(false);
|
||||
this.borderedWrap.remove(editWidgetPanel);
|
||||
this.borderedWrap.add(widgetTreeContainer, BorderLayout.CENTER);
|
||||
widgetTreeContainer.revalidate();
|
||||
widgetTreeContainer.setVisible(true);
|
||||
widgetTreeContainer.repaint();
|
||||
}
|
||||
|
||||
private JPanel createWidgetTreePanel()
|
||||
{
|
||||
widgetTreeContainer = new JPanel();
|
||||
widgetTreeContainer.setLayout(new BorderLayout(0, 3));
|
||||
|
||||
JTree tree = new JTree(new DefaultMutableTreeNode());
|
||||
tree.setRootVisible(false);
|
||||
tree.setShowsRootHandles(true);
|
||||
tree.getSelectionModel().addTreeSelectionListener(e ->
|
||||
{
|
||||
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);
|
||||
log.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();
|
||||
log.debug("Set item index to {}", plugin.itemIndex);
|
||||
}
|
||||
});
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(tree);
|
||||
widgetTreeContainer.add(scrollPane, BorderLayout.CENTER);
|
||||
|
||||
JButton refreshWidgetsBtn = new JButton("Refresh Widgets");
|
||||
refreshWidgetsBtn.addActionListener(e ->
|
||||
{
|
||||
new SwingWorker<DefaultMutableTreeNode, Void>()
|
||||
{
|
||||
@Override
|
||||
protected DefaultMutableTreeNode doInBackground() throws Exception
|
||||
{
|
||||
return refreshWidgets();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done()
|
||||
{
|
||||
try
|
||||
{
|
||||
tree.setModel(new DefaultTreeModel(get()));
|
||||
}
|
||||
catch (InterruptedException | ExecutionException ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
});
|
||||
|
||||
JPanel btnContainer = new JPanel();
|
||||
btnContainer.setLayout(new BorderLayout());
|
||||
btnContainer.add(refreshWidgetsBtn);
|
||||
widgetTreeContainer.add(btnContainer, BorderLayout.NORTH);
|
||||
|
||||
JPanel infoContainer = new JPanel();
|
||||
infoContainer.setLayout(new GridLayout(0, 1));
|
||||
|
||||
textLbl = new JLabel("Text: ");
|
||||
textColorLbl = new JLabel("Text Color: ");
|
||||
nameLbl = new JLabel("Name: ");
|
||||
modelLbl = new JLabel("Model ID: ");
|
||||
textureLbl = new JLabel("Texture ID: ");
|
||||
typeLbl = new JLabel("Type: ");
|
||||
contentTypeLbl = new JLabel("Content Type: ");
|
||||
editWidgetBtn = new JButton("Edit");
|
||||
editWidgetBtn.addActionListener(e ->
|
||||
{
|
||||
editWidget(plugin.currentWidget);
|
||||
});
|
||||
|
||||
infoContainer.add(textLbl);
|
||||
infoContainer.add(textColorLbl);
|
||||
infoContainer.add(nameLbl);
|
||||
infoContainer.add(modelLbl);
|
||||
infoContainer.add(textureLbl);
|
||||
infoContainer.add(typeLbl);
|
||||
infoContainer.add(contentTypeLbl);
|
||||
infoContainer.add(editWidgetBtn);
|
||||
|
||||
JScrollPane infoScrollPane = new JScrollPane(infoContainer);
|
||||
infoScrollPane.setBorder(new EmptyBorder(6, 6, 6, 6));
|
||||
widgetTreeContainer.add(infoScrollPane, BorderLayout.SOUTH);
|
||||
|
||||
return widgetTreeContainer;
|
||||
}
|
||||
|
||||
private void setWidgetInfo(Widget widget)
|
||||
{
|
||||
if (widget == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
textLbl.setText("Text: " + widget.getText().trim());
|
||||
textColorLbl.setText("Text Color: " + widget.getTextColor());
|
||||
nameLbl.setText("Name: " + widget.getName().trim());
|
||||
modelLbl.setText("Model ID: " + widget.getModelId());
|
||||
textureLbl.setText("Sprite ID: " + widget.getSpriteId());
|
||||
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)
|
||||
{
|
||||
if (button.getBackground().equals(Color.GREEN))
|
||||
@@ -422,90 +245,4 @@ public class DevToolsPanel extends PluginPanel
|
||||
button.setBackground(Color.GREEN);
|
||||
}
|
||||
}
|
||||
|
||||
private DefaultMutableTreeNode refreshWidgets()
|
||||
{
|
||||
Widget[] rootWidgets = client.getWidgetRoots();
|
||||
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
|
||||
|
||||
plugin.currentWidget = null;
|
||||
plugin.itemIndex = -1;
|
||||
|
||||
for (Widget widget : rootWidgets)
|
||||
{
|
||||
DefaultMutableTreeNode childNode = addWidget("R", widget);
|
||||
if (childNode != null)
|
||||
{
|
||||
root.add(childNode);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
DefaultMutableTreeNode childNode = addWidget("D", component);
|
||||
if (childNode != null)
|
||||
{
|
||||
node.add(childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<WidgetItem> items = widget.getWidgetItems();
|
||||
if (items != null)
|
||||
{
|
||||
for (WidgetItem item : items)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
node.add(new WidgetItemNode(item));
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
package net.runelite.client.plugins.devtools;
|
||||
|
||||
import com.google.inject.Provides;
|
||||
import java.awt.Font;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.Arrays;
|
||||
@@ -31,6 +32,7 @@ import java.util.Collection;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.plugins.Plugin;
|
||||
import net.runelite.client.plugins.PluginDescriptor;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
@@ -70,6 +72,12 @@ public class DevToolsPlugin extends Plugin
|
||||
private Font font;
|
||||
private NavigationButton navButton;
|
||||
|
||||
@Provides
|
||||
DevToolsConfig provideConfig(ConfigManager configManager)
|
||||
{
|
||||
return configManager.getConfig(DevToolsConfig.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void startUp() throws Exception
|
||||
{
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Dreyri <https://github.com/Dreyri>
|
||||
* 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 lombok.extern.slf4j.Slf4j;
|
||||
import javax.swing.JTextField;
|
||||
|
||||
@Slf4j
|
||||
public class NumberField extends JTextField
|
||||
{
|
||||
private int number;
|
||||
|
||||
public NumberField()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
public NumberField(int number)
|
||||
{
|
||||
super(String.valueOf(number));
|
||||
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
public NumberField(String text)
|
||||
{
|
||||
super(text);
|
||||
}
|
||||
|
||||
public int getNumber()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.number = Integer.valueOf(super.getText());
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
log.warn("Not a number!", e);
|
||||
super.setText(String.valueOf(this.number));
|
||||
}
|
||||
|
||||
return this.number;
|
||||
}
|
||||
}
|
||||
@@ -1,290 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Dreyri <https://github.com/Dreyri>
|
||||
* 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.GridBagConstraints;
|
||||
import java.awt.GridBagLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JTextField;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
|
||||
@Slf4j
|
||||
public class WidgetEditPanel extends JPanel
|
||||
{
|
||||
private Widget widget;
|
||||
|
||||
private JLabel nameLbl = new JLabel();
|
||||
private JLabel textLbl = new JLabel();
|
||||
private JLabel typeLbl = new JLabel();
|
||||
private JLabel contentTypeLbl = new JLabel();
|
||||
private JLabel textColorLbl = new JLabel();
|
||||
private JLabel hiddenLbl = new JLabel();
|
||||
private JLabel spriteLbl = new JLabel();
|
||||
private JLabel relativeXLbl = new JLabel();
|
||||
private JLabel relativeYLbl = new JLabel();
|
||||
private JLabel widthLbl = new JLabel();
|
||||
private JLabel heightLbl = new JLabel();
|
||||
|
||||
private JTextField nameTF = new JTextField();
|
||||
private JTextField textTF = new JTextField();
|
||||
private NumberField typeTF = new NumberField();
|
||||
private NumberField contentTypeTF = new NumberField();
|
||||
private NumberField textColorTF = new NumberField();
|
||||
private JCheckBox hiddenCB = new JCheckBox();
|
||||
private NumberField spriteTF = new NumberField();
|
||||
private NumberField relativeXTF = new NumberField();
|
||||
private NumberField relativeYTF = new NumberField();
|
||||
private NumberField widthTF = new NumberField();
|
||||
private NumberField heightTF = new NumberField();
|
||||
|
||||
private JButton cancelBtn = new JButton();
|
||||
private JButton applyBtn = new JButton();
|
||||
|
||||
private final DevToolsPanel owner;
|
||||
|
||||
public WidgetEditPanel(DevToolsPanel panel, Widget w)
|
||||
{
|
||||
this.owner = panel;
|
||||
this.widget = w;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
private void init()
|
||||
{
|
||||
createInputElements();
|
||||
|
||||
this.setLayout(new GridBagLayout());
|
||||
|
||||
errorCheck();
|
||||
createInterfaceElements();
|
||||
setupInterface();
|
||||
}
|
||||
|
||||
private void errorCheck()
|
||||
{
|
||||
if (widget == null)
|
||||
{
|
||||
JLabel errorLabel = new JLabel("Widget could not be loaded!");
|
||||
errorLabel.setForeground(Color.RED);
|
||||
this.add(errorLabel);
|
||||
}
|
||||
}
|
||||
|
||||
public void setWidget(Widget w)
|
||||
{
|
||||
this.removeAll();
|
||||
this.widget = w;
|
||||
init();
|
||||
|
||||
}
|
||||
|
||||
private void createInputElements()
|
||||
{
|
||||
if (widget == null)
|
||||
return;
|
||||
|
||||
nameTF = new JTextField(widget.getName());
|
||||
textTF = new JTextField(widget.getText());
|
||||
typeTF = new NumberField(widget.getType());
|
||||
contentTypeTF = new NumberField(widget.getContentType());
|
||||
textColorTF = new NumberField(widget.getTextColor());
|
||||
hiddenCB = new JCheckBox();
|
||||
spriteTF = new NumberField(widget.getSpriteId());
|
||||
relativeXTF = new NumberField(widget.getRelativeX());
|
||||
relativeYTF = new NumberField(widget.getRelativeY());
|
||||
widthTF = new NumberField(widget.getWidth());
|
||||
heightTF = new NumberField(widget.getHeight());
|
||||
|
||||
hiddenCB.setSelected(widget.isHidden());
|
||||
}
|
||||
|
||||
private void createInterfaceElements()
|
||||
{
|
||||
nameLbl = new JLabel("Name");
|
||||
textLbl = new JLabel("Text");
|
||||
typeLbl = new JLabel("Type");
|
||||
contentTypeLbl = new JLabel("Content type");
|
||||
textColorLbl = new JLabel(String.valueOf("Text color"));
|
||||
hiddenLbl = new JLabel("Hidden");
|
||||
spriteLbl = new JLabel("Sprite");
|
||||
relativeXLbl = new JLabel("Relative X");
|
||||
relativeYLbl = new JLabel("Relative Y");
|
||||
widthLbl = new JLabel("Width");
|
||||
heightLbl = new JLabel("Height");
|
||||
|
||||
cancelBtn = new JButton("Cancel");
|
||||
applyBtn = new JButton("Apply");
|
||||
|
||||
this.cancelBtn.addActionListener(e ->
|
||||
{
|
||||
owner.cancelEdit();
|
||||
});
|
||||
|
||||
this.applyBtn.addActionListener(e ->
|
||||
{
|
||||
applyChanges();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* only change when actual change happened to prevent sending too many change events
|
||||
*/
|
||||
private void applyChanges()
|
||||
{
|
||||
boolean hidden = hiddenCB.isSelected();
|
||||
String name = nameTF.getText();
|
||||
String text = textTF.getText();
|
||||
int type = typeTF.getNumber();
|
||||
int contentType = contentTypeTF.getNumber();
|
||||
int textColor = textColorTF.getNumber();
|
||||
int sprite = spriteTF.getNumber();
|
||||
int relativeX = relativeXTF.getNumber();
|
||||
int relativeY = relativeYTF.getNumber();
|
||||
int width = widthTF.getNumber();
|
||||
int height = heightTF.getNumber();
|
||||
|
||||
if (hidden != widget.isHidden())
|
||||
widget.setHidden(hidden);
|
||||
|
||||
if (!name.equals(widget.getName()))
|
||||
widget.setName(name);
|
||||
|
||||
if (!text.equals(widget.getText()))
|
||||
widget.setText(text);
|
||||
|
||||
if (type != widget.getType())
|
||||
widget.setType(type);
|
||||
|
||||
if (contentType != widget.getContentType())
|
||||
widget.setContentType(contentType);
|
||||
|
||||
if (textColor != widget.getTextColor())
|
||||
widget.setTextColor(textColor);
|
||||
|
||||
if (sprite != widget.getSpriteId())
|
||||
widget.setSpriteId(sprite);
|
||||
|
||||
if (relativeX != widget.getRelativeX())
|
||||
widget.setRelativeX(relativeX);
|
||||
|
||||
if (relativeY != widget.getRelativeY())
|
||||
widget.setRelativeY(relativeY);
|
||||
|
||||
if (width != widget.getWidth())
|
||||
widget.setWidth(width);
|
||||
|
||||
if (height != widget.getHeight())
|
||||
widget.setHeight(height);
|
||||
}
|
||||
|
||||
private void setupInterface()
|
||||
{
|
||||
GridBagConstraints constraints = new GridBagConstraints();
|
||||
|
||||
constraints.fill = GridBagConstraints.HORIZONTAL;
|
||||
constraints.weightx = 0.5;
|
||||
|
||||
constraints.gridwidth = 1;
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 2;
|
||||
this.add(nameLbl, constraints);
|
||||
|
||||
constraints.gridx = 1;
|
||||
this.add(nameTF, constraints);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 3;
|
||||
this.add(textLbl, constraints);
|
||||
constraints.gridx = 1;
|
||||
this.add(textTF, constraints);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 4;
|
||||
this.add(typeLbl, constraints);
|
||||
constraints.gridx = 1;
|
||||
this.add(typeTF, constraints);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 5;
|
||||
this.add(contentTypeLbl, constraints);
|
||||
constraints.gridx = 1;
|
||||
this.add(contentTypeTF, constraints);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 6;
|
||||
this.add(textColorLbl, constraints);
|
||||
constraints.gridx = 1;
|
||||
this.add(textColorTF, constraints);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 7;
|
||||
this.add(hiddenLbl, constraints);
|
||||
constraints.gridx = 1;
|
||||
this.add(hiddenCB, constraints);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 8;
|
||||
this.add(spriteLbl, constraints);
|
||||
constraints.gridx = 1;
|
||||
this.add(spriteTF, constraints);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 9;
|
||||
this.add(relativeXLbl, constraints);
|
||||
constraints.gridx = 1;
|
||||
this.add(relativeXTF, constraints);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 10;
|
||||
this.add(relativeYLbl, constraints);
|
||||
constraints.gridx = 1;
|
||||
this.add(relativeYTF, constraints);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 11;
|
||||
this.add(widthLbl, constraints);
|
||||
constraints.gridx = 1;
|
||||
this.add(widthTF, constraints);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 12;
|
||||
this.add(heightLbl, constraints);
|
||||
constraints.gridx = 1;
|
||||
this.add(heightTF, constraints);
|
||||
|
||||
constraints.gridx = 0;
|
||||
constraints.gridy = 13;
|
||||
this.add(cancelBtn, constraints);
|
||||
|
||||
constraints.gridx = 1;
|
||||
this.add(applyBtn, constraints);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.client.plugins.devtools;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
|
||||
@Slf4j
|
||||
public class WidgetField<T>
|
||||
{
|
||||
@Getter
|
||||
private final String name;
|
||||
|
||||
private final Function<Widget, T> getter;
|
||||
|
||||
private final BiConsumer<Widget, T> setter;
|
||||
|
||||
private final Class<T> type;
|
||||
|
||||
WidgetField(String name, Function<Widget, T> getter)
|
||||
{
|
||||
this(name, getter, null, null);
|
||||
}
|
||||
|
||||
WidgetField(String name, Function<Widget, T> getter, BiConsumer<Widget, T> setter, Class<T> type)
|
||||
{
|
||||
this.name = name;
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
Object getValue(Widget widget)
|
||||
{
|
||||
Object value = getter.apply(widget);
|
||||
// These types are handled by the JTable automatically
|
||||
if (value instanceof Boolean || value instanceof Number || value instanceof String)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return MessageFormatter.format("{}", value).getMessage();
|
||||
}
|
||||
|
||||
void setValue(Widget widget, Object inValue)
|
||||
{
|
||||
Object value = null;
|
||||
if ("null".equals(inValue))
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
if (type.isAssignableFrom(inValue.getClass()))
|
||||
{
|
||||
value = inValue;
|
||||
}
|
||||
else if (type == Boolean.class)
|
||||
{
|
||||
value = Boolean.valueOf((String) inValue);
|
||||
}
|
||||
else if (type == Integer.class)
|
||||
{
|
||||
value = Integer.valueOf((String) inValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.warn("Type {} is not supported for editing", type);
|
||||
}
|
||||
setter.accept(widget, (T) value);
|
||||
}
|
||||
|
||||
boolean isSettable()
|
||||
{
|
||||
return setter != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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.client.plugins.devtools;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
|
||||
public class WidgetInfoTableModel extends AbstractTableModel
|
||||
{
|
||||
private static final int COL_FIELD = 0;
|
||||
private static final int COL_VALUE = 1;
|
||||
|
||||
private static final List<WidgetField> fields = populateWidgetFields();
|
||||
|
||||
private Widget widget = null;
|
||||
|
||||
public void setWidget(Widget w)
|
||||
{
|
||||
this.widget = w;
|
||||
fireTableStructureChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnName(int col)
|
||||
{
|
||||
switch (col)
|
||||
{
|
||||
case COL_FIELD:
|
||||
return "Field";
|
||||
case COL_VALUE:
|
||||
return "Value";
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowCount()
|
||||
{
|
||||
if (widget == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return fields.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValueAt(int rowIndex, int columnIndex)
|
||||
{
|
||||
WidgetField<?> field = fields.get(rowIndex);
|
||||
switch (columnIndex)
|
||||
{
|
||||
case COL_FIELD:
|
||||
return field.getName();
|
||||
case COL_VALUE:
|
||||
return field.getValue(widget);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex)
|
||||
{
|
||||
if (columnIndex == COL_VALUE)
|
||||
{
|
||||
WidgetField<?> field = fields.get(rowIndex);
|
||||
return field.isSettable();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAt(Object value, int rowIndex, int columnIndex)
|
||||
{
|
||||
WidgetField<?> field = fields.get(rowIndex);
|
||||
field.setValue(widget, value);
|
||||
}
|
||||
|
||||
private static List<WidgetField> populateWidgetFields()
|
||||
{
|
||||
List<WidgetField> out = new ArrayList<>();
|
||||
|
||||
out.add(new WidgetField<>("Id", Widget::getId));
|
||||
out.add(new WidgetField<>("Type", Widget::getType, Widget::setType, Integer.class));
|
||||
out.add(new WidgetField<>("ContentType", Widget::getContentType, Widget::setContentType, Integer.class));
|
||||
out.add(new WidgetField<>("ParentId", Widget::getParentId));
|
||||
out.add(new WidgetField<>("SelfHidden", Widget::isSelfHidden, Widget::setHidden, Boolean.class));
|
||||
out.add(new WidgetField<>("Hidden", Widget::isHidden));
|
||||
out.add(new WidgetField<>("Text", Widget::getText, Widget::setText, String.class));
|
||||
out.add(new WidgetField<>("TextColor",
|
||||
w -> Integer.toString(w.getTextColor(), 16),
|
||||
(w, str) -> w.setTextColor(Integer.parseInt(str, 16)),
|
||||
String.class
|
||||
));
|
||||
out.add(new WidgetField<>("Name", w -> w.getName().trim(), Widget::setName, String.class));
|
||||
out.add(new WidgetField<>("ItemId", Widget::getItemId));
|
||||
out.add(new WidgetField<>("ItemQuantity", Widget::getItemQuantity));
|
||||
out.add(new WidgetField<>("ModelId", Widget::getModelId));
|
||||
out.add(new WidgetField<>("SpriteId", Widget::getSpriteId, Widget::setSpriteId, Integer.class));
|
||||
out.add(new WidgetField<>("Width", Widget::getWidth, Widget::setWidth, Integer.class));
|
||||
out.add(new WidgetField<>("Height", Widget::getHeight, Widget::setHeight, Integer.class));
|
||||
out.add(new WidgetField<>("RelativeX", Widget::getRelativeX, Widget::setRelativeX, Integer.class));
|
||||
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<>("OriginalX", Widget::getOriginalX));
|
||||
out.add(new WidgetField<>("OriginalY", Widget::getOriginalY));
|
||||
out.add(new WidgetField<>("PaddingX", Widget::getPaddingX));
|
||||
out.add(new WidgetField<>("PaddingY", Widget::getPaddingY));
|
||||
|
||||
return out;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
/*
|
||||
* 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 com.google.common.eventbus.EventBus;
|
||||
import com.google.common.eventbus.Subscribe;
|
||||
import com.google.inject.Inject;
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JSplitPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.SwingWorker;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.events.ConfigChanged;
|
||||
import net.runelite.api.widgets.Widget;
|
||||
import net.runelite.api.widgets.WidgetItem;
|
||||
import net.runelite.client.ui.ClientUI;
|
||||
|
||||
@Slf4j
|
||||
class WidgetInspector extends JFrame
|
||||
{
|
||||
private final Client client;
|
||||
private final DevToolsPlugin plugin;
|
||||
private final DevToolsConfig config;
|
||||
|
||||
private final JTree widgetTree;
|
||||
private final WidgetInfoTableModel infoTableModel;
|
||||
private final JCheckBox alwaysOnTop;
|
||||
|
||||
@Inject
|
||||
WidgetInspector(DevToolsPlugin plugin, Client client, WidgetInfoTableModel infoTableModel, DevToolsConfig config, EventBus eventBus)
|
||||
{
|
||||
this.plugin = plugin;
|
||||
this.client = client;
|
||||
this.infoTableModel = infoTableModel;
|
||||
this.config = config;
|
||||
|
||||
eventBus.register(this);
|
||||
|
||||
setTitle("RuneLite Widget Inspector");
|
||||
setIconImage(ClientUI.ICON);
|
||||
|
||||
// Reset highlight on close
|
||||
addWindowListener(new WindowAdapter()
|
||||
{
|
||||
@Override
|
||||
public void windowClosing(WindowEvent e)
|
||||
{
|
||||
plugin.currentWidget = null;
|
||||
plugin.itemIndex = -1;
|
||||
}
|
||||
});
|
||||
|
||||
setLayout(new BorderLayout());
|
||||
|
||||
widgetTree = new JTree(new DefaultMutableTreeNode());
|
||||
widgetTree.setRootVisible(false);
|
||||
widgetTree.setShowsRootHandles(true);
|
||||
widgetTree.getSelectionModel().addTreeSelectionListener(e ->
|
||||
{
|
||||
Object selected = widgetTree.getLastSelectedPathComponent();
|
||||
if (selected instanceof WidgetTreeNode)
|
||||
{
|
||||
WidgetTreeNode node = (WidgetTreeNode) selected;
|
||||
Widget widget = node.getWidget();
|
||||
plugin.currentWidget = widget;
|
||||
plugin.itemIndex = widget.getItemId();
|
||||
refreshInfo();
|
||||
log.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();
|
||||
log.debug("Set item index to {}", plugin.itemIndex);
|
||||
}
|
||||
});
|
||||
|
||||
final JScrollPane treeScrollPane = new JScrollPane(widgetTree);
|
||||
treeScrollPane.setPreferredSize(new Dimension(200, 400));
|
||||
|
||||
|
||||
final JTable widgetInfo = new JTable(infoTableModel);
|
||||
|
||||
final JScrollPane infoScrollPane = new JScrollPane(widgetInfo);
|
||||
infoScrollPane.setPreferredSize(new Dimension(400, 400));
|
||||
|
||||
|
||||
final JPanel bottomPanel = new JPanel();
|
||||
add(bottomPanel, BorderLayout.SOUTH);
|
||||
|
||||
final JButton refreshWidgetsBtn = new JButton("Refresh");
|
||||
refreshWidgetsBtn.addActionListener(e -> refreshWidgets());
|
||||
bottomPanel.add(refreshWidgetsBtn);
|
||||
|
||||
alwaysOnTop = new JCheckBox("Always on top");
|
||||
alwaysOnTop.addItemListener(ev -> config.inspectorAlwaysOnTop(alwaysOnTop.isSelected()));
|
||||
onConfigChanged(null);
|
||||
bottomPanel.add(alwaysOnTop);
|
||||
|
||||
|
||||
final JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treeScrollPane, infoScrollPane);
|
||||
add(split, BorderLayout.CENTER);
|
||||
|
||||
pack();
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
private void onConfigChanged(ConfigChanged ev)
|
||||
{
|
||||
boolean onTop = config.inspectorAlwaysOnTop();
|
||||
setAlwaysOnTop(onTop);
|
||||
alwaysOnTop.setSelected(onTop);
|
||||
}
|
||||
|
||||
private void refreshWidgets()
|
||||
{
|
||||
new SwingWorker<DefaultMutableTreeNode, Void>()
|
||||
{
|
||||
@Override
|
||||
protected DefaultMutableTreeNode doInBackground() throws Exception
|
||||
{
|
||||
Widget[] rootWidgets = client.getWidgetRoots();
|
||||
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
|
||||
|
||||
plugin.currentWidget = null;
|
||||
plugin.itemIndex = -1;
|
||||
|
||||
for (Widget widget : rootWidgets)
|
||||
{
|
||||
DefaultMutableTreeNode childNode = addWidget("R", widget);
|
||||
if (childNode != null)
|
||||
{
|
||||
root.add(childNode);
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done()
|
||||
{
|
||||
try
|
||||
{
|
||||
plugin.currentWidget = null;
|
||||
plugin.itemIndex = -1;
|
||||
refreshInfo();
|
||||
widgetTree.setModel(new DefaultTreeModel(get()));
|
||||
}
|
||||
catch (InterruptedException | ExecutionException ex)
|
||||
{
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
DefaultMutableTreeNode childNode = addWidget("D", component);
|
||||
if (childNode != null)
|
||||
{
|
||||
node.add(childNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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<WidgetItem> items = widget.getWidgetItems();
|
||||
if (items != null)
|
||||
{
|
||||
for (WidgetItem item : items)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
node.add(new WidgetItemNode(item));
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
private void refreshInfo()
|
||||
{
|
||||
infoTableModel.setWidget(plugin.currentWidget);
|
||||
}
|
||||
}
|
||||
@@ -75,7 +75,7 @@ import org.pushingpixels.substance.internal.utils.SubstanceTitlePaneUtilities;
|
||||
public class ClientUI extends JFrame
|
||||
{
|
||||
private static final int PANEL_EXPANDED_WIDTH = PluginPanel.PANEL_WIDTH + PluginPanel.SCROLLBAR_WIDTH;
|
||||
private static final BufferedImage ICON;
|
||||
public static final BufferedImage ICON;
|
||||
|
||||
@Getter
|
||||
private TrayIcon trayIcon;
|
||||
|
||||
@@ -143,7 +143,7 @@ public abstract class RSWidgetMixin implements RSWidget
|
||||
return true;
|
||||
}
|
||||
|
||||
return isRSHidden();
|
||||
return isSelfHidden();
|
||||
}
|
||||
|
||||
@Inject
|
||||
|
||||
@@ -118,7 +118,8 @@ public interface RSWidget extends Widget
|
||||
void setHeight(int height);
|
||||
|
||||
@Import("isHidden")
|
||||
boolean isRSHidden();
|
||||
@Override
|
||||
boolean isSelfHidden();
|
||||
|
||||
@Import("isHidden")
|
||||
void setHidden(boolean hidden);
|
||||
|
||||
Reference in New Issue
Block a user