Merge pull request #2833 from open-osrs/2110-upstream
project: Merge upstream
This commit is contained in:
@@ -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());
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)))
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user