diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java index 3cf5fcdb..7a41027b 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatLaf.java @@ -234,7 +234,7 @@ public abstract class FlatLaf return parseInstance( value ); // insets - if( key.endsWith( ".margin" ) || key.endsWith( ".padding" ) ) + if( key.endsWith( ".margin" ) || key.endsWith( ".padding" ) || key.endsWith( "Insets" ) ) return parseInsets( value ); // insets 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 new file mode 100644 index 00000000..55dd159d --- /dev/null +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSliderUI.java @@ -0,0 +1,176 @@ +/* + * Copyright 2019 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.formdev.flatlaf.ui; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.Path2D; +import java.awt.geom.RoundRectangle2D; +import javax.swing.JComponent; +import javax.swing.JSlider; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.basic.BasicSliderUI; +import com.formdev.flatlaf.util.UIScale; + +/** + * Provides the Flat LaF UI delegate for {@link javax.swing.JSlider}. + * + * @uiDefault Slider.font Font + * @uiDefault Slider.background Color + * @uiDefault Slider.foreground Color unused + * @uiDefault Slider.disabledForeground Color used for track and thumb if disabled + * @uiDefault Slider.trackColor Color + * @uiDefault Slider.thumbColor Color + * @uiDefault Slider.tickColor Color + * @uiDefault Slider.trackWidth int + * @uiDefault Slider.thumbWidth int + * @uiDefault Slider.horizontalSize Dimension preferred horizontal size; height is ignored; computed slider height is used + * @uiDefault Slider.verticalSize Dimension preferred vertical size; width is ignored; computed slider width is used + * @uiDefault Slider.minimumHorizontalSize Dimension height is ignored; computed slider height is used + * @uiDefault Slider.minimumVerticalSize Dimension width is ignored; computed slider width is used + * + * @author Karl Tauber + */ +public class FlatSliderUI + extends BasicSliderUI +{ + private int trackWidth; + private int thumbWidth; + + private Color trackColor; + private Color thumbColor; + private Color disabledForeground; + + public static ComponentUI createUI( JComponent c ) { + return new FlatSliderUI(); + } + + public FlatSliderUI() { + super( null ); + } + + @Override + protected void installDefaults( JSlider slider ) { + super.installDefaults( slider ); + + trackWidth = UIManager.getInt( "Slider.trackWidth" ); + thumbWidth = UIManager.getInt( "Slider.thumbWidth" ); + + trackColor = UIManager.getColor( "Slider.trackColor" ); + thumbColor = UIManager.getColor( "Slider.thumbColor" ); + disabledForeground = UIManager.getColor( "Slider.disabledForeground" ); + } + + @Override + public Dimension getPreferredHorizontalSize() { + return UIScale.scale( super.getPreferredHorizontalSize() ); + } + + @Override + public Dimension getPreferredVerticalSize() { + return UIScale.scale( super.getPreferredVerticalSize() ); + } + + @Override + public Dimension getMinimumHorizontalSize() { + return UIScale.scale( super.getMinimumHorizontalSize() ); + } + + @Override + public Dimension getMinimumVerticalSize() { + return UIScale.scale( super.getMinimumVerticalSize() ); + } + + @Override + protected int getTickLength() { + return UIScale.scale( super.getTickLength() ); + } + + @Override + protected Dimension getThumbSize() { + return new Dimension( UIScale.scale( thumbWidth ), UIScale.scale( thumbWidth ) ); + } + + @Override + public void paint( Graphics g, JComponent c ) { + FlatUIUtils.setRenderingHints( (Graphics2D) g ); + + super.paint( g, c ); + } + + @Override + public void paintFocus( Graphics g ) { + // do not paint dashed focus rectangle + } + + @Override + public void paintTrack( Graphics g ) { + g.setColor( slider.isEnabled() ? trackColor : disabledForeground ); + + float tw = UIScale.scale( (float) trackWidth ); + float arc = tw; + + if( slider.getOrientation() == JSlider.HORIZONTAL ) { + float y = trackRect.y + (trackRect.height - tw) / 2f; + ((Graphics2D)g).fill( new RoundRectangle2D.Float( trackRect.x, y, trackRect.width, tw, arc, arc ) ); + } else { + float x = trackRect.x + (trackRect.width - tw) / 2f; + ((Graphics2D)g).fill( new RoundRectangle2D.Float( x, trackRect.y, tw, trackRect.height, arc, arc ) ); + } + } + + @Override + public void paintThumb( Graphics g ) { + g.setColor( slider.isEnabled() ? thumbColor : disabledForeground ); + + if( !slider.getPaintTicks() ) + g.fillOval( thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height ); + else { + double w = thumbRect.width; + double h = thumbRect.height; + double wh = w / 2; + + Path2D thumb = new Path2D.Float( Path2D.WIND_NON_ZERO ); + thumb.moveTo( 0, 0 ); + thumb.lineTo( w, 0 ); + thumb.lineTo( w, h - wh ); + thumb.lineTo( wh, h ); + thumb.lineTo( 0, h - wh ); + thumb.closePath(); + + Graphics2D g2 = (Graphics2D) g.create(); + try { + g2.translate( thumbRect.x, thumbRect.y ); + if( slider.getOrientation() == JSlider.VERTICAL ) { + if( slider.getComponentOrientation().isLeftToRight() ) { + g2.translate( 0, thumbRect.height ); + g2.rotate( Math.toRadians( 270 ) ); + } else { + g2.translate( thumbRect.width, 0 ); + g2.rotate( Math.toRadians( 90 ) ); + } + } + g2.fill( thumb ); + } finally { + g2.dispose(); + } + } + } +} diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties index 31c551a1..40448c9e 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties @@ -117,3 +117,11 @@ ScrollBar.thumb=47A6A6A6 #---- Separator ---- Separator.foreground=515151 + + +#---- Slider ---- + +Slider.trackColor=646464 +Slider.thumbColor=A6A6A6 +Slider.tickColor=888888 +Slider.disabledForeground=4c5052 diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties index 4d4f95b8..63bdb8a9 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -28,6 +28,7 @@ RadioButtonUI=com.formdev.flatlaf.ui.FlatRadioButtonUI ScrollBarUI=com.formdev.flatlaf.ui.FlatScrollBarUI ScrollPaneUI=com.formdev.flatlaf.ui.FlatScrollPaneUI SeparatorUI=com.formdev.flatlaf.ui.FlatSeparatorUI +SliderUI=com.formdev.flatlaf.ui.FlatSliderUI TextAreaUI=com.formdev.flatlaf.ui.FlatTextAreaUI TextFieldUI=com.formdev.flatlaf.ui.FlatTextFieldUI TextPaneUI=com.formdev.flatlaf.ui.FlatTextPaneUI @@ -107,6 +108,13 @@ ScrollPane.border=com.formdev.flatlaf.ui.FlatBorder ScrollPane.background=@@ScrollBar.track +#---- Slider ---- + +Slider.focusInsets=0,0,0,0 +Slider.trackWidth=2 +Slider.thumbWidth=10 + + #---- TextArea ---- TextArea.border=com.formdev.flatlaf.ui.FlatMarginBorder diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties index 9ac14cd7..88ad20b0 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties @@ -117,3 +117,11 @@ ScrollBar.thumb=33737373 #---- Separator ---- Separator.foreground=cdcdcd + + +#---- Slider ---- + +Slider.trackColor=c4c4c4 +Slider.thumbColor=6e6e6e +Slider.tickColor=888888 +Slider.disabledForeground=c0c0c0 diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatComponentsTest.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatComponentsTest.java index b1bbfc06..b9f63b66 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatComponentsTest.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatComponentsTest.java @@ -120,6 +120,8 @@ public class FlatComponentsTest JScrollBar scrollBar2 = new JScrollBar(); JScrollBar scrollBar3 = new JScrollBar(); JSeparator separator2 = new JSeparator(); + JSlider slider2 = new JSlider(); + JSlider slider4 = new JSlider(); JScrollPane scrollPane14 = new JScrollPane(); progressBar3 = new JProgressBar(); progressBar4 = new JProgressBar(); @@ -128,6 +130,11 @@ public class FlatComponentsTest JScrollBar scrollBar4 = new JScrollBar(); JLabel separatorLabel = new JLabel(); JSeparator separator1 = new JSeparator(); + JLabel sliderLabel = new JLabel(); + JSlider slider1 = new JSlider(); + JSlider slider6 = new JSlider(); + JSlider slider3 = new JSlider(); + JSlider slider5 = new JSlider(); JLabel progressBarLabel = new JLabel(); progressBar1 = new JProgressBar(); progressBar2 = new JProgressBar(); @@ -159,6 +166,8 @@ public class FlatComponentsTest "[]" + "[]" + "[]" + + "[]" + + "[]" + "[]")); //---- labelLabel ---- @@ -565,15 +574,29 @@ public class FlatComponentsTest scrollPane13.setViewportView(panel1); } add(scrollPane13, "cell 1 11,grow,width 70,height 70"); - add(scrollBar2, "cell 2 11,growy"); + add(scrollBar2, "cell 2 11 1 4,growy"); //---- scrollBar3 ---- scrollBar3.setEnabled(false); - add(scrollBar3, "cell 2 11,growy"); + add(scrollBar3, "cell 2 11 1 4,growy"); //---- separator2 ---- separator2.setOrientation(SwingConstants.VERTICAL); - add(separator2, "cell 2 11,growy"); + add(separator2, "cell 2 11 1 4,growy"); + + //---- slider2 ---- + slider2.setOrientation(SwingConstants.VERTICAL); + slider2.setValue(30); + add(slider2, "cell 2 11 1 4,growy"); + + //---- slider4 ---- + slider4.setMinorTickSpacing(10); + slider4.setPaintTicks(true); + slider4.setMajorTickSpacing(50); + slider4.setPaintLabels(true); + slider4.setOrientation(SwingConstants.VERTICAL); + slider4.setValue(30); + add(slider4, "cell 2 11 1 4,growy"); add(scrollPane14, "cell 3 11,grow"); //---- progressBar3 ---- @@ -605,23 +628,53 @@ public class FlatComponentsTest add(separatorLabel, "cell 0 14"); add(separator1, "cell 1 14,growx"); + //---- sliderLabel ---- + sliderLabel.setText("JSlider:"); + add(sliderLabel, "cell 0 15"); + + //---- slider1 ---- + slider1.setValue(30); + add(slider1, "cell 1 15,aligny top,grow 100 0"); + + //---- slider6 ---- + slider6.setEnabled(false); + slider6.setValue(30); + add(slider6, "cell 2 15,aligny top,grow 100 0"); + + //---- slider3 ---- + slider3.setMinorTickSpacing(10); + slider3.setPaintTicks(true); + slider3.setMajorTickSpacing(50); + slider3.setPaintLabels(true); + slider3.setValue(30); + add(slider3, "cell 1 16,aligny top,grow 100 0"); + + //---- slider5 ---- + slider5.setMinorTickSpacing(10); + slider5.setPaintTicks(true); + slider5.setMajorTickSpacing(50); + slider5.setPaintLabels(true); + slider5.setEnabled(false); + slider5.setValue(30); + add(slider5, "cell 2 16,aligny top,grow 100 0"); + //---- progressBarLabel ---- progressBarLabel.setText("JProgressBar:"); - add(progressBarLabel, "cell 0 15"); + add(progressBarLabel, "cell 0 17"); //---- progressBar1 ---- progressBar1.setValue(50); - add(progressBar1, "cell 1 15"); + add(progressBar1, "cell 1 17"); //---- progressBar2 ---- progressBar2.setStringPainted(true); progressBar2.setValue(55); - add(progressBar2, "cell 3 15"); + add(progressBar2, "cell 3 17"); //---- indeterminateCheckBox ---- indeterminateCheckBox.setText("indeterminate"); indeterminateCheckBox.addActionListener(e -> indeterminateCheckBoxActionPerformed()); - add(indeterminateCheckBox, "cell 4 15"); + add(indeterminateCheckBox, "cell 4 17"); // JFormDesigner - End of component initialization //GEN-END:initComponents } diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatComponentsTest.jfd b/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatComponentsTest.jfd index 1695ebc1..3a0c4bc8 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatComponentsTest.jfd +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/FlatComponentsTest.jfd @@ -9,7 +9,7 @@ new FormModel { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "insets 0,hidemode 3,gap 5 5,ltr" "$columnConstraints": "[][][][][][]" - "$rowConstraints": "[][][][][][][][][][][][][][][][]" + "$rowConstraints": "[][][][][][][][][][][][][][][][][][]" } ) { name: "this" add( new FormComponent( "javax.swing.JLabel" ) { @@ -513,19 +513,37 @@ new FormModel { add( new FormComponent( "javax.swing.JScrollBar" ) { name: "scrollBar2" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 2 11,growy" + "value": "cell 2 11 1 4,growy" } ) add( new FormComponent( "javax.swing.JScrollBar" ) { name: "scrollBar3" "enabled": false }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 2 11,growy" + "value": "cell 2 11 1 4,growy" } ) add( new FormComponent( "javax.swing.JSeparator" ) { name: "separator2" "orientation": 1 }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 2 11,growy" + "value": "cell 2 11 1 4,growy" + } ) + add( new FormComponent( "javax.swing.JSlider" ) { + name: "slider2" + "orientation": 1 + "value": 30 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 11 1 4,growy" + } ) + add( new FormComponent( "javax.swing.JSlider" ) { + name: "slider4" + "minorTickSpacing": 10 + "paintTicks": true + "majorTickSpacing": 50 + "paintLabels": true + "orientation": 1 + "value": 30 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 11 1 4,growy" } ) add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) { name: "scrollPane14" @@ -583,11 +601,51 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 14,growx" } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "sliderLabel" + "text": "JSlider:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 15" + } ) + add( new FormComponent( "javax.swing.JSlider" ) { + name: "slider1" + "value": 30 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 15,aligny top,grow 100 0" + } ) + add( new FormComponent( "javax.swing.JSlider" ) { + name: "slider6" + "enabled": false + "value": 30 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 15,aligny top,grow 100 0" + } ) + add( new FormComponent( "javax.swing.JSlider" ) { + name: "slider3" + "minorTickSpacing": 10 + "paintTicks": true + "majorTickSpacing": 50 + "paintLabels": true + "value": 30 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 16,aligny top,grow 100 0" + } ) + add( new FormComponent( "javax.swing.JSlider" ) { + name: "slider5" + "minorTickSpacing": 10 + "paintTicks": true + "majorTickSpacing": 50 + "paintLabels": true + "enabled": false + "value": 30 + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 16,aligny top,grow 100 0" + } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "progressBarLabel" "text": "JProgressBar:" }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 15" + "value": "cell 0 17" } ) add( new FormComponent( "javax.swing.JProgressBar" ) { name: "progressBar1" @@ -596,7 +654,7 @@ new FormModel { "JavaCodeGenerator.variableLocal": false } }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 15" + "value": "cell 1 17" } ) add( new FormComponent( "javax.swing.JProgressBar" ) { name: "progressBar2" @@ -606,7 +664,7 @@ new FormModel { "JavaCodeGenerator.variableLocal": false } }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 3 15" + "value": "cell 3 17" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "indeterminateCheckBox" @@ -616,11 +674,11 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "indeterminateCheckBoxActionPerformed", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 4 15" + "value": "cell 4 17" } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) - "size": new java.awt.Dimension( 720, 650 ) + "size": new java.awt.Dimension( 790, 715 ) } ) } } diff --git a/flatlaf-core/src/test/resources/com/formdev/flatlaf/FlatTestLaf.properties b/flatlaf-core/src/test/resources/com/formdev/flatlaf/FlatTestLaf.properties index c6e1df08..1ccc2d86 100644 --- a/flatlaf-core/src/test/resources/com/formdev/flatlaf/FlatTestLaf.properties +++ b/flatlaf-core/src/test/resources/com/formdev/flatlaf/FlatTestLaf.properties @@ -110,3 +110,11 @@ ScrollBar.thumb=33737373 #---- Separator ---- Separator.foreground=00bb00 + + +#---- Slider ---- + +Slider.trackColor=00bb00 +Slider.thumbColor=880000 +Slider.tickColor=ff0000 +Slider.disabledForeground=000088