Slider: support per component custom thumb and track colors

This commit is contained in:
Karl Tauber
2021-01-14 13:50:42 +01:00
parent 0dab1b73cc
commit 23e67a2908
6 changed files with 91 additions and 10 deletions

View File

@@ -11,6 +11,8 @@ FlatLaf Change Log
UIManager.put("Button.defaultButtonFollowsFocus",true);`. UIManager.put("Button.defaultButtonFollowsFocus",true);`.
- ComboBox, Spinner and SplitPaneDivider: Added pressed feedback to arrow - ComboBox, Spinner and SplitPaneDivider: Added pressed feedback to arrow
buttons. buttons.
- Slider: Support per component custom thumb and track colors via
`JSlider.setForeground(Color)` and `JSlider.setBackground(Color)`.
- TextComponent: Clip placeholder text if it does not fit into visible area. (PR - TextComponent: Clip placeholder text if it does not fit into visible area. (PR
#229) #229)
- Extras: UI defaults inspector: - Extras: UI defaults inspector:

View File

@@ -91,6 +91,9 @@ public class FlatSliderUI
protected Color disabledThumbColor; protected Color disabledThumbColor;
protected Color disabledThumbBorderColor; protected Color disabledThumbBorderColor;
private Color defaultBackground;
private Color defaultForeground;
protected boolean thumbHover; protected boolean thumbHover;
protected boolean thumbPressed; protected boolean thumbPressed;
@@ -131,6 +134,9 @@ public class FlatSliderUI
disabledTrackColor = UIManager.getColor( "Slider.disabledTrackColor" ); disabledTrackColor = UIManager.getColor( "Slider.disabledTrackColor" );
disabledThumbColor = UIManager.getColor( "Slider.disabledThumbColor" ); disabledThumbColor = UIManager.getColor( "Slider.disabledThumbColor" );
disabledThumbBorderColor = FlatUIUtils.getUIColor( "Slider.disabledThumbBorderColor", "Component.disabledBorderColor" ); disabledThumbBorderColor = FlatUIUtils.getUIColor( "Slider.disabledThumbBorderColor", "Component.disabledBorderColor" );
defaultBackground = UIManager.getColor( "Slider.background" );
defaultForeground = UIManager.getColor( "Slider.foreground" );
} }
@Override @Override
@@ -149,6 +155,9 @@ public class FlatSliderUI
disabledTrackColor = null; disabledTrackColor = null;
disabledThumbColor = null; disabledThumbColor = null;
disabledThumbBorderColor = null; disabledThumbBorderColor = null;
defaultBackground = null;
defaultForeground = null;
} }
@Override @Override
@@ -289,25 +298,28 @@ debug*/
coloredTrack = temp; coloredTrack = temp;
} }
g.setColor( trackValueColor ); g.setColor( getTrackValueColor() );
((Graphics2D)g).fill( coloredTrack ); ((Graphics2D)g).fill( coloredTrack );
} }
g.setColor( enabled ? trackColor : disabledTrackColor ); g.setColor( enabled ? getTrackColor() : disabledTrackColor );
((Graphics2D)g).fill( track ); ((Graphics2D)g).fill( track );
} }
@Override @Override
public void paintThumb( Graphics g ) { public void paintThumb( Graphics g ) {
Color thumbColor = getThumbColor();
Color color = stateColor( slider, thumbHover, thumbPressed, Color color = stateColor( slider, thumbHover, thumbPressed,
thumbColor, disabledThumbColor, null, hoverThumbColor, pressedThumbColor ); thumbColor, disabledThumbColor, null, hoverThumbColor, pressedThumbColor );
color = FlatUIUtils.deriveColor( color, thumbColor ); color = FlatUIUtils.deriveColor( color, thumbColor );
Color borderColor = (thumbBorderColor != null) Color foreground = slider.getForeground();
Color borderColor = (thumbBorderColor != null && foreground == defaultForeground)
? stateColor( slider, false, false, thumbBorderColor, disabledThumbBorderColor, focusedThumbBorderColor, null, null ) ? stateColor( slider, false, false, thumbBorderColor, disabledThumbBorderColor, focusedThumbBorderColor, null, null )
: null; : null;
Color focusedColor = FlatUIUtils.deriveColor( this.focusedColor, focusBaseColor ); Color focusedColor = FlatUIUtils.deriveColor( this.focusedColor,
(foreground != defaultForeground) ? foreground : focusBaseColor );
paintThumb( g, slider, thumbRect, isRoundThumb(), color, borderColor, focusedColor, focusWidth ); paintThumb( g, slider, thumbRect, isRoundThumb(), color, borderColor, focusedColor, focusWidth );
} }
@@ -436,6 +448,21 @@ debug*/
return path; return path;
} }
protected Color getTrackValueColor() {
Color foreground = slider.getForeground();
return (foreground != defaultForeground) ? foreground : trackValueColor;
}
protected Color getTrackColor() {
Color backround = slider.getBackground();
return (backround != defaultBackground) ? backround : trackColor;
}
protected Color getThumbColor() {
Color foreground = slider.getForeground();
return (foreground != defaultForeground) ? foreground : thumbColor;
}
public static Color stateColor( JSlider slider, boolean hover, boolean pressed, public static Color stateColor( JSlider slider, boolean hover, boolean pressed,
Color enabledColor, Color disabledColor, Color focusedColor, Color hoverColor, Color pressedColor ) Color enabledColor, Color disabledColor, Color focusedColor, Color hoverColor, Color pressedColor )
{ {

View File

@@ -64,6 +64,9 @@ public class FlatRangeSliderUI
protected Color disabledThumbColor; protected Color disabledThumbColor;
protected Color disabledThumbBorderColor; protected Color disabledThumbBorderColor;
private Color defaultBackground;
private Color defaultForeground;
private Object[] oldRenderingHints; private Object[] oldRenderingHints;
public static ComponentUI createUI( JComponent c ) { public static ComponentUI createUI( JComponent c ) {
@@ -129,6 +132,9 @@ public class FlatRangeSliderUI
disabledTrackColor = UIManager.getColor( "Slider.disabledTrackColor" ); disabledTrackColor = UIManager.getColor( "Slider.disabledTrackColor" );
disabledThumbColor = UIManager.getColor( "Slider.disabledThumbColor" ); disabledThumbColor = UIManager.getColor( "Slider.disabledThumbColor" );
disabledThumbBorderColor = FlatUIUtils.getUIColor( "Slider.disabledThumbBorderColor", "Component.disabledBorderColor" ); disabledThumbBorderColor = FlatUIUtils.getUIColor( "Slider.disabledThumbBorderColor", "Component.disabledBorderColor" );
defaultBackground = UIManager.getColor( "Slider.background" );
defaultForeground = UIManager.getColor( "Slider.foreground" );
} }
@Override @Override
@@ -149,6 +155,9 @@ public class FlatRangeSliderUI
disabledTrackColor = null; disabledTrackColor = null;
disabledThumbColor = null; disabledThumbColor = null;
disabledThumbBorderColor = null; disabledThumbBorderColor = null;
defaultBackground = null;
defaultForeground = null;
} }
@Override @Override
@@ -278,13 +287,14 @@ debug*/
track = new RoundRectangle2D.Float( x, trackRect.y, tw, trackRect.height, arc, arc ); track = new RoundRectangle2D.Float( x, trackRect.y, tw, trackRect.height, arc, arc );
} }
g.setColor( enabled ? trackColor : disabledTrackColor ); g.setColor( enabled ? getTrackColor() : disabledTrackColor );
((Graphics2D)g).fill( track ); ((Graphics2D)g).fill( track );
if( coloredTrack != null ) { if( coloredTrack != null ) {
boolean trackHover = hover && rollover1 && rollover2; boolean trackHover = hover && rollover1 && rollover2;
boolean trackPressed = pressed1 && pressed2; boolean trackPressed = pressed1 && pressed2;
Color trackValueColor = getTrackValueColor();
Color color = FlatSliderUI.stateColor( slider, trackHover, trackPressed, Color color = FlatSliderUI.stateColor( slider, trackHover, trackPressed,
trackValueColor, null, null, hoverTrackColor, pressedTrackColor ); trackValueColor, null, null, hoverTrackColor, pressedTrackColor );
@@ -298,19 +308,37 @@ debug*/
boolean thumbHover = hover && ((!second && rollover1) || (second && rollover2)); boolean thumbHover = hover && ((!second && rollover1) || (second && rollover2));
boolean thumbPressed = (!second && pressed1) || (second && pressed2); boolean thumbPressed = (!second && pressed1) || (second && pressed2);
Color thumbColor = getThumbColor();
Color color = FlatSliderUI.stateColor( slider, thumbHover, thumbPressed, Color color = FlatSliderUI.stateColor( slider, thumbHover, thumbPressed,
thumbColor, disabledThumbColor, null, hoverThumbColor, pressedThumbColor ); thumbColor, disabledThumbColor, null, hoverThumbColor, pressedThumbColor );
color = FlatUIUtils.deriveColor( color, thumbColor ); color = FlatUIUtils.deriveColor( color, thumbColor );
Color borderColor = (thumbBorderColor != null) Color foreground = slider.getForeground();
Color borderColor = (thumbBorderColor != null && foreground == defaultForeground)
? FlatSliderUI.stateColor( slider, false, false, thumbBorderColor, disabledThumbBorderColor, focusedThumbBorderColor, null, null ) ? FlatSliderUI.stateColor( slider, false, false, thumbBorderColor, disabledThumbBorderColor, focusedThumbBorderColor, null, null )
: null; : null;
Color focusedColor = FlatUIUtils.deriveColor( this.focusedColor, focusBaseColor ); Color focusedColor = FlatUIUtils.deriveColor( this.focusedColor,
(foreground != defaultForeground) ? foreground : focusBaseColor );
FlatSliderUI.paintThumb( g, slider, thumbRect, isRoundThumb(), color, borderColor, focusedColor, focusWidth ); FlatSliderUI.paintThumb( g, slider, thumbRect, isRoundThumb(), color, borderColor, focusedColor, focusWidth );
} }
protected Color getTrackValueColor() {
Color foreground = slider.getForeground();
return (foreground != defaultForeground) ? foreground : trackValueColor;
}
protected Color getTrackColor() {
Color backround = slider.getBackground();
return (backround != defaultBackground) ? backround : trackColor;
}
protected Color getThumbColor() {
Color foreground = slider.getForeground();
return (foreground != defaultForeground) ? foreground : thumbColor;
}
protected boolean isRoundThumb() { protected boolean isRoundThumb() {
return !slider.getPaintTicks() && !slider.getPaintLabels(); return !slider.getPaintTicks() && !slider.getPaintLabels();
} }

View File

@@ -214,6 +214,13 @@ public class FlatComponentsTest
slider.setSnapToTicks( snapToTicks ); slider.setSnapToTicks( snapToTicks );
} }
private void sliderBorderChanged() {
boolean border = sliderBorderCheckBox.isSelected();
UIManager.put( "Slider.thumbBorderColor", border ? Color.green : null );
for( JSlider slider : allSliders )
slider.updateUI();
}
private void majorThickSpacingChanged() { private void majorThickSpacingChanged() {
int majorTickSpacing = (Integer) majorTickSpacingSpinner.getValue(); int majorTickSpacing = (Integer) majorTickSpacingSpinner.getValue();
for( JSlider slider : directionalSliders ) { for( JSlider slider : directionalSliders ) {
@@ -395,6 +402,7 @@ public class FlatComponentsTest
sliderInvertedCheckBox = new JCheckBox(); sliderInvertedCheckBox = new JCheckBox();
sliderSnapToTicksCheckBox = new JCheckBox(); sliderSnapToTicksCheckBox = new JCheckBox();
majorTickSpacingSpinner = new JSpinner(); majorTickSpacingSpinner = new JSpinner();
sliderBorderCheckBox = new JCheckBox();
minorTickSpacingSpinner = new JSpinner(); minorTickSpacingSpinner = new JSpinner();
sliderValueLabel = new JLabel(); sliderValueLabel = new JLabel();
JPanel panel7 = new JPanel(); JPanel panel7 = new JPanel();
@@ -1381,10 +1389,15 @@ public class FlatComponentsTest
majorTickSpacingSpinner.addChangeListener(e -> majorThickSpacingChanged()); majorTickSpacingSpinner.addChangeListener(e -> majorThickSpacingChanged());
panel6.add(majorTickSpacingSpinner, "cell 0 2"); panel6.add(majorTickSpacingSpinner, "cell 0 2");
//---- sliderBorderCheckBox ----
sliderBorderCheckBox.setText("border");
sliderBorderCheckBox.addActionListener(e -> sliderBorderChanged());
panel6.add(sliderBorderCheckBox, "cell 0 2");
//---- minorTickSpacingSpinner ---- //---- minorTickSpacingSpinner ----
minorTickSpacingSpinner.setModel(new SpinnerNumberModel(10, 0, 100, 5)); minorTickSpacingSpinner.setModel(new SpinnerNumberModel(10, 0, 100, 5));
minorTickSpacingSpinner.addChangeListener(e -> minorThickSpacingChanged()); minorTickSpacingSpinner.addChangeListener(e -> minorThickSpacingChanged());
panel6.add(minorTickSpacingSpinner, "cell 0 2"); panel6.add(minorTickSpacingSpinner, "cell 0 3");
//---- sliderValueLabel ---- //---- sliderValueLabel ----
sliderValueLabel.setText("slider value"); sliderValueLabel.setText("slider value");
@@ -1625,6 +1638,7 @@ public class FlatComponentsTest
private JCheckBox sliderInvertedCheckBox; private JCheckBox sliderInvertedCheckBox;
private JCheckBox sliderSnapToTicksCheckBox; private JCheckBox sliderSnapToTicksCheckBox;
private JSpinner majorTickSpacingSpinner; private JSpinner majorTickSpacingSpinner;
private JCheckBox sliderBorderCheckBox;
private JSpinner minorTickSpacingSpinner; private JSpinner minorTickSpacingSpinner;
private JLabel sliderValueLabel; private JLabel sliderValueLabel;
private JCheckBox indeterminateCheckBox; private JCheckBox indeterminateCheckBox;

View File

@@ -1243,6 +1243,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2" "value": "cell 0 2"
} ) } )
add( new FormComponent( "javax.swing.JCheckBox" ) {
name: "sliderBorderCheckBox"
"text": "border"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "sliderBorderChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2"
} )
add( new FormComponent( "javax.swing.JSpinner" ) { add( new FormComponent( "javax.swing.JSpinner" ) {
name: "minorTickSpacingSpinner" name: "minorTickSpacingSpinner"
"model": new javax.swing.SpinnerNumberModel( 10, 0, 100, 5 ) "model": new javax.swing.SpinnerNumberModel( 10, 0, 100, 5 )
@@ -1251,7 +1261,7 @@ new FormModel {
} }
addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "minorThickSpacingChanged", false ) ) addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "minorThickSpacingChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2" "value": "cell 0 3"
} ) } )
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
name: "sliderValueLabel" name: "sliderValueLabel"

View File

@@ -446,7 +446,7 @@ public class FlatTestFrame
Color green = dark ? Color.green.darker() : Color.green; Color green = dark ? Color.green.darker() : Color.green;
updateComponentsRecur( content, (c, type) -> { updateComponentsRecur( content, (c, type) -> {
if( type == "view" || type == "tab" ) { if( type == "view" || type == "tab" || c instanceof JSlider ) {
c.setForeground( explicit ? magenta : restoreColor ); c.setForeground( explicit ? magenta : restoreColor );
c.setBackground( explicit ? orange : restoreColor ); c.setBackground( explicit ? orange : restoreColor );
} else { } else {