Add tag tabs to bank tags plugin

Bring the ability to add tabs to your bank for quick access to search tags.

Features:
* Adding a tab
* Selecting and deselecting a tab
* Changing a tab's icon
* Reordering tabs
* Scrolling of tabs (With mouse wheel, ingame buttons, and dragging an item/tab over ingame buttons)
* Saving scroll position
* Dragging an item to a tab to tag the item
* Tagging placeholders
* Removing only a tab
* Removing a tab and deleting all tags from said tab
* Faster bank search when using tag tabs

Closes #1205
Closes #4426
Supersedes / Closes #4862
Supersedes / Closes #3750
Can close #4082.

Signed-off-by: Tomas Slusny <slusnucky@gmail.com>
Co-authored-by: Tomas Slusny <slusnucky@gmail.com>
This commit is contained in:
raiyni
2018-10-04 15:35:48 +02:00
committed by Tomas Slusny
parent ace185805b
commit a0b5e490cd
13 changed files with 1397 additions and 99 deletions

View File

@@ -0,0 +1,62 @@
/*
* Copyright (c) 2018, Ron Young <https://github.com/raiyni>
* 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.banktags;
import net.runelite.client.config.Config;
import net.runelite.client.config.ConfigGroup;
import net.runelite.client.config.ConfigItem;
@ConfigGroup("banktags")
public interface BankTagsConfig extends Config
{
@ConfigItem(
keyName = "useTabs",
name = "Use Tag Tabs",
description = "Enable the ability to add tabs to your bank which allow fast access to tags.",
position = 1
)
default boolean tabs()
{
return true;
}
@ConfigItem(
keyName = "position",
name = "",
description = "",
hidden = true
)
default int position()
{
return 0;
}
@ConfigItem(
keyName = "position",
name = "",
description = ""
)
void position(int idx);
}

View File

@@ -1,5 +1,7 @@
/*
* Copyright (c) 2018, Adam <Adam@sigterm.info>
* Copyright (c) 2018, Ron Young <https://github.com/raiyni>
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -24,9 +26,12 @@
*/
package net.runelite.client.plugins.banktags;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.eventbus.Subscribe;
import com.google.inject.Provides;
import java.awt.event.MouseWheelEvent;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.api.InventoryID;
@@ -35,86 +40,100 @@ import net.runelite.api.ItemComposition;
import net.runelite.api.ItemContainer;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
import net.runelite.api.events.ConfigChanged;
import net.runelite.api.events.DraggingWidgetChanged;
import net.runelite.api.events.GameTick;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.events.ScriptCallbackEvent;
import net.runelite.api.events.WidgetLoaded;
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.game.ChatboxInputManager;
import net.runelite.client.game.ItemManager;
import net.runelite.client.input.MouseManager;
import net.runelite.client.input.MouseWheelListener;
import net.runelite.client.plugins.Plugin;
import net.runelite.client.plugins.PluginDescriptor;
import net.runelite.client.plugins.banktags.tabs.TabInterface;
import net.runelite.client.plugins.banktags.tabs.TabSprites;
@PluginDescriptor(
name = "Bank Tags",
description = "Enable tagging of bank items and searching of bank tags",
tags = {"searching", "tagging"}
)
public class BankTagsPlugin extends Plugin
public class BankTagsPlugin extends Plugin implements MouseWheelListener
{
private static final String CONFIG_GROUP = "banktags";
private static final String ITEM_KEY_PREFIX = "item_";
public static final Splitter SPLITTER = Splitter.on(",").omitEmptyStrings().trimResults();
public static final Joiner JOINER = Joiner.on(",").skipNulls();
public static final String CONFIG_GROUP = "banktags";
public static final String TAG_SEARCH = "tag:";
public static final String EDIT_TAGS_MENU_OPTION = "Edit-tags";
public static final String ICON_SEARCH = "icon_";
private static final String SEARCH_BANK_INPUT_TEXT =
"Show items whose names or tags contain the following text:<br>" +
"(To show only tagged items, start your search with 'tag:')";
private static final String SEARCH_BANK_INPUT_TEXT_FOUND =
"Show items whose names or tags contain the following text: (%d found)<br>" +
"(To show only tagged items, start your search with 'tag:')";
private static final String TAG_SEARCH = "tag:";
private static final String EDIT_TAGS_MENU_OPTION = "Edit-tags";
@Inject
private Client client;
@Inject
private ItemManager itemManager;
@Inject
private ConfigManager configManager;
private Client client;
@Inject
private ClientThread clientThread;
@Inject
private ChatboxInputManager chatboxInputManager;
private String getTags(int itemId)
@Inject
private MouseManager mouseManager;
@Inject
private BankTagsConfig config;
@Inject
private TagManager tagManager;
@Inject
private TabInterface tabInterface;
@Provides
BankTagsConfig getConfig(ConfigManager configManager)
{
String config = configManager.getConfiguration(CONFIG_GROUP, ITEM_KEY_PREFIX + itemId);
if (config == null)
{
return "";
}
return config;
return configManager.getConfig(BankTagsConfig.class);
}
private void setTags(int itemId, String tags)
@Override
public void startUp()
{
if (tags == null || tags.isEmpty())
{
configManager.unsetConfiguration(CONFIG_GROUP, ITEM_KEY_PREFIX + itemId);
}
else
{
configManager.setConfiguration(CONFIG_GROUP, ITEM_KEY_PREFIX + itemId, tags);
}
mouseManager.registerMouseWheelListener(this);
clientThread.invokeLater(tabInterface::init);
client.getSpriteOverrides().putAll(TabSprites.toMap(client));
}
private int getTagCount(int itemId)
@Override
public void shutDown()
{
String tags = getTags(itemId);
if (tags.length() > 0)
mouseManager.unregisterMouseWheelListener(this);
clientThread.invokeLater(tabInterface::destroy);
for (TabSprites value : TabSprites.values())
{
return tags.split(",").length;
client.getSpriteOverrides().remove(value.getSpriteId());
}
return 0;
}
@Subscribe
public void onScriptEvent(ScriptCallbackEvent event)
public void onScriptCallbackEvent(ScriptCallbackEvent event)
{
String eventName = event.getEventName();
@@ -141,29 +160,15 @@ public class BankTagsPlugin extends Plugin
case "bankSearchFilter":
int itemId = itemManager.canonicalize(intStack[intStackSize - 1]);
String itemName = stringStack[stringStackSize - 2];
String searchInput = stringStack[stringStackSize - 1];
String search = stringStack[stringStackSize - 1];
String tagsConfig = configManager.getConfiguration(CONFIG_GROUP, ITEM_KEY_PREFIX + itemId);
if (tagsConfig == null || tagsConfig.length() == 0)
{
intStack[intStackSize - 2] = itemName.contains(searchInput) ? 1 : 0;
return;
}
boolean tagSearch = searchInput.startsWith(TAG_SEARCH);
String search;
boolean tagSearch = search.startsWith(TAG_SEARCH);
if (tagSearch)
{
search = searchInput.substring(TAG_SEARCH.length()).trim();
}
else
{
search = searchInput;
search = search.substring(TAG_SEARCH.length()).trim();
}
List<String> tags = Arrays.asList(tagsConfig.toLowerCase().split(","));
if (tags.stream().anyMatch(tag -> tag.contains(search.toLowerCase())))
if (tagManager.findTag(itemId, search))
{
// return true
intStack[intStackSize - 2] = 1;
@@ -173,54 +178,42 @@ public class BankTagsPlugin extends Plugin
intStack[intStackSize - 2] = itemName.contains(search) ? 1 : 0;
}
break;
case "getSearchingTagTab":
intStack[intStackSize - 1] = tabInterface.isActive() ? 1 : 0;
break;
}
}
@Subscribe
public void onMenuEntryAdded(MenuEntryAdded event)
{
int widgetId = event.getActionParam1();
if (widgetId != WidgetInfo.BANK_ITEM_CONTAINER.getId())
{
return;
}
int index = event.getActionParam0();
if (index < 0)
{
return;
}
// Examine is the only guaranteed menuop to be added
if (!"Examine".equals(event.getOption()))
{
return;
}
Widget container = client.getWidget(WidgetInfo.BANK_ITEM_CONTAINER);
Widget item = container.getChild(index);
int itemID = itemManager.canonicalize(item.getItemId());
String text = EDIT_TAGS_MENU_OPTION;
int tagCount = getTagCount(itemID);
if (tagCount > 0)
{
text += " (" + tagCount + ")";
}
MenuEntry editTags = new MenuEntry();
editTags.setParam0(event.getActionParam0());
editTags.setParam1(event.getActionParam1());
editTags.setTarget(event.getTarget());
editTags.setOption(text);
editTags.setType(MenuAction.RUNELITE.getId());
editTags.setIdentifier(event.getIdentifier());
MenuEntry[] entries = client.getMenuEntries();
entries = Arrays.copyOf(entries, entries.length + 1);
entries[entries.length - 1] = editTags;
client.setMenuEntries(entries);
if (event.getActionParam1() == WidgetInfo.BANK_ITEM_CONTAINER.getId()
&& event.getOption().equals("Examine"))
{
Widget container = client.getWidget(WidgetInfo.BANK_ITEM_CONTAINER);
Widget item = container.getChild(event.getActionParam0());
int itemID = itemManager.canonicalize(item.getItemId());
String text = EDIT_TAGS_MENU_OPTION;
int tagCount = tagManager.getTags(itemID).size();
if (tagCount > 0)
{
text += " (" + tagCount + ")";
}
MenuEntry editTags = new MenuEntry();
editTags.setParam0(event.getActionParam0());
editTags.setParam1(event.getActionParam1());
editTags.setTarget(event.getTarget());
editTags.setOption(text);
editTags.setType(MenuAction.RUNELITE.getId());
editTags.setIdentifier(event.getIdentifier());
entries = Arrays.copyOf(entries, entries.length + 1);
entries[entries.length - 1] = editTags;
client.setMenuEntries(entries);
}
tabInterface.handleAdd(event);
}
@Subscribe
@@ -249,11 +242,9 @@ public class BankTagsPlugin extends Plugin
}
int itemId = itemManager.canonicalize(item.getId());
ItemComposition itemComposition = itemManager.getItemComposition(itemId);
String itemName = itemComposition.getName();
String initialValue = getTags(itemId);
String initialValue = tagManager.getTagString(itemId);
chatboxInputManager.openInputWindow(itemName + " tags:", initialValue, (newTags) ->
{
@@ -261,9 +252,57 @@ public class BankTagsPlugin extends Plugin
{
return;
}
setTags(itemId, newTags);
tagManager.setTagString(itemId, newTags);
});
}
else
{
tabInterface.handleClick(event);
}
}
@Subscribe
public void onConfigChanged(ConfigChanged configChanged)
{
if (configChanged.getGroup().equals("banktags") && configChanged.getKey().equals("useTabs"))
{
if (config.tabs())
{
clientThread.invokeLater(tabInterface::init);
}
else
{
clientThread.invokeLater(tabInterface::destroy);
}
}
}
@Subscribe
public void onGameTick(GameTick event)
{
tabInterface.update();
}
@Subscribe
public void onDraggingWidgetChanged(DraggingWidgetChanged event)
{
tabInterface.handleDrag(event.isDraggingWidget());
}
@Subscribe
public void onWidgetLoaded(WidgetLoaded event)
{
if (event.getGroupId() == WidgetID.BANK_GROUP_ID)
{
tabInterface.init();
}
}
@Override
public MouseWheelEvent mouseWheelMoved(MouseWheelEvent event)
{
clientThread.invokeLater(() -> tabInterface.handleWheel(event));
return event;
}
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* Copyright (c) 2018, Ron Young <https://github.com/raiyni>
* 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.banktags;
import com.google.common.base.Strings;
import java.util.Collection;
import java.util.LinkedHashSet;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.runelite.client.config.ConfigManager;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.CONFIG_GROUP;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.JOINER;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.SPLITTER;
import net.runelite.client.util.Text;
@Singleton
public class TagManager
{
private static final String ITEM_KEY_PREFIX = "item_";
private final ConfigManager configManager;
@Inject
private TagManager(final ConfigManager configManager)
{
this.configManager = configManager;
}
public String getTagString(int itemId)
{
String config = configManager.getConfiguration(CONFIG_GROUP, ITEM_KEY_PREFIX + itemId);
if (config == null)
{
return "";
}
return config;
}
Collection<String> getTags(int itemId)
{
return new LinkedHashSet<>(SPLITTER.splitToList(getTagString(itemId).toLowerCase()));
}
public void setTagString(int itemId, String tags)
{
if (Strings.isNullOrEmpty(tags))
{
configManager.unsetConfiguration(CONFIG_GROUP, ITEM_KEY_PREFIX + itemId);
}
else
{
configManager.setConfiguration(CONFIG_GROUP, ITEM_KEY_PREFIX + itemId, tags);
}
}
public void addTag(int itemId, String tag)
{
final Collection<String> tags = getTags(itemId);
if (tags.add(Text.standardize(tag)))
{
setTags(itemId, tags);
}
}
private void setTags(int itemId, Collection<String> tags)
{
setTagString(itemId, JOINER.join(tags));
}
boolean findTag(int itemId, String search)
{
return getTags(itemId).stream().anyMatch(tag -> tag.contains(Text.standardize(search)));
}
public void removeTag(String tag)
{
final String prefix = CONFIG_GROUP + "." + ITEM_KEY_PREFIX;
configManager.getConfigurationKeys(prefix).forEach(item -> removeTag(Integer.parseInt(item.replace(prefix, "")), tag));
}
public void removeTag(int itemId, String tag)
{
final Collection<String> tags = getTags(itemId);
if (tags.remove(Text.standardize(tag)))
{
setTags(itemId, tags);
}
}
}

View File

@@ -0,0 +1,792 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* Copyright (c) 2018, Ron Young <https://github.com/raiyni>
* 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.banktags.tabs;
import com.google.common.base.Strings;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.event.MouseWheelEvent;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.Getter;
import net.runelite.api.Client;
import net.runelite.api.InventoryID;
import net.runelite.api.Item;
import net.runelite.api.ItemComposition;
import net.runelite.api.ItemContainer;
import net.runelite.api.MenuAction;
import net.runelite.api.MenuEntry;
import net.runelite.api.Point;
import net.runelite.api.ScriptID;
import net.runelite.api.SoundEffectID;
import net.runelite.api.SpriteID;
import net.runelite.api.VarClientInt;
import net.runelite.api.VarClientStr;
import net.runelite.api.Varbits;
import net.runelite.api.WidgetType;
import net.runelite.api.events.MenuEntryAdded;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.api.vars.InputType;
import net.runelite.api.widgets.Widget;
import net.runelite.api.widgets.WidgetConfig;
import net.runelite.api.widgets.WidgetInfo;
import net.runelite.client.callback.ClientThread;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.game.ChatboxInputManager;
import net.runelite.client.game.ItemManager;
import net.runelite.client.plugins.banktags.BankTagsConfig;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.CONFIG_GROUP;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.ICON_SEARCH;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.TAG_SEARCH;
import net.runelite.client.plugins.banktags.TagManager;
import net.runelite.client.util.ColorUtil;
import net.runelite.client.util.Text;
@Singleton
public class TabInterface
{
private static final Color HILIGHT_COLOR = Color.decode("#ff9040");
private static final String SCROLL_UP = "Scroll up";
private static final String SCROLL_DOWN = "Scroll down";
private static final String NEW_TAB = "New tag tab";
private static final String REMOVE_TAB = "Delete tag tab";
private static final String VIEW_TAB = "View tag tab";
private static final String CHANGE_ICON = "Change icon";
private static final String REMOVE_TAG = "Remove-tag";
private static final int TAB_HEIGHT = 40;
private static final int TAB_WIDTH = 39;
private static final int BUTTON_HEIGHT = 20;
private static final int MARGIN = 1;
private static final int SCROLL_TICK = 500;
// Widget indexes for searching
private static final int INNER_CONTAINER_IDX = 2;
private static final int SETTINGS_IDX = 4;
private static final int ITEM_CONTAINER_IDX = 7;
private static final int SCROLLBAR_IDX = 8;
private static final int BOTTOM_BAR_IDX = 9;
private static final int SEARCH_BUTTON_BACKGROUND_IDX = 15;
private static final int TITLE_BAR_IDX = 16;
private static final int ITEM_COUNT_IDX = 17;
private static final int TAB_BAR_IDX = 18;
private static final int INCINERATOR_IDX = 19;
private static final int INCINERATOR_CONFIRM_IDX = 20;
private static final int HIDDEN_WIDGET_IDX = 21;
private final Client client;
private final ClientThread clientThread;
private final ItemManager itemManager;
private final ConfigManager configManager;
private final TagManager tagManager;
private final TabManager tabManager;
private final ChatboxInputManager chatboxInputManager;
private final BankTagsConfig config;
private final Rectangle bounds = new Rectangle();
private final Rectangle canvasBounds = new Rectangle();
private TagTab activeTab;
private int maxTabs;
private int currentTabIndex;
private TagTab iconToSet = null;
private Instant startScroll = Instant.now();
private Object[] widgetIds;
@Getter
private Widget upButton;
@Getter
private Widget downButton;
@Getter
private Widget newTab;
@Getter
private Widget parent;
@Inject
private TabInterface(
final Client client,
final ClientThread clientThread,
final ItemManager itemManager,
final ConfigManager configManager,
final TagManager tagManager,
final TabManager tabManager,
final ChatboxInputManager chatboxInputManager,
final BankTagsConfig config)
{
this.client = client;
this.clientThread = clientThread;
this.itemManager = itemManager;
this.configManager = configManager;
this.tagManager = tagManager;
this.tabManager = tabManager;
this.chatboxInputManager = chatboxInputManager;
this.config = config;
}
public boolean isActive()
{
return activeTab != null;
}
public void init()
{
if (isHidden())
{
return;
}
Widget bankContainer = client.getWidget(WidgetInfo.BANK_CONTAINER);
widgetIds = bankContainer.getOnLoadListener();
currentTabIndex = config.position();
parent = client.getWidget(WidgetInfo.BANK_CONTENT_CONTAINER);
updateBounds();
upButton = createGraphic("", TabSprites.UP_ARROW.getSpriteId(), -1, TAB_WIDTH, BUTTON_HEIGHT, bounds.x, 0, true);
upButton.setAction(1, SCROLL_UP);
int clickmask = upButton.getClickMask();
clickmask |= WidgetConfig.DRAG;
upButton.setClickMask(clickmask);
downButton = createGraphic("", TabSprites.DOWN_ARROW.getSpriteId(), -1, TAB_WIDTH, BUTTON_HEIGHT, bounds.x, 0, true);
downButton.setAction(1, SCROLL_DOWN);
clickmask = downButton.getClickMask();
clickmask |= WidgetConfig.DRAG;
downButton.setClickMask(clickmask);
newTab = createGraphic("", TabSprites.NEW_TAB.getSpriteId(), -1, TAB_WIDTH, 39, bounds.x, 0, true);
newTab.setAction(1, NEW_TAB);
tabManager.clear();
tabManager.getAllTabs().forEach(this::loadTab);
activateTab(null);
scrollTab(0);
}
public void destroy()
{
activeTab = null;
currentTabIndex = 0;
maxTabs = 0;
parent = null;
if (upButton != null)
{
upButton.setHidden(true);
downButton.setHidden(true);
newTab.setHidden(true);
}
tabManager.clear();
}
public void update()
{
if (isHidden())
{
parent = null;
// If bank window was just hidden, update last active tab position
if (currentTabIndex != config.position())
{
config.position(currentTabIndex);
}
return;
}
String str = client.getVar(VarClientStr.INPUT_TEXT);
if (Strings.isNullOrEmpty(str))
{
str = "";
}
Widget bankTitle = client.getWidget(WidgetInfo.BANK_TITLE_BAR);
if (bankTitle != null && !bankTitle.isHidden())
{
str = bankTitle.getText().replaceFirst("Showing items: ", "");
if (str.startsWith("Tab "))
{
str = "";
}
}
str = Text.standardize(str);
if (str.startsWith("tag:"))
{
str = str.substring(4);
activateTab(tabManager.find(str));
}
else
{
activateTab(null);
}
updateBounds();
scrollTab(0);
}
public void handleWheel(final MouseWheelEvent event)
{
if (isHidden())
{
return;
}
if (canvasBounds.contains(event.getPoint()))
{
scrollTab(event.getWheelRotation());
}
}
public void handleAdd(MenuEntryAdded event)
{
if (isHidden())
{
return;
}
MenuEntry[] entries = client.getMenuEntries();
MenuEntry entry = entries[entries.length - 1];
if (activeTab != null
&& event.getActionParam1() == WidgetInfo.BANK_ITEM_CONTAINER.getId()
&& event.getOption().equals("Examine"))
{
MenuEntry removeTag = new MenuEntry();
removeTag.setParam0(event.getActionParam0());
removeTag.setParam1(event.getActionParam1());
removeTag.setTarget(event.getTarget());
removeTag.setOption(REMOVE_TAG + " (" + activeTab.getTag() + ")");
removeTag.setType(MenuAction.RUNELITE.getId());
removeTag.setIdentifier(event.getIdentifier());
entries = Arrays.copyOf(entries, entries.length + 1);
entries[entries.length - 1] = removeTag;
client.setMenuEntries(entries);
}
else if (iconToSet != null && (entry.getOption().startsWith("Withdraw-") || entry.getOption().equals("Release")))
{
// TODO: Do not replace every withdraw option with change icon option
entry.setOption(CHANGE_ICON + " (" + iconToSet.getTag() + ")");
client.setMenuEntries(entries);
}
}
public void handleClick(MenuOptionClicked event)
{
if (isHidden())
{
return;
}
if (iconToSet != null)
{
if (event.getMenuOption().startsWith(CHANGE_ICON))
{
ItemComposition item = getItem(event.getActionParam());
int itemId = itemManager.canonicalize(item.getId());
iconToSet.setIconItemId(itemId);
iconToSet.getIcon().setItemId(itemId);
configManager.setConfiguration(CONFIG_GROUP, ICON_SEARCH + iconToSet.getTag(), itemId + "");
event.consume();
}
// Reset icon selection even when we do not clicked item with icon
iconToSet = null;
}
if (activeTab != null
&& event.getMenuOption().equals("Search")
&& client.getWidget(WidgetInfo.BANK_SEARCH_BUTTON_BACKGROUND).getSpriteId() != SpriteID.EQUIPMENT_SLOT_SELECTED)
{
activateTab(null);
// This ensures that when clicking Search when tab is selected, the search input is opened rather
// than client trying to close it first
client.setVar(VarClientStr.INPUT_TEXT, "");
client.setVar(VarClientInt.INPUT_TYPE, 0);
}
else if (activeTab != null
&& event.getMenuOption().startsWith("View tab"))
{
activateTab(null);
}
else if (activeTab != null
&& event.getWidgetId() == WidgetInfo.BANK_ITEM_CONTAINER.getId()
&& event.getMenuAction() == MenuAction.RUNELITE
&& event.getMenuOption().startsWith(REMOVE_TAG))
{
// Add "remove" menu entry to all items in bank while tab is selected
event.consume();
final ItemComposition item = getItem(event.getActionParam());
final int itemId = itemManager.canonicalize(item.getId());
tagManager.removeTag(itemId, activeTab.getTag());
doSearch(InputType.SEARCH, TAG_SEARCH + activeTab.getTag());
}
else
{
switch (event.getMenuOption())
{
case SCROLL_UP:
event.consume();
scrollTab(-1);
break;
case SCROLL_DOWN:
event.consume();
scrollTab(1);
break;
case CHANGE_ICON:
event.consume();
iconToSet = tabManager.find(Text.removeTags(event.getMenuTarget()));
break;
case VIEW_TAB:
event.consume();
client.setVarbitValue(client.getVarps(), Varbits.CURRENT_BANK_TAB.getId(), 0);
Widget[] children = parent.getDynamicChildren();
Widget clicked = children[event.getActionParam()];
TagTab tab = tabManager.find(Text.removeTags(clicked.getName()));
if (tab.equals(activeTab))
{
resetSearch();
clientThread.invokeLater(() -> client.runScript(ScriptID.CLOSE_CHATBOX_INPUT));
}
else
{
openTag(TAG_SEARCH + Text.removeTags(clicked.getName()));
}
client.playSoundEffect(SoundEffectID.UI_BOOP);
break;
case NEW_TAB:
event.consume();
chatboxInputManager.openInputWindow("Tag Name", "", (tagName) ->
{
if (!Strings.isNullOrEmpty(tagName))
{
loadTab(tagName);
tabManager.save();
scrollTab(0);
}
});
break;
case REMOVE_TAB:
event.consume();
String target = Text.standardize(event.getMenuTarget());
// TODO: Replace this number input selection with actual in-game select input
chatboxInputManager.openInputWindow(
"1. Delete tab " + target + " and tag from all items<br>" +
"2. Delete tab " + target + "<br>" +
"3. Cancel", "", (response) ->
{
switch (response)
{
case "1":
tagManager.removeTag(target);
if (activeTab != null && activeTab.getTag().equals(target))
{
resetSearch();
}
case "2":
deleteTab(target);
break;
default:
break;
}
});
break;
}
}
}
public void handleDrag(boolean isDragging)
{
if (isHidden())
{
return;
}
Widget draggedOn = client.getDraggedOnWidget();
Widget draggedWidget = client.getDraggedWidget();
if (!isDragging || draggedOn == null)
{
return;
}
// is dragging widget and mouse button released
if (client.getMouseCurrentButton() == 0)
{
if (draggedWidget.getItemId() > 0 && draggedWidget.getId() != parent.getId())
{
// Tag an item dragged on a tag tab
if (draggedOn.getId() == parent.getId())
{
int itemId = itemManager.canonicalize(draggedWidget.getItemId());
tagManager.addTag(itemId, draggedOn.getName());
}
}
else if (parent.getId() == draggedOn.getId() && parent.getId() == draggedWidget.getId())
{
// Reorder tag tabs
if (!Strings.isNullOrEmpty(draggedOn.getName()))
{
tabManager.move(draggedWidget.getName(), draggedOn.getName());
tabManager.save();
updateTabs();
}
}
}
else if (draggedWidget.getItemId() > 0)
{
MenuEntry[] entries = client.getMenuEntries();
if (entries.length > 0)
{
MenuEntry entry = entries[entries.length - 1];
if (draggedWidget.getItemId() > 0 && entry.getOption().equals(VIEW_TAB) && draggedOn.getId() != draggedWidget.getId())
{
entry.setOption(TAG_SEARCH + Text.removeTags(entry.getTarget()));
entry.setTarget(draggedWidget.getName());
client.setMenuEntries(entries);
}
if (entry.getOption().equals(SCROLL_UP))
{
scrollTick(-1);
}
else if (entry.getOption().equals(SCROLL_DOWN))
{
scrollTick(1);
}
}
}
}
private void resetSearch()
{
doSearch(InputType.NONE, "");
}
private boolean isHidden()
{
Widget widget = client.getWidget(WidgetInfo.BANK_CONTAINER);
return !config.tabs() || widget == null || widget.isHidden();
}
private void loadTab(String tag)
{
TagTab tagTab = tabManager.load(tag);
if (tagTab.getBackground() == null)
{
Widget btn = createGraphic(ColorUtil.wrapWithColorTag(tagTab.getTag(), HILIGHT_COLOR), TabSprites.TAB_BACKGROUND.getSpriteId(), -1, TAB_WIDTH, TAB_HEIGHT, bounds.x, 1, true);
btn.setAction(1, VIEW_TAB);
btn.setAction(2, CHANGE_ICON);
btn.setAction(3, REMOVE_TAB);
tagTab.setBackground(btn);
}
if (tagTab.getIcon() == null)
{
Widget icon = createGraphic(ColorUtil.wrapWithColorTag(tagTab.getTag(), HILIGHT_COLOR), -1, tagTab.getIconItemId(), 36, 32, bounds.x + 3, 1, false);
int clickmask = icon.getClickMask();
clickmask |= WidgetConfig.DRAG;
clickmask |= WidgetConfig.DRAG_ON;
icon.setClickMask(clickmask);
icon.setDragDeadTime(5);
icon.setDragDeadZone(5);
tagTab.setIcon(icon);
}
tabManager.add(tagTab);
}
private void deleteTab(String tag)
{
if (activeTab != null && activeTab.getTag().equals(tag))
{
doSearch(InputType.SEARCH, "");
}
tabManager.remove(tag);
configManager.unsetConfiguration(CONFIG_GROUP, ICON_SEARCH + tag);
tabManager.save();
updateBounds();
scrollTab(0);
}
private void scrollTick(int direction)
{
// This ensures that dragging on scroll buttons do not scrolls too fast
if (startScroll.until(Instant.now(), ChronoUnit.MILLIS) >= SCROLL_TICK)
{
startScroll = Instant.now();
scrollTab(direction);
}
}
private void scrollTab(int direction)
{
maxTabs = (bounds.height - BUTTON_HEIGHT * 2 - MARGIN * 2) / TAB_HEIGHT;
// prevent running into the incinerator
while (bounds.y + maxTabs * TAB_HEIGHT + MARGIN * maxTabs + BUTTON_HEIGHT * 2 + MARGIN > bounds.y + bounds.height)
{
--maxTabs;
}
if (currentTabIndex + direction >= tabManager.size() || currentTabIndex + direction < 0)
{
currentTabIndex = 0;
}
if ((tabManager.size() - (currentTabIndex + direction) >= maxTabs) && (currentTabIndex + direction > -1))
{
currentTabIndex += direction;
}
else if (maxTabs < tabManager.size() && tabManager.size() - (currentTabIndex + direction) < maxTabs)
{
// Edge case when only 1 tab displays instead of up to maxTabs when one is deleted at the end of the list
currentTabIndex += direction;
scrollTab(-1);
}
updateTabs();
}
private void activateTab(TagTab tagTab)
{
if (activeTab != null && activeTab.equals(tagTab))
{
return;
}
if (activeTab != null)
{
Widget tab = activeTab.getBackground();
tab.setSpriteId(TabSprites.TAB_BACKGROUND.getSpriteId());
tab.revalidate();
activeTab = null;
}
if (tagTab != null)
{
Widget tab = tagTab.getBackground();
tab.setSpriteId(TabSprites.TAB_BACKGROUND_ACTIVE.getSpriteId());
tab.revalidate();
activeTab = tagTab;
}
}
private void updateBounds()
{
Widget itemContainer = client.getWidget(WidgetInfo.BANK_ITEM_CONTAINER);
if (itemContainer == null)
{
return;
}
int height = itemContainer.getHeight();
// If player isn't using normal bank tabs
if (itemContainer.getRelativeY() == 0)
{
height -= (TAB_HEIGHT + MARGIN);
}
bounds.setSize(TAB_WIDTH + MARGIN * 2, height);
bounds.setLocation(MARGIN, TAB_HEIGHT + MARGIN);
Widget incinerator = client.getWidget(WidgetInfo.BANK_INCINERATOR);
if (incinerator != null && !incinerator.isHidden())
{
// This is the required way to move incinerator, don't change it!
incinerator.setOriginalHeight(39);
incinerator.setOriginalWidth(48);
incinerator.setRelativeY(itemContainer.getHeight());
incinerator.revalidate();
Widget child = incinerator.getDynamicChildren()[0];
child.setHeight(39);
child.setWidth(48);
child.setType(WidgetType.GRAPHIC);
child.setSpriteId(TabSprites.INCINERATOR.getSpriteId());
bounds.setSize(TAB_WIDTH + MARGIN * 2, height - incinerator.getHeight());
}
if (upButton != null)
{
Point p = upButton.getCanvasLocation();
canvasBounds.setBounds(p.getX(), p.getY() + BUTTON_HEIGHT, bounds.width, maxTabs * TAB_HEIGHT + maxTabs * MARGIN);
}
}
private void updateTabs()
{
int y = bounds.y + MARGIN + BUTTON_HEIGHT;
if (maxTabs >= tabManager.size())
{
currentTabIndex = 0;
}
else
{
y -= (currentTabIndex * TAB_HEIGHT + currentTabIndex * MARGIN);
}
for (TagTab tab : tabManager.getTabs())
{
updateWidget(tab.getBackground(), y);
updateWidget(tab.getIcon(), y + 4);
// Edge case where item icon is 1 pixel out of bounds
tab.getIcon().setHidden(tab.getBackground().isHidden());
// Keep item widget shown while drag scrolling
if (client.getDraggedWidget() == tab.getIcon())
{
tab.getIcon().setHidden(false);
}
y += TAB_HEIGHT + MARGIN;
}
boolean hidden = !(tabManager.size() > 0);
upButton.setHidden(hidden);
upButton.setOriginalY(bounds.y);
upButton.revalidate();
downButton.setHidden(hidden);
downButton.setOriginalY(bounds.y + maxTabs * TAB_HEIGHT + MARGIN * maxTabs + BUTTON_HEIGHT + MARGIN);
downButton.revalidate();
}
private Widget createGraphic(String name, int spriteId, int itemId, int width, int height, int x, int y, boolean hasListener)
{
Widget widget = parent.createChild(-1, WidgetType.GRAPHIC);
widget.setOriginalWidth(width);
widget.setOriginalHeight(height);
widget.setOriginalX(x);
widget.setOriginalY(y);
widget.setSpriteId(spriteId);
if (itemId > -1)
{
widget.setItemId(itemId);
widget.setItemQuantity(-1);
widget.setBorderType(1);
}
if (hasListener)
{
widget.setOnOpListener(ScriptID.NULL);
widget.setHasListener(true);
}
widget.setName(name);
widget.revalidate();
return widget;
}
private void updateWidget(Widget t, int y)
{
t.setOriginalY(y);
t.setRelativeY(y);
t.setHidden(y < (bounds.y + BUTTON_HEIGHT + MARGIN) || y > (bounds.y + bounds.height - TAB_HEIGHT - MARGIN - BUTTON_HEIGHT));
t.revalidate();
}
private void doSearch(InputType inputType, String search)
{
// In case the widget ids array is incorrect, do not proceed
if (widgetIds == null || widgetIds.length < 21)
{
return;
}
clientThread.invokeLater(() ->
{
// 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.setVar(VarClientInt.INPUT_TYPE, inputType.getType());
client.setVar(VarClientStr.INPUT_TEXT, search);
client.runScript(ScriptID.BANK_LAYOUT,
WidgetInfo.BANK_CONTAINER.getId(),
widgetIds[INNER_CONTAINER_IDX],
widgetIds[SETTINGS_IDX],
widgetIds[ITEM_CONTAINER_IDX],
widgetIds[SCROLLBAR_IDX],
widgetIds[BOTTOM_BAR_IDX],
widgetIds[TITLE_BAR_IDX],
widgetIds[ITEM_COUNT_IDX],
widgetIds[SEARCH_BUTTON_BACKGROUND_IDX],
widgetIds[TAB_BAR_IDX],
widgetIds[INCINERATOR_IDX],
widgetIds[INCINERATOR_CONFIRM_IDX],
widgetIds[HIDDEN_WIDGET_IDX]);
});
}
private ItemComposition getItem(int idx)
{
ItemContainer bankContainer = client.getItemContainer(InventoryID.BANK);
Item item = bankContainer.getItems()[idx];
return itemManager.getItemComposition(item.getId());
}
private void openTag(String tag)
{
doSearch(InputType.SEARCH, tag);
activateTab(tabManager.find(tag.substring(4)));
// When tab is selected with search window open, the search window closes but the search button
// stays highlighted, this solves that issue
Widget searchBackground = client.getWidget(WidgetInfo.BANK_SEARCH_BUTTON_BACKGROUND);
searchBackground.setSpriteId(SpriteID.EQUIPMENT_SLOT_TILE);
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* Copyright (c) 2018, Ron Young <https://github.com/raiyni>
* 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.banktags.tabs;
import com.google.common.base.MoreObjects;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.Getter;
import net.runelite.api.ItemID;
import net.runelite.client.config.ConfigManager;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.CONFIG_GROUP;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.ICON_SEARCH;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.JOINER;
import static net.runelite.client.plugins.banktags.BankTagsPlugin.SPLITTER;
import net.runelite.client.util.Text;
import org.apache.commons.lang3.math.NumberUtils;
@Singleton
class TabManager
{
private static final String TAG_TABS_CONFIG = "tagtabs";
@Getter
private final List<TagTab> tabs = new ArrayList<>();
private final ConfigManager configManager;
@Inject
private TabManager(ConfigManager configManager)
{
this.configManager = configManager;
}
void add(TagTab tagTab)
{
if (!contains(tagTab.getTag()))
{
tabs.add(tagTab);
}
}
void clear()
{
tabs.forEach(t -> t.setHidden(true));
tabs.clear();
}
TagTab find(String tag)
{
Optional<TagTab> first = tabs.stream().filter(t -> t.getTag().equals(Text.standardize(tag))).findAny();
return first.orElse(null);
}
List<String> getAllTabs()
{
return SPLITTER.splitToList(MoreObjects.firstNonNull(configManager.getConfiguration(CONFIG_GROUP, TAG_TABS_CONFIG), ""));
}
TagTab load(String tag)
{
TagTab tagTab = find(tag);
if (tagTab == null)
{
tag = Text.standardize(tag);
String item = configManager.getConfiguration(CONFIG_GROUP, ICON_SEARCH + tag);
int itemid = NumberUtils.toInt(item, ItemID.SPADE);
tagTab = new TagTab(itemid, tag);
}
return tagTab;
}
void move(String tagToMove, String tagDestination)
{
tagToMove = Text.standardize(tagToMove);
tagDestination = Text.standardize(tagDestination);
if (contains(tagToMove) && contains(tagDestination))
{
Collections.swap(tabs, indexOf(tagToMove), indexOf(tagDestination));
}
}
void remove(String tag)
{
TagTab tagTab = find(tag);
if (tagTab != null)
{
tagTab.setHidden(true);
tabs.remove(tagTab);
}
}
void save()
{
String tags = JOINER.join(tabs.stream().map(TagTab::getTag).collect(Collectors.toList()));
configManager.setConfiguration(CONFIG_GROUP, TAG_TABS_CONFIG, tags);
}
int size()
{
return tabs.size();
}
private boolean contains(String tag)
{
return tabs.stream().anyMatch(t -> t.getTag().equals(tag));
}
private int indexOf(TagTab tagTab)
{
return tabs.indexOf(tagTab);
}
private int indexOf(String tag)
{
return indexOf(find(tag));
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* Copyright (c) 2018, Ron Young <https://github.com/raiyni>
* 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.banktags.tabs;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.SpritePixels;
import net.runelite.client.util.ImageUtil;
@Slf4j
public enum TabSprites
{
INCINERATOR(-200, "incinerator.png"),
TAB_BACKGROUND(-201, "tag-tab.png"),
TAB_BACKGROUND_ACTIVE(-202, "tag-tab-active.png"),
UP_ARROW(-203, "up-arrow.png"),
DOWN_ARROW(-204, "down-arrow.png"),
NEW_TAB(-205, "new-tab.png");
@Getter
private final int spriteId;
private final BufferedImage image;
TabSprites(final int spriteId, final String imageName)
{
this.spriteId = spriteId;
this.image = ImageUtil.getResourceStreamFromClass(this.getClass(), imageName);
}
public static Map<Integer, SpritePixels> toMap(Client client)
{
final Map<Integer, SpritePixels> map = new HashMap<>();
for (TabSprites value : values())
{
map.put(value.spriteId, getSpritePixels(client, value.image));
}
return map;
}
private static SpritePixels getSpritePixels(Client client, BufferedImage image)
{
int[] pixels = new int[image.getWidth() * image.getHeight()];
try
{
new PixelGrabber(image, 0, 0, image.getWidth(), image.getHeight(), pixels, 0, image.getWidth())
.grabPixels();
}
catch (InterruptedException ex)
{
log.debug("PixelGrabber was interrupted: ", ex);
}
return client.createSpritePixels(pixels, image.getWidth(), image.getHeight());
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2018, Tomas Slusny <slusnucky@gmail.com>
* Copyright (c) 2018, Ron Young <https://github.com/raiyni>
* 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.banktags.tabs;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.runelite.api.widgets.Widget;
@Data
@EqualsAndHashCode(of = "tag")
class TagTab
{
private final String tag;
private int iconItemId;
private Widget background;
private Widget icon;
TagTab(int iconItemId, String tag)
{
this.iconItemId = iconItemId;
this.tag = tag;
}
void setHidden(boolean hide)
{
if (background != null)
{
background.setHidden(hide);
}
if (icon != null)
{
icon.setHidden(hide);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 720 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 759 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B