api: make MenuEntry an interface
This adds a new createMenuEntry api method to make MenuEntries instead. Menu entries now have an associated callback called when they are clicked on, avoiding most plugins from having to hook separately to detect the menu click. Additionally get/set type has changed to take a MenuAction.
This commit is contained in:
@@ -24,9 +24,12 @@
|
||||
*/
|
||||
package net.runelite.client.menus;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.inject.Guice;
|
||||
import com.google.inject.testing.fieldbinder.Bind;
|
||||
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.inject.Inject;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.MenuAction;
|
||||
@@ -38,24 +41,18 @@ import static net.runelite.api.widgets.WidgetInfo.MINIMAP_WORLDMAP_OPTIONS;
|
||||
import net.runelite.client.util.Text;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.atLeastOnce;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class MenuManagerTest
|
||||
{
|
||||
private static final MenuEntry CANCEL = new MenuEntry();
|
||||
|
||||
@Inject
|
||||
private MenuManager menuManager;
|
||||
|
||||
@@ -63,14 +60,18 @@ public class MenuManagerTest
|
||||
@Bind
|
||||
private Client client;
|
||||
|
||||
private MenuEntry[] clientMenuEntries = {CANCEL};
|
||||
private final MenuEntry CANCEL = createMenuEntry("Cancel", "", MenuAction.CANCEL, MINIMAP_WORLDMAP_OPTIONS.getPackedId());
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass()
|
||||
private final List<MenuEntry> createdMenuEntries = new ArrayList<>();
|
||||
|
||||
private static MenuEntry createMenuEntry(String option, String target, MenuAction type, int param1)
|
||||
{
|
||||
CANCEL.setOption("Cancel");
|
||||
CANCEL.setType(MenuAction.CANCEL.getId());
|
||||
CANCEL.setParam1(MINIMAP_WORLDMAP_OPTIONS.getPackedId());
|
||||
MenuEntry menuEntry = new TestMenuEntry();
|
||||
menuEntry.setOption(option);
|
||||
menuEntry.setTarget(target);
|
||||
menuEntry.setType(type);
|
||||
menuEntry.setParam1(param1);
|
||||
return menuEntry;
|
||||
}
|
||||
|
||||
@Before
|
||||
@@ -78,35 +79,25 @@ public class MenuManagerTest
|
||||
{
|
||||
Guice.createInjector(BoundFieldModule.of(this)).injectMembers(this);
|
||||
|
||||
doAnswer((Answer<Void>) invocationOnMock ->
|
||||
{
|
||||
clientMenuEntries = invocationOnMock.getArgument(0, MenuEntry[].class);
|
||||
return null;
|
||||
}).when(client).setMenuEntries(ArgumentMatchers.any(MenuEntry[].class));
|
||||
when(client.getMenuEntries()).thenAnswer((Answer<MenuEntry[]>) invocationMock -> clientMenuEntries);
|
||||
when(client.createMenuEntry(anyInt()))
|
||||
.thenAnswer(a ->
|
||||
{
|
||||
MenuEntry e = new TestMenuEntry();
|
||||
createdMenuEntries.add(e);
|
||||
return e;
|
||||
});
|
||||
when(client.getMenuEntries()).thenReturn(new MenuEntry[]{CANCEL});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManagedMenuOrder()
|
||||
{
|
||||
final MenuEntry first = new MenuEntry();
|
||||
final MenuEntry second = new MenuEntry();
|
||||
final MenuEntry third = new MenuEntry();
|
||||
first.setOption("Test");
|
||||
first.setTarget("First Entry");
|
||||
first.setParam1(MINIMAP_WORLDMAP_OPTIONS.getPackedId());
|
||||
first.setType(RUNELITE.getId());
|
||||
second.setOption("Test");
|
||||
second.setTarget("Second Entry");
|
||||
second.setParam1(MINIMAP_WORLDMAP_OPTIONS.getPackedId());
|
||||
second.setType(RUNELITE.getId());
|
||||
third.setOption("Test");
|
||||
third.setTarget("Third Entry");
|
||||
third.setParam1(MINIMAP_WORLDMAP_OPTIONS.getPackedId());
|
||||
third.setType(RUNELITE.getId());
|
||||
menuManager.addManagedCustomMenu(new WidgetMenuOption(first.getOption(), first.getTarget(), MINIMAP_WORLDMAP_OPTIONS));
|
||||
menuManager.addManagedCustomMenu(new WidgetMenuOption(second.getOption(), second.getTarget(), MINIMAP_WORLDMAP_OPTIONS));
|
||||
menuManager.addManagedCustomMenu(new WidgetMenuOption(third.getOption(), third.getTarget(), MINIMAP_WORLDMAP_OPTIONS));
|
||||
final MenuEntry first = createMenuEntry("Test", "First Entry", RUNELITE, MINIMAP_WORLDMAP_OPTIONS.getPackedId());
|
||||
final MenuEntry second = createMenuEntry("Test", "Second Entry", RUNELITE, MINIMAP_WORLDMAP_OPTIONS.getPackedId());
|
||||
final MenuEntry third = createMenuEntry("Test", "Third Entry", RUNELITE, MINIMAP_WORLDMAP_OPTIONS.getPackedId());
|
||||
menuManager.addManagedCustomMenu(new WidgetMenuOption(first.getOption(), first.getTarget(), MINIMAP_WORLDMAP_OPTIONS), null);
|
||||
menuManager.addManagedCustomMenu(new WidgetMenuOption(second.getOption(), second.getTarget(), MINIMAP_WORLDMAP_OPTIONS), null);
|
||||
menuManager.addManagedCustomMenu(new WidgetMenuOption(third.getOption(), third.getTarget(), MINIMAP_WORLDMAP_OPTIONS), null);
|
||||
|
||||
menuManager.onMenuEntryAdded(new MenuEntryAdded(
|
||||
CANCEL.getOption(),
|
||||
@@ -116,12 +107,10 @@ public class MenuManagerTest
|
||||
CANCEL.getParam0(),
|
||||
CANCEL.getParam1()));
|
||||
|
||||
ArgumentCaptor<MenuEntry[]> captor = ArgumentCaptor.forClass(MenuEntry[].class);
|
||||
verify(client, atLeastOnce()).setMenuEntries(captor.capture());
|
||||
verify(client, times(3)).createMenuEntry(anyInt());
|
||||
|
||||
final MenuEntry[] resultMenuEntries = captor.getValue();
|
||||
// Strip color tags from menu options before array comparison
|
||||
for (MenuEntry resultEntry : resultMenuEntries)
|
||||
for (MenuEntry resultEntry : createdMenuEntries)
|
||||
{
|
||||
final String resultTarget = resultEntry.getTarget();
|
||||
if (resultTarget != null)
|
||||
@@ -130,6 +119,7 @@ public class MenuManagerTest
|
||||
}
|
||||
}
|
||||
|
||||
assertArrayEquals(new MenuEntry[]{CANCEL, third, second, first}, resultMenuEntries);
|
||||
assertArrayEquals(new MenuEntry[]{third, second, first},
|
||||
Lists.reverse(createdMenuEntries).toArray(new MenuEntry[0]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 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.menus;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import net.runelite.api.MenuAction;
|
||||
import net.runelite.api.MenuEntry;
|
||||
|
||||
@EqualsAndHashCode
|
||||
public class TestMenuEntry implements MenuEntry
|
||||
{
|
||||
private String option;
|
||||
private String target;
|
||||
private int identifier;
|
||||
private int type;
|
||||
private int param0;
|
||||
private int param1;
|
||||
private boolean forceLeftClick;
|
||||
|
||||
@Override
|
||||
public String getOption()
|
||||
{
|
||||
return option;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuEntry setOption(String option)
|
||||
{
|
||||
this.option = option;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTarget()
|
||||
{
|
||||
return target;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuEntry setTarget(String target)
|
||||
{
|
||||
this.target = target;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIdentifier()
|
||||
{
|
||||
return this.identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuEntry setIdentifier(int identifier)
|
||||
{
|
||||
this.identifier = identifier;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuAction getType()
|
||||
{
|
||||
return MenuAction.of(this.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuEntry setType(MenuAction type)
|
||||
{
|
||||
this.type = type.getId();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParam0()
|
||||
{
|
||||
return this.param0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuEntry setParam0(int param0)
|
||||
{
|
||||
this.param0 = param0;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParam1()
|
||||
{
|
||||
return this.param1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuEntry setParam1(int param1)
|
||||
{
|
||||
this.param1 = param1;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isForceLeftClick()
|
||||
{
|
||||
return this.forceLeftClick;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuEntry setForceLeftClick(boolean forceLeftClick)
|
||||
{
|
||||
this.forceLeftClick = forceLeftClick;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDeprioritized()
|
||||
{
|
||||
return type >= MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDeprioritized(boolean deprioritized)
|
||||
{
|
||||
if (deprioritized)
|
||||
{
|
||||
if (type < MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET)
|
||||
{
|
||||
type += MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (type >= MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET)
|
||||
{
|
||||
type -= MenuAction.MENU_ACTION_DEPRIORITIZE_OFFSET;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuEntry onClick(Consumer<MenuEntry> callback)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import com.google.inject.Guice;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.testing.fieldbinder.Bind;
|
||||
import com.google.inject.testing.fieldbinder.BoundFieldModule;
|
||||
import java.util.Arrays;
|
||||
import net.runelite.api.Client;
|
||||
import net.runelite.api.GameState;
|
||||
import net.runelite.api.KeyCode;
|
||||
@@ -37,6 +38,7 @@ import net.runelite.api.events.ClientTick;
|
||||
import net.runelite.api.events.MenuEntryAdded;
|
||||
import net.runelite.client.config.ConfigManager;
|
||||
import net.runelite.client.game.ItemManager;
|
||||
import net.runelite.client.menus.TestMenuEntry;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@@ -88,9 +90,7 @@ public class MenuEntrySwapperPluginTest
|
||||
{
|
||||
// The menu implementation returns a copy of the array, which causes swap() to not
|
||||
// modify the same array being iterated in onClientTick
|
||||
MenuEntry[] copy = new MenuEntry[entries.length];
|
||||
System.arraycopy(entries, 0, copy, 0, entries.length);
|
||||
return copy;
|
||||
return Arrays.copyOf(entries, entries.length);
|
||||
});
|
||||
doAnswer((Answer<Void>) invocationOnMock ->
|
||||
{
|
||||
@@ -109,10 +109,10 @@ public class MenuEntrySwapperPluginTest
|
||||
|
||||
private static MenuEntry menu(String option, String target, MenuAction menuAction, int identifier)
|
||||
{
|
||||
MenuEntry menuEntry = new MenuEntry();
|
||||
MenuEntry menuEntry = new TestMenuEntry();
|
||||
menuEntry.setOption(option);
|
||||
menuEntry.setTarget(target);
|
||||
menuEntry.setType(menuAction.getId());
|
||||
menuEntry.setType(menuAction);
|
||||
menuEntry.setIdentifier(identifier);
|
||||
return menuEntry;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ import net.runelite.api.NPC;
|
||||
import net.runelite.api.events.MenuEntryAdded;
|
||||
import net.runelite.api.events.NpcChanged;
|
||||
import net.runelite.api.events.NpcSpawned;
|
||||
import net.runelite.client.menus.TestMenuEntry;
|
||||
import net.runelite.client.ui.overlay.OverlayManager;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
@@ -48,7 +49,6 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
||||
@@ -109,13 +109,12 @@ public class NpcIndicatorsPluginTest
|
||||
|
||||
when(client.getCachedNPCs()).thenReturn(new NPC[]{npc}); // id 0
|
||||
|
||||
when(client.getMenuEntries()).thenReturn(new MenuEntry[]{new MenuEntry()});
|
||||
MenuEntry entry = new TestMenuEntry();
|
||||
when(client.getMenuEntries()).thenReturn(new MenuEntry[]{entry});
|
||||
MenuEntryAdded menuEntryAdded = new MenuEntryAdded("", "Goblin", MenuAction.NPC_FIRST_OPTION.getId(), 0, -1, -1);
|
||||
npcIndicatorsPlugin.onMenuEntryAdded(menuEntryAdded);
|
||||
|
||||
MenuEntry target = new MenuEntry();
|
||||
target.setTarget("<col=ff0000>Goblin"); // red
|
||||
verify(client).setMenuEntries(new MenuEntry[]{target});
|
||||
assertEquals("<col=ff0000>Goblin", entry.getTarget()); // red
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -133,13 +132,12 @@ public class NpcIndicatorsPluginTest
|
||||
|
||||
when(client.getCachedNPCs()).thenReturn(new NPC[]{npc}); // id 0
|
||||
|
||||
when(client.getMenuEntries()).thenReturn(new MenuEntry[]{new MenuEntry()});
|
||||
MenuEntry entry = new TestMenuEntry();
|
||||
when(client.getMenuEntries()).thenReturn(new MenuEntry[]{entry});
|
||||
MenuEntryAdded menuEntryAdded = new MenuEntryAdded("", "Goblin", MenuAction.NPC_FIRST_OPTION.getId(), 0, -1, -1);
|
||||
npcIndicatorsPlugin.onMenuEntryAdded(menuEntryAdded);
|
||||
|
||||
MenuEntry target = new MenuEntry();
|
||||
target.setTarget("<col=0000ff>Goblin"); // blue
|
||||
verify(client).setMenuEntries(new MenuEntry[]{target});
|
||||
assertEquals("<col=0000ff>Goblin", entry.getTarget()); // blue
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user