IconTextField: add combobox-style suggestion dropdown

This commit is contained in:
Max Weber
2020-05-15 02:08:32 -06:00
committed by Adam
parent cb0d9ce3d0
commit d8d5631734

View File

@@ -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<String> 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<String> 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;
}
}