6490753: JComboBox doesn't look as native combobox in different states of component

Reviewed-by: serb, alexsch
This commit is contained in:
Martin Mraz 2017-03-06 17:03:26 +03:00 committed by Alexander Scherbatiy
parent ce4a8c41db
commit bc2bb1fae1
5 changed files with 129 additions and 17 deletions

View File

@ -36,7 +36,6 @@ import java.awt.event.*;
import javax.swing.*;
import com.sun.java.swing.plaf.windows.TMSchema.State;
import static com.sun.java.swing.plaf.windows.TMSchema.State.*;
import com.sun.java.swing.plaf.windows.TMSchema.Part;
@ -383,18 +382,25 @@ class AnimationController implements ActionListener, PropertyChangeListener {
updateProgress();
if (! isDone()) {
Graphics2D g = (Graphics2D) _g.create();
skin.paintSkinRaw(g, dx, dy, dw, dh, startState);
float alpha;
if (isForward) {
alpha = progress;
if (skin.haveToSwitchStates()) {
skin.paintSkinRaw(g, dx, dy, dw, dh, state);
g.setComposite(AlphaComposite.SrcOver.derive(1 - progress));
skin.paintSkinRaw(g, dx, dy, dw, dh, startState);
} else {
alpha = 1 - progress;
skin.paintSkinRaw(g, dx, dy, dw, dh, startState);
float alpha;
if (isForward) {
alpha = progress;
} else {
alpha = 1 - progress;
}
g.setComposite(AlphaComposite.SrcOver.derive(alpha));
skin.paintSkinRaw(g, dx, dy, dw, dh, state);
}
g.setComposite(AlphaComposite.SrcOver.derive(alpha));
skin.paintSkinRaw(g, dx, dy, dw, dh, state);
g.dispose();
} else {
skin.paintSkinRaw(_g, dx, dy, dw, dh, state);
skin.switchStates(false);
}
}
boolean isDone() {

View File

@ -121,6 +121,12 @@ class TMSchema {
LBP_LISTBOX(Control.LISTBOX, 0),
LBCP_BORDER_HSCROLL (Control.LISTBOX, 1),
LBCP_BORDER_HVSCROLL (Control.LISTBOX, 2),
LBCP_BORDER_NOSCROLL (Control.LISTBOX, 3),
LBCP_BORDER_VSCROLL (Control.LISTBOX, 4),
LBCP_ITEM (Control.LISTBOX, 5),
LVP_LISTVIEW(Control.LISTVIEW, 0),
PP_PROGRESS (Control.PROGRESS, 0),
@ -343,6 +349,12 @@ class TMSchema {
stateMap.put(Part.HP_HEADERSORTARROW,
new State[] {SORTEDDOWN, SORTEDUP});
State[] listBoxStates = new State[] { NORMAL, PRESSED, HOT, DISABLED};
stateMap.put(Part.LBCP_BORDER_HSCROLL, listBoxStates);
stateMap.put(Part.LBCP_BORDER_HVSCROLL, listBoxStates);
stateMap.put(Part.LBCP_BORDER_NOSCROLL, listBoxStates);
stateMap.put(Part.LBCP_BORDER_VSCROLL, listBoxStates);
State[] scrollBarStates = new State[] { NORMAL, HOT, PRESSED, DISABLED, HOVER };
stateMap.put(Part.SBP_SCROLLBAR, scrollBarStates);
stateMap.put(Part.SBP_THUMBBTNVERT, scrollBarStates);

View File

@ -41,6 +41,7 @@ import static com.sun.java.swing.plaf.windows.XPStyle.Skin;
import sun.swing.DefaultLookup;
import sun.swing.StringUIClientPropertyKey;
import com.sun.java.swing.plaf.windows.WindowsBorders.DashedBorder;
/**
* Windows combo box.
@ -97,6 +98,9 @@ public class WindowsComboBoxUI extends BasicComboBoxUI {
} else if (source instanceof XPComboBoxButton) {
rv = ((XPComboBoxButton) source)
.getWindowsComboBoxUI().comboBox;
} else if (source instanceof JTextField &&
((JTextField) source).getParent() instanceof JComboBox) {
rv = (JComboBox) ((JTextField) source).getParent();
}
return rv;
}
@ -149,6 +153,8 @@ public class WindowsComboBoxUI extends BasicComboBoxUI {
//is initialized after installListeners is invoked
comboBox.addMouseListener(rolloverListener);
arrowButton.addMouseListener(rolloverListener);
// set empty border as default to see vista animated border
comboBox.setBorder(new EmptyBorder(0,0,0,0));
}
}
@ -224,6 +230,9 @@ public class WindowsComboBoxUI extends BasicComboBoxUI {
state = State.DISABLED;
} else if (isPopupVisible(comboBox)) {
state = State.PRESSED;
} else if (comboBox.isEditable()
&& comboBox.getEditor().getEditorComponent().isFocusOwner()) {
state = State.PRESSED;
} else if (isRollover) {
state = State.HOT;
}
@ -242,7 +251,7 @@ public class WindowsComboBoxUI extends BasicComboBoxUI {
skin = xp.getSkin(c, Part.CP_READONLY);
}
if (skin == null) {
skin = xp.getSkin(c, Part.CP_COMBOBOX);
skin = xp.getSkin(c, Part.CP_BORDER);
}
skin.paintSkin(g, 0, 0, c.getWidth(), c.getHeight(), state);
}
@ -368,7 +377,7 @@ public class WindowsComboBoxUI extends BasicComboBoxUI {
}
protected ComboPopup createPopup() {
return super.createPopup();
return new WinComboPopUp(comboBox);
}
/**
@ -414,8 +423,10 @@ public class WindowsComboBoxUI extends BasicComboBoxUI {
@SuppressWarnings("serial") // Superclass is not serializable across versions
private class XPComboBoxButton extends XPStyle.GlyphButton {
private State prevState = null;
public XPComboBoxButton(XPStyle xp) {
super(null,
super(comboBox,
(! xp.isSkinDefined(comboBox, Part.CP_DROPDOWNBUTTONRIGHT))
? Part.CP_DROPDOWNBUTTON
: (comboBox.getComponentOrientation() == ComponentOrientation.RIGHT_TO_LEFT)
@ -428,18 +439,33 @@ public class WindowsComboBoxUI extends BasicComboBoxUI {
@Override
protected State getState() {
State rv;
getModel().setPressed(comboBox.isPopupVisible());
rv = super.getState();
XPStyle xp = XPStyle.getXP();
if (rv != State.DISABLED
&& comboBox != null && ! comboBox.isEditable()
&& xp != null && xp.isSkinDefined(comboBox,
Part.CP_DROPDOWNBUTTONRIGHT)) {
&& comboBox != null && ! comboBox.isEditable()
&& xp != null && xp.isSkinDefined(comboBox,
Part.CP_DROPDOWNBUTTONRIGHT)) {
/*
* for non editable ComboBoxes Vista seems to have the
* same glyph for all non DISABLED states
*/
rv = State.NORMAL;
}
if (rv == State.NORMAL && (prevState == State.HOT || prevState == State.PRESSED)) {
/*
* State NORMAL of combobox button cannot overpaint states HOT or PRESSED
* Therefore HOT state must be painted from alpha 1 to 0 and not as usual that
* NORMAL state is painted from alpha 0 to alpha 1.
*/
skin.switchStates(true);
}
if (rv != prevState) {
prevState = rv;
}
return rv;
}
@ -484,6 +510,39 @@ public class WindowsComboBoxUI extends BasicComboBoxUI {
}
}
@SuppressWarnings("serial") // Same-version serialization only
protected class WinComboPopUp extends BasicComboPopup {
private Skin listBoxBorder = null;
private XPStyle xp;
public WinComboPopUp(JComboBox<Object> combo) {
super(combo);
xp = XPStyle.getXP();
if (xp != null && xp.isSkinDefined(combo, Part.LBCP_BORDER_NOSCROLL)) {
this.listBoxBorder = new Skin(combo, Part.LBCP_BORDER_NOSCROLL);
this.setBorder(new EmptyBorder(1,1,1,1));
}
}
protected KeyListener createKeyListener() {
return new InvocationKeyHandler();
}
protected class InvocationKeyHandler extends BasicComboPopup.InvocationKeyHandler {
protected InvocationKeyHandler() {
WinComboPopUp.this.super();
}
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (this.listBoxBorder != null) {
this.listBoxBorder.paintSkinRaw(g, this.getX(), this.getY(),
this.getWidth(), this.getHeight(), State.HOT);
}
}
}
/**
* Subclassed to highlight selected item in an editable combo box.
@ -498,6 +557,7 @@ public class WindowsComboBoxUI extends BasicComboBoxUI {
protected JTextField createEditorComponent() {
JTextField editor = super.createEditorComponent();
Border border = (Border)UIManager.get("ComboBox.editorBorder");
if (border != null) {
editor.setBorder(border);
}
@ -524,6 +584,31 @@ public class WindowsComboBoxUI extends BasicComboBoxUI {
private static final Object BORDER_KEY
= new StringUIClientPropertyKey("BORDER_KEY");
private static final Border NULL_BORDER = new EmptyBorder(0, 0, 0, 0);
// Create own version of DashedBorder with more space on left side
private class WindowsComboBoxDashedBorder extends DashedBorder {
public WindowsComboBoxDashedBorder(Color color, int thickness) {
super(color, thickness);
}
public WindowsComboBoxDashedBorder(Color color) {
super(color);
}
@Override
public Insets getBorderInsets(Component c, Insets i) {
return new Insets(0,2,0,0);
}
}
public WindowsComboBoxRenderer() {
super();
// correct space on the left side of text items in the combo popup list
Insets i = getBorder().getBorderInsets(this);
setBorder(new EmptyBorder(0, 2, 0, i.right));
}
/**
* {@inheritDoc}
*/
@ -542,7 +627,7 @@ public class WindowsComboBoxUI extends BasicComboBoxUI {
if (index == -1 && isSelected) {
Border border = component.getBorder();
Border dashedBorder =
new WindowsBorders.DashedBorder(list.getForeground());
new WindowsComboBoxDashedBorder(list.getForeground());
component.setBorder(dashedBorder);
//store current border in client property if needed
if (component.getClientProperty(BORDER_KEY) == null) {

View File

@ -672,7 +672,7 @@ public class WindowsLookAndFeel extends BasicLookAndFeel
"ComboBox.buttonHighlight", ControlHighlightColor,
"ComboBox.selectionBackground", SelectionBackgroundColor,
"ComboBox.selectionForeground", SelectionTextColor,
"ComboBox.editorBorder", new XPValue(new EmptyBorder(1,2,1,1),
"ComboBox.editorBorder", new XPValue(new EmptyBorder(1,4,1,1),
new EmptyBorder(1,4,1,4)),
"ComboBox.disabledBackground",
new XPColorValue(Part.CP_COMBOBOX, State.DISABLED,

View File

@ -479,6 +479,7 @@ class XPStyle {
private final String string;
private Dimension size = null;
private boolean switchStates = false;
Skin(Component component, Part part) {
this(component, part, null);
@ -513,6 +514,14 @@ class XPStyle {
return (insets != null) ? insets : new Insets(0, 0, 0, 0);
}
boolean haveToSwitchStates() {
return switchStates;
}
void switchStates(boolean b) {
switchStates = b;
}
private int getWidth(State state) {
if (size == null) {
size = getPartSize(part, state);
@ -689,7 +698,7 @@ class XPStyle {
@SuppressWarnings("serial") // Superclass is not serializable across versions
static class GlyphButton extends JButton {
private Skin skin;
protected Skin skin;
public GlyphButton(Component parent, Part part) {
XPStyle xp = getXP();