diff --git a/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java b/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java index a3ef3f484d..e5dfe923d4 100644 --- a/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java +++ b/http-api/src/main/java/net/runelite/http/api/ge/GrandExchangeTrade.java @@ -32,10 +32,11 @@ public class GrandExchangeTrade { private boolean buy; private boolean cancel; + private boolean login; private int itemId; private int quantity; private int total; - private int price; + private int spent; private int offer; private WorldType worldType; } diff --git a/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java b/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java index dac4474cb9..3f4d1dacbd 100644 --- a/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java +++ b/runelite-client/src/main/java/net/runelite/client/game/ItemMapping.java @@ -249,7 +249,12 @@ public enum ItemMapping ITEM_CRYSTAL_SHIELD(CRYSTAL_WEAPON_SEED, CRYSTAL_SHIELD, CRYSTAL_SHIELD_24127, CRYSTAL_SHIELD_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); + 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), + + // 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); private static final Multimap MAPPINGS = HashMultimap.create(); private final int tradeableItem; diff --git a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListPanel.java b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListPanel.java index 8c2c74f88a..34933edef0 100644 --- a/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListPanel.java +++ b/runelite-client/src/main/java/net/runelite/client/plugins/config/PluginListPanel.java @@ -102,6 +102,15 @@ 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 List CATEGORY_TAGS = List.of( + "Combat", + "Chat", + "Item", + "Minigame", + "Notification", + "Skilling", + "XP" + ); private static final List colorOptions = Arrays.asList("enabledColors", "pvmColor", "pvpColor", "skillingColor", "utilityColor", "minigameColor", "miscellaneousColor", "gamemodeColor"); private static final List definedOrder = List.of(PluginType.IMPORTANT, PluginType.PVM, PluginType.SKILLING, PluginType.PVP, PluginType.UTILITY, PluginType.MINIGAME, PluginType.MISCELLANEOUS, PluginType.GAMEMODE, PluginType.UNCATEGORIZED); @@ -223,6 +232,7 @@ public class PluginListPanel extends PluginPanel onSearchBarChanged(); } }); + CATEGORY_TAGS.forEach(searchBar.getSuggestionListModel()::addElement); setLayout(new BorderLayout()); setBackground(ColorScheme.DARK_GRAY_COLOR); diff --git a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java index 83fb860185..b007434a75 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/ClientUI.java @@ -1047,17 +1047,27 @@ public class ClientUI if (opacity != null && opacity) { - GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); - GraphicsDevice gd = ge.getDefaultScreenDevice(); - - if (gd.isWindowTranslucencySupported(TRANSLUCENT)) + // Update window opacity if the frame is undecorated, translucency capable and not fullscreen + if (frame.isUndecorated() && + frame.getGraphicsConfiguration().isTranslucencyCapable() && + frame.getGraphicsConfiguration().getDevice().getFullScreenWindow() == null) { - setOpacity(); + frame.setOpacity(Float.parseFloat(configManager.getConfiguration(PLUS_CONFIG_GROUP, CONFIG_OPACITY_AMOUNT)) / 100F); } else { - log.warn("Opacity isn't supported on your system!"); - configManager.setConfiguration(PLUS_CONFIG_GROUP, CONFIG_OPACITY, false); + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + + if (gd.isWindowTranslucencySupported(TRANSLUCENT)) + { + setOpacity(); + } + else + { + log.warn("Opacity isn't supported on your system!"); + configManager.setConfiguration(PLUS_CONFIG_GROUP, CONFIG_OPACITY, false); + } } } else if (frame.getOpacity() != 1F) diff --git a/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java b/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java index 0408837302..0266caa450 100644 --- a/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java +++ b/runelite-client/src/main/java/net/runelite/client/ui/components/IconTextField.java @@ -31,25 +31,36 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.function.Consumer; +import javax.swing.DefaultListModel; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JLabel; +import javax.swing.JList; import javax.swing.JPanel; +import javax.swing.JPopupMenu; import javax.swing.JTextField; +import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; +import javax.swing.event.ListDataEvent; +import javax.swing.event.ListDataListener; import javax.swing.text.Document; import lombok.Getter; import lombok.RequiredArgsConstructor; import net.runelite.client.ui.ColorScheme; import net.runelite.client.ui.FontManager; +import net.runelite.client.util.SwingUtil; +import org.apache.commons.lang3.StringUtils; +import org.pushingpixels.substance.internal.ui.SubstanceListUI; /** * This component is a FlatTextField with an icon on its left side, and a clear button (×) on its right side. @@ -58,10 +69,13 @@ public class IconTextField extends JPanel { // To support gifs, the icon needs to be wrapped in a JLabel private final JLabel iconWrapperLabel; - private final FlatTextField textField; private final JButton clearButton; + private final JButton suggestionButton; + + @Getter + private final DefaultListModel suggestionListModel; public IconTextField() { @@ -108,66 +122,146 @@ public class IconTextField extends JPanel textField.addMouseListener(hoverEffect); innerTxt.addMouseListener(hoverEffect); - clearButton = new JButton("×"); - clearButton.setPreferredSize(new Dimension(30, 0)); - clearButton.setFont(FontManager.getRunescapeBoldFont()); - clearButton.setForeground(ColorScheme.PROGRESS_ERROR_COLOR); - clearButton.setBorder(null); - clearButton.setBorderPainted(false); - clearButton.setContentAreaFilled(false); - clearButton.setVisible(false); - - // ActionListener for keyboard use (via Tab -> Space) + clearButton = createRHSButton(ColorScheme.PROGRESS_ERROR_COLOR, Color.PINK); + clearButton.setText("×"); clearButton.addActionListener(evt -> setText(null)); - // MouseListener for hover and click events - clearButton.addMouseListener(new MouseAdapter() + suggestionListModel = new DefaultListModel<>(); + suggestionListModel.addListDataListener(new ListDataListener() { @Override - public void mousePressed(MouseEvent mouseEvent) + public void intervalAdded(ListDataEvent e) { - setText(null); + updateContextButton(); } @Override - public void mouseEntered(MouseEvent mouseEvent) + public void intervalRemoved(ListDataEvent e) { - clearButton.setForeground(Color.PINK); - textField.dispatchEvent(mouseEvent); + updateContextButton(); } @Override - public void mouseExited(MouseEvent mouseEvent) + public void contentsChanged(ListDataEvent e) { - clearButton.setForeground(ColorScheme.PROGRESS_ERROR_COLOR); - textField.dispatchEvent(mouseEvent); + updateContextButton(); } }); + JList suggestionList = new JList<>(); + suggestionList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + suggestionList.setModel(suggestionListModel); + suggestionList.addListSelectionListener(e -> + { + String val = suggestionList.getSelectedValue(); + if (val == null) + { + return; + } + + textField.setText(val); + textField.getTextField().selectAll(); + textField.getTextField().requestFocusInWindow(); + }); + + JPopupMenu popup = new JPopupMenu(); + popup.setLightWeightPopupEnabled(true); + popup.setLayout(new BorderLayout()); + popup.add(suggestionList, BorderLayout.CENTER); + popup.addFocusListener(new FocusAdapter() + { + @Override + public void focusLost(FocusEvent e) + { + popup.setVisible(false); + suggestionList.clearSelection(); + + SubstanceListUI ui = (SubstanceListUI) suggestionList.getUI(); + ui.resetRolloverIndex(); + } + }); + + suggestionButton = createRHSButton(ColorScheme.LIGHT_GRAY_COLOR, ColorScheme.MEDIUM_GRAY_COLOR); + suggestionButton.setText("▾"); + suggestionButton.addActionListener(e -> + { + popup.setPopupSize(getWidth(), suggestionList.getPreferredSize().height); + popup.show(IconTextField.this, 0, suggestionButton.getHeight()); + popup.revalidate(); + popup.requestFocusInWindow(); + }); + // Show the clear button when text is present, and hide again when empty textField.getTextField().getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { - SwingUtilities.invokeLater(() -> clearButton.setVisible(true)); + updateContextButton(); } @Override public void removeUpdate(DocumentEvent e) { - SwingUtilities.invokeLater(() -> clearButton.setVisible(!getText().isEmpty())); + updateContextButton(); } @Override public void changedUpdate(DocumentEvent e) { + updateContextButton(); } }); + JPanel rhsButtons = new JPanel(); + rhsButtons.setBackground(new Color(0, 0, 0, 0)); + rhsButtons.setOpaque(false); + rhsButtons.setLayout(new BorderLayout()); + rhsButtons.add(clearButton, BorderLayout.EAST); + rhsButtons.add(suggestionButton, BorderLayout.WEST); + updateContextButton(); + add(iconWrapperLabel, BorderLayout.WEST); add(textField, BorderLayout.CENTER); - add(clearButton, BorderLayout.EAST); + add(rhsButtons, BorderLayout.EAST); + } + + private JButton createRHSButton(Color fg, Color rollover) + { + JButton b = new JButton(); + b.setPreferredSize(new Dimension(30, 0)); + b.setFont(FontManager.getRunescapeBoldFont()); + b.setBorder(null); + b.setRolloverEnabled(true); + SwingUtil.removeButtonDecorations(b); + b.setForeground(fg); + + b.addMouseListener(new MouseAdapter() + { + @Override + public void mouseEntered(MouseEvent mouseEvent) + { + b.setForeground(rollover); + textField.dispatchEvent(mouseEvent); + } + + @Override + public void mouseExited(MouseEvent mouseEvent) + { + b.setForeground(fg); + textField.dispatchEvent(mouseEvent); + } + }); + + return b; + } + + private void updateContextButton() + { + boolean empty = StringUtils.isBlank(textField.getText()); + + clearButton.setVisible(!empty); + suggestionButton.setVisible(!suggestionListModel.isEmpty() && empty); } public void addActionListener(ActionListener actionListener) @@ -188,6 +282,7 @@ public class IconTextField extends JPanel public void setText(String text) { + assert SwingUtilities.isEventDispatchThread(); textField.setText(text); } @@ -290,5 +385,4 @@ public class IconTextField extends JPanel private final String file; } - } diff --git a/runelite-client/src/main/scripts/ClanSendKick.rs2asm b/runelite-client/src/main/scripts/ClanSendKick.rs2asm index 1da495029f..f26f49c73a 100644 --- a/runelite-client/src/main/scripts/ClanSendKick.rs2asm +++ b/runelite-client/src/main/scripts/ClanSendKick.rs2asm @@ -6,6 +6,9 @@ ; callback "confirmClanKick" ; Used by the ClanChat plugin to show a chatbox panel confirming the requested kick ; Also requires the "confirmKicks" option of ClanChatConfig to be enabled +; callback "sendKickName" +; Used by the ClanChat plugin to modify the kick message to include player name +; Also requires the "kickWithName" option of ClanChatConfig to be enabled invoke 1942 iconst 1 if_icmpeq LABEL4 @@ -16,6 +19,10 @@ LABEL4: return LABEL7: sconst "-Attempting to kick player from friends chat..." + sload 0 ; Username we are kicking + sconst "sendKickName" + runelite_callback + pop_string ; Username we are kicking iconst 2 invoke 96 sload 0