Add ChatboxPanelManager to allow for more advanced chatbox inputs

This commit is contained in:
Max Weber
2018-10-08 01:36:29 -06:00
parent 33dec14a38
commit 2434557e1a
24 changed files with 1831 additions and 25 deletions

View File

@@ -0,0 +1,57 @@
/*
* 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;
/**
* IDs of fonts in the cache
*/
public final class FontID
{
public static final int PLAIN_11 = 494;
public static final int PLAIN_12 = 495;
public static final int BOLD_12 = 496;
public static final int QUILL_8 = 497;
public static final int QUILL_MEDIUM = 645;
public static final int QUILL_CAPS_LARGE = 646;
public static final int FAIRY_SMALL = 647;
public static final int FAIRY_LARGE = 648;
public static final int BARBARIAN = 764;
public static final int SUROK = 819;
public static final int VERDANA_11 = 1442;
public static final int VERDANA_11_BOLD = 1443;
public static final int TAHOMA_11 = 1444;
public static final int VERDANA_13 = 1445;
public static final int VERDANA_13_BOLD = 1446;
public static final int VERDANA_15 = 1447;
}

View File

@@ -0,0 +1,35 @@
/*
* 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;
/**
* A bitmap Font in Jagex's format
*/
public interface FontTypeFace
{
int getTextWidth(String text);
int getBaseline();
}

View File

@@ -56,10 +56,16 @@ public final class ScriptID
* Closes the chatbox input
* <ul>
* <li> int (boolean) Clear the current text </li>
* <li> int (boolean) Unknown; set to 1 </li>
* <li> int (boolean) Restore to chat view </li>
* </ul>
*/
public static final int CLOSE_CHATBOX_INPUT = 299;
public static final int RESET_CHATBOX_INPUT = 299;
/**
* Readies the chatbox panel for things like the chatbox input
* Inverse of RESET_CHATBOX_INPUT
*/
public static final int CLEAR_CHATBOX_PANEL = 677;
/**
* Updates the Diary/Quest interface's scrollbar

View File

@@ -35,6 +35,7 @@ import net.runelite.api.VarClientInt;
@RequiredArgsConstructor
public enum InputType
{
RUNELITE_CHATBOX_PANEL(-3),
RUNELITE(-2),
NONE(0),
SEARCH(11);

View File

@@ -26,6 +26,7 @@ package net.runelite.api.widgets;
import java.awt.Rectangle;
import java.util.Collection;
import net.runelite.api.FontTypeFace;
import net.runelite.api.Point;
/**
@@ -201,13 +202,22 @@ public interface Widget
int getTextColor();
/**
* Sets the RGB color of the displayed text.
* Sets the RGB color of the displayed text or rectangle.
*
* @param textColor the new text color
* @see java.awt.Color#getRGB()
*/
void setTextColor(int textColor);
/**
* Sets the opacity of the rectangle
*/
int getOpacity();
/**
* Gets the opacity of the rectangle
*/
void setOpacity(int opacity);
/**
* Gets the name of the widget.
* <p>
@@ -489,6 +499,11 @@ public interface Widget
*/
Widget createChild(int index, int type);
/**
* Removes all of this widget's dynamic children
*/
void deleteAllChildren();
/**
* Creates a menu action on the widget
*
@@ -505,6 +520,41 @@ public interface Widget
*/
void setOnOpListener(Object... args);
/**
* Sets a script to be ran when the dialog is canceled
*
* @param args A ScriptID, then the args for the script
*/
void setOnDialogAbortListener(Object... args);
/**
* Sets a script to be ran on key input
*
* @param args A ScriptID, then the args for the script
*/
void setOnKeyListener(Object... args);
/**
* Sets a script to be ran when the mouse enters the widget bounds
*
* @param args A ScriptID, then the args for the script
*/
void setOnMouseOverListener(Object... args);
/**
* Sets a script to be ran when the mouse leaves the widget bounds
*
* @param args A ScriptID, then the args for the script
*/
void setOnMouseLeaveListener(Object... args);
/**
* Sets a script to be ran every frame
*
* @param args A ScriptID, then the args for the script
*/
void setOnTimerListener(Object... args);
/**
* If this widget has any listeners on it
*/
@@ -602,4 +652,103 @@ public interface Widget
* Sets the widget {@link net.runelite.api.widgets.ItemQuantityMode}
*/
void setItemQuantityMode(int itemQuantityMode);
/**
* Gets the mode that the X position is calculated from the original X position
*
* @see WidgetPositionMode
*/
int getXPositionMode();
/**
* Sets the mode that the X position is calculated from the original X position
*
* @see WidgetPositionMode
*/
void setXPositionMode(int xpm);
/**
* Gets the mode that the Y position is calculated from the original Y position
*
* @see WidgetPositionMode
*/
int getYPositionMode();
/**
* Sets the mode that the Y position is calculated from the original Y position
*
* @see WidgetPositionMode
*/
void setYPositionMode(int ypm);
/**
* Gets the X axis text position mode
*
* @see WidgetTextAlignment
*/
int getXTextAlignment();
/**
* Sets the X axis text position mode
*
* @see WidgetTextAlignment
*/
void setXTextAlignment(int xta);
/**
* Gets the Y axis text position mode
*
* @see WidgetTextAlignment
*/
int getYTextAlignment();
/**
* Sets the Y axis text position mode
*
* @see WidgetTextAlignment
*/
void setYTextAlignment(int yta);
/**
* Gets the mode controlling widget width
*
* @see WidgetSizeMode
*/
int getWidthMode();
/**
* Sets the mode controlling widget width
*
* @see WidgetSizeMode
*/
void setWidthMode(int widthMode);
/**
* Gets the mode controlling widget width
*
* @see WidgetSizeMode
*/
int getHeightMode();
/**
* Sets the mode controlling widget width
*
* @see WidgetSizeMode
*/
void setHeightMode(int heightMode);
/**
* Gets the font that this widget uses
*/
FontTypeFace getFont();
/**
* Gets if the rectangle is filled or just stroked
*/
boolean isFilled();
/**
* Sets if the rectangle is filled or just stroked
*/
void setFilled(boolean filled);
}

View File

@@ -410,12 +410,15 @@ public class WidgetID
static class Chatbox
{
static final int CHATBOX_PARENT = 0;
static final int CHATBOX_BUTTONS = 1;
static final int CHATBOX_REPORT_TEXT = 36;
static final int CHATBOX_FRAME = 37;
static final int CHATBOX_MESSAGES = 55;
static final int CHATBOX_INPUT = 57;
static final int PARENT = 0;
static final int BUTTONS = 1;
static final int REPORT_TEXT = 36;
static final int FRAME = 37;
static final int CONTAINER = 40;
static final int TITLE = 44;
static final int FULL_INPUT = 45;
static final int MESSAGES = 55;
static final int INPUT = 57;
}
static class Prayer

View File

@@ -322,12 +322,15 @@ public enum WidgetInfo
SLAYER_REWARDS_TOPBAR(WidgetID.SLAYER_REWARDS_GROUP_ID, WidgetID.SlayerRewards.TOP_BAR),
CHATBOX_PARENT(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.CHATBOX_PARENT),
CHATBOX(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.CHATBOX_FRAME),
CHATBOX_MESSAGES(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.CHATBOX_MESSAGES),
CHATBOX_BUTTONS(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.CHATBOX_BUTTONS),
CHATBOX_REPORT_TEXT(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.CHATBOX_REPORT_TEXT),
CHATBOX_INPUT(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.CHATBOX_INPUT),
CHATBOX_PARENT(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.PARENT),
CHATBOX(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.FRAME),
CHATBOX_MESSAGES(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.MESSAGES),
CHATBOX_BUTTONS(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.BUTTONS),
CHATBOX_TITLE(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.TITLE),
CHATBOX_FULL_INPUT(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.FULL_INPUT),
CHATBOX_CONTAINER(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.CONTAINER),
CHATBOX_REPORT_TEXT(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.REPORT_TEXT),
CHATBOX_INPUT(WidgetID.CHATBOX_GROUP_ID, WidgetID.Chatbox.INPUT),
BA_HEAL_WAVE_TEXT(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.CURRENT_WAVE),
BA_HEAL_CALL_TEXT(WidgetID.BA_HEALER_GROUP_ID, WidgetID.BarbarianAssault.TO_CALL),

View File

@@ -0,0 +1,39 @@
/*
* 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.widgets;
public final class WidgetPositionMode
{
public static final int ABSOLUTE_LEFT = 0;
public static final int ABSOLUTE_TOP = 0;
public static final int ABSOLUTE_CENTER = 1;
public static final int ABSOLUTE_RIGHT = 2;
public static final int ABSOLUTE_BOTTOM = 2;
public static final int LEFT_16384THS = 3;
public static final int TOP_16384THS = 3;
public static final int CENTER_16384THS = 4;
public static final int RIGHT_16384THS = 5;
public static final int BOTTOM_16384THS = 5;
}

View File

@@ -0,0 +1,43 @@
/*
* 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.widgets;
public final class WidgetSizeMode
{
/**
* dim = originalDim
*/
public static final int ABSOLUTE = 0;
/**
* dim = parentDim - originalDim
*/
public static final int MINUS = 1;
/**
* dim = parentDim * (originalDim / 16384)
*/
public static final int ABSOLUTE_16384THS = 2;
}

View File

@@ -0,0 +1,34 @@
/*
* 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.widgets;
public final class WidgetTextAlignment
{
public static final int LEFT = 0;
public static final int TOP = 0;
public static final int CENTER = 1;
public static final int RIGHT = 2;
public static final int BOTTOM = 2;
}

View File

@@ -53,6 +53,7 @@ import net.runelite.client.discord.DiscordService;
import net.runelite.client.game.ClanManager;
import net.runelite.client.game.ItemManager;
import net.runelite.client.game.LootManager;
import net.runelite.client.game.chatbox.ChatboxPanelManager;
import net.runelite.client.menus.MenuManager;
import net.runelite.client.plugins.PluginManager;
import net.runelite.client.rs.ClientUpdateCheckMode;
@@ -141,6 +142,9 @@ public class RuneLite
@Inject
private Provider<LootManager> lootManager;
@Inject
private Provider<ChatboxPanelManager> chatboxPanelManager;
@Inject
@Nullable
private Client client;
@@ -278,6 +282,7 @@ public class RuneLite
eventBus.register(chatMessageManager.get());
eventBus.register(commandManager.get());
eventBus.register(lootManager.get());
eventBus.register(chatboxPanelManager.get());
// Add core overlays
WidgetOverlay.createOverlays(client).forEach(overlayManager::add);

View File

@@ -98,7 +98,7 @@ public class ChatboxInputManager
}
this.open = false;
clientThread.invoke(() -> client.runScript(
ScriptID.CLOSE_CHATBOX_INPUT,
ScriptID.RESET_CHATBOX_INPUT,
1,
1
));

View File

@@ -0,0 +1,39 @@
/*
* 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.game.chatbox;
/**
* A modal input that lives in the chatbox panel.
*/
public abstract class ChatboxInput
{
protected void open()
{
}
protected void close()
{
}
}

View File

@@ -0,0 +1,177 @@
/*
* 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.game.chatbox;
import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.ScriptID;
import net.runelite.api.VarClientInt;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.vars.InputType;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.KeyManager;
import net.runelite.client.input.MouseListener;
import net.runelite.client.input.MouseManager;
import net.runelite.client.input.MouseWheelListener;
@Singleton
@Slf4j
public class ChatboxPanelManager
{
private final Client client;
private final ClientThread clientThread;
private final EventBus eventBus;
private final KeyManager keyManager;
private final MouseManager mouseManager;
private final Provider<ChatboxTextMenuInput> chatboxTextMenuInputProvider;
private final Provider<ChatboxTextInput> chatboxTextInputProvider;
@Getter
private ChatboxInput currentInput = null;
@Inject
private ChatboxPanelManager(EventBus eventBus, Client client, ClientThread clientThread,
KeyManager keyManager, MouseManager mouseManager,
Provider<ChatboxTextMenuInput> chatboxTextMenuInputProvider, Provider<ChatboxTextInput> chatboxTextInputProvider)
{
this.client = client;
this.clientThread = clientThread;
this.eventBus = eventBus;
this.keyManager = keyManager;
this.mouseManager = mouseManager;
this.chatboxTextMenuInputProvider = chatboxTextMenuInputProvider;
this.chatboxTextInputProvider = chatboxTextInputProvider;
}
public void close()
{
clientThread.invokeLater(this::unsafeCloseInput);
}
private void unsafeCloseInput()
{
client.runScript(
ScriptID.RESET_CHATBOX_INPUT,
0,
1
);
}
private void unsafeOpenInput(ChatboxInput input)
{
client.runScript(ScriptID.CLEAR_CHATBOX_PANEL);
eventBus.register(input);
if (input instanceof KeyListener)
{
keyManager.registerKeyListener((KeyListener) input);
}
if (input instanceof MouseListener)
{
mouseManager.registerMouseListener((MouseListener) input);
}
if (input instanceof MouseWheelListener)
{
mouseManager.registerMouseWheelListener((MouseWheelListener) input);
}
currentInput = input;
client.setVar(VarClientInt.INPUT_TYPE, InputType.RUNELITE_CHATBOX_PANEL.getType());
client.getWidget(WidgetInfo.CHATBOX_TITLE).setHidden(true);
client.getWidget(WidgetInfo.CHATBOX_FULL_INPUT).setHidden(true);
Widget c = getContainerWidget();
c.deleteAllChildren();
c.setOnDialogAbortListener((JavaScriptCallback) ev -> this.unsafeCloseInput());
input.open();
}
public void openInput(ChatboxInput input)
{
clientThread.invokeLater(() -> unsafeOpenInput(input));
}
public ChatboxTextMenuInput openTextMenuInput(String title)
{
return chatboxTextMenuInputProvider.get()
.title(title);
}
public ChatboxTextInput openTextInput(String prompt)
{
return chatboxTextInputProvider.get()
.prompt(prompt);
}
@Subscribe
public void onScriptCallbackEvent(ScriptCallbackEvent ev)
{
if (currentInput != null && "resetChatboxInput".equals(ev.getEventName()))
{
try
{
currentInput.close();
}
catch (Exception e)
{
log.warn("Exception closing {}", currentInput.getClass(), e);
}
eventBus.unregister(currentInput);
if (currentInput instanceof KeyListener)
{
keyManager.unregisterKeyListener((KeyListener) currentInput);
}
if (currentInput instanceof MouseListener)
{
mouseManager.unregisterMouseListener((MouseListener) currentInput);
}
if (currentInput instanceof MouseWheelListener)
{
mouseManager.unregisterMouseWheelListener((MouseWheelListener) currentInput);
}
currentInput = null;
}
}
public Widget getContainerWidget()
{
return client.getWidget(WidgetInfo.CHATBOX_CONTAINER);
}
}

View File

@@ -0,0 +1,666 @@
/*
* 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.game.chatbox;
import com.google.inject.Inject;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.function.Consumer;
import java.util.function.IntPredicate;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
import javax.swing.SwingUtilities;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.FontTypeFace;
import net.runelite.api.FontID;
import net.runelite.api.WidgetType;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetPositionMode;
import net.runelite.api.widgets.WidgetSizeMode;
import net.runelite.api.widgets.WidgetTextAlignment;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.input.KeyListener;
import net.runelite.client.input.MouseListener;
@Slf4j
public class ChatboxTextInput extends ChatboxInput implements KeyListener, MouseListener
{
private static final int CURSOR_FLASH_RATE_MILLIS = 1000;
private final ChatboxPanelManager chatboxPanelManager;
private final ClientThread clientThread;
private static IntPredicate getDefaultCharValidator()
{
return i -> i >= 32 && i < 127;
}
@Getter
private String prompt;
private StringBuffer value = new StringBuffer();
@Getter
private int cursor = 0;
@Getter
private int cursorEnd = 0;
private int selectionStart = -1;
private int selectionEnd = -1;
@Getter
private IntPredicate charValidator = getDefaultCharValidator();
@Getter
private Runnable onClose = null;
@Getter
private Consumer<String> onDone = null;
@Getter
private Consumer<String> onChanged = null;
@Getter
private int fontID = FontID.QUILL_8;
// This is a lambda so I can have atomic updates for it's captures
private ToIntFunction<MouseEvent> getCharOffset = null;
private Predicate<MouseEvent> isInBounds = null;
private boolean built = false;
@Inject
protected ChatboxTextInput(ChatboxPanelManager chatboxPanelManager, ClientThread clientThread)
{
this.chatboxPanelManager = chatboxPanelManager;
this.clientThread = clientThread;
}
public ChatboxTextInput prompt(String prompt)
{
this.prompt = prompt;
if (built)
{
clientThread.invoke(this::update);
}
return this;
}
public ChatboxTextInput value(String value)
{
this.value = new StringBuffer(value);
if (built)
{
clientThread.invoke(this::update);
}
return this;
}
public ChatboxTextInput cursorAt(int index)
{
return cursorAt(index, index);
}
public ChatboxTextInput cursorAt(int indexA, int indexB)
{
if (indexA < 0)
{
indexA = 0;
}
if (indexB < 0)
{
indexB = 0;
}
if (indexA > value.length())
{
indexA = value.length();
}
if (indexB > value.length())
{
indexB = value.length();
}
int start = indexA;
int end = indexB;
if (start > end)
{
int v = start;
start = end;
end = v;
}
this.cursor = start;
this.cursorEnd = end;
if (built)
{
clientThread.invoke(this::update);
}
return this;
}
public String getValue()
{
return value.toString();
}
public ChatboxTextInput charValidator(IntPredicate val)
{
if (val == null)
{
val = getDefaultCharValidator();
}
this.charValidator = val;
return this;
}
public ChatboxTextInput onClose(Runnable onClose)
{
this.onClose = onClose;
return this;
}
public ChatboxTextInput onDone(Consumer<String> onDone)
{
this.onDone = onDone;
return this;
}
public ChatboxTextInput onChanged(Consumer<String> onChanged)
{
this.onChanged = onChanged;
return this;
}
public ChatboxTextInput fontID(int fontID)
{
this.fontID = fontID;
return this;
}
protected void update()
{
this.built = true;
Widget container = chatboxPanelManager.getContainerWidget();
container.deleteAllChildren();
Widget promptWidget = container.createChild(-1, WidgetType.TEXT);
promptWidget.setText(this.prompt);
promptWidget.setTextColor(0x800000);
promptWidget.setFontId(fontID);
promptWidget.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
promptWidget.setOriginalX(0);
promptWidget.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
promptWidget.setOriginalY(8);
promptWidget.setOriginalHeight(24);
promptWidget.setXTextAlignment(WidgetTextAlignment.CENTER);
promptWidget.setYTextAlignment(WidgetTextAlignment.CENTER);
promptWidget.setWidthMode(WidgetSizeMode.MINUS);
promptWidget.revalidate();
buildEdit(0, 50, container.getWidth(), 0);
}
protected void buildEdit(int x, int y, int w, int h)
{
Widget container = chatboxPanelManager.getContainerWidget();
String lt = value.substring(0, this.cursor);
String mt = value.substring(this.cursor, this.cursorEnd);
String rt = value.substring(this.cursorEnd);
Widget leftText = container.createChild(-1, WidgetType.TEXT);
Widget cursor = container.createChild(-1, WidgetType.RECTANGLE);
Widget middleText = container.createChild(-1, WidgetType.TEXT);
Widget rightText = container.createChild(-1, WidgetType.TEXT);
leftText.setFontId(fontID);
FontTypeFace font = leftText.getFont();
if (h <= 0)
{
h = font.getBaseline();
}
int ltw = font.getTextWidth(lt);
int mtw = font.getTextWidth(mt);
int rtw = font.getTextWidth(rt);
int fullWidth = ltw + mtw + rtw;
int ox = x;
if (w > 0)
{
x += (w - fullWidth) / 2;
}
int ltx = x;
int mtx = ltx + ltw;
int rtx = mtx + mtw;
leftText.setText(lt);
leftText.setOriginalX(ltx);
leftText.setOriginalY(y);
leftText.setOriginalWidth(ltw);
leftText.setOriginalHeight(h);
leftText.revalidate();
if (mt.length() > 0)
{
cursor.setTextColor(0x113399);
}
else
{
cursor.setTextColor(0xFFFFFF);
cursor.setOnTimerListener((JavaScriptCallback) ev ->
{
boolean on = System.currentTimeMillis() % CURSOR_FLASH_RATE_MILLIS > (CURSOR_FLASH_RATE_MILLIS / 2);
cursor.setOpacity(on ? 255 : 0);
});
}
cursor.setFilled(true);
cursor.setOriginalX(mtx - 1);
cursor.setOriginalY(y);
cursor.setOriginalWidth(2 + mtw);
cursor.setOriginalHeight(h);
cursor.revalidate();
middleText.setText(mt);
middleText.setFontId(fontID);
middleText.setOriginalX(mtx);
middleText.setOriginalY(y);
middleText.setOriginalWidth(mtw);
middleText.setOriginalHeight(h);
middleText.setTextColor(0xFFFFFF);
middleText.revalidate();
rightText.setText(rt);
rightText.setFontId(fontID);
rightText.setOriginalX(rtx);
rightText.setOriginalY(y);
rightText.setOriginalWidth(rtw);
rightText.setOriginalHeight(h);
rightText.revalidate();
net.runelite.api.Point ccl = container.getCanvasLocation();
int canvasX = ltx + ccl.getX();
Rectangle bounds = new Rectangle(ccl.getX() + ox, ccl.getY() + y, w > 0 ? w : fullWidth, h);
String tsValue = value.toString();
isInBounds = ev -> bounds.contains(ev.getPoint());
getCharOffset = ev ->
{
int cx = ev.getX() - canvasX;
int charIndex = (tsValue.length() * cx) / fullWidth;
// `i` is used to track max execution time incase there is a font with ligature width data that causes this to fail
for (int i = tsValue.length(); i >= 0 && charIndex >= 0 && charIndex <= tsValue.length(); i--)
{
int lcx = charIndex > 0 ? font.getTextWidth(tsValue.substring(0, charIndex - 1)) : 0;
int mcx = font.getTextWidth(tsValue.substring(0, charIndex));
int rcx = charIndex + 1 <= tsValue.length() ? font.getTextWidth(tsValue.substring(0, charIndex + 1)) : mcx;
int leftBound = (lcx + mcx) / 2;
int rightBound = (mcx + rcx) / 2;
if (cx < leftBound)
{
charIndex--;
continue;
}
if (cx > rightBound)
{
charIndex++;
continue;
}
break;
}
if (charIndex < 0)
{
charIndex = 0;
}
if (charIndex > tsValue.length())
{
charIndex = tsValue.length();
}
return charIndex;
};
}
@Override
protected void open()
{
update();
}
@Override
protected void close()
{
if (this.onClose != null)
{
this.onClose.run();
}
}
public ChatboxTextInput build()
{
if (prompt == null)
{
throw new IllegalStateException("prompt must be non-null");
}
chatboxPanelManager.openInput(this);
return this;
}
@Override
public void keyTyped(KeyEvent e)
{
char c = e.getKeyChar();
if (charValidator.test(c))
{
if (cursor != cursorEnd)
{
value.delete(cursor, cursorEnd);
}
value.insert(cursor, c);
cursorAt(cursor + 1);
if (onChanged != null)
{
onChanged.accept(getValue());
}
}
}
@Override
public void keyPressed(KeyEvent ev)
{
int code = ev.getKeyCode();
if (ev.isControlDown())
{
switch (code)
{
case KeyEvent.VK_X:
case KeyEvent.VK_C:
if (cursor != cursorEnd)
{
String s = value.substring(cursor, cursorEnd);
if (code == KeyEvent.VK_X)
{
value.delete(cursor, cursorEnd);
cursorAt(cursor);
}
Toolkit.getDefaultToolkit()
.getSystemClipboard()
.setContents(new StringSelection(s), null);
}
return;
case KeyEvent.VK_V:
try
{
String s = Toolkit.getDefaultToolkit()
.getSystemClipboard()
.getData(DataFlavor.stringFlavor)
.toString();
if (cursor != cursorEnd)
{
value.delete(cursor, cursorEnd);
}
for (int i = 0; i < s.length(); i++)
{
char ch = s.charAt(i);
if (charValidator.test(ch))
{
value.insert(cursor, ch);
cursor++;
}
}
cursorAt(cursor);
if (onChanged != null)
{
onChanged.accept(getValue());
}
}
catch (IOException | UnsupportedFlavorException ex)
{
log.warn("Unable to get clipboard", ex);
}
return;
}
return;
}
int newPos = cursor;
if (ev.isShiftDown())
{
if (selectionEnd == -1 || selectionStart == -1)
{
selectionStart = cursor;
selectionEnd = cursor;
}
newPos = selectionEnd;
}
else
{
selectionStart = -1;
selectionEnd = -1;
}
switch (code)
{
case KeyEvent.VK_DELETE:
if (cursor != cursorEnd)
{
value.delete(cursor, cursorEnd);
cursorAt(cursor);
if (onChanged != null)
{
onChanged.accept(getValue());
}
return;
}
if (cursor < value.length())
{
value.deleteCharAt(cursor);
cursorAt(cursor);
if (onChanged != null)
{
onChanged.accept(getValue());
}
}
return;
case KeyEvent.VK_BACK_SPACE:
if (cursor != cursorEnd)
{
value.delete(cursor, cursorEnd);
cursorAt(cursor);
if (onChanged != null)
{
onChanged.accept(getValue());
}
return;
}
if (cursor > 0)
{
value.deleteCharAt(cursor - 1);
cursorAt(cursor - 1);
if (onChanged != null)
{
onChanged.accept(getValue());
}
}
return;
case KeyEvent.VK_LEFT:
ev.consume();
newPos--;
break;
case KeyEvent.VK_RIGHT:
ev.consume();
newPos++;
break;
case KeyEvent.VK_HOME:
ev.consume();
newPos = 0;
break;
case KeyEvent.VK_END:
ev.consume();
newPos = value.length();
break;
case KeyEvent.VK_ENTER:
ev.consume();
if (onDone != null)
{
onDone.accept(getValue());
}
chatboxPanelManager.close();
return;
case KeyEvent.VK_ESCAPE:
ev.consume();
if (cursor != cursorEnd)
{
cursorAt(cursor);
return;
}
chatboxPanelManager.close();
return;
default:
return;
}
if (newPos > value.length())
{
newPos = value.length();
}
if (newPos < 0)
{
newPos = 0;
}
if (ev.isShiftDown())
{
selectionEnd = newPos;
cursorAt(selectionStart, newPos);
}
else
{
cursorAt(newPos);
}
}
@Override
public void keyReleased(KeyEvent e)
{
}
@Override
public MouseEvent mouseClicked(MouseEvent mouseEvent)
{
return mouseEvent;
}
@Override
public MouseEvent mousePressed(MouseEvent mouseEvent)
{
if (mouseEvent.getButton() != MouseEvent.BUTTON1)
{
return mouseEvent;
}
if (isInBounds == null || !isInBounds.test(mouseEvent))
{
if (cursor != cursorEnd)
{
selectionStart = -1;
selectionEnd = -1;
cursorAt(getCharOffset.applyAsInt(mouseEvent));
}
return mouseEvent;
}
int nco = getCharOffset.applyAsInt(mouseEvent);
if (mouseEvent.isShiftDown() && selectionEnd != -1)
{
selectionEnd = nco;
cursorAt(selectionStart, selectionEnd);
}
else
{
selectionStart = nco;
cursorAt(nco);
}
return mouseEvent;
}
@Override
public MouseEvent mouseReleased(MouseEvent mouseEvent)
{
return mouseEvent;
}
@Override
public MouseEvent mouseEntered(MouseEvent mouseEvent)
{
return mouseEvent;
}
@Override
public MouseEvent mouseExited(MouseEvent mouseEvent)
{
return mouseEvent;
}
@Override
public MouseEvent mouseDragged(MouseEvent mouseEvent)
{
if (!SwingUtilities.isLeftMouseButton(mouseEvent))
{
return mouseEvent;
}
int nco = getCharOffset.applyAsInt(mouseEvent);
if (selectionStart != -1)
{
selectionEnd = nco;
cursorAt(selectionStart, selectionEnd);
}
return mouseEvent;
}
@Override
public MouseEvent mouseMoved(MouseEvent mouseEvent)
{
return mouseEvent;
}
}

View File

@@ -0,0 +1,212 @@
/*
* 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.game.chatbox;
import com.google.inject.Inject;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.FontID;
import net.runelite.api.WidgetType;
import net.runelite.api.widgets.JavaScriptCallback;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetPositionMode;
import net.runelite.api.widgets.WidgetSizeMode;
import net.runelite.api.widgets.WidgetTextAlignment;
import net.runelite.client.input.KeyListener;
@Slf4j
public class ChatboxTextMenuInput extends ChatboxInput implements KeyListener
{
@Data
@AllArgsConstructor
private static final class Entry
{
private String text;
private Runnable callback;
}
private final ChatboxPanelManager chatboxPanelManager;
@Getter
private String title;
@Getter
private List<Entry> options = new ArrayList<>();
@Getter
private Runnable onClose;
@Inject
protected ChatboxTextMenuInput(ChatboxPanelManager chatboxPanelManager)
{
this.chatboxPanelManager = chatboxPanelManager;
}
public ChatboxTextMenuInput title(String title)
{
this.title = title;
return this;
}
public ChatboxTextMenuInput option(String text, Runnable callback)
{
options.add(new Entry(text, callback));
return this;
}
public ChatboxTextMenuInput onClose(Runnable onClose)
{
this.onClose = onClose;
return this;
}
public void build()
{
if (title == null)
{
throw new IllegalStateException("Title must be set");
}
if (options.size() < 1)
{
throw new IllegalStateException("You must have atleast 1 option");
}
chatboxPanelManager.openInput(this);
}
@Override
protected void open()
{
Widget container = chatboxPanelManager.getContainerWidget();
Widget prompt = container.createChild(-1, WidgetType.TEXT);
prompt.setText(title);
prompt.setTextColor(0x800000);
prompt.setFontId(FontID.QUILL_8);
prompt.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
prompt.setOriginalX(0);
prompt.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
prompt.setOriginalY(8);
prompt.setOriginalHeight(24);
prompt.setXTextAlignment(WidgetTextAlignment.CENTER);
prompt.setYTextAlignment(WidgetTextAlignment.CENTER);
prompt.setWidthMode(WidgetSizeMode.MINUS);
prompt.revalidate();
int y = prompt.getRelativeX() + prompt.getHeight() + 6;
int height = container.getHeight() - y - 8;
int step = height / options.size();
int maxStep = options.size() >= 3 ? 25 : 30;
if (step > maxStep)
{
int ds = step - maxStep;
step = maxStep;
y += (ds * options.size()) / 2;
}
for (Entry option : options)
{
Widget optWidget = container.createChild(-1, WidgetType.TEXT);
optWidget.setText(option.text);
optWidget.setFontId(FontID.QUILL_8);
optWidget.setXPositionMode(WidgetPositionMode.ABSOLUTE_CENTER);
optWidget.setOriginalX(0);
optWidget.setYPositionMode(WidgetPositionMode.ABSOLUTE_TOP);
optWidget.setOriginalY(y);
optWidget.setOriginalHeight(24);
optWidget.setXTextAlignment(WidgetTextAlignment.CENTER);
optWidget.setYTextAlignment(WidgetTextAlignment.CENTER);
optWidget.setWidthMode(WidgetSizeMode.MINUS);
optWidget.setAction(0, "Continue");
optWidget.setOnOpListener((JavaScriptCallback) ev -> callback(option));
optWidget.setOnMouseOverListener((JavaScriptCallback) ev -> optWidget.setTextColor(0xFFFFFF));
optWidget.setOnMouseLeaveListener((JavaScriptCallback) ev -> optWidget.setTextColor(0));
optWidget.setHasListener(true);
optWidget.revalidate();
y += step;
}
}
private void callback(Entry entry)
{
Widget container = chatboxPanelManager.getContainerWidget();
container.setOnKeyListener((Object[]) null);
chatboxPanelManager.close();
entry.callback.run();
}
@Override
protected void close()
{
if (onClose != null)
{
onClose.run();
}
}
@Override
public void keyTyped(KeyEvent e)
{
char c = e.getKeyChar();
if (c == '\033')
{
chatboxPanelManager.close();
e.consume();
return;
}
int n = c - '1';
if (n >= 0 && n < options.size())
{
callback(options.get(n));
e.consume();
}
}
@Override
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ESCAPE)
{
e.consume();
}
}
@Override
public void keyReleased(KeyEvent e)
{
}
}

View File

@@ -501,7 +501,7 @@ public class TabInterface
{
resetSearch();
clientThread.invokeLater(() -> client.runScript(ScriptID.CLOSE_CHATBOX_INPUT));
clientThread.invokeLater(() -> client.runScript(ScriptID.RESET_CHATBOX_INPUT));
}
else
{
@@ -934,7 +934,7 @@ public class TabInterface
{
// This ensures that any chatbox input (e.g from search) will not remain visible when
// selecting/changing tab
client.runScript(ScriptID.CLOSE_CHATBOX_INPUT);
client.runScript(ScriptID.RESET_CHATBOX_INPUT);
client.setVar(VarClientInt.INPUT_TYPE, inputType.getType());
client.setVar(VarClientStr.INPUT_TEXT, search);

View File

@@ -148,6 +148,7 @@ public class WidgetInfoTableModel extends AbstractTableModel
(w, str) -> w.setTextColor(Integer.parseInt(str, 16)),
String.class
));
out.add(new WidgetField<>("Opacity", Widget::getOpacity, Widget::setOpacity, Integer.class));
out.add(new WidgetField<>("FontId", Widget::getFontId, Widget::setFontId, Integer.class));
out.add(new WidgetField<>("TextShadowed", Widget::getTextShadowed, Widget::setTextShadowed, Boolean.class));
out.add(new WidgetField<>("Name", w -> w.getName().trim(), Widget::setName, String.class));
@@ -156,23 +157,32 @@ public class WidgetInfoTableModel extends AbstractTableModel
out.add(new WidgetField<>("ItemQuantityMode", Widget::getItemQuantityMode, Widget::setItemQuantityMode, Integer.class));
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<>("BorderType", Widget::getBorderType, Widget::setBorderType, Integer.class));
out.add(new WidgetField<>("IsIf3", Widget::isIf3));
out.add(new WidgetField<>("HasListener", Widget::hasListener, Widget::setHasListener, Boolean.class));
out.add(new WidgetField<>("Filled", Widget::isFilled, Widget::setFilled, Boolean.class));
out.add(new WidgetField<>("OriginalX", Widget::getOriginalX, Widget::setOriginalX, Integer.class));
out.add(new WidgetField<>("OriginalY", Widget::getOriginalY, Widget::setOriginalY, Integer.class));
out.add(new WidgetField<>("OriginalWidth", Widget::getOriginalWidth, Widget::setOriginalWidth, Integer.class));
out.add(new WidgetField<>("OriginalHeight", Widget::getOriginalHeight, Widget::setOriginalHeight, Integer.class));
out.add(new WidgetField<>("XPositionMode", Widget::getXPositionMode, Widget::setXPositionMode, Integer.class));
out.add(new WidgetField<>("YPositionMode", Widget::getYPositionMode, Widget::setYPositionMode, Integer.class));
out.add(new WidgetField<>("WidthMode", Widget::getWidthMode, Widget::setWidthMode, Integer.class));
out.add(new WidgetField<>("HeightMode", Widget::getHeightMode, Widget::setHeightMode, Integer.class));
out.add(new WidgetField<>("XTextAlignment", Widget::getXTextAlignment, Widget::setXTextAlignment, Integer.class));
out.add(new WidgetField<>("YTextAlignment", Widget::getYTextAlignment, Widget::setYTextAlignment, 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<>("Width", Widget::getWidth, Widget::setWidth, Integer.class));
out.add(new WidgetField<>("Height", Widget::getHeight, Widget::setHeight, Integer.class));
out.add(new WidgetField<>("CanvasLocation", Widget::getCanvasLocation));
out.add(new WidgetField<>("Bounds", Widget::getBounds));
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<>("BorderType", Widget::getBorderType, Widget::setBorderType, Integer.class));
out.add(new WidgetField<>("DragDeadZone", Widget::getDragDeadZone, Widget::setDragDeadZone, Integer.class));
out.add(new WidgetField<>("DragDeadTime", Widget::getDragDeadTime, Widget::setDragDeadTime, Integer.class));
out.add(new WidgetField<>("IsIf3", Widget::isIf3));
out.add(new WidgetField<>("HasListener", Widget::hasListener, Widget::setHasListener, Boolean.class));
return out;
}

View File

@@ -142,6 +142,17 @@ class WidgetInspector extends JFrame
onConfigChanged(null);
bottomPanel.add(alwaysOnTop);
final JButton revalidateWidget = new JButton("Revalidate");
revalidateWidget.addActionListener(ev -> clientThread.invokeLater(() ->
{
if (plugin.currentWidget == null)
{
return;
}
plugin.currentWidget.revalidate();
}));
bottomPanel.add(revalidateWidget);
final JSplitPane split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, treeScrollPane, infoScrollPane);
add(split, BorderLayout.CENTER);

View File

@@ -0,0 +1 @@
BA21C990EACCA53E54286CA139D58C3C7EA053BBB63C340B7BE4A0B91B156089

View File

@@ -0,0 +1,180 @@
.id 299
.int_stack_count 2
.string_stack_count 0
.int_var_count 3
.string_var_count 0
load_string "resetChatboxInput"
runelite_callback
load_int 1
load_int 10616872
widget_put_hidden_widget
load_int 0
load_int 10616887
widget_put_hidden_widget
invoke 923
load_int 0
istore 2
iload 1
load_int 1
if_icmpeq LABEL13
jump LABEL27
LABEL13:
invoke 553
istore 2
iload 2
invoke 84
iload 2
invoke 89
invoke 223
load_int 1
invoke 927
invoke 1972
load_int 1
if_icmpeq LABEL26
jump LABEL27
LABEL26:
invoke 1984
LABEL27:
invoke 1972
load_int 1
if_icmpeq LABEL31
jump LABEL32
LABEL31:
invoke 2581
LABEL32:
load_int 0
put_varc 5
iload 0
load_int 1
if_icmpeq LABEL38
jump LABEL40
LABEL38:
load_string ""
put_varc_string 22
LABEL40:
load_int 0
load_int -8
load_int 1
load_int 1
load_int 10616876
widget_put_position_widget
load_int 0
load_int 40
load_int 1
load_int 0
load_int 10616876
widget_put_size_widget
load_int 0
load_int 22
load_int 1
load_int 1
load_int 10616877
widget_put_position_widget
load_int 0
load_int 20
load_int 1
load_int 0
load_int 10616877
widget_put_size_widget
load_int 0
load_int 10616876
widget_put_hidden_widget
load_int 0
load_int 10616877
widget_put_hidden_widget
load_int 1
load_int 10616881
widget_put_hidden_widget
load_int 10616885
widget_unset_children
load_int 10616886
widget_unset_children
load_int -1
load_string ""
load_int 10616872
widget_put_mouse_press_listener_widget
load_int -1
load_string ""
load_int 10616872
widget_put_render_listener_widget
load_int 10616872
widget_unset_children
load_int 10616878
widget_unset_children
load_int 10616879
widget_unset_children
load_int 10616880
widget_unset_children
load_int 1
load_int 10616878
widget_put_hidden_widget
load_int 1
load_int 10616879
widget_put_hidden_widget
load_int 1
load_int 10616880
widget_put_hidden_widget
load_int -1
load_string ""
load_int 10616878
widget_put_mouse_hover_listener_widget
load_int -1
load_string ""
load_int 10616879
widget_put_mouse_hover_listener_widget
load_int -1
load_string ""
load_int 10616880
widget_put_mouse_hover_listener_widget
load_int -1
load_string ""
load_int 10616878
widget_put_mouse_exit_listener_widget
load_int -1
load_string ""
load_int 10616879
widget_put_mouse_exit_listener_widget
load_int -1
load_string ""
load_int 10616880
widget_put_mouse_exit_listener_widget
load_int -1
load_string ""
load_int 10616878
widget_put_render_listener_widget
load_int -1
load_string ""
load_int 10616879
widget_put_render_listener_widget
load_int -1
load_string ""
load_int 10616880
widget_put_render_listener_widget
load_int -1
load_string ""
load_int 10616878
widget_put_mouse_press_listener_widget
load_int -1
load_string ""
load_int 10616879
widget_put_mouse_press_listener_widget
load_int -1
load_string ""
load_int 10616880
widget_put_mouse_press_listener_widget
get_varc 41
load_int -1
if_icmpeq LABEL154
jump LABEL156
LABEL154:
invoke 2526
pop_int
LABEL156:
invoke 1972
load_int 1
if_icmpeq LABEL160
jump LABEL161
LABEL160:
invoke 2581
LABEL161:
return

View File

@@ -26,6 +26,7 @@ package net.runelite.mixins;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import net.runelite.api.HashTable;
@@ -559,4 +560,14 @@ public abstract class RSWidgetMixin implements RSWidget
client.revalidateWidget(this);
client.revalidateWidgetScroll(client.getWidgets()[TO_GROUP(this.getId())], this, false);
}
@Inject
@Override
public void deleteAllChildren()
{
if (getChildren() != null)
{
Arrays.fill(getChildren(), null);
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* 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.rs.api;
import net.runelite.api.FontTypeFace;
import net.runelite.mapping.Import;
public interface RSFontTypeFace extends FontTypeFace
{
@Import("getTextWidth")
@Override
int getTextWidth(String text);
@Import("verticalSpace")
@Override
int getBaseline();
}

View File

@@ -104,8 +104,13 @@ public interface RSWidget extends Widget
void setTextColor(int textColor);
@Import("opacity")
@Override
int getOpacity();
@Import("opacity")
@Override
void setOpacity(int opacity);
@Import("relativeX")
@Override
int getRelativeX();
@@ -311,6 +316,26 @@ public interface RSWidget extends Widget
@Override
Object[] getOnLoadListener();
@Import("onDialogAbortListener")
@Override
void setOnDialogAbortListener(Object... args);
@Import("onKeyListener")
@Override
void setOnKeyListener(Object... args);
@Import("onMouseOverListener")
@Override
void setOnMouseOverListener(Object... args);
@Import("onMouseLeaveListener")
@Override
void setOnMouseLeaveListener(Object... args);
@Import("onTimerListener")
@Override
void setOnTimerListener(Object... args);
@Import("fontId")
@Override
int getFontId();
@@ -350,4 +375,64 @@ public interface RSWidget extends Widget
@Import("itemQuantityMode")
@Override
void setItemQuantityMode(int itemQuantityMode);
@Import("xPositionMode")
@Override
int getXPositionMode();
@Import("xPositionMode")
@Override
void setXPositionMode(int xpm);
@Import("yPositionMode")
@Override
int getYPositionMode();
@Import("yPositionMode")
@Override
void setYPositionMode(int ypm);
@Import("xTextAlignment")
@Override
int getXTextAlignment();
@Import("xTextAlignment")
@Override
void setXTextAlignment(int xta);
@Import("yTextAlignment")
@Override
int getYTextAlignment();
@Import("yTextAlignment")
@Override
void setYTextAlignment(int yta);
@Import("widthMode")
@Override
int getWidthMode();
@Import("widthMode")
@Override
void setWidthMode(int widthMode);
@Import("heightMode")
@Override
int getHeightMode();
@Import("heightMode")
@Override
void setHeightMode(int heightMode);
@Import("getFont")
@Override
RSFontTypeFace getFont();
@Import("filled")
@Override
boolean isFilled();
@Import("filled")
@Override
void setFilled(boolean filled);
}