project: Merge upstream

This commit is contained in:
Owain van Brakel
2020-10-21 12:57:38 +02:00
28 changed files with 968 additions and 278 deletions

View File

@@ -102,7 +102,7 @@ import net.runelite.client.ui.overlay.OverlayRenderer;
import net.runelite.client.ui.overlay.WidgetOverlay;
import net.runelite.client.ui.overlay.arrow.ArrowMinimapOverlay;
import net.runelite.client.ui.overlay.arrow.ArrowWorldOverlay;
import net.runelite.client.ui.overlay.infobox.InfoBoxOverlay;
import net.runelite.client.ui.overlay.infobox.InfoBoxManager;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
import net.runelite.client.ui.overlay.tooltip.TooltipOverlay;
import net.runelite.client.ui.overlay.worldmap.WorldMapOverlay;
@@ -190,7 +190,7 @@ public class RuneLite
private Provider<CommandManager> commandManager;
@Inject
private Provider<InfoBoxOverlay> infoBoxOverlay;
private Provider<InfoBoxManager> infoBoxManager;
@Inject
private Provider<TooltipOverlay> tooltipOverlay;
@@ -511,6 +511,7 @@ public class RuneLite
// Initialize chat colors
chatMessageManager.get().loadColors();
infoBoxManager.get();
overlayRenderer.get();
friendChatManager.get();
itemManager.get();
@@ -522,14 +523,12 @@ public class RuneLite
playerManager.get();
chatboxPanelManager.get();
partyService.get();
infoBoxOverlay.get();
eventBus.subscribe(GameStateChanged.class, this, hooks::onGameStateChanged);
eventBus.subscribe(ScriptCallbackEvent.class, this, hooks::onScriptCallbackEvent);
// Add core overlays
WidgetOverlay.createOverlays(client).forEach(overlayManager::add);
overlayManager.add(infoBoxOverlay.get());
overlayManager.add(worldMapOverlay.get());
overlayManager.add(tooltipOverlay.get());
overlayManager.add(arrowWorldOverlay.get());

View File

@@ -400,12 +400,25 @@ public interface RuneLiteConfig extends Config
return new Title();
}
@ConfigItem(
keyName = "infoBoxTextOutline",
name = "Outline infobox text",
description = "Draw a full outline instead of a simple shadow for infobox text",
position = 31,
titleSection = "infoboxTitle"
)
default boolean infoBoxTextOutline()
{
return false;
}
@ConfigItem(
keyName = "infoBoxVertical",
name = "Display infoboxes vertically",
description = "Toggles the infoboxes to display vertically",
position = 31,
titleSection = "infoboxTitle"
position = 32,
titleSection = "infoboxTitle",
hidden = true
)
default boolean infoBoxVertical()
{
@@ -416,7 +429,7 @@ public interface RuneLiteConfig extends Config
keyName = "infoBoxSize",
name = "Infobox size",
description = "Configures the size of each infobox in pixels",
position = 32,
position = 33,
titleSection = "infoboxTitle"
)
@Units(Units.PIXELS)
@@ -429,7 +442,7 @@ public interface RuneLiteConfig extends Config
keyName = "keybindsTitle",
name = "Key binds",
description = "",
position = 33
position = 34
)
default Title keybindsTitle()
{
@@ -440,7 +453,7 @@ public interface RuneLiteConfig extends Config
keyName = "sidebarToggleKey",
name = "Sidebar Toggle Key",
description = "The key that will toggle the sidebar (accepts modifiers)",
position = 34,
position = 35,
titleSection = "keybindsTitle"
)
default Keybind sidebarToggleKey()
@@ -452,7 +465,7 @@ public interface RuneLiteConfig extends Config
keyName = "panelToggleKey",
name = "Plugin Panel Toggle Key",
description = "The key that will toggle the current or last opened plugin panel (accepts modifiers)",
position = 35,
position = 36,
titleSection = "keybindsTitle"
)
default Keybind panelToggleKey()
@@ -464,7 +477,7 @@ public interface RuneLiteConfig extends Config
keyName = "blockExtraMouseButtons",
name = "Block Extra Mouse Buttons",
description = "Blocks extra mouse buttons (4 and above)",
position = 36,
position = 37,
titleSection = "keybindsTitle"
)
default boolean blockExtraMouseButtons()

View File

@@ -187,6 +187,7 @@ public enum AgilityShortcut
AL_KHARID_WINDOW(70, "Window", new WorldPoint(3293, 3158, 0), BROKEN_WALL_33344, BIG_WINDOW),
GWD_SARADOMIN_ROPE_NORTH(70, "Rope Descent", new WorldPoint(2912, 5300, 0), NULL_26371, NULL_26561),
GWD_SARADOMIN_ROPE_SOUTH(70, "Rope Descent", new WorldPoint(2951, 5267, 0), NULL_26375, NULL_26562),
GU_TANOTH_CRUMBLING_WALL(71, "Rocks", new WorldPoint(2545, 3032, 0), CRUMBLING_WALL_40355, ROCKS_40356),
SLAYER_TOWER_ADVANCED_CHAIN_FIRST(71, "Spiked Chain (Floor 2)", new WorldPoint(3447, 3578, 0), SPIKEY_CHAIN ),
SLAYER_TOWER_ADVANCED_CHAIN_SECOND(71, "Spiked Chain (Floor 3)", new WorldPoint(3446, 3576, 0), SPIKEY_CHAIN_16538),
STRONGHOLD_SLAYER_CAVE_TUNNEL(72, "Tunnel", new WorldPoint(2431, 9806, 0), TUNNEL_30174, TUNNEL_30175),

View File

@@ -32,6 +32,7 @@ import io.reactivex.rxjava3.schedulers.Schedulers;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -276,10 +277,10 @@ public class ItemManager
/**
* Look up an item's price
*
* @param itemID item id
* @param ignoreUntradeableMap should the price returned ignore the {@link UntradeableItemMapping}
* @param itemID item id
* @param ignoreUntradeableMap should the price returned ignore items that are not tradeable for coins in regular way
* @return item price
*/
* */
public int getItemPrice(int itemID, boolean ignoreUntradeableMap)
{
if (itemID == ItemID.COINS_995)
@@ -291,31 +292,38 @@ public class ItemManager
return 1000;
}
ItemDefinition itemComposition = getItemDefinition(itemID);
if (itemComposition.getNote() != -1)
ItemDefinition itemDefinition = getItemDefinition(itemID);
if (itemDefinition.getNote() != -1)
{
itemID = itemComposition.getLinkedNoteId();
itemID = itemDefinition.getLinkedNoteId();
}
itemID = WORN_ITEMS.getOrDefault(itemID, itemID);
if (!ignoreUntradeableMap)
{
UntradeableItemMapping p = UntradeableItemMapping.map(ItemVariationMapping.map(itemID));
if (p != null)
{
return getItemPrice(p.getPriceID()) * p.getQuantity();
}
}
int price = 0;
for (int mappedID : ItemMapping.map(itemID))
final Collection<ItemMapping> mappedItems = ItemMapping.map(itemID);
if (mappedItems == null)
{
ItemPrice ip = itemPrices.get(mappedID);
final ItemPrice ip = itemPrices.get(itemID);
if (ip != null)
{
price += ip.getPrice();
}
}
else
{
for (final ItemMapping mappedItem : mappedItems)
{
if (ignoreUntradeableMap && mappedItem.isUntradeable())
{
continue;
}
price += getItemPrice(mappedItem.getTradeableItem(), ignoreUntradeableMap) * mappedItem.getQuantity();
}
}
return price;
}

View File

@@ -28,12 +28,14 @@ package net.runelite.client.game;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import java.util.Collection;
import java.util.Collections;
import javax.annotation.Nullable;
import lombok.Getter;
import static net.runelite.api.ItemID.*;
/**
* Converts untradeable items to it's tradeable counterparts
*/
@Getter
public enum ItemMapping
{
// Barrows equipment
@@ -249,6 +251,9 @@ public enum ItemMapping
ITEM_CRYSTAL_BOW(CRYSTAL_WEAPON_SEED, CRYSTAL_BOW, CRYSTAL_BOW_24123, CRYSTAL_BOW_INACTIVE),
ITEM_CRYSTAL_HALBERD(CRYSTAL_WEAPON_SEED, CRYSTAL_HALBERD, CRYSTAL_HALBERD_24125, CRYSTAL_HALBERD_INACTIVE),
ITEM_CRYSTAL_SHIELD(CRYSTAL_WEAPON_SEED, CRYSTAL_SHIELD, CRYSTAL_SHIELD_24127, CRYSTAL_SHIELD_INACTIVE),
ITEM_CRYSTAL_HELMET(CRYSTAL_ARMOUR_SEED, CRYSTAL_HELM, CRYSTAL_HELM_INACTIVE),
ITEM_CRYSTAL_LEGS(CRYSTAL_ARMOUR_SEED, 2L, CRYSTAL_LEGS, CRYSTAL_LEGS_INACTIVE),
ITEM_CRYSTAL_BODY(CRYSTAL_ARMOUR_SEED, 3L, CRYSTAL_BODY, CRYSTAL_BODY_INACTIVE),
// Bird nests
ITEM_BIRD_NEST(BIRD_NEST_5075, BIRD_NEST, BIRD_NEST_5071, BIRD_NEST_5072, BIRD_NEST_5073, BIRD_NEST_5074, BIRD_NEST_7413, BIRD_NEST_13653, BIRD_NEST_22798, BIRD_NEST_22800, CLUE_NEST_EASY, CLUE_NEST_MEDIUM, CLUE_NEST_HARD, CLUE_NEST_ELITE),
@@ -256,11 +261,41 @@ public enum ItemMapping
// Ancestral robes
ITEM_ANCESTRAL_HAT(ANCESTRAL_HAT, TWISTED_ANCESTRAL_HAT),
ITEM_ANCESTRAL_ROBE_TOP(ANCESTRAL_ROBE_TOP, TWISTED_ANCESTRAL_ROBE_TOP),
ITEM_ANCESTRAL_ROBE_BOTTOM(ANCESTRAL_ROBE_BOTTOM, TWISTED_ANCESTRAL_ROBE_BOTTOM);
ITEM_ANCESTRAL_ROBE_BOTTOM(ANCESTRAL_ROBE_BOTTOM, TWISTED_ANCESTRAL_ROBE_BOTTOM),
private static final Multimap<Integer, Integer> MAPPINGS = HashMultimap.create();
// Graceful
ITEM_MARK_OF_GRACE(AMYLASE_CRYSTAL, true, 10L, MARK_OF_GRACE),
ITEM_GRACEFUL_HOOD(MARK_OF_GRACE, true, 28L, GRACEFUL_HOOD),
ITEM_GRACEFUL_TOP(MARK_OF_GRACE, true, 44L, GRACEFUL_TOP),
ITEM_GRACEFUL_LEGS(MARK_OF_GRACE, true, 48L, GRACEFUL_LEGS),
ITEM_GRACEFUL_GLOVES(MARK_OF_GRACE, true, 24L, GRACEFUL_GLOVES),
ITEM_GRACEFUL_BOOTS(MARK_OF_GRACE, true, 32L, GRACEFUL_BOOTS),
ITEM_GRACEFUL_CAPE(MARK_OF_GRACE, true, 32L, GRACEFUL_CAPE),
// 10 golden nuggets = 100 soft clay
ITEM_GOLDEN_NUGGET(SOFT_CLAY, true, 10L, GOLDEN_NUGGET),
ITEM_PROSPECTOR_HELMET(GOLDEN_NUGGET, true, 32L, PROSPECTOR_HELMET),
ITEM_PROSPECTOR_JACKET(GOLDEN_NUGGET, true, 48L, PROSPECTOR_JACKET),
ITEM_PROSPECTOR_LEGS(GOLDEN_NUGGET, true, 40L, PROSPECTOR_LEGS),
ITEM_PROSPECTOR_BOOTS(GOLDEN_NUGGET, true, 24L, PROSPECTOR_BOOTS),
// 10 unidentified minerals = 100 soft clay
ITEM_UNIDENTIFIED_MINERALS(SOFT_CLAY, true, 10L, UNIDENTIFIED_MINERALS),
// Converted to coins
ITEM_TATTERED_PAGE(COINS_995, true, 1000L, TATTERED_MOON_PAGE, TATTERED_SUN_PAGE, TATTERED_TEMPLE_PAGE),
ITEM_LONG_BONE(COINS_995, true, 1000L, LONG_BONE),
ITEM_CURVED_BONE(COINS_995, true, 2000L, CURVED_BONE),
ITEM_PERFECT_SHELL(COINS_995, true, 600L, PERFECT_SHELL),
ITEM_PERFECT_SNAIL_SHELL(COINS_995, true, 600L, PERFECT_SNAIL_SHELL),
ITEM_SNAIL_SHELL(COINS_995, true, 600L, SNAIL_SHELL),
ITEM_TORTOISE_SHELL(COINS_995, true, 250L, TORTOISE_SHELL);
private static final Multimap<Integer, ItemMapping> MAPPINGS = HashMultimap.create();
private final int tradeableItem;
private final int[] untradableItems;
private final long quantity;
private final boolean untradeable;
static
{
@@ -268,15 +303,35 @@ public enum ItemMapping
{
for (int itemId : item.untradableItems)
{
MAPPINGS.put(itemId, item.tradeableItem);
if (item.untradeable)
{
for (final Integer variation : ItemVariationMapping.getVariations(itemId))
{
MAPPINGS.put(variation, item);
}
}
MAPPINGS.put(itemId, item);
}
}
}
ItemMapping(int tradeableItem, int... untradableItems)
ItemMapping(int tradeableItem, boolean untradeable, long quantity, int... untradableItems)
{
this.tradeableItem = tradeableItem;
this.untradableItems = untradableItems;
this.quantity = quantity;
this.untradeable = untradeable;
}
ItemMapping(int tradeableItem, long quantity, int... untradableItems)
{
this(tradeableItem, false, quantity, untradableItems);
}
ItemMapping(int tradeableItem, int... untradableItems)
{
this(tradeableItem, 1L, untradableItems);
}
/**
@@ -285,36 +340,19 @@ public enum ItemMapping
* @param itemId the item id
* @return the collection
*/
public static Collection<Integer> map(int itemId)
@Nullable
public static Collection<ItemMapping> map(int itemId)
{
final Collection<Integer> mapping = MAPPINGS.get(itemId);
final Collection<ItemMapping> mapping = MAPPINGS.get(itemId);
if (mapping == null || mapping.isEmpty())
if (mapping.isEmpty())
{
return Collections.singleton(itemId);
return null;
}
return mapping;
}
/**
* Map an item from its untradeable version to its tradeable version
*
* @param itemId
* @return
*/
public static int mapFirst(int itemId)
{
final Collection<Integer> mapping = MAPPINGS.get(itemId);
if (mapping == null || mapping.isEmpty())
{
return itemId;
}
return mapping.iterator().next();
}
public static boolean isMapped(int itemId)
{
return MAPPINGS.containsValue(itemId);

View File

@@ -1,90 +0,0 @@
/*
* Copyright (c) 2018, TheStonedTurtle <https://github.com/TheStonedTurtle>
* 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;
import com.google.common.collect.ImmutableMap;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import net.runelite.api.ItemID;
@Getter
@RequiredArgsConstructor
public enum UntradeableItemMapping
{
MARK_OF_GRACE(ItemID.MARK_OF_GRACE, 10, ItemID.AMYLASE_CRYSTAL),
GRACEFUL_HOOD(ItemID.GRACEFUL_HOOD, 28, ItemID.MARK_OF_GRACE),
GRACEFUL_TOP(ItemID.GRACEFUL_TOP, 44, ItemID.MARK_OF_GRACE),
GRACEFUL_LEGS(ItemID.GRACEFUL_LEGS, 48, ItemID.MARK_OF_GRACE),
GRACEFUL_GLOVES(ItemID.GRACEFUL_GLOVES, 24, ItemID.MARK_OF_GRACE),
GRACEFUL_BOOTS(ItemID.GRACEFUL_BOOTS, 32, ItemID.MARK_OF_GRACE),
GRACEFUL_CAPE(ItemID.GRACEFUL_CAPE, 32, ItemID.MARK_OF_GRACE),
// 10 golden nuggets = 100 soft clay
GOLDEN_NUGGET(ItemID.GOLDEN_NUGGET, 10, ItemID.SOFT_CLAY),
PROSPECTOR_HELMET(ItemID.PROSPECTOR_HELMET, 32, ItemID.GOLDEN_NUGGET),
PROSPECTOR_JACKET(ItemID.PROSPECTOR_JACKET, 48, ItemID.GOLDEN_NUGGET),
PROSPECTOR_LEGS(ItemID.PROSPECTOR_LEGS, 40, ItemID.GOLDEN_NUGGET),
PROSPECTOR_BOOTS(ItemID.PROSPECTOR_BOOTS, 24, ItemID.GOLDEN_NUGGET),
CRYSTAL_HELMET(ItemID.CRYSTAL_HELM, 1, ItemID.CRYSTAL_ARMOUR_SEED),
CRYSTAL_HELMET_INACTIVE(ItemID.CRYSTAL_HELM_INACTIVE, 1, ItemID.CRYSTAL_ARMOUR_SEED),
CRYSTAL_LEGS(ItemID.CRYSTAL_LEGS, 2, ItemID.CRYSTAL_ARMOUR_SEED),
CRYSTAL_LEGS_INACTIVE(ItemID.CRYSTAL_LEGS_INACTIVE, 2, ItemID.CRYSTAL_ARMOUR_SEED),
CRYSTAL_BODY(ItemID.CRYSTAL_BODY, 3, ItemID.CRYSTAL_ARMOUR_SEED),
CRYSTAL_BODY_INACTIVE(ItemID.CRYSTAL_BODY_INACTIVE, 3, ItemID.CRYSTAL_ARMOUR_SEED),
TATTERED_MOON_PAGE(ItemID.TATTERED_MOON_PAGE, 1000, ItemID.COINS_995),
TATTERED_SUN_PAGE(ItemID.TATTERED_SUN_PAGE, 1000, ItemID.COINS_995),
TATTERED_TEMPLE_PAGE(ItemID.TATTERED_TEMPLE_PAGE, 1000, ItemID.COINS_995),
LONG_BONE(ItemID.LONG_BONE, 1000, ItemID.COINS_995),
CURVED_BONE(ItemID.CURVED_BONE, 2000, ItemID.COINS_995),
PERFECT_SHELL(ItemID.PERFECT_SHELL, 600, ItemID.COINS_995),
PERFECT_SNAIL_SHELL(ItemID.PERFECT_SNAIL_SHELL, 600, ItemID.COINS_995),
SNAIL_SHELL(ItemID.SNAIL_SHELL, 600, ItemID.COINS_995),
TORTOISE_SHELL(ItemID.TORTOISE_SHELL, 250, ItemID.COINS_995);
private static final ImmutableMap<Integer, UntradeableItemMapping> UNTRADEABLE_RECLAIM_MAP;
private final int itemID;
private final int quantity;
private final int priceID;
static
{
ImmutableMap.Builder<Integer, UntradeableItemMapping> map = ImmutableMap.builder();
for (UntradeableItemMapping p : values())
{
map.put(p.getItemID(), p);
}
UNTRADEABLE_RECLAIM_MAP = map.build();
}
public static UntradeableItemMapping map(int itemId)
{
return UNTRADEABLE_RECLAIM_MAP.get(itemId);
}
}

View File

@@ -30,10 +30,12 @@ import java.util.concurrent.CopyOnWriteArrayList;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
@Singleton
@Slf4j
public class KeyManager
{
private final Client client;
@@ -50,13 +52,18 @@ public class KeyManager
{
if (!keyListeners.contains(keyListener))
{
log.debug("Registering key listener: {}", keyListener);
keyListeners.add(keyListener);
}
}
public void unregisterKeyListener(KeyListener keyListener)
{
keyListeners.remove(keyListener);
final boolean unregistered = keyListeners.remove(keyListener);
if (unregistered)
{
log.debug("Unregistered key listener: {}", keyListener);
}
}
public void processKeyPressed(KeyEvent keyEvent)
@@ -73,9 +80,12 @@ public class KeyManager
continue;
}
log.trace("Processing key pressed {} for key listener {}", keyEvent.paramString(), keyListener);
keyListener.keyPressed(keyEvent);
if (keyEvent.isConsumed())
{
log.debug("Consuming key pressed {} for key listener {}", keyEvent.paramString(), keyListener);
break;
}
}
@@ -95,9 +105,12 @@ public class KeyManager
continue;
}
log.trace("Processing key released {} for key listener {}", keyEvent.paramString(), keyListener);
keyListener.keyReleased(keyEvent);
if (keyEvent.isConsumed())
{
log.debug("Consuming key released {} for listener {}", keyEvent.paramString(), keyListener);
break;
}
}
@@ -117,9 +130,12 @@ public class KeyManager
continue;
}
log.trace("Processing key typed {} for key listener {}", keyEvent.paramString(), keyListener);
keyListener.keyTyped(keyEvent);
if (keyEvent.isConsumed())
{
log.debug("Consuming key typed {} for key listener {}", keyEvent.paramString(), keyListener);
break;
}
}

View File

@@ -24,6 +24,7 @@
*/
package net.runelite.client.plugins.config;
import com.google.common.base.Splitter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
@@ -102,6 +103,7 @@ public class PluginListPanel extends PluginPanel
private static final String RUNELITE_GROUP_NAME = RuneLiteConfig.class.getAnnotation(ConfigGroup.class).value();
private static final String PINNED_PLUGINS_CONFIG_KEY = "pinnedPlugins";
private static final Splitter SPLITTER = Splitter.on(" ").trimResults().omitEmptyStrings();
private static final List<String> CATEGORY_TAGS = List.of(
"Combat",
"Chat",
@@ -443,10 +445,9 @@ public class PluginListPanel extends PluginPanel
}
else
{
final String[] searchTerms = text.toLowerCase().split(" ");
pluginList.forEach(listItem ->
{
if (pinned == listItem.isPinned() && Text.matchesSearchTerms(searchTerms, listItem.getKeywords()))
if (pinned == listItem.isPinned() && Text.matchesSearchTerms(SPLITTER.split(text.toLowerCase()), listItem.getKeywords()))
{
if (openOSRSConfig.pluginSortMode() == OpenOSRSConfig.SortStyle.ALPHABETICALLY || (!openOSRSConfig.enableCategories() && (openOSRSConfig.pluginSortMode() != OpenOSRSConfig.SortStyle.REPOSITORY)))
{

View File

@@ -24,6 +24,7 @@
*/
package net.runelite.client.ui;
import com.google.common.annotations.VisibleForTesting;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
@@ -49,6 +50,7 @@ public class ContainableFrame extends JFrame
NEVER
}
private static final int SCREEN_EDGE_CLOSE_DISTANCE = 40;
private static boolean jdk8231564;
static
@@ -56,9 +58,7 @@ public class ContainableFrame extends JFrame
try
{
String javaVersion = System.getProperty("java.version");
String[] s = javaVersion.split("\\.");
int major = Integer.parseInt(s[0]), minor = Integer.parseInt(s[1]), patch = Integer.parseInt(s[2]);
jdk8231564 = major > 11 || (major == 11 && minor > 0) || (major == 11 && minor == 0 && patch >= 8);
jdk8231564 = jdk8231564(javaVersion);
}
catch (Exception ex)
{
@@ -66,7 +66,23 @@ public class ContainableFrame extends JFrame
}
}
private static final int SCREEN_EDGE_CLOSE_DISTANCE = 40;
@VisibleForTesting
static boolean jdk8231564(String javaVersion)
{
int idx = javaVersion.indexOf('_');
if (idx != -1)
{
javaVersion = javaVersion.substring(0, idx);
}
String[] s = javaVersion.split("\\.");
int major = Integer.parseInt(s[0]), minor = Integer.parseInt(s[1]), patch = Integer.parseInt(s[2]);
if (major == 12 || major == 13 || major == 14)
{
// These versions are since EOL & do not include JDK-8231564
return false;
}
return major > 11 || (major == 11 && minor > 0) || (major == 11 && minor == 0 && patch >= 8);
}
@Setter
private ExpandResizeType expandResizeType;

View File

@@ -30,6 +30,7 @@ import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import net.runelite.client.plugins.Plugin;
@@ -52,6 +53,13 @@ public abstract class Overlay implements LayoutableRenderableEntity
private boolean resizable;
private boolean resettable = true;
/**
* Whether this overlay can be dragged onto other overlays & have
* other overlays dragged onto it.
*/
@Setter(AccessLevel.PROTECTED)
private boolean dragTargetable;
protected Overlay()
{
plugin = null;
@@ -75,4 +83,17 @@ public abstract class Overlay implements LayoutableRenderableEntity
public void onMouseOver()
{
}
/**
* Called when an overlay is dragged onto this, if dragTargetable is true.
* Return true to consume the mouse event and prevent the other
* overlay from being moved
*
* @param other the overlay being dragged
* @return
*/
public boolean onDrag(Overlay other)
{
return false;
}
}

View File

@@ -49,6 +49,7 @@ import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.GameState;
import net.runelite.api.KeyCode;
import net.runelite.api.MenuEntry;
import net.runelite.api.events.BeforeRender;
import net.runelite.api.events.ClientTick;
@@ -80,6 +81,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
private static final Color SNAP_CORNER_ACTIVE_COLOR = new Color(0, 255, 0, 100);
private static final Color MOVING_OVERLAY_COLOR = new Color(255, 255, 0, 100);
private static final Color MOVING_OVERLAY_ACTIVE_COLOR = new Color(255, 255, 0, 200);
private static final Color MOVING_OVERLAY_TARGET_COLOR = Color.RED;
private static final Color MOVING_OVERLAY_RESIZING_COLOR = new Color(255, 0, 255, 200);
private final Client client;
private final OverlayManager overlayManager;
@@ -90,11 +92,11 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
private final Point overlayOffset = new Point();
private final Point mousePosition = new Point();
private Overlay currentManagedOverlay;
private Overlay dragTargetOverlay;
private Rectangle currentManagedBounds;
private boolean inOverlayManagingMode;
private boolean inOverlayResizingMode;
private boolean inOverlayDraggingMode;
private boolean inMenuEntryMode;
private boolean startedMovingOverlay;
private MenuEntry[] menuEntries;
@@ -141,7 +143,6 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
resetOverlayManagementMode();
}
inMenuEntryMode = false;
menuEntries = null;
}
}
@@ -153,7 +154,8 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
return;
}
if (!inMenuEntryMode && runeLiteConfig.menuEntryShift())
final boolean shift = client.isKeyPressed(KeyCode.KC_SHIFT);
if (!shift && runeLiteConfig.menuEntryShift())
{
return;
}
@@ -313,15 +315,28 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
{
if (inOverlayManagingMode)
{
Color boundsColor;
if (inOverlayResizingMode && currentManagedOverlay == overlay)
{
graphics.setColor(MOVING_OVERLAY_RESIZING_COLOR);
boundsColor = MOVING_OVERLAY_RESIZING_COLOR;
}
else if (inOverlayDraggingMode && currentManagedOverlay == overlay)
{
boundsColor = MOVING_OVERLAY_ACTIVE_COLOR;
}
else if (inOverlayDraggingMode && overlay.isDragTargetable() && currentManagedOverlay.isDragTargetable()
&& currentManagedOverlay.getBounds().intersects(bounds))
{
boundsColor = MOVING_OVERLAY_TARGET_COLOR;
assert currentManagedOverlay != overlay;
dragTargetOverlay = overlay;
}
else
{
graphics.setColor(inOverlayDraggingMode && currentManagedOverlay == overlay ? MOVING_OVERLAY_ACTIVE_COLOR : MOVING_OVERLAY_COLOR);
boundsColor = MOVING_OVERLAY_COLOR;
}
graphics.setColor(boundsColor);
graphics.draw(bounds);
graphics.setPaint(paint);
}
@@ -402,6 +417,12 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
{
for (Overlay overlay : overlayManager.getOverlays())
{
if (overlay.getPosition() == OverlayPosition.DYNAMIC || overlay.getPosition() == OverlayPosition.TOOLTIP)
{
// never allow moving dynamic or tooltip overlays
continue;
}
final Rectangle bounds = overlay.getBounds();
if (bounds.contains(mousePoint))
{
@@ -472,6 +493,12 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
return mouseEvent;
}
if (dragTargetOverlay != null && !currentManagedOverlay.getBounds().intersects(dragTargetOverlay.getBounds()))
{
// No longer over drag target
dragTargetOverlay = null;
}
final Rectangle canvasRect = new Rectangle(client.getRealDimensions());
if (!canvasRect.contains(p))
@@ -598,7 +625,17 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
mousePosition.setLocation(-1, -1);
// do not snapcorner detached overlays
if (dragTargetOverlay != null)
{
if (dragTargetOverlay.onDrag(currentManagedOverlay))
{
mouseEvent.consume();
resetOverlayManagementMode();
return mouseEvent;
}
}
// Check if the overlay is over a snapcorner and move it if so, unless it is a detached overlay
if (currentManagedOverlay.getPosition() != OverlayPosition.DETACHED && inOverlayDraggingMode)
{
final OverlayBounds snapCorners = this.snapCorners.translated(-SNAP_CORNER_SIZE.width, -SNAP_CORNER_SIZE.height);
@@ -640,11 +677,6 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
{
inOverlayManagingMode = true;
}
if (e.isShiftDown() && runeLiteConfig.menuEntryShift())
{
inMenuEntryMode = true;
}
}
@Override
@@ -655,11 +687,6 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
inOverlayManagingMode = false;
resetOverlayManagementMode();
}
if (!e.isShiftDown())
{
inMenuEntryMode = false;
}
}
private void safeRender(Client client, Overlay overlay, OverlayLayer layer, Graphics2D graphics, Point point)
@@ -750,6 +777,7 @@ public class OverlayRenderer extends MouseAdapter implements KeyListener
inOverlayResizingMode = false;
inOverlayDraggingMode = false;
currentManagedOverlay = null;
dragTargetOverlay = null;
currentManagedBounds = null;
clientUI.setCursor(clientUI.getDefaultCursor());
}

View File

@@ -53,6 +53,7 @@ public class InfoBoxComponent implements LayoutableRenderableEntity
private Dimension preferredSize = new Dimension(DEFAULT_SIZE, DEFAULT_SIZE);
private String text;
private Color color = Color.WHITE;
private boolean outline;
private Color backgroundColor = ComponentConstants.STANDARD_BACKGROUND_COLOR;
private BufferedImage image;
@Getter
@@ -93,6 +94,7 @@ public class InfoBoxComponent implements LayoutableRenderableEntity
{
final TextComponent textComponent = new TextComponent();
textComponent.setColor(color);
textComponent.setOutline(outline);
textComponent.setText(text);
textComponent.setPosition(new Point(baseX + ((size - metrics.stringWidth(text)) / 2), baseY + size - SEPARATOR));
textComponent.render(graphics);

View File

@@ -114,7 +114,7 @@ public class ProgressBarComponent implements LayoutableRenderableEntity
// Draw bar
graphics.setColor(backgroundColor);
graphics.fillRect(barX, barY, width, height);
graphics.fillRect(barX + progressFill, barY, width - progressFill, height);
graphics.setColor(foregroundColor);
graphics.fillRect(barX, barY, progressFill, height);

View File

@@ -81,4 +81,11 @@ public abstract class InfoBox
{
return false;
}
public String getName()
{
// Use a combination of plugin name and infobox implementation name to try and make each infobox as unique
// as possible by default
return plugin.getClass().getSimpleName() + "_" + getClass().getSimpleName();
}
}

View File

@@ -24,43 +24,112 @@
*/
package net.runelite.client.ui.overlay.infobox;
import com.google.common.base.Strings;
import com.google.common.collect.ComparisonChain;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
import net.runelite.api.Client;
import net.runelite.api.MenuOpcode;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.ConfigChanged;
import net.runelite.client.events.InfoBoxMenuClicked;
import net.runelite.client.ui.overlay.OverlayManager;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.components.ComponentOrientation;
import net.runelite.client.ui.overlay.tooltip.TooltipManager;
import net.runelite.client.util.AsyncBufferedImage;
@Singleton
@Slf4j
public class InfoBoxManager
{
private final List<InfoBox> infoBoxes = new CopyOnWriteArrayList<>();
private static final String INFOBOXLAYER_KEY = "infoboxlayer";
private static final String INFOBOXOVERLAY_KEY = "infoboxoverlay";
private static final String INFOBOXOVERLAY_ORIENTATION_PREFIX = "orient_";
private static final String DEFAULT_LAYER = "InfoBoxOverlay";
private static final String DETACH = "Detach";
private static final String FLIP = "Flip";
private static final String DELETE = "Delete";
private static final OverlayMenuEntry DETACH_ME = new OverlayMenuEntry(MenuOpcode.RUNELITE_INFOBOX, DETACH, "InfoBox");
private static final OverlayMenuEntry FLIP_ME = new OverlayMenuEntry(MenuOpcode.RUNELITE_INFOBOX, FLIP, "InfoBox Group");
private static final OverlayMenuEntry DELETE_ME = new OverlayMenuEntry(MenuOpcode.RUNELITE_INFOBOX, DELETE, "InfoBox Group");
private final Map<String, InfoBoxOverlay> layers = new ConcurrentHashMap<>();
private final RuneLiteConfig runeLiteConfig;
private final TooltipManager tooltipManager;
private final Client client;
private final EventBus eventBus;
private final OverlayManager overlayManager;
private final ConfigManager configManager;
@Inject
private InfoBoxManager(final RuneLiteConfig runeLiteConfig, final EventBus eventbus)
private InfoBoxManager(final RuneLiteConfig runeLiteConfig,
final TooltipManager tooltipManager,
final Client client,
final EventBus eventBus,
final OverlayManager overlayManager,
final ConfigManager configManager,
final EventBus eventbus)
{
this.runeLiteConfig = runeLiteConfig;
this.tooltipManager = tooltipManager;
this.client = client;
this.eventBus = eventBus;
this.overlayManager = overlayManager;
this.configManager = configManager;
eventbus.subscribe(ConfigChanged.class, this, this::onConfigChanged);
eventbus.subscribe(InfoBoxMenuClicked.class, this, this::onInfoBoxMenuClicked);
}
private void onConfigChanged(ConfigChanged event)
{
if (event.getGroup().equals("runelite") && event.getKey().equals("infoBoxSize"))
{
infoBoxes.forEach(this::updateInfoBoxImage);
layers.values().forEach(l -> l.getInfoBoxes().forEach(this::updateInfoBoxImage));
}
}
private void onInfoBoxMenuClicked(InfoBoxMenuClicked event)
{
if (DETACH.equals(event.getEntry().getOption()))
{
// The layer name doesn't matter as long as it is unique
splitInfobox(event.getInfoBox().getName() + "_" + System.currentTimeMillis(), event.getInfoBox());
}
else if (FLIP.equals(event.getEntry().getOption()))
{
InfoBoxOverlay infoBoxOverlay = layers.get(getLayer(event.getInfoBox()));
ComponentOrientation newOrientation = infoBoxOverlay.flip();
setOrientation(infoBoxOverlay.getName(), newOrientation);
}
else if (DELETE.equals(event.getEntry().getOption()))
{
// This is just a merge into the default layer
InfoBoxOverlay source = layers.get(getLayer(event.getInfoBox()));
InfoBoxOverlay dest = layers.computeIfAbsent(DEFAULT_LAYER, this::makeOverlay);
if (source != dest)
{
mergeInfoBoxes(source, dest);
}
}
}
@@ -71,14 +140,25 @@ public class InfoBoxManager
updateInfoBoxImage(infoBox);
String layerName = getLayer(infoBox);
InfoBoxOverlay overlay = layers.computeIfAbsent(layerName, this::makeOverlay);
List<OverlayMenuEntry> menuEntries = infoBox.getMenuEntries();
menuEntries.add(DETACH_ME);
menuEntries.add(FLIP_ME);
if (!layerName.equals(DEFAULT_LAYER))
{
// Non default-group infoboxes have a delete option to delete the group
menuEntries.add(DELETE_ME);
}
synchronized (this)
{
int idx = findInsertionIndex(infoBoxes, infoBox, (b1, b2) -> ComparisonChain
int idx = findInsertionIndex(overlay.getInfoBoxes(), infoBox, (b1, b2) -> ComparisonChain
.start()
.compare(b1.getPriority(), b2.getPriority())
.compare(b1.getPlugin().getName(), b2.getPlugin().getName())
.result());
infoBoxes.add(idx, infoBox);
overlay.getInfoBoxes().add(idx, infoBox);
}
BufferedImage image = infoBox.getImage();
@@ -92,28 +172,40 @@ public class InfoBoxManager
public synchronized void removeInfoBox(InfoBox infoBox)
{
if (infoBoxes.remove(infoBox))
if (infoBox == null)
{
return;
}
if (layers.get(getLayer(infoBox)).getInfoBoxes().remove(infoBox))
{
log.debug("Removed InfoBox {}", infoBox);
}
infoBox.getMenuEntries().remove(DETACH_ME);
infoBox.getMenuEntries().remove(FLIP_ME);
infoBox.getMenuEntries().remove(DELETE_ME);
}
public synchronized void removeIf(Predicate<InfoBox> filter)
{
if (infoBoxes.removeIf(filter))
for (InfoBoxOverlay overlay : layers.values())
{
log.debug("Removed InfoBoxes for filter {}", filter);
if (overlay.getInfoBoxes().removeIf(filter))
{
log.debug("Removed InfoBoxes for filter {} from {}", filter, overlay);
}
}
}
public List<InfoBox> getInfoBoxes()
{
return Collections.unmodifiableList(infoBoxes);
return layers.values().stream().map(InfoBoxOverlay::getInfoBoxes).flatMap(Collection::stream).collect(Collectors.toList());
}
public synchronized void cull()
{
infoBoxes.removeIf(InfoBox::cull);
layers.values().forEach(l -> l.getInfoBoxes().removeIf(InfoBox::cull));
}
public void updateInfoBoxImage(final InfoBox infoBox)
@@ -152,9 +244,144 @@ public class InfoBoxManager
infoBox.setScaledImage(resultImage);
}
private InfoBoxOverlay makeOverlay(String name)
{
ComponentOrientation orientation = getOrientation(name);
if (orientation == null)
{
if (name.equals(DEFAULT_LAYER))
{
// Fall back to old orientation config option
orientation = runeLiteConfig.infoBoxVertical() ? ComponentOrientation.VERTICAL : ComponentOrientation.HORIZONTAL;
setOrientation(name, orientation);
}
else
{
// Default infobox orientation
orientation = ComponentOrientation.HORIZONTAL;
}
}
InfoBoxOverlay infoBoxOverlay = new InfoBoxOverlay(
this,
tooltipManager,
client,
runeLiteConfig,
eventBus,
name,
orientation);
overlayManager.add(infoBoxOverlay);
return infoBoxOverlay;
}
private void removeOverlay(InfoBoxOverlay overlay)
{
unsetOrientation(overlay.getName());
eventBus.unregister(overlay);
overlayManager.remove(overlay);
layers.remove(overlay.getName());
}
private synchronized void splitInfobox(String newLayer, InfoBox infoBox)
{
String layer = getLayer(infoBox);
InfoBoxOverlay oldOverlay = layers.get(layer);
// Find all infoboxes with the same name, as they are all within the same group and so move at once.
Collection<InfoBox> filtered = oldOverlay.getInfoBoxes().stream()
.filter(i -> i.getName().equals(infoBox.getName())).collect(Collectors.toList());
oldOverlay.getInfoBoxes().removeAll(filtered);
if (oldOverlay.getInfoBoxes().isEmpty())
{
log.debug("Deleted layer: {}", oldOverlay.getName());
removeOverlay(oldOverlay);
}
InfoBoxOverlay newOverlay = layers.computeIfAbsent(newLayer, this::makeOverlay);
newOverlay.getInfoBoxes().addAll(filtered);
// Adjust config for new infoboxes
for (InfoBox i : filtered)
{
setLayer(i, newLayer);
if (!i.getMenuEntries().contains(DELETE_ME))
{
i.getMenuEntries().add(DELETE_ME);
}
}
log.debug("Moving infobox named {} (layer {}) to layer {}: {} boxes", infoBox.getName(), layer, newLayer, filtered.size());
}
public synchronized void mergeInfoBoxes(InfoBoxOverlay source, InfoBoxOverlay dest)
{
Collection<InfoBox> infoBoxesToMove = source.getInfoBoxes();
boolean isDefault = dest.getName().equals(DEFAULT_LAYER);
log.debug("Merging InfoBoxes from {} into {} ({} boxes)", source.getName(), dest.getName(), infoBoxesToMove.size());
for (InfoBox infoBox : infoBoxesToMove)
{
setLayer(infoBox, dest.getName());
if (isDefault)
{
infoBox.getMenuEntries().remove(DELETE_ME);
}
}
dest.getInfoBoxes().addAll(infoBoxesToMove);
source.getInfoBoxes().clear();
// remove source
removeOverlay(source);
log.debug("Deleted layer: {}", source.getName());
}
private String getLayer(InfoBox infoBox)
{
String name = configManager.getConfiguration(INFOBOXLAYER_KEY, infoBox.getName());
if (Strings.isNullOrEmpty(name))
{
return DEFAULT_LAYER;
}
return name;
}
private void setLayer(InfoBox infoBox, String layer)
{
if (layer.equals(DEFAULT_LAYER))
{
configManager.unsetConfiguration(INFOBOXLAYER_KEY, infoBox.getName());
}
else
{
configManager.setConfiguration(INFOBOXLAYER_KEY, infoBox.getName(), layer);
}
}
ComponentOrientation getOrientation(String name)
{
return configManager.getConfiguration(INFOBOXOVERLAY_KEY, INFOBOXOVERLAY_ORIENTATION_PREFIX + name, ComponentOrientation.class);
}
void setOrientation(String name, ComponentOrientation orientation)
{
configManager.setConfiguration(INFOBOXOVERLAY_KEY, INFOBOXOVERLAY_ORIENTATION_PREFIX + name, orientation);
}
void unsetOrientation(String name)
{
configManager.unsetConfiguration(INFOBOXOVERLAY_KEY, INFOBOXOVERLAY_ORIENTATION_PREFIX + name);
}
/**
* Find insertion point for the given key into the given sorted list. If key already exists in the list,
* return the index after the last occurrence.
*
* @param list
* @param key
* @param c

View File

@@ -33,14 +33,17 @@ import java.awt.Point;
import java.awt.Rectangle;
import java.util.Collections;
import java.util.List;
import javax.inject.Inject;
import java.util.concurrent.CopyOnWriteArrayList;
import javax.inject.Singleton;
import lombok.Getter;
import lombok.NonNull;
import net.runelite.api.Client;
import net.runelite.api.MenuOpcode;
import net.runelite.api.events.MenuOptionClicked;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.eventbus.EventBus;
import net.runelite.client.events.InfoBoxMenuClicked;
import net.runelite.client.ui.overlay.Overlay;
import net.runelite.client.ui.overlay.OverlayMenuEntry;
import net.runelite.client.ui.overlay.OverlayPanel;
import net.runelite.client.ui.overlay.OverlayPosition;
@@ -61,24 +64,33 @@ public class InfoBoxOverlay extends OverlayPanel
private final Client client;
private final RuneLiteConfig config;
private final EventBus eventBus;
private final String name;
private ComponentOrientation orientation;
@Getter
private final List<InfoBox> infoBoxes = new CopyOnWriteArrayList<>();
private InfoBoxComponent hoveredComponent;
@Inject
private InfoBoxOverlay(
InfoBoxOverlay(
InfoBoxManager infoboxManager,
TooltipManager tooltipManager,
Client client,
RuneLiteConfig config,
EventBus eventBus)
EventBus eventBus,
String name,
@NonNull ComponentOrientation orientation)
{
this.tooltipManager = tooltipManager;
this.infoboxManager = infoboxManager;
this.client = client;
this.config = config;
this.eventBus = eventBus;
this.name = name;
this.orientation = orientation;
setPosition(OverlayPosition.TOP_LEFT);
setClearChildren(false);
setDragTargetable(true);
panelComponent.setWrap(true);
panelComponent.setBackgroundColor(null);
@@ -88,11 +100,15 @@ public class InfoBoxOverlay extends OverlayPanel
eventBus.subscribe(MenuOptionClicked.class, this, this::onMenuOptionClicked);
}
@Override
public String getName()
{
return this.name;
}
@Override
public Dimension render(Graphics2D graphics)
{
final List<InfoBox> infoBoxes = infoboxManager.getInfoBoxes();
final boolean menuOpen = client.isMenuOpen();
if (!menuOpen)
{
@@ -107,9 +123,7 @@ public class InfoBoxOverlay extends OverlayPanel
// Set preferred size to the size of DEFAULT_WRAP_COUNT infoboxes, including the padding - which is applied
// to the last infobox prior to wrapping too.
panelComponent.setPreferredSize(new Dimension(DEFAULT_WRAP_COUNT * (config.infoBoxSize() + GAP), DEFAULT_WRAP_COUNT * (config.infoBoxSize() + GAP)));
panelComponent.setOrientation(config.infoBoxVertical()
? ComponentOrientation.VERTICAL
: ComponentOrientation.HORIZONTAL);
panelComponent.setOrientation(orientation);
for (InfoBox box : infoBoxes)
{
@@ -127,6 +141,7 @@ public class InfoBoxOverlay extends OverlayPanel
{
infoBoxComponent.setColor(color);
}
infoBoxComponent.setOutline(config.infoBoxTextOutline());
infoBoxComponent.setImage(box.getScaledImage());
infoBoxComponent.setTooltip(box.getTooltip());
infoBoxComponent.setPreferredSize(new Dimension(config.infoBoxSize(), config.infoBoxSize()));
@@ -177,7 +192,7 @@ public class InfoBoxOverlay extends OverlayPanel
public void onMenuOptionClicked(MenuOptionClicked menuOptionClicked)
{
if (menuOptionClicked.getMenuOpcode() != MenuOpcode.RUNELITE_INFOBOX)
if (menuOptionClicked.getMenuOpcode() != MenuOpcode.RUNELITE_INFOBOX || hoveredComponent == null)
{
return;
}
@@ -187,4 +202,21 @@ public class InfoBoxOverlay extends OverlayPanel
.filter(me -> me.getOption().equals(menuOptionClicked.getOption()))
.findAny().ifPresent(overlayMenuEntry -> eventBus.post(InfoBoxMenuClicked.class, new InfoBoxMenuClicked(overlayMenuEntry, infoBox)));
}
@Override
public boolean onDrag(Overlay source)
{
if (!(source instanceof InfoBoxOverlay))
{
return false;
}
infoboxManager.mergeInfoBoxes((InfoBoxOverlay) source, this);
return true;
}
ComponentOrientation flip()
{
return orientation = orientation == ComponentOrientation.HORIZONTAL ? ComponentOrientation.VERTICAL : ComponentOrientation.HORIZONTAL;
}
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright (c) 2020, Adam <Adam@sigterm.info>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package net.runelite.client.ui;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class ContainableFrameTest
{
@Test
public void testJdk8231564()
{
assertTrue(ContainableFrame.jdk8231564("11.0.8"));
assertFalse(ContainableFrame.jdk8231564("11.0.7"));
assertFalse(ContainableFrame.jdk8231564("1.8.0_261"));
assertFalse(ContainableFrame.jdk8231564("12.0.0"));
assertFalse(ContainableFrame.jdk8231564("13.0.0"));
assertFalse(ContainableFrame.jdk8231564("14.0.0"));
}
}

View File

@@ -32,6 +32,8 @@ import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import javax.inject.Inject;
import net.runelite.api.Client;
import net.runelite.client.config.ConfigManager;
import net.runelite.client.config.OpenOSRSConfig;
import net.runelite.client.config.RuneLiteConfig;
import net.runelite.client.plugins.Plugin;
@@ -58,6 +60,14 @@ public class InfoBoxManagerTest
@Bind
private OpenOSRSConfig openOSRSConfig;
@Mock
@Bind
private ConfigManager configManager;
@Mock
@Bind
private Client client;
@Before
public void before()
{

View File

@@ -28,8 +28,6 @@ import java.awt.Color;
import java.util.HashMap;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class ColorUtilTest
@@ -97,26 +95,4 @@ public class ColorUtilTest
COLOR_HEXSTRING_MAP.forEach((color, hex) ->
assertEquals(hex, ColorUtil.colorToHexCode(color)));
}
@Test
public void isFullyTransparent()
{
for (Color color : COLOR_HEXSTRING_MAP.keySet())
{
assertFalse(ColorUtil.isFullyTransparent(color));
}
assertTrue(ColorUtil.isFullyTransparent(new Color(0, 0, 0, 0)));
assertFalse(ColorUtil.isFullyTransparent(new Color(0, 0, 0, 1)));
}
@Test
public void isNotFullyTransparent()
{
for (Color color : COLOR_HEXSTRING_MAP.keySet())
{
assertTrue(ColorUtil.isNotFullyTransparent(color));
}
assertFalse(ColorUtil.isNotFullyTransparent(new Color(0, 0, 0, 0)));
assertTrue(ColorUtil.isNotFullyTransparent(new Color(0, 0, 0, 1)));
}
}

View File

@@ -35,7 +35,6 @@ import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferInt;
import java.util.Arrays;
import java.util.function.Predicate;
import javax.annotation.Nonnull;
import org.apache.commons.lang3.ArrayUtils;
import static org.junit.Assert.assertEquals;
@@ -256,11 +255,6 @@ public class ImageUtilTest
assertTrue(bufferedImagesEqual(centeredPixel(GRAY), ImageUtil.fillImage(centeredPixel(BLACK), GRAY)));
assertTrue(bufferedImagesEqual(solidColor(3, 3, GREEN), ImageUtil.fillImage(solidColor(3, 3, BLACK), GREEN)));
assertTrue(bufferedImagesEqual(oneByOne(BLACK_TRANSPARENT), ImageUtil.fillImage(oneByOne(BLACK_TRANSPARENT), WHITE)));
// fillImage(BufferedImage image, Color color, Predicate<Color> fillCondition)
BufferedImage expected = solidColor(CORNER_SIZE, CORNER_SIZE, WHITE);
expected.setRGB(0, 0, new Color(0, true).getRGB());
assertTrue(bufferedImagesEqual(expected, ImageUtil.fillImage(BLACK_PIXEL_TOP_LEFT, WHITE, ColorUtil::isFullyTransparent)));
}
@Test
@@ -287,39 +281,11 @@ public class ImageUtilTest
expected.setRGB(1, 1, new Color(0, true).getRGB());
assertTrue(bufferedImagesEqual(expected, ImageUtil.outlineImage(BLACK_PIXEL_TOP_LEFT, WHITE)));
// outlineImage(BufferedImage image, Color color, Predicate<Color> fillCondition)
BufferedImage test = new BufferedImage(CORNER_SIZE, CORNER_SIZE, BufferedImage.TYPE_INT_ARGB);
test.setRGB(0, 0, BLACK.getRGB());
test.setRGB(1, 0, GRAY.getRGB());
expected = test;
expected.setRGB(0, 1, BLUE.getRGB());
assertTrue(bufferedImagesEqual(expected, ImageUtil.outlineImage(test, BLUE, (color -> color.equals(BLACK)))));
// outlineImage(BufferedImage image, Color color, Boolean outlineCorners)
expected = solidColor(CORNER_SIZE, CORNER_SIZE, WHITE);
expected.setRGB(0, 0, BLACK.getRGB());
assertTrue(bufferedImagesEqual(expected, ImageUtil.outlineImage(BLACK_PIXEL_TOP_LEFT, WHITE, true)));
assertTrue(bufferedImagesEqual(solidColor(3, 3, BLACK), ImageUtil.outlineImage(centeredPixel(BLACK), BLACK, true)));
// outlineImage(BufferedImage image, Color color, Predicate<Color> fillCondition, Boolean outlineCorners)
test = new BufferedImage(5, 5, BufferedImage.TYPE_INT_ARGB);
test.setRGB(2, 2, BLACK.getRGB());
test.setRGB(1, 2, new Color(50, 50, 50).getRGB());
test.setRGB(3, 2, new Color(100, 100, 100).getRGB());
test.setRGB(2, 3, new Color(150, 150, 150).getRGB());
expected = test;
expected.setRGB(2, 1, RED.getRGB());
expected.setRGB(3, 1, RED.getRGB());
expected.setRGB(4, 1, RED.getRGB());
expected.setRGB(4, 2, RED.getRGB());
expected.setRGB(1, 3, RED.getRGB());
expected.setRGB(3, 3, RED.getRGB());
expected.setRGB(4, 3, RED.getRGB());
expected.setRGB(1, 4, RED.getRGB());
expected.setRGB(2, 4, RED.getRGB());
expected.setRGB(3, 4, RED.getRGB());
Predicate<Color> testPredicate = (color -> ColorUtil.isNotFullyTransparent(color) && color.getRed() > 75 && color.getGreen() > 75 && color.getBlue() > 75);
assertTrue(bufferedImagesEqual(expected, ImageUtil.outlineImage(test, RED, testPredicate, true)));
}
/**