IDEA-178632 Switching Default/Darcula themes on mac breaks combobox borders

This commit is contained in:
Kirill Kirichenko
2017-09-28 17:55:31 +03:00
parent 83935c0ce0
commit 3eb83d888c
5 changed files with 38 additions and 207 deletions
@@ -15,19 +15,15 @@
*/
package com.intellij.openapi.ui;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.ui.Gray;
import com.intellij.ui.components.JBTextField;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.MacUIUtil;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.ComboBoxUI;
@@ -37,8 +33,6 @@ import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Method;
/**
@@ -47,22 +41,10 @@ import java.lang.reflect.Method;
* User: spLeaner
*/
public class FixedComboBoxEditor implements ComboBoxEditor {
public static final Border EDITOR_BORDER = new MacComboBoxEditorBorder(false);
public static final Border DISABLED_EDITOR_BORDER = new MacComboBoxEditorBorder(true);
@NotNull private final JBTextField myField;
@NotNull
private final JBTextField myField = UIUtil.isUnderDefaultMacTheme() ? new MacComboBoxTextField() : new JBTextField();
private Object oldValue;
public FixedComboBoxEditor() {
if (SystemInfo.isMac && (UIUtil.isUnderAquaLookAndFeel() || UIUtil.isUnderIntelliJLaF())) {
myField = new MacComboBoxTextField();
}
else {
myField = new JBTextField();
myField.setBorder(null);
}
}
@NotNull
public JBTextField getField() {
return myField;
@@ -95,8 +77,8 @@ public class FixedComboBoxEditor implements ComboBoxEditor {
// Must take the value from the editor and get the value and cast it to the new type.
Class cls = oldValue.getClass();
try {
Method method = cls.getMethod("valueOf", new Class[]{String.class});
newValue = method.invoke(oldValue, new Object[]{myField.getText()});
Method method = cls.getMethod("valueOf", String.class);
newValue = method.invoke(oldValue, myField.getText());
}
catch (Exception ex) {
// Fail silently and return the newValue (a String object)
@@ -108,22 +90,16 @@ public class FixedComboBoxEditor implements ComboBoxEditor {
public void selectAll() {
myField.selectAll();
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> {
IdeFocusManager.getGlobalInstance().requestFocus(myField, true);
});
IdeFocusManager.getGlobalInstance().doWhenFocusSettlesDown(() -> IdeFocusManager.getGlobalInstance().requestFocus(myField, true));
}
@Override
public void addActionListener(ActionListener l) {
}
@Override public void addActionListener(ActionListener l) {}
@Override
public void removeActionListener(ActionListener l) {
}
@Override public void removeActionListener(ActionListener l) {}
@Nullable
private static ComboPopup getComboboxPopup(final JComboBox comboBox) {
final ComboBoxUI ui = comboBox.getUI();
private static ComboPopup getComboboxPopup(JComboBox comboBox) {
ComboBoxUI ui = comboBox.getUI();
ComboPopup popup = null;
if (ui instanceof BasicComboBoxUI) {
popup = ReflectionUtil.getField(BasicComboBoxUI.class, ui, ComboPopup.class, "popup");
@@ -134,7 +110,7 @@ public class FixedComboBoxEditor implements ComboBoxEditor {
private class MacComboBoxTextField extends JBTextField implements DocumentListener, FocusListener {
private MacComboBoxTextField() {
final InputMap inputMap = getInputMap();
InputMap inputMap = getInputMap();
inputMap.put(KeyStroke.getKeyStroke("DOWN"), "aquaSelectNext");
inputMap.put(KeyStroke.getKeyStroke("KP_DOWN"), "aquaSelectNext");
@@ -149,42 +125,12 @@ public class FixedComboBoxEditor implements ComboBoxEditor {
inputMap.put(KeyStroke.getKeyStroke("ENTER"), "aquaEnterPressed");
inputMap.put(KeyStroke.getKeyStroke("SPACE"), "aquaSpacePressed");
//getActionMap().put("macEnterPressed", macEnterPressedAction);
//getDocument().addDocumentListener(this);
addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("enabled".equals(evt.getPropertyName())) {
if (SystemInfo.isMac && UIUtil.isUnderIntelliJLaF()) {
//ignore
} else {
setBorder(Boolean.TRUE.equals(evt.getNewValue()) ? EDITOR_BORDER : DISABLED_EDITOR_BORDER);
}
repaint();
}
}
});
addFocusListener(this);
}
@Override
public void updateUI() {
super.updateUI();
if (SystemInfo.isMac && UIUtil.isUnderIntelliJLaF()) {
setBorder(JBUI.Borders.empty());
setOpaque(false);
} else {
setBorder(isEnabled() ? EDITOR_BORDER : DISABLED_EDITOR_BORDER);
}
}
@Override
public boolean hasFocus() {
final Container parent = getParent();
Container parent = getParent();
if (parent instanceof ComboBox && ((ComboBox)parent).myPaintingNow) {
return false; // to disable focus painting around combobox button
}
@@ -196,40 +142,25 @@ public class FixedComboBoxEditor implements ComboBoxEditor {
repaintCombobox();
}
@Override
public void focusLost(FocusEvent e) {
repaintCombobox();
}
private void repaintCombobox() {
final Container parent = getParent();
if (parent == null) return;
if (parent instanceof JComponent && Boolean.TRUE == ((JComponent)parent).getClientProperty("JComboBox.isTableCellEditor")) return;
final Container grandParent = parent.getParent();
Container parent = getParent();
if (parent == null || parent instanceof JComponent && Boolean.TRUE == ((JComponent)parent).getClientProperty("JComboBox.isTableCellEditor")) return;
Container grandParent = parent.getParent();
if (grandParent != null) {
grandParent.repaint();
}
}
@Override
public void focusLost(FocusEvent e) {
repaintCombobox();
}
@Override
public Dimension getMinimumSize() {
final Dimension minimumSize = super.getMinimumSize();
return new Dimension(minimumSize.width, minimumSize.height + 2);
}
@Override
public Dimension getPreferredSize() {
return getMinimumSize();
}
@Override
public void setBounds(final int x, final int y, final int width, final int height) {
UIUtil.setComboBoxEditorBounds(x, y, width, height, this);
}
@Override
public Color getBackground() {
if (SystemInfo.isMac && UIUtil.isUnderIntelliJLaF()) {
if (UIUtil.isUnderDefaultMacTheme()) {
Container parent = getParent();
if (parent != null && !parent.isEnabled()) {
return Gray.xF8;
@@ -254,18 +185,18 @@ public class FixedComboBoxEditor implements ComboBoxEditor {
}
private void textChanged() {
final Container ancestor = SwingUtilities.getAncestorOfClass(JComboBox.class, this);
Container ancestor = SwingUtilities.getAncestorOfClass(JComboBox.class, this);
if (ancestor == null || !ancestor.isVisible()) return;
final JComboBox comboBox = (JComboBox)ancestor;
JComboBox comboBox = (JComboBox)ancestor;
if (!comboBox.isPopupVisible()) return;
final ComboPopup popup = getComboboxPopup(comboBox);
ComboPopup popup = getComboboxPopup(comboBox);
if (popup == null) return;
String s = myField.getText();
final ListModel listmodel = comboBox.getModel();
ListModel listmodel = comboBox.getModel();
int i = listmodel.getSize();
if (s.length() > 0) {
for (int j = 0; j < i; j++) {
@@ -283,65 +214,4 @@ public class FixedComboBoxEditor implements ComboBoxEditor {
popup.getList().clearSelection();
}
}
public static class MacComboBoxEditorBorder implements Border {
private boolean myDisabled;
public MacComboBoxEditorBorder(final boolean disabled) {
myDisabled = disabled;
}
@Override
public void paintBorder(final Component c, final Graphics g, final int x, final int y, final int width, final int height) {
Color topColor;
Color secondTopColor;
Color leftRightColor;
Color bottomColor;
if (myDisabled) {
topColor = Gray._200;
secondTopColor = Gray._250;
leftRightColor = Gray._205;
bottomColor = Gray._220;
}
else {
topColor = Gray._150;
secondTopColor = Gray._230;
leftRightColor = Gray._175;
bottomColor = Gray._200;
}
int _y = y + MacUIUtil.MAC_COMBO_BORDER_V_OFFSET;
g.setColor(topColor);
g.drawLine(x + 3, _y + 3, x + width - 1, _y + 3);
g.setColor(secondTopColor);
g.drawLine(x + 3, _y + 4, x + width - 1, _y + 4);
g.setColor(leftRightColor);
g.drawLine(x + 3, _y + 4, x + 3, _y + height - 4);
g.drawLine(x + width - 1, _y + 4, x + width - 1, _y + height - 4);
g.setColor(bottomColor);
g.drawLine(x + 4, _y + height - 4, x + width - 2, _y + height - 4);
g.setColor(UIUtil.getPanelBackground());
g.fillRect(x, y, width, 3 + (SystemInfo.isMacOSLion ? 1 : 0));
g.fillRect(x, _y, 3, height);
g.fillRect(x, _y + height - 3, width, 3);
}
@Override
public Insets getBorderInsets(final Component c) {
return new Insets(6, 6, 4, 3);
}
@Override
public boolean isBorderOpaque() {
return true;
}
}
}
@@ -21,7 +21,6 @@ import com.intellij.ui.ColorUtil;
import com.intellij.ui.Gray;
import com.intellij.ui.JBGradientPaint;
import com.intellij.util.ui.EmptyIcon;
import com.intellij.util.ui.GraphicsUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import sun.swing.SwingUtilities2;
@@ -95,7 +94,6 @@ public class DarculaRadioButtonUI extends MetalRadioButtonUI {
JBGradientPaint ijGradient = new JBGradientPaint(c, new Color(0x4985e4), new Color(0x4074c9));
//setup AA for lines
GraphicsConfig config = GraphicsUtil.setupAAPainting(g);
boolean focus = c.hasFocus();
boolean selected = ((AbstractButton)c).isSelected();
@@ -69,9 +69,9 @@ public class MacComboBoxBorder extends MacIntelliJTextBorder {
} else {
Path2D path = new Path2D.Double(Path2D.WIND_EVEN_ODD);
path.moveTo(i.left + VALUE_OFFSET, i.top);
path.lineTo(i.left + VALUE_OFFSET, c.getHeight() - i.bottom);
path.lineTo(i.left + arc, c.getHeight() - i.bottom);
path.quadTo(i.left, c.getHeight() - i.bottom, i.left, c.getHeight() - arc - i.bottom);
path.lineTo(i.left + VALUE_OFFSET, height - i.bottom);
path.lineTo(i.left + arc, height - i.bottom);
path.quadTo(i.left, height - i.bottom, i.left, height - arc - i.bottom);
path.lineTo(i.left, arc + i.top);
path.quadTo(i.left, i.top, arc + i.left, i.top);
path.closePath();
@@ -82,13 +82,13 @@ public class MacComboBoxBorder extends MacIntelliJTextBorder {
Path2D border = new Path2D.Double(Path2D.WIND_EVEN_ODD);
float lw = JBUI.scale(UIUtil.isRetina(g2) ? 0.5f : 1.0f);
border.append(new RoundRectangle2D.Double(JBUI.scale(3), JBUI.scale(3),
c.getWidth() - JBUI.scale(3)*2,
c.getHeight() - JBUI.scale(3)*2,
width - JBUI.scale(3)*2,
height - JBUI.scale(3)*2,
arc, arc), false);
float innerArc = JBUI.scale(arc > 0 ? arc - lw : 0.0f);
border.append(new RoundRectangle2D.Double(JBUI.scale(3) + lw, JBUI.scale(3) + lw,
c.getWidth() - (JBUI.scale(3) + lw) * 2,
c.getHeight() - (JBUI.scale(3) + lw) * 2,
width - (JBUI.scale(3) + lw) * 2,
height - (JBUI.scale(3) + lw) * 2,
innerArc, innerArc), false);
g2.setColor(Gray.xBC);
g2.fill(border);
@@ -54,11 +54,12 @@ public class MacIntelliJComboBoxUI extends BasicComboBoxUI {
}
@Override
public void installUI(final JComponent c) {
public void installUI(JComponent c) {
super.installUI(c);
DEFAULT_ICON = EmptyIcon.create(MacIntelliJIconCache.getIcon("comboRight", comboBox.isEditable(), false, false, true));
comboBox.setOpaque(false);
comboBox.setBorder(new MacComboBoxBorder());
myEditorBorderChangeListener = (evt) -> {
Object value = evt.getNewValue();
@@ -21,33 +21,16 @@ import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.FocusChangeListener;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.FixedComboBoxEditor;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.IdeFocusManager;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
public class ComboboxEditorTextField extends EditorTextField {
public static final Border EDITOR_TEXTFIELD_BORDER = new FixedComboBoxEditor.MacComboBoxEditorBorder(false) {
@Override
public Insets getBorderInsets(Component c) {
return JBUI.insets(5, 6, 5, 3);
}
};
public static final Border EDITOR_TEXTFIELD_DISABLED_BORDER = new FixedComboBoxEditor.MacComboBoxEditorBorder(true) {
@Override
public Insets getBorderInsets(Component c) {
return JBUI.insets(5, 6, 5, 3);
}
};
public ComboboxEditorTextField(@NotNull String text, Project project, FileType fileType) {
super(text, project, fileType);
setOneLineMode(true);
@@ -69,20 +52,11 @@ public class ComboboxEditorTextField extends EditorTextField {
}
@Override
public void setBounds(int x, int y, int width, int height) {
UIUtil.setComboBoxEditorBounds(x, y, width, height, this);
}
@Override
protected void updateBorder(@NotNull final EditorEx editor) {
if (UIUtil.isUnderAquaLookAndFeel()) {
editor.setBorder(isEnabled() ? EDITOR_TEXTFIELD_BORDER : EDITOR_TEXTFIELD_DISABLED_BORDER);
}
}
protected void updateBorder(@NotNull EditorEx editor) {}
@Override
protected EditorEx createEditor() {
final EditorEx result = super.createEditor();
EditorEx result = super.createEditor();
result.addFocusListener(new FocusChangeListener() {
@Override
@@ -106,22 +80,10 @@ public class ComboboxEditorTextField extends EditorTextField {
@Override
public Dimension getPreferredSize() {
final Dimension preferredSize = super.getPreferredSize();
Dimension preferredSize = super.getPreferredSize();
return new Dimension(preferredSize.width, UIUtil.fixComboBoxHeight(preferredSize.height));
}
@Override
public void setEnabled(boolean enabled) {
if (UIUtil.isUnderAquaLookAndFeel()) {
final Editor editor = getEditor();
if (editor != null) {
editor.setBorder(enabled ? EDITOR_TEXTFIELD_BORDER : EDITOR_TEXTFIELD_DISABLED_BORDER);
}
}
super.setEnabled(enabled);
}
private void repaintComboBox() {
// TODO:
if (UIUtil.isUnderDarcula() || UIUtil.isUnderIntelliJLaF() || (SystemInfo.isMac && UIUtil.isUnderAquaLookAndFeel())) {