IDEA-263715 Popup Lists: place mnemonics between icon and text

(cherry picked from commit 782ac4c268d2748d7cf8433c8fd9592f68abfb21)

IJ-CR-7890

GitOrigin-RevId: 685defe0d93486dd0ba532b8238aa91c2f9f4ea7
This commit is contained in:
Mikhail Sokolov
2021-04-06 17:25:18 +00:00
committed by intellij-monorepo-bot
parent 2c74451549
commit 3d74578e26
7 changed files with 88 additions and 19 deletions
@@ -36,9 +36,12 @@ import com.intellij.openapi.util.registry.Registry;
import com.intellij.ui.popup.NumericMnemonicItem;
import com.intellij.ui.popup.WizardPopup;
import com.intellij.ui.popup.list.ListPopupImpl;
import com.intellij.ui.popup.list.PopupListElementRenderer;
import com.intellij.ui.speedSearch.SpeedSearch;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.ui.GridBag;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
@@ -758,6 +761,30 @@ public final class ChooseRunConfigurationPopup implements ExecutorProvider {
return false;
}
@Override
protected ListCellRenderer<?> getListElementRenderer() {
return new PopupListElementRenderer<>(this){
@Override
protected JComponent createIconBar(JList<?> list, Object value, boolean selected) {
JPanel res = new JPanel(new GridBagLayout());
res.setOpaque(false);
res.setBorder(JBUI.Borders.emptyRight(JBUI.CurrentTheme.ActionsList.elementIconGap()));
GridBag gbc = new GridBag()
.setDefaultAnchor(GridBagConstraints.CENTER)
.setDefaultWeightX(1)
.setDefaultInsets(0, 0, 0, 0)
.setDefaultFill(GridBagConstraints.BOTH);
res.add(myMnemonicLabel, gbc.next());
res.add(Box.createHorizontalStrut(JBUI.CurrentTheme.ActionsList.MNEMONIC_ICON_GAP), gbc.next());
res.add(myIconLabel, gbc.next());
return res;
}
};
}
@Override
public void handleSelect(boolean handleFinalChoices, InputEvent e) {
if (e instanceof MouseEvent && e.isShiftDown()) {
@@ -50,9 +50,7 @@ public abstract class GroupedElementsRenderer implements Accessible {
AccessibleContextUtil.setName(myRendererComponent, myTextLabel);
AccessibleContextUtil.setDescription(myRendererComponent, myTextLabel);
myTextLabel.setIcon(icon);
myTextLabel.setDisabledIcon(disabledIcon);
myTextLabel.setIconTextGap(JBUI.CurrentTheme.ActionsList.elementIconGap());
setComponentIcon(icon, disabledIcon);
setSelected(myComponent, isSelected);
setSelected(myTextLabel, isSelected);
@@ -62,6 +60,12 @@ public abstract class GroupedElementsRenderer implements Accessible {
return myRendererComponent;
}
protected void setComponentIcon(Icon icon, Icon disabledIcon) {
myTextLabel.setIcon(icon);
myTextLabel.setDisabledIcon(disabledIcon);
myTextLabel.setIconTextGap(JBUI.CurrentTheme.ActionsList.elementIconGap());
}
protected final void setSelected(JComponent aComponent) {
setSelected(aComponent, true);
}
@@ -18,4 +18,4 @@ OptionPane.informationIcon=AllIcons.General.InformationDialog
OptionPane.questionIcon=AllIcons.General.QuestionDialog
ActionsList.mnemonicsBorderInsets=0,8,1,8
ActionsList.icon.gap=8
ActionsList.icon.gap=6
@@ -21,4 +21,4 @@ OptionPane.informationIcon=AllIcons.General.InformationDialog
OptionPane.questionIcon=AllIcons.General.QuestionDialog
ActionsList.mnemonicsBorderInsets=0,8,1,8
ActionsList.icon.gap=8
ActionsList.icon.gap=6
@@ -33,10 +33,12 @@ public class PopupListElementRenderer<E> extends GroupedItemsListRenderer<E> {
private JLabel myShortcutLabel;
private @Nullable JLabel myValueLabel;
protected JLabel myMnemonicLabel;
protected JLabel myIconLabel;
protected JComponent myRightPart;
protected JComponent myLeftPart;
protected JComponent myButtonPane;
protected JComponent myMainPane;
protected JComponent myNextStepButtonSeparator;
protected JComponent myIconBar;
public PopupListElementRenderer(final ListPopupImpl aPopup) {
super(new ListItemDescriptorAdapter<>() {
@@ -117,6 +119,8 @@ public class PopupListElementRenderer<E> extends GroupedItemsListRenderer<E> {
myMnemonicLabel.setBorder(new JBEmptyBorder(insets));
myMnemonicLabel.setFont(JBUI.CurrentTheme.ActionsList.applyStylesForNumberMnemonic(myMnemonicLabel.getFont()));
myIconLabel = new JLabel();
return layoutComponent(panel);
}
@@ -157,12 +161,18 @@ public class PopupListElementRenderer<E> extends GroupedItemsListRenderer<E> {
result.add(left, gbc.next());
result.add(right, gbc.next());
myLeftPart = left;
myRightPart = right;
myMainPane = left;
myButtonPane = right;
return result;
}
@Override
protected void setComponentIcon(Icon icon, Icon disabledIcon) {
myIconLabel.setIcon(icon);
myIconLabel.setDisabledIcon(disabledIcon);
}
@NotNull
protected static JComponent createNextStepButtonSeparator() {
SeparatorComponent separator = new SeparatorComponent(JBColor.namedColor("Menu.separatorColor", JBColor.lightGray), SeparatorOrientation.VERTICAL);
@@ -194,8 +204,8 @@ public class PopupListElementRenderer<E> extends GroupedItemsListRenderer<E> {
setSelected(myComponent, isSelected && isSelectable);
setSelected(myTextLabel, isSelected && isSelectable);
myLeftPart.setOpaque(false);
myRightPart.setOpaque(false);
myMainPane.setOpaque(false);
myButtonPane.setOpaque(false);
myNextStepButtonSeparator.setVisible(false);
boolean nextStepButtonSelected = false;
@@ -203,14 +213,14 @@ public class PopupListElementRenderer<E> extends GroupedItemsListRenderer<E> {
myNextStepLabel.setVisible(isSelectable);
if (Registry.is("ide.list.popup.separate.next.step.button") && step.isFinal(value)) {
myLeftPart.setOpaque(true);
myRightPart.setOpaque(true);
myMainPane.setOpaque(true);
myButtonPane.setOpaque(true);
setSelected(myComponent, false, isSelected);
nextStepButtonSelected = isNextStepButtonSelected(list);
setSelected(myLeftPart, isSelected && !nextStepButtonSelected, isSelected);
setSelected(myMainPane, isSelected && !nextStepButtonSelected, isSelected);
setSelected(myTextLabel, isSelected && !nextStepButtonSelected, isSelected);
setSelected(myRightPart, isSelected && nextStepButtonSelected, isSelected);
setSelected(myButtonPane, isSelected && nextStepButtonSelected, isSelected);
myNextStepLabel.setIcon(isSelectable & isSelected && nextStepButtonSelected ? AllIcons.Icons.Ide.MenuArrowSelected : AllIcons.Icons.Ide.MenuArrow);
myNextStepButtonSeparator.setVisible(!isSelected);
}
@@ -240,7 +250,6 @@ public class PopupListElementRenderer<E> extends GroupedItemsListRenderer<E> {
Character mnemonic = ((NumericMnemonicItem)value).getMnemonicChar();
myMnemonicLabel.setText(mnemonic != null ? String.valueOf(mnemonic) : "");
myMnemonicLabel.setForeground(isSelected && isSelectable && !nextStepButtonSelected ? getSelectionForeground() : JBUI.CurrentTheme.ActionsList.MNEMONIC_FOREGROUND);
myLeftPart.add(myMnemonicLabel, BorderLayout.WEST);
}
if (step.isMnemonicsNavigationEnabled()) {
@@ -287,6 +296,24 @@ public class PopupListElementRenderer<E> extends GroupedItemsListRenderer<E> {
myValueLabel.setText(step instanceof ListPopupStepEx<?> ? ((ListPopupStepEx<E>)step).getValueFor(value) : null);
setSelected(myValueLabel, isSelected && isSelectable && !nextStepButtonSelected, isSelected);
}
if (myIconBar != null) myMainPane.remove(myIconBar);
myIconBar = createIconBar(list, value, isSelected);
if (myIconBar != null) myMainPane.add(myIconBar, BorderLayout.WEST);
}
@Nullable
protected JComponent createIconBar(JList<? extends E> list, E value, boolean selected) {
boolean mnemonicShown = value instanceof NumericMnemonicItem && ((NumericMnemonicItem)value).digitMnemonicsEnabled();
boolean iconShown = myIconLabel.getIcon() != null;
if (!mnemonicShown && !iconShown) return null;
Box res = Box.createHorizontalBox();
res.setBorder(JBUI.Borders.emptyRight(JBUI.CurrentTheme.ActionsList.elementIconGap()));
if (iconShown) res.add(myIconLabel);
if (mnemonicShown) res.add(myMnemonicLabel);
return res;
}
private void setSelected(JComponent component, boolean selected, boolean hovered) {
@@ -421,6 +421,7 @@ public class JBUI {
public static final class ActionsList {
public static final Color MNEMONIC_FOREGROUND = JBColor.namedColor("Label.infoForeground", new JBColor(Gray.x78, Gray.x8C));
public static final int MNEMONIC_ICON_GAP = scale(4);
@NotNull
public static Insets numberMnemonicInsets() {
@@ -434,7 +435,7 @@ public class JBUI {
@NotNull
public static int elementIconGap() {
return new JBValue.UIInteger("ActionsList.icon.gap", scale(8)).get();
return new JBValue.UIInteger("ActionsList.icon.gap", scale(6)).get();
}
@NotNull
@@ -10,6 +10,7 @@ import com.intellij.ui.popup.list.PopupListElementRenderer;
import com.intellij.util.IconUtil;
import com.intellij.util.ui.JBUI;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.Border;
@@ -37,11 +38,20 @@ public class PopupListElementRendererWithIcon extends PopupListElementRenderer<O
@Override
protected void customizeComponent(JList<?> list, Object value, boolean isSelected) {
super.customizeComponent(list, value, isSelected);
myTextLabel.setIcon(null);
myTextLabel.setDisabledIcon(null);
myIconLabel.setIcon(isSelected ? IconUtil.wrapToSelectionAwareIcon(myDescriptor.getSelectedIconFor(value)) : myDescriptor.getIconFor(value));
}
@Override
protected void setComponentIcon(Icon icon, Icon disabledIcon) {
myIconLabel.setIcon(icon);
myIconLabel.setDisabledIcon(disabledIcon);
}
@Override
protected @Nullable JComponent createIconBar(JList<?> list, Object value, boolean selected) {
return myIconLabel;
}
@Override
protected JComponent createItemComponent() {
myTextLabel = new ErrorLabel();