diff --git a/runelite-api/src/main/java/net/runelite/api/Client.java b/runelite-api/src/main/java/net/runelite/api/Client.java index 25b4dea225..7bf4c02360 100644 --- a/runelite-api/src/main/java/net/runelite/api/Client.java +++ b/runelite-api/src/main/java/net/runelite/api/Client.java @@ -2081,9 +2081,15 @@ public interface Client extends GameShell List getOutdatedScripts(); + //TODO: Implement void queueChangedVarp(int varp); + //TODO: Implement VarbitComposition getVarbit(Integer id); + //TODO: Implement Widget getWidget(int param1); + + //TODO: Implement + Widget getScriptActiveWidget(); } diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraConfig.java b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraConfig.java new file mode 100644 index 0000000000..4c406af095 --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraConfig.java @@ -0,0 +1,183 @@ +/* + * 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.camera; + +import net.runelite.client.config.Config; +import net.runelite.client.config.ConfigGroup; +import net.runelite.client.config.ConfigItem; +import net.runelite.client.config.Range; + +@ConfigGroup("zoom") // using the old plugin's group name +public interface CameraConfig extends Config +{ + int OUTER_LIMIT_MIN = -400; + int OUTER_LIMIT_MAX = 400; + /** + * The largest (most zoomed in) value that can be used without the client crashing. + * + * Larger values trigger an overflow in the engine's fov to scale code. + */ + int INNER_ZOOM_LIMIT = 1004; + + @ConfigItem( + keyName = "inner", + name = "Expand inner zoom limit", + description = "Configures whether or not the inner zoom limit is reduced", + position = 1 + ) + default boolean innerLimit() + { + return false; + } + + @Range( + min = OUTER_LIMIT_MIN, + max = OUTER_LIMIT_MAX + ) + @ConfigItem( + keyName = "outerLimit", + name = "Expand outer zoom limit", + description = "Configures how much the outer zoom limit is adjusted", + position = 2 + ) + default int outerLimit() + { + return 0; + } + + @ConfigItem( + keyName = "relaxCameraPitch", + name = "Vertical camera", + description = "Relax the camera's upper pitch limit", + position = 3 + ) + default boolean relaxCameraPitch() + { + return false; + } + + @ConfigItem( + keyName = "controlFunction", + name = "Control Function", + description = "Configures the zoom function when control is pressed", + position = 4 + ) + default ControlFunction controlFunction() + { + return ControlFunction.NONE; + } + + @ConfigItem( + keyName = "ctrlZoomValue", + name = "Reset zoom position", + description = "Position of zoom when it is reset", + position = 5 + ) + @Range( + min = OUTER_LIMIT_MIN, + max = INNER_ZOOM_LIMIT + ) + default int ctrlZoomValue() + { + return 512; + } + + @ConfigItem( + keyName = "zoomIncrement", + name = "Zoom Speed", + description = "Speed of zoom", + position = 6 + ) + default int zoomIncrement() + { + return 25; + } + + @ConfigItem( + keyName = "rightClickMovesCamera", + name = "Right click moves camera", + description = "Remaps right click to middle mouse click if there are no menu options", + position = 7 + ) + default boolean rightClickMovesCamera() + { + return false; + } + + @ConfigItem( + keyName = "ignoreExamine", + name = "Ignore Examine", + description = "Ignore the Examine menu entry", + position = 8 + ) + default boolean ignoreExamine() + { + return false; + } + + @ConfigItem( + keyName = "middleClickMenu", + name = "Middle-button opens menu", + description = "Middle-mouse button always opens the menu", + position = 9 + ) + default boolean middleClickMenu() + { + return false; + } + + @ConfigItem( + keyName = "compassLook", + name = "Compass options", + description = "Adds Look South, East, and West options to the compass", + position = 10 + ) + default boolean compassLook() + { + return true; + } + + @ConfigItem( + keyName = "invertYaw", + name = "Invert Yaw", + description = "Makes moving the camera horizontally with the mouse backwards", + position = 11 + ) + default boolean invertYaw() + { + return false; + } + + @ConfigItem( + keyName = "invertPitch", + name = "Invert Pitch", + description = "Makes moving the camera vertically with the mouse backwards", + position = 12 + ) + default boolean invertPitch() + { + return false; + } +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java new file mode 100644 index 0000000000..4e0ee6b16e --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/camera/CameraPlugin.java @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2018 Abex + * Copyright (c) 2018, Adam + * Copyright (c) 2019, Wynadorn + * 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.camera; + +import com.google.common.primitives.Ints; +import com.google.inject.Provides; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.Arrays; +import javax.inject.Inject; +import javax.swing.SwingUtilities; +import net.runelite.api.Client; +import net.runelite.api.MenuAction; +import net.runelite.api.MenuEntry; +import net.runelite.api.ScriptID; +import net.runelite.api.SettingID; +import net.runelite.api.VarClientInt; +import net.runelite.api.VarPlayer; +import net.runelite.api.events.BeforeRender; +import net.runelite.api.events.ClientTick; +import net.runelite.api.events.FocusChanged; +import net.runelite.api.events.MenuEntryAdded; +import net.runelite.api.events.ScriptCallbackEvent; +import net.runelite.api.events.ScriptPreFired; +import net.runelite.api.events.WidgetLoaded; +import net.runelite.api.widgets.JavaScriptCallback; +import net.runelite.api.widgets.Widget; +import net.runelite.api.widgets.WidgetID; +import net.runelite.api.widgets.WidgetInfo; +import net.runelite.client.callback.ClientThread; +import net.runelite.client.config.ConfigManager; +import net.runelite.client.eventbus.Subscribe; +import net.runelite.client.events.ConfigChanged; +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.plugins.Plugin; +import net.runelite.client.plugins.PluginDescriptor; +import net.runelite.client.ui.overlay.tooltip.Tooltip; +import net.runelite.client.ui.overlay.tooltip.TooltipManager; + +@PluginDescriptor( + name = "Camera", + description = "Expands zoom limit, provides vertical camera, and remaps mouse input keys", + tags = {"zoom", "limit", "vertical", "click", "mouse"}, + enabledByDefault = false +) +public class CameraPlugin extends Plugin implements KeyListener, MouseListener +{ + private static final int DEFAULT_ZOOM_INCREMENT = 25; + private static final int DEFAULT_OUTER_ZOOM_LIMIT = 128; + static final int DEFAULT_INNER_ZOOM_LIMIT = 896; + + private static final String LOOK_NORTH = "Look North"; + private static final String LOOK_SOUTH = "Look South"; + private static final String LOOK_EAST = "Look East"; + private static final String LOOK_WEST = "Look West"; + + private boolean controlDown; + // flags used to store the mousedown states + private boolean rightClick; + private boolean middleClick; + /** + * Whether or not the current menu has any non-ignored menu entries + */ + private boolean menuHasEntries; + + @Inject + private Client client; + + @Inject + private ClientThread clientThread; + + @Inject + private CameraConfig config; + + @Inject + private KeyManager keyManager; + + @Inject + private MouseManager mouseManager; + + @Inject + private TooltipManager tooltipManager; + + private Tooltip sliderTooltip; + + @Provides + CameraConfig getConfig(ConfigManager configManager) + { + return configManager.getConfig(CameraConfig.class); + } + + @Override + protected void startUp() + { + rightClick = false; + middleClick = false; + menuHasEntries = false; + copyConfigs(); + keyManager.registerKeyListener(this); + mouseManager.registerMouseListener(this); + clientThread.invoke(() -> + { + Widget sideSlider = client.getWidget(WidgetInfo.SETTINGS_SIDE_CAMERA_ZOOM_SLIDER_TRACK); + if (sideSlider != null) + { + addZoomTooltip(sideSlider); + } + + Widget settingsInit = client.getWidget(WidgetInfo.SETTINGS_INIT); + if (settingsInit != null) + { + throw new UnsupportedOperationException("Implement"); + //client.createScriptEvent(settingsInit.getOnLoadListener()) + //.setSource(settingsInit) + //.run(); + } + }); + } + + @Override + protected void shutDown() + { + client.setCameraPitchRelaxerEnabled(false); + client.setInvertYaw(false); + client.setInvertPitch(false); + keyManager.unregisterKeyListener(this); + mouseManager.unregisterMouseListener(this); + controlDown = false; + + clientThread.invoke(() -> + { + Widget sideSlider = client.getWidget(WidgetInfo.SETTINGS_SIDE_CAMERA_ZOOM_SLIDER_TRACK); + if (sideSlider != null) + { + sideSlider.setOnMouseRepeatListener((Object[]) null); + } + + Widget settingsInit = client.getWidget(WidgetInfo.SETTINGS_INIT); + if (settingsInit != null) + { + throw new UnsupportedOperationException("Implement"); + //client.createScriptEvent(settingsInit.getOnLoadListener()) + //.setSource(settingsInit) + //.run(); + } + }); + } + + void copyConfigs() + { + client.setCameraPitchRelaxerEnabled(config.relaxCameraPitch()); + client.setInvertYaw(config.invertYaw()); + client.setInvertPitch(config.invertPitch()); + } + + @Subscribe + public void onMenuEntryAdded(MenuEntryAdded menuEntryAdded) + { + if (menuEntryAdded.getType() == MenuAction.CC_OP.getId() && menuEntryAdded.getOption().equals(LOOK_NORTH) && config.compassLook()) + { + MenuEntry[] menuEntries = client.getMenuEntries(); + int len = menuEntries.length; + MenuEntry north = menuEntries[len - 1]; + + menuEntries = Arrays.copyOf(menuEntries, len + 3); + + // The handling for these entries is done in ToplevelCompassOp.rs2asm + menuEntries[--len] = createCameraLookEntry(menuEntryAdded, 4, LOOK_WEST); + menuEntries[++len] = createCameraLookEntry(menuEntryAdded, 3, LOOK_EAST); + menuEntries[++len] = createCameraLookEntry(menuEntryAdded, 2, LOOK_SOUTH); + menuEntries[++len] = north; + + client.setMenuEntries(menuEntries); + } + } + + private MenuEntry createCameraLookEntry(MenuEntryAdded lookNorth, int identifier, String option) + { + MenuEntry m = new MenuEntry(); + m.setOption(option); + m.setTarget(lookNorth.getTarget()); + m.setIdentifier(identifier); + m.setType(MenuAction.CC_OP.getId()); + m.setParam0(lookNorth.getActionParam0()); + m.setParam1(lookNorth.getActionParam1()); + return m; + } + + @Subscribe + public void onScriptCallbackEvent(ScriptCallbackEvent event) + { + if (client.getIndexScripts().isOverlayOutdated()) + { + // if any cache overlay fails to load then assume at least one of the zoom scripts is outdated + // and prevent zoom extending entirely. + return; + } + + int[] intStack = client.getIntStack(); + int intStackSize = client.getIntStackSize(); + + if (!controlDown && "scrollWheelZoom".equals(event.getEventName()) && config.controlFunction() == ControlFunction.CONTROL_TO_ZOOM) + { + intStack[intStackSize - 1] = 1; + } + + if ("innerZoomLimit".equals(event.getEventName()) && config.innerLimit()) + { + intStack[intStackSize - 1] = CameraConfig.INNER_ZOOM_LIMIT; + return; + } + + if ("outerZoomLimit".equals(event.getEventName())) + { + int outerLimit = Ints.constrainToRange(config.outerLimit(), CameraConfig.OUTER_LIMIT_MIN, CameraConfig.OUTER_LIMIT_MAX); + int outerZoomLimit = DEFAULT_OUTER_ZOOM_LIMIT - outerLimit; + intStack[intStackSize - 1] = outerZoomLimit; + return; + } + + if ("scrollWheelZoomIncrement".equals(event.getEventName()) && config.zoomIncrement() != DEFAULT_ZOOM_INCREMENT) + { + intStack[intStackSize - 1] = config.zoomIncrement(); + return; + } + + if (config.innerLimit()) + { + // This lets the options panel's slider have an exponential rate + final double exponent = 2.d; + switch (event.getEventName()) + { + case "zoomLinToExp": + { + double range = intStack[intStackSize - 1]; + double value = intStack[intStackSize - 2]; + value = Math.pow(value / range, exponent) * range; + intStack[intStackSize - 2] = (int) value; + break; + } + case "zoomExpToLin": + { + double range = intStack[intStackSize - 1]; + double value = intStack[intStackSize - 2]; + value = Math.pow(value / range, 1.d / exponent) * range; + intStack[intStackSize - 2] = (int) value; + break; + } + } + } + } + + @Subscribe + public void onFocusChanged(FocusChanged event) + { + if (!event.isFocused()) + { + controlDown = false; + } + } + + @Subscribe + public void onConfigChanged(ConfigChanged ev) + { + copyConfigs(); + } + + @Override + public void keyTyped(KeyEvent e) + { + } + + @Override + public void keyPressed(KeyEvent e) + { + if (e.getKeyCode() == KeyEvent.VK_CONTROL) + { + controlDown = true; + } + } + + @Override + public void keyReleased(KeyEvent e) + { + if (e.getKeyCode() == KeyEvent.VK_CONTROL) + { + controlDown = false; + + if (config.controlFunction() == ControlFunction.CONTROL_TO_RESET) + { + final int zoomValue = Ints.constrainToRange(config.ctrlZoomValue(), CameraConfig.OUTER_LIMIT_MIN, CameraConfig.INNER_ZOOM_LIMIT); + clientThread.invokeLater(() -> client.runScript(ScriptID.CAMERA_DO_ZOOM, zoomValue, zoomValue)); + } + } + } + + /** + * Checks if the menu has any non-ignored entries + */ + private boolean hasMenuEntries(MenuEntry[] menuEntries) + { + for (MenuEntry menuEntry : menuEntries) + { + MenuAction action = MenuAction.of(menuEntry.getType()); + switch (action) + { + case CANCEL: + case WALK: + break; + case EXAMINE_OBJECT: + case EXAMINE_NPC: + case EXAMINE_ITEM_GROUND: + case EXAMINE_ITEM: + case CC_OP_LOW_PRIORITY: + if (config.ignoreExamine()) + { + break; + } + default: + return true; + } + } + return false; + } + + /** + * Checks if the menu has any options, because menu entries are built each + * tick and the MouseListener runs on the awt thread + */ + @Subscribe + public void onClientTick(ClientTick event) + { + menuHasEntries = hasMenuEntries(client.getMenuEntries()); + } + + @Subscribe + private void onScriptPreFired(ScriptPreFired ev) + { + if (ev.getScriptId() == ScriptID.SETTINGS_SLIDER_CHOOSE_ONOP) + { + int arg = client.getIntStackSize() - 7; + int[] is = client.getIntStack(); + + if (is[arg] == SettingID.CAMERA_ZOOM) + { + addZoomTooltip(client.getScriptActiveWidget()); + } + } + } + + @Subscribe + private void onWidgetLoaded(WidgetLoaded ev) + { + if (ev.getGroupId() == WidgetID.SETTINGS_SIDE_GROUP_ID) + { + addZoomTooltip(client.getWidget(WidgetInfo.SETTINGS_SIDE_CAMERA_ZOOM_SLIDER_TRACK)); + } + } + + private void addZoomTooltip(Widget w) + { + w.setOnMouseRepeatListener((JavaScriptCallback) ev -> + { + int value = client.getVar(VarClientInt.CAMERA_ZOOM_RESIZABLE_VIEWPORT); + int max = config.innerLimit() ? config.INNER_ZOOM_LIMIT : CameraPlugin.DEFAULT_INNER_ZOOM_LIMIT; + sliderTooltip = new Tooltip("Camera Zoom: " + value + " / " + max); + }); + } + + @Subscribe + private void onBeforeRender(BeforeRender ev) + { + if (sliderTooltip != null) + { + tooltipManager.add(sliderTooltip); + sliderTooltip = null; + } + } + + /** + * The event that is triggered when a mouse button is pressed + * In this method the right click is changed to a middle-click to enable rotating the camera + *

+ * This method also provides the config option to enable the middle-mouse button to always open the right click menu + */ + @Override + public MouseEvent mousePressed(MouseEvent mouseEvent) + { + if (SwingUtilities.isRightMouseButton(mouseEvent) && config.rightClickMovesCamera()) + { + boolean oneButton = client.getVar(VarPlayer.MOUSE_BUTTONS) == 1; + // Only move the camera if there is nothing at the menu, or if + // in one-button mode. In one-button mode, left and right click always do the same thing, + // so always treat it as the menu is empty + if (!menuHasEntries || oneButton) + { + // Set the rightClick flag to true so we can release the button in mouseReleased() later + rightClick = true; + // Change the mousePressed() MouseEvent to the middle mouse button + mouseEvent = new MouseEvent((java.awt.Component) mouseEvent.getSource(), + mouseEvent.getID(), + mouseEvent.getWhen(), + mouseEvent.getModifiersEx(), + mouseEvent.getX(), + mouseEvent.getY(), + mouseEvent.getClickCount(), + mouseEvent.isPopupTrigger(), + MouseEvent.BUTTON2); + } + } + else if (SwingUtilities.isMiddleMouseButton((mouseEvent)) && config.middleClickMenu()) + { + // Set the middleClick flag to true so we can release it later in mouseReleased() + middleClick = true; + // Chance the middle mouse button MouseEvent to a right-click + mouseEvent = new MouseEvent((java.awt.Component) mouseEvent.getSource(), + mouseEvent.getID(), + mouseEvent.getWhen(), + mouseEvent.getModifiersEx(), + mouseEvent.getX(), + mouseEvent.getY(), + mouseEvent.getClickCount(), + mouseEvent.isPopupTrigger(), + MouseEvent.BUTTON3); + } + return mouseEvent; + } + + /** + * Correct the MouseEvent to release the correct button + */ + @Override + public MouseEvent mouseReleased(MouseEvent mouseEvent) + { + if (rightClick) + { + rightClick = false; + // Change the MouseEvent to button 2 so the middle mouse button will be released + mouseEvent = new MouseEvent((java.awt.Component) mouseEvent.getSource(), + mouseEvent.getID(), + mouseEvent.getWhen(), + mouseEvent.getModifiersEx(), + mouseEvent.getX(), + mouseEvent.getY(), + mouseEvent.getClickCount(), + mouseEvent.isPopupTrigger(), + MouseEvent.BUTTON2); + + } + if (middleClick) + { + middleClick = false; + // Change the MouseEvent ot button 3 so the right mouse button will be released + mouseEvent = new MouseEvent((java.awt.Component) mouseEvent.getSource(), + mouseEvent.getID(), + mouseEvent.getWhen(), + mouseEvent.getModifiersEx(), + mouseEvent.getX(), + mouseEvent.getY(), + mouseEvent.getClickCount(), + mouseEvent.isPopupTrigger(), + MouseEvent.BUTTON3); + } + return mouseEvent; + } + + /* + * These methods are unused but required to be present in a MouseListener implementation + */ + // region Unused MouseListener methods + @Override + public MouseEvent mouseDragged(MouseEvent mouseEvent) + { + return mouseEvent; + } + + @Override + public MouseEvent mouseMoved(MouseEvent mouseEvent) + { + return mouseEvent; + } + + @Override + public MouseEvent mouseClicked(MouseEvent mouseEvent) + { + return mouseEvent; + } + + @Override + public MouseEvent mouseEntered(MouseEvent mouseEvent) + { + return mouseEvent; + } + + @Override + public MouseEvent mouseExited(MouseEvent mouseEvent) + { + return mouseEvent; + } + // endregion +} diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/camera/ControlFunction.java b/runelite-client/src/main/java/net/runelite/client/plugins/camera/ControlFunction.java new file mode 100644 index 0000000000..07fecfd5ba --- /dev/null +++ b/runelite-client/src/main/java/net/runelite/client/plugins/camera/ControlFunction.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019, Jacob M + * 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 HOLDER 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.camera; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ControlFunction +{ + NONE("None"), + CONTROL_TO_ZOOM("Hold to zoom"), + CONTROL_TO_RESET("Reset zoom"); + + private final String name; + + @Override + public String toString() + { + return getName(); + } +}