diff --git a/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/FlatJideOssDefaultsAddon.java b/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/FlatJideOssDefaultsAddon.java index cb0494d5..096a0ded 100644 --- a/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/FlatJideOssDefaultsAddon.java +++ b/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/FlatJideOssDefaultsAddon.java @@ -71,7 +71,8 @@ public class FlatJideOssDefaultsAddon Object key = e.getKey(); if( key instanceof String && (((String)key).startsWith( "Jide" ) || - ((String)key).equals( "Resizable.resizeBorder" )) ) + key.equals( "RangeSliderUI" ) || + key.equals( "Resizable.resizeBorder" )) ) { jideDefaults.put( key, e.getValue() ); } 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 new file mode 100644 index 00000000..6302c13d --- /dev/null +++ b/flatlaf-jide-oss/src/main/java/com/formdev/flatlaf/jideoss/ui/FlatRangeSliderUI.java @@ -0,0 +1,261 @@ +package com.formdev.flatlaf.jideoss.ui; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.Path2D; +import java.awt.geom.RoundRectangle2D; +import java.util.Dictionary; +import java.util.Enumeration; +import javax.swing.JComponent; +import javax.swing.JSlider; +import javax.swing.LookAndFeel; +import javax.swing.UIManager; +import javax.swing.plaf.ComponentUI; +import com.formdev.flatlaf.ui.FlatUIUtils; +import com.formdev.flatlaf.util.UIScale; +import com.jidesoft.plaf.basic.BasicRangeSliderUI; + +public class FlatRangeSliderUI + extends BasicRangeSliderUI + +{ + + private int trackWidth; + private int thumbWidth; + private Color trackColor; + private Color thumbColor; + private Color focusColor; + private Color hoverColor; + private Color disabledForeground; + private Rectangle firstThumbRect; + + public FlatRangeSliderUI( JComponent slider ) { + super( (JSlider) slider ); + } + + public static ComponentUI createUI( JComponent slider ) { + return new FlatRangeSliderUI( slider ); + } + + @Override + public void installUI( JComponent c ) { + super.installUI( c ); + + // update label UIs, which is necessary because RangeSlider does not invoke JSlider.updateLabelUIs() + updateLabelUIs( c ); + } + + @Override + public void uninstallUI( JComponent c ) { + // update label UIs also on uninstall to avoid light labels when switching + // from dark FlatLaf theme to another Laf + updateLabelUIs( c ); + + super.uninstallUI( c ); + } + + protected void updateLabelUIs( JComponent c ) { + Dictionary labelTable = ((JSlider)c).getLabelTable(); + if( labelTable == null ) + return; + + Enumeration e = labelTable.elements(); + while( e.hasMoreElements() ) { + JComponent label = (JComponent) e.nextElement(); + label.updateUI(); + label.setSize( label.getPreferredSize() ); + } + } + + @Override + public void paint( Graphics g, JComponent c ) { + FlatUIUtils.setRenderingHints( (Graphics2D) g ); + + second = false; + super.paint( g, c ); + + Rectangle clip = g.getClipBounds(); + + firstThumbRect = new Rectangle( thumbRect ); + + second = true; + Point p = adjustThumbForHighValue(); + + if( clip.intersects( thumbRect ) ) { + paintTrack( g ); + paintThumb( g ); + } + + restoreThumbForLowValue( p ); + second = false; + } + + @Override + public void paintTrack( Graphics g ) { + boolean enabled = slider.isEnabled(); + float tw = UIScale.scale( (float) trackWidth ); + float arc = tw; + + RoundRectangle2D coloredTrack = null; + RoundRectangle2D track; + if( slider.getOrientation() == JSlider.HORIZONTAL ) { + float y = trackRect.y + (trackRect.height - tw) / 2f; + if( enabled ) { + if( slider.getComponentOrientation().isLeftToRight() ) { + int cw = thumbRect.x + (thumbRect.width / 2) - trackRect.x; + if( second ) { + track = new RoundRectangle2D.Float( trackRect.x + cw, y, trackRect.width - cw, tw, arc, arc ); + int firstCw = firstThumbRect.x + (firstThumbRect.width / 2) - trackRect.x; + coloredTrack = new RoundRectangle2D.Float( trackRect.x + firstCw, y, cw - firstCw, tw, arc, + arc ); + } else { + track = new RoundRectangle2D.Float( trackRect.x, y, cw, tw, arc, arc ); + } + } else { + int cw = trackRect.x + trackRect.width - thumbRect.x - (thumbRect.width / 2); + if( second ) { + int firstCw = trackRect.x + trackRect.width - firstThumbRect.x - (firstThumbRect.width / 2); + track = new RoundRectangle2D.Float( trackRect.x, y, trackRect.width - cw, tw, arc, arc ); + coloredTrack = new RoundRectangle2D.Float( trackRect.x + trackRect.width - cw, y, cw - firstCw, + tw, arc, arc ); + } else { + track = new RoundRectangle2D.Float( trackRect.x + trackRect.width - cw, y, cw, tw, arc, arc ); + } + } + } else { + track = new RoundRectangle2D.Float( trackRect.x, y, trackRect.width, tw, arc, arc ); + } + } else { + float x = trackRect.x + (trackRect.width - tw) / 2f; + if( enabled ) { + int ch = thumbRect.y + (thumbRect.height / 2) - trackRect.y; + if( second ) { + int firstCh = firstThumbRect.y + (firstThumbRect.height / 2) - trackRect.y; + track = new RoundRectangle2D.Float( x, trackRect.y, tw, ch, arc, arc ); + coloredTrack = new RoundRectangle2D.Float( x, trackRect.y + ch, tw, firstCh - ch, arc, arc ); + } else { + track = new RoundRectangle2D.Float( x, trackRect.y + ch, tw, trackRect.height - ch, arc, arc ); + } + } else { + track = new RoundRectangle2D.Float( x, trackRect.y, tw, trackRect.height, arc, arc ); + } + } + + if( coloredTrack != null ) { + g.setColor( FlatUIUtils.deriveColor( + FlatUIUtils.isPermanentFocusOwner( slider ) ? focusColor : (hover ? hoverColor : thumbColor), + thumbColor ) ); + ((Graphics2D) g).fill( coloredTrack ); + } + + g.setColor( enabled ? trackColor : disabledForeground ); + ((Graphics2D) g).fill( track ); + + } + + //above here the code is same of FlatSliderUI + + @Override + protected void installDefaults( JSlider slider ) { + super.installDefaults( slider ); + + LookAndFeel.installProperty( slider, "opaque", false ); + + trackWidth = UIManager.getInt( "Slider.trackWidth" ); + thumbWidth = UIManager.getInt( "Slider.thumbWidth" ); + + trackColor = UIManager.getColor( "Slider.trackColor" ); + thumbColor = UIManager.getColor( "Slider.thumbColor" ); + focusColor = FlatUIUtils.getUIColor( "Slider.focusedColor", "Component.focusColor" ); + hoverColor = FlatUIUtils.getUIColor( "Slider.hoverColor", focusColor ); + disabledForeground = UIManager.getColor( "Slider.disabledForeground" ); + } + + @Override + protected void uninstallDefaults( JSlider slider ) { + super.uninstallDefaults( slider ); + + trackColor = null; + thumbColor = null; + focusColor = null; + hoverColor = null; + disabledForeground = null; + } + + @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 paintFocus( Graphics g ) { + // do not paint dashed focus rectangle + } + + @Override + public void paintThumb( Graphics g ) { + g.setColor( FlatUIUtils.deriveColor( slider.isEnabled() ? (FlatUIUtils.isPermanentFocusOwner( slider ) + ? focusColor + : (hover ? hoverColor : thumbColor)) : disabledForeground, thumbColor ) ); + + if( isRoundThumb() ) + 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 = FlatUIUtils.createPath( 0, 0, w, 0, w, (h - wh), wh, h, 0, (h - wh) ); + + 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(); + } + } + } + + private boolean isRoundThumb() { + return !slider.getPaintTicks() && !slider.getPaintLabels(); + } +} diff --git a/flatlaf-jide-oss/src/main/resources/com/formdev/flatlaf/jideoss/FlatLaf.properties b/flatlaf-jide-oss/src/main/resources/com/formdev/flatlaf/jideoss/FlatLaf.properties index 3cd194af..af28ab79 100644 --- a/flatlaf-jide-oss/src/main/resources/com/formdev/flatlaf/jideoss/FlatLaf.properties +++ b/flatlaf-jide-oss/src/main/resources/com/formdev/flatlaf/jideoss/FlatLaf.properties @@ -17,6 +17,7 @@ #---- UI delegates ---- JideTabbedPaneUI=com.formdev.flatlaf.jideoss.ui.FlatJideTabbedPaneUI +RangeSliderUI=com.formdev.flatlaf.jideoss.ui.FlatRangeSliderUI #---- JidePopup ---- diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/jideoss/FlatRangeSliderTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/jideoss/FlatRangeSliderTest.java new file mode 100644 index 00000000..896ba05b --- /dev/null +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/jideoss/FlatRangeSliderTest.java @@ -0,0 +1,159 @@ +package com.formdev.flatlaf.testing.jideoss; + +import javax.swing.JCheckBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.SwingConstants; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import com.formdev.flatlaf.testing.FlatTestFrame; +import com.formdev.flatlaf.testing.FlatTestPanel; +import com.jgoodies.forms.factories.CC; +import com.jgoodies.forms.layout.FormLayout; +import com.jidesoft.plaf.LookAndFeelFactory; +import com.jidesoft.swing.RangeSlider; +import net.miginfocom.swing.MigLayout; + +public class FlatRangeSliderTest + extends FlatTestPanel +{ + + public static void main( String[] args ) { + SwingUtilities.invokeLater( () -> { + FlatTestFrame frame = FlatTestFrame.create( args, "FlatRangeSliderTest" ); + LookAndFeelFactory.installJideExtension(); + frame.showFrame( FlatRangeSliderTest::new ); + + UIManager.addPropertyChangeListener( e -> { + if( "lookAndFeel".equals( e.getPropertyName() ) ) { + LookAndFeelFactory.installJideExtension(); + } + } ); + } ); + } + + FlatRangeSliderTest() { + initComponents(); + } + + private void paintLabels() { + horizontalRangeSlider.setPaintLabels( paintLabel.isSelected() ); + verticalRangeSlider.setPaintLabels( paintLabel.isSelected() ); + } + + private void paintTicks() { + horizontalRangeSlider.setPaintTicks( paintTick.isSelected() ); + verticalRangeSlider.setPaintTicks( paintTick.isSelected() ); + } + + private void initComponents() { + // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents + // Generated using JFormDesigner Evaluation license - unknown + JPanel mainPanel = new JPanel(); + JLabel tabbedPaneLabel = new JLabel(); + JLabel horizontalLabel = new JLabel(); + horizontalRangeSlider = new RangeSlider(); + JLabel verticalLabel = new JLabel(); + verticalRangeSlider = new RangeSlider(); + JPanel configurationPanel = new JPanel(); + paintTick = new JCheckBox(); + paintLabel = new JCheckBox(); + + //======== this ======== + setBorder (new javax. swing. border. CompoundBorder( new javax .swing .border .TitledBorder (new javax + . swing. border. EmptyBorder( 0, 0, 0, 0) , "JF\u006frmD\u0065sig\u006eer \u0045val\u0075ati\u006fn", javax. swing + . border. TitledBorder. CENTER, javax. swing. border. TitledBorder. BOTTOM, new java .awt . + Font ("Dia\u006cog" ,java .awt .Font .BOLD ,12 ), java. awt. Color. red + ) , getBorder( )) ); addPropertyChangeListener (new java. beans. PropertyChangeListener( ){ @Override + public void propertyChange (java .beans .PropertyChangeEvent e) {if ("\u0062ord\u0065r" .equals (e .getPropertyName ( + ) )) throw new RuntimeException( ); }} ); + setLayout(new MigLayout( + "insets dialog,hidemode 3", + // columns + "[grow,fill]", + // rows + "[grow,fill]")); + + //======== mainPanel ======== + { + mainPanel.setOpaque(false); + mainPanel.setLayout(new FormLayout( + "70dlu:grow, $lcgap, 70dlu:grow", + "pref, 2*($lgap, fill:70dlu:grow), $lgap, pref")); + + //---- tabbedPaneLabel ---- + tabbedPaneLabel.setText("RangeSlider:"); + mainPanel.add(tabbedPaneLabel, CC.xy(1, 1)); + + //---- horizontalLabel ---- + horizontalLabel.setText("Horizontal"); + mainPanel.add(horizontalLabel, CC.xy(1, 3)); + mainPanel.add(horizontalRangeSlider, CC.xy(3, 3)); + + //---- verticalLabel ---- + verticalLabel.setText("Vertical"); + mainPanel.add(verticalLabel, CC.xy(1, 5)); + mainPanel.add(verticalRangeSlider, CC.xy(3, 5)); + + //======== configurationPanel ======== + { + configurationPanel.setOpaque(false); + configurationPanel.setLayout(new MigLayout( + "insets 0,hidemode 3", + // columns + "[]" + + "[]" + + "[]", + // rows + "[center]")); + + //---- paintTick ---- + paintTick.setText("PaintTicks"); + paintTick.setMnemonic('T'); + paintTick.setSelected(true); + paintTick.addActionListener(e -> paintTicks()); + configurationPanel.add(paintTick, "cell 0 0"); + + //---- paintLabel ---- + paintLabel.setText("PaintLabels"); + paintLabel.setMnemonic('L'); + paintLabel.setSelected(true); + paintLabel.addActionListener(e -> paintLabels()); + configurationPanel.add(paintLabel, "cell 2 0,alignx left,growx 0"); + } + mainPanel.add(configurationPanel, CC.xywh(1, 7, 3, 1)); + } + add(mainPanel, "cell 0 0"); + // JFormDesigner - End of component initialization //GEN-END:initComponents + + horizontalRangeSlider.setOrientation( SwingConstants.HORIZONTAL ); + horizontalRangeSlider.setMinimum( 0 ); + horizontalRangeSlider.setMaximum( 100 ); + horizontalRangeSlider.setLowValue( 10 ); + horizontalRangeSlider.setHighValue( 90 ); + horizontalRangeSlider.setLabelTable( horizontalRangeSlider.createStandardLabels( 10 ) ); + horizontalRangeSlider.setMinorTickSpacing( 5 ); + horizontalRangeSlider.setMajorTickSpacing( 10 ); + horizontalRangeSlider.setPaintTicks( true ); + horizontalRangeSlider.setPaintLabels( true ); + + verticalRangeSlider.setOrientation( SwingConstants.VERTICAL ); + verticalRangeSlider.setMinimum( 0 ); + verticalRangeSlider.setMaximum( 100 ); + verticalRangeSlider.setLowValue( 10 ); + verticalRangeSlider.setHighValue( 90 ); + verticalRangeSlider.setLabelTable( horizontalRangeSlider.createStandardLabels( 10 ) ); + verticalRangeSlider.setMinorTickSpacing( 5 ); + verticalRangeSlider.setMajorTickSpacing( 10 ); + verticalRangeSlider.setPaintTicks( true ); + verticalRangeSlider.setPaintLabels( true ); + } + + // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables + // Generated using JFormDesigner Evaluation license - unknown + private RangeSlider horizontalRangeSlider; + private RangeSlider verticalRangeSlider; + private JCheckBox paintTick; + private JCheckBox paintLabel; + // JFormDesigner - End of variables declaration //GEN-END:variables +} diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/jideoss/FlatRangeSliderTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/jideoss/FlatRangeSliderTest.jfd new file mode 100644 index 00000000..58fe9188 --- /dev/null +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/jideoss/FlatRangeSliderTest.jfd @@ -0,0 +1,102 @@ +JFDML JFormDesigner: "7.0.2.6.321" Java: "11.0.8" encoding: "UTF-8" + +new FormModel { + contentType: "form/swing" + root: new FormRoot { + auxiliary() { + "JavaCodeGenerator.defaultVariableLocal": true + } + add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$layoutConstraints": "insets dialog,hidemode 3" + "$columnConstraints": "[grow,fill]" + "$rowConstraints": "[grow,fill]" + } ) { + name: "this" + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class com.jgoodies.forms.layout.FormLayout ) { + "$columnSpecs": "70dlu:grow, labelcompgap, 70dlu:grow" + "$rowSpecs": "pref, linegap, fill:70dlu:grow, linegap, fill:70dlu:grow, linegap, pref" + } ) { + name: "mainPanel" + "opaque": false + add( new FormComponent( "javax.swing.JLabel" ) { + name: "tabbedPaneLabel" + "text": "RangeSlider:" + }, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) { + "gridX": 1 + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "horizontalLabel" + "text": "Horizontal" + }, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) { + "gridX": 1 + "gridY": 3 + } ) + add( new FormComponent( "com.jidesoft.swing.RangeSlider" ) { + name: "horizontalRangeSlider" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) { + "gridX": 3 + "gridY": 3 + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "verticalLabel" + "text": "Vertical" + }, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) { + "gridX": 1 + "gridY": 5 + } ) + add( new FormComponent( "com.jidesoft.swing.RangeSlider" ) { + name: "verticalRangeSlider" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) { + "gridY": 5 + "gridX": 3 + } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$layoutConstraints": "insets 0,hidemode 3" + "$columnConstraints": "[][][]" + "$rowConstraints": "[center]" + } ) { + name: "configurationPanel" + "opaque": false + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "paintTick" + "text": "PaintTicks" + "mnemonic": 84 + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "paintTicks", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "paintLabel" + "text": "PaintLabels" + "mnemonic": 76 + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "paintLabels", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 0,alignx left,growx 0" + } ) + }, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) { + "gridY": 7 + "gridWidth": 3 + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 0 ) + "size": new java.awt.Dimension( 550, 500 ) + } ) + } +}