diff --git a/CHANGELOG.md b/CHANGELOG.md index 178cdfa6..c0775469 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,8 @@ FlatLaf Change Log #### New features and improvements -- Slider: Clicking on track now immediately moves the thumb to mouse location - and starts dragging the thumb. Use `UIManager.put( +- Slider and JIDE RangeSlider: Clicking on track now immediately moves the thumb + to mouse location and starts dragging the thumb. Use `UIManager.put( "Slider.scrollOnTrackClick", true )` to enable old behavior that scrolls the thumb when clicking on track. - Slider: Snap to ticks is now done while dragging the thumb. Use 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 da9de82c..a8793da6 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 @@ -23,12 +23,14 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; +import java.awt.event.MouseEvent; 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.SwingUtilities; import javax.swing.UIManager; import javax.swing.plaf.ComponentUI; import com.formdev.flatlaf.ui.FlatSliderUI; @@ -144,6 +146,11 @@ public class FlatRangeSliderUI disabledThumbBorderColor = null; } + @Override + protected TrackListener createTrackListener( JSlider slider ) { + return new FlatRangeTrackListener( super.createTrackListener( slider ) ); + } + @Override public int getBaseline( JComponent c, int width, int height ) { if( c == null ) @@ -300,4 +307,64 @@ debug*/ protected boolean isRoundThumb() { return !slider.getPaintTicks() && !slider.getPaintLabels(); } + + //---- class FlatRangeTrackListener --------------------------------------- + + protected class FlatRangeTrackListener + extends RangeTrackListener + { + public FlatRangeTrackListener( TrackListener listener ) { + super( listener ); + } + + @Override + public void mousePressed( MouseEvent e ) { + if( !slider.isEnabled() ) + return; + + // use "old" behavior when clicking on track + if( UIManager.getBoolean( "Slider.scrollOnTrackClick" ) ) { + super.mousePressed( e ); + return; + } + + // "new" behavior set thumb to mouse location when clicking on track + + int x = e.getX(); + int y = e.getY(); + int handle = getMouseHandle( x, y ); + + // clicked on thumb --> let super class do the work + if( handle != MOUSE_HANDLE_LOWER && handle != MOUSE_HANDLE_UPPER ) { + super.mousePressed( e ); + return; + } + + if( UIManager.getBoolean( "Slider.onlyLeftMouseButtonDrag" ) && + !SwingUtilities.isLeftMouseButton( e ) ) + return; + + // get low or high thumb rectangle + Rectangle thumbRect = FlatRangeSliderUI.this.thumbRect; + if( handle == MOUSE_HANDLE_UPPER ) { + Point p = adjustThumbForHighValue(); + thumbRect = new Rectangle( FlatRangeSliderUI.this.thumbRect ); + restoreThumbForLowValue( p ); + } + + // move the mouse event coordinates to the center of the thumb + int tx = thumbRect.x + (thumbRect.width / 2) - x; + int ty = thumbRect.y + (thumbRect.height / 2) - y; + e.translatePoint( tx, ty ); + + // invoke super mousePressed() to start dragging thumb + super.mousePressed( e ); + + // move the mouse event coordinates back to current mouse location + e.translatePoint( -tx, -ty ); + + // invoke mouseDragged() to update thumb location + mouseDragged( e ); + } + } } 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 index 00eaa0a5..a84c6c88 100644 --- 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 @@ -16,12 +16,14 @@ package com.formdev.flatlaf.testing.jideoss; +import javax.swing.*; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JSlider; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; +import javax.swing.event.ChangeListener; import com.formdev.flatlaf.testing.FlatTestFrame; import com.formdev.flatlaf.testing.FlatTestPanel; import com.jidesoft.plaf.LookAndFeelFactory; @@ -46,8 +48,43 @@ public class FlatRangeSliderTest } ); } + private final JSlider[] allSliders; + private final JSlider[] directionalSliders; + FlatRangeSliderTest() { initComponents(); + + allSliders = new JSlider[] { + horizontalRangeSlider, + verticalRangeSlider, + horizontalSlider, + verticalSlider, + horizontalRangeSlider2, + verticalRangeSlider2, + horizontalSlider2, + verticalSlider2, + }; + directionalSliders = new JSlider[] { + horizontalRangeSlider, + verticalRangeSlider, + horizontalSlider, + verticalSlider, + }; + + ChangeListener sliderChanged = e -> { + JSlider slider = (JSlider) e.getSource(); + String text; + if( slider instanceof RangeSlider ) { + RangeSlider rangeSlider = (RangeSlider) slider; + text = rangeSlider.getLowValue() + " - " + rangeSlider.getHighValue() + + " " + slider.getValueIsAdjusting(); + } else + text = slider.getValue() + " " + slider.getValueIsAdjusting(); + sliderValueLabel.setText( text ); +// System.out.println( text ); + }; + for( JSlider slider : allSliders ) + slider.addChangeListener( sliderChanged ); } private void paintLabels() { @@ -66,6 +103,26 @@ public class FlatRangeSliderTest verticalSlider.setPaintTicks( selected ); } + private void sliderSnapToTicksChanged() { + boolean snapToTicks = sliderSnapToTicksCheckBox.isSelected(); + for( JSlider slider : allSliders ) + slider.setSnapToTicks( snapToTicks ); + } + + private void majorThickSpacingChanged() { + int majorTickSpacing = (Integer) majorTickSpacingSpinner.getValue(); + for( JSlider slider : directionalSliders ) { + slider.setLabelTable( null ); + slider.setMajorTickSpacing( majorTickSpacing ); + } + } + + private void minorThickSpacingChanged() { + int minorTickSpacing = (Integer) minorTickSpacingSpinner.getValue(); + for( JSlider slider : directionalSliders ) + slider.setMinorTickSpacing( minorTickSpacing ); + } + private void initComponents() { // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents JLabel tabbedPaneLabel = new JLabel(); @@ -81,13 +138,18 @@ public class FlatRangeSliderTest verticalSlider2 = new JSlider(); paintTick = new JCheckBox(); paintLabel = new JCheckBox(); + sliderSnapToTicksCheckBox = new JCheckBox(); + majorTickSpacingSpinner = new JSpinner(); + minorTickSpacingSpinner = new JSpinner(); + sliderValueLabel = new JLabel(); //======== this ======== setLayout(new MigLayout( "insets dialog,hidemode 3", // columns "[left]" + - "[240,left]", + "[240,left]" + + "[fill]", // rows "[fill]" + "[center]" + @@ -170,14 +232,33 @@ public class FlatRangeSliderTest paintTick.setMnemonic('T'); paintTick.setSelected(true); paintTick.addActionListener(e -> paintTicks()); - add(paintTick, "cell 0 6 2 1"); + add(paintTick, "cell 0 6 3 1"); //---- paintLabel ---- paintLabel.setText("PaintLabels"); paintLabel.setMnemonic('L'); paintLabel.setSelected(true); paintLabel.addActionListener(e -> paintLabels()); - add(paintLabel, "cell 0 6 2 1"); + add(paintLabel, "cell 0 6 3 1"); + + //---- sliderSnapToTicksCheckBox ---- + sliderSnapToTicksCheckBox.setText("snap to ticks"); + sliderSnapToTicksCheckBox.addActionListener(e -> sliderSnapToTicksChanged()); + add(sliderSnapToTicksCheckBox, "cell 0 6 3 1"); + + //---- majorTickSpacingSpinner ---- + majorTickSpacingSpinner.setModel(new SpinnerNumberModel(10, 0, 100, 5)); + majorTickSpacingSpinner.addChangeListener(e -> majorThickSpacingChanged()); + add(majorTickSpacingSpinner, "cell 0 6 3 1"); + + //---- minorTickSpacingSpinner ---- + minorTickSpacingSpinner.setModel(new SpinnerNumberModel(5, 0, 100, 5)); + minorTickSpacingSpinner.addChangeListener(e -> minorThickSpacingChanged()); + add(minorTickSpacingSpinner, "cell 0 6 3 1"); + + //---- sliderValueLabel ---- + sliderValueLabel.setText("slider value"); + add(sliderValueLabel, "cell 0 6 3 1"); // JFormDesigner - End of component initialization //GEN-END:initComponents } @@ -192,5 +273,9 @@ public class FlatRangeSliderTest private JSlider verticalSlider2; private JCheckBox paintTick; private JCheckBox paintLabel; + private JCheckBox sliderSnapToTicksCheckBox; + private JSpinner majorTickSpacingSpinner; + private JSpinner minorTickSpacingSpinner; + private JLabel sliderValueLabel; // 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 index 7cd55f14..c5a93466 100644 --- 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 @@ -1,4 +1,4 @@ -JFDML JFormDesigner: "7.0.2.0.298" Java: "15" encoding: "UTF-8" +JFDML JFormDesigner: "7.0.3.1.342" Java: "15" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -8,7 +8,7 @@ new FormModel { } add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "insets dialog,hidemode 3" - "$columnConstraints": "[left][240,left]" + "$columnConstraints": "[left][240,left][fill]" "$rowConstraints": "[fill][center][][][][grow,fill][]" } ) { name: "this" @@ -136,7 +136,7 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "paintTicks", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 6 2 1" + "value": "cell 0 6 3 1" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "paintLabel" @@ -148,7 +148,46 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "paintLabels", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 6 2 1" + "value": "cell 0 6 3 1" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "sliderSnapToTicksCheckBox" + "text": "snap to ticks" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "sliderSnapToTicksChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 6 3 1" + } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "majorTickSpacingSpinner" + "model": new javax.swing.SpinnerNumberModel( 10, 0, 100, 5 ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "majorThickSpacingChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 6 3 1" + } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "minorTickSpacingSpinner" + "model": new javax.swing.SpinnerNumberModel( 5, 0, 100, 5 ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "minorThickSpacingChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 6 3 1" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "sliderValueLabel" + "text": "slider value" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 6 3 1" } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 )