diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f0bb275..cc563775 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ FlatLaf Change Log UIManager.put("Button.defaultButtonFollowsFocus",true);`. - ComboBox, Spinner and SplitPaneDivider: Added pressed feedback to arrow 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 #229) - Extras: UI defaults inspector: diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSliderUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSliderUI.java index a88bcf9c..b44f769f 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSliderUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSliderUI.java @@ -91,6 +91,9 @@ public class FlatSliderUI protected Color disabledThumbColor; protected Color disabledThumbBorderColor; + private Color defaultBackground; + private Color defaultForeground; + protected boolean thumbHover; protected boolean thumbPressed; @@ -131,6 +134,9 @@ public class FlatSliderUI disabledTrackColor = UIManager.getColor( "Slider.disabledTrackColor" ); disabledThumbColor = UIManager.getColor( "Slider.disabledThumbColor" ); disabledThumbBorderColor = FlatUIUtils.getUIColor( "Slider.disabledThumbBorderColor", "Component.disabledBorderColor" ); + + defaultBackground = UIManager.getColor( "Slider.background" ); + defaultForeground = UIManager.getColor( "Slider.foreground" ); } @Override @@ -149,6 +155,9 @@ public class FlatSliderUI disabledTrackColor = null; disabledThumbColor = null; disabledThumbBorderColor = null; + + defaultBackground = null; + defaultForeground = null; } @Override @@ -289,25 +298,28 @@ debug*/ coloredTrack = temp; } - g.setColor( trackValueColor ); + g.setColor( getTrackValueColor() ); ((Graphics2D)g).fill( coloredTrack ); } - g.setColor( enabled ? trackColor : disabledTrackColor ); + g.setColor( enabled ? getTrackColor() : disabledTrackColor ); ((Graphics2D)g).fill( track ); } @Override public void paintThumb( Graphics g ) { + Color thumbColor = getThumbColor(); Color color = stateColor( slider, thumbHover, thumbPressed, thumbColor, disabledThumbColor, null, hoverThumbColor, pressedThumbColor ); 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 ) : 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 ); } @@ -436,6 +448,21 @@ debug*/ 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, Color enabledColor, Color disabledColor, Color focusedColor, Color hoverColor, Color pressedColor ) { diff --git a/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatRangeSliderUI.java b/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatRangeSliderUI.java index 0591cba8..fbd9f482 100644 --- a/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatRangeSliderUI.java +++ b/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatRangeSliderUI.java @@ -64,6 +64,9 @@ public class FlatRangeSliderUI protected Color disabledThumbColor; protected Color disabledThumbBorderColor; + private Color defaultBackground; + private Color defaultForeground; + private Object[] oldRenderingHints; public static ComponentUI createUI( JComponent c ) { @@ -129,6 +132,9 @@ public class FlatRangeSliderUI disabledTrackColor = UIManager.getColor( "Slider.disabledTrackColor" ); disabledThumbColor = UIManager.getColor( "Slider.disabledThumbColor" ); disabledThumbBorderColor = FlatUIUtils.getUIColor( "Slider.disabledThumbBorderColor", "Component.disabledBorderColor" ); + + defaultBackground = UIManager.getColor( "Slider.background" ); + defaultForeground = UIManager.getColor( "Slider.foreground" ); } @Override @@ -149,6 +155,9 @@ public class FlatRangeSliderUI disabledTrackColor = null; disabledThumbColor = null; disabledThumbBorderColor = null; + + defaultBackground = null; + defaultForeground = null; } @Override @@ -278,13 +287,14 @@ debug*/ 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 ); if( coloredTrack != null ) { boolean trackHover = hover && rollover1 && rollover2; boolean trackPressed = pressed1 && pressed2; + Color trackValueColor = getTrackValueColor(); Color color = FlatSliderUI.stateColor( slider, trackHover, trackPressed, trackValueColor, null, null, hoverTrackColor, pressedTrackColor ); @@ -298,19 +308,37 @@ debug*/ boolean thumbHover = hover && ((!second && rollover1) || (second && rollover2)); boolean thumbPressed = (!second && pressed1) || (second && pressed2); + Color thumbColor = getThumbColor(); Color color = FlatSliderUI.stateColor( slider, thumbHover, thumbPressed, thumbColor, disabledThumbColor, null, hoverThumbColor, pressedThumbColor ); 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 ) : 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 ); } + 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() { return !slider.getPaintTicks() && !slider.getPaintLabels(); } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponentsTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponentsTest.java index 371d9a1d..94df07b0 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponentsTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponentsTest.java @@ -214,6 +214,13 @@ public class FlatComponentsTest 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() { int majorTickSpacing = (Integer) majorTickSpacingSpinner.getValue(); for( JSlider slider : directionalSliders ) { @@ -395,6 +402,7 @@ public class FlatComponentsTest sliderInvertedCheckBox = new JCheckBox(); sliderSnapToTicksCheckBox = new JCheckBox(); majorTickSpacingSpinner = new JSpinner(); + sliderBorderCheckBox = new JCheckBox(); minorTickSpacingSpinner = new JSpinner(); sliderValueLabel = new JLabel(); JPanel panel7 = new JPanel(); @@ -1381,10 +1389,15 @@ public class FlatComponentsTest majorTickSpacingSpinner.addChangeListener(e -> majorThickSpacingChanged()); panel6.add(majorTickSpacingSpinner, "cell 0 2"); + //---- sliderBorderCheckBox ---- + sliderBorderCheckBox.setText("border"); + sliderBorderCheckBox.addActionListener(e -> sliderBorderChanged()); + panel6.add(sliderBorderCheckBox, "cell 0 2"); + //---- minorTickSpacingSpinner ---- minorTickSpacingSpinner.setModel(new SpinnerNumberModel(10, 0, 100, 5)); minorTickSpacingSpinner.addChangeListener(e -> minorThickSpacingChanged()); - panel6.add(minorTickSpacingSpinner, "cell 0 2"); + panel6.add(minorTickSpacingSpinner, "cell 0 3"); //---- sliderValueLabel ---- sliderValueLabel.setText("slider value"); @@ -1625,6 +1638,7 @@ public class FlatComponentsTest private JCheckBox sliderInvertedCheckBox; private JCheckBox sliderSnapToTicksCheckBox; private JSpinner majorTickSpacingSpinner; + private JCheckBox sliderBorderCheckBox; private JSpinner minorTickSpacingSpinner; private JLabel sliderValueLabel; private JCheckBox indeterminateCheckBox; diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponentsTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponentsTest.jfd index a8c70741..c6ec4fae 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponentsTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatComponentsTest.jfd @@ -1243,6 +1243,16 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "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" ) { name: "minorTickSpacingSpinner" "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 ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 2" + "value": "cell 0 3" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "sliderValueLabel" diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java index fff7b226..c93d54e2 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatTestFrame.java @@ -446,7 +446,7 @@ public class FlatTestFrame Color green = dark ? Color.green.darker() : Color.green; updateComponentsRecur( content, (c, type) -> { - if( type == "view" || type == "tab" ) { + if( type == "view" || type == "tab" || c instanceof JSlider ) { c.setForeground( explicit ? magenta : restoreColor ); c.setBackground( explicit ? orange : restoreColor ); } else {