diff --git a/CHANGELOG.md b/CHANGELOG.md index 76bee1fa..c7952464 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ FlatLaf Change Log `libflatlaf-macos-x86_64.dylib`. See also https://www.formdev.com/flatlaf/native-libraries/. - ScrollPane: Support rounded border. (PR #713) +- SplitPane: Support divider hover and pressed background colors. (PR #788) - TabbedPane: Support vertical tabs. (PR #758, issue #633) - TabbedPane: Paint rounded tab area background for rounded cards. (issue #717) - ToolBar: Added styling properties `separatorWidth` and `separatorColor`. diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSplitPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSplitPaneUI.java index 2914f655..273d1fbf 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSplitPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatSplitPaneUI.java @@ -16,7 +16,9 @@ package com.formdev.flatlaf.ui; +import java.awt.Canvas; import java.awt.Color; +import java.awt.Component; import java.awt.Container; import java.awt.Cursor; import java.awt.Graphics; @@ -67,6 +69,8 @@ import com.formdev.flatlaf.util.UIScale; * * * @uiDefault Component.arrowType String chevron (default) or triangle + * @uiDefault SplitPaneDivider.hoverColor Color optional + * @uiDefault SplitPaneDivider.pressedColor Color optional * @uiDefault SplitPaneDivider.oneTouchArrowColor Color * @uiDefault SplitPaneDivider.oneTouchHoverArrowColor Color * @uiDefault SplitPaneDivider.oneTouchPressedArrowColor Color @@ -83,6 +87,7 @@ public class FlatSplitPaneUI implements StyleableUI { @Styleable protected String arrowType; + /** @since 3.3 */ @Styleable protected Color draggingColor; @Styleable protected Color oneTouchArrowColor; @Styleable protected Color oneTouchHoverArrowColor; @Styleable protected Color oneTouchPressedArrowColor; @@ -104,6 +109,8 @@ public class FlatSplitPaneUI protected void installDefaults() { arrowType = UIManager.getString( "Component.arrowType" ); + draggingColor = UIManager.getColor( "SplitPaneDivider.draggingColor" ); + // get one-touch colors before invoking super.installDefaults() because they are // used in there on LaF switching oneTouchArrowColor = UIManager.getColor( "SplitPaneDivider.oneTouchArrowColor" ); @@ -117,6 +124,8 @@ public class FlatSplitPaneUI protected void uninstallDefaults() { super.uninstallDefaults(); + draggingColor = null; + oneTouchArrowColor = null; oneTouchHoverArrowColor = null; oneTouchPressedArrowColor = null; @@ -183,12 +192,49 @@ public class FlatSplitPaneUI return FlatStylingSupport.getAnnotatedStyleableValue( this, key ); } + @Override + protected Component createDefaultNonContinuousLayoutDivider() { + // only used for non-continuous layout if left or right component is heavy weight + return new Canvas() { + @Override + public void paint( Graphics g ) { + if( !isContinuousLayout() && getLastDragLocation() != -1 ) + paintDragDivider( g, 0 ); + } + }; + } + + @Override + public void finishedPaintingChildren( JSplitPane sp, Graphics g ) { + if( sp == splitPane && getLastDragLocation() != -1 && !isContinuousLayout() && !draggingHW ) + paintDragDivider( g, getLastDragLocation() ); + } + + private void paintDragDivider( Graphics g, int dividerLocation ) { + // divider bounds + boolean horizontal = (getOrientation() == JSplitPane.HORIZONTAL_SPLIT); + int x = horizontal ? dividerLocation : 0; + int y = !horizontal ? dividerLocation : 0; + int width = horizontal ? dividerSize : splitPane.getWidth(); + int height = !horizontal ? dividerSize : splitPane.getHeight(); + + // paint background + g.setColor( FlatUIUtils.deriveColor( draggingColor, splitPane.getBackground() ) ); + g.fillRect( x, y, width, height ); + + // paint divider style (e.g. grip) + if( divider instanceof FlatSplitPaneDivider ) + ((FlatSplitPaneDivider)divider).paintStyle( g, x, y, width, height ); + } + //---- class FlatSplitPaneDivider ----------------------------------------- protected class FlatSplitPaneDivider extends BasicSplitPaneDivider { @Styleable protected String style = UIManager.getString( "SplitPaneDivider.style" ); + /** @since 3.3 */ @Styleable protected Color hoverColor = UIManager.getColor( "SplitPaneDivider.hoverColor" ); + /** @since 3.3 */ @Styleable protected Color pressedColor = UIManager.getColor( "SplitPaneDivider.pressedColor" ); @Styleable protected Color gripColor = UIManager.getColor( "SplitPaneDivider.gripColor" ); @Styleable protected int gripDotCount = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotCount", 3 ); @Styleable protected int gripDotSize = FlatUIUtils.getUIInt( "SplitPaneDivider.gripDotSize", 3 ); @@ -251,15 +297,31 @@ public class FlatSplitPaneUI @Override public void paint( Graphics g ) { + // paint hover or pressed background + Color hoverOrPressedColor = (isContinuousLayout() && dragger != null) + ? pressedColor + : (isMouseOver() && dragger == null + ? hoverColor + : null); + if( hoverOrPressedColor != null ) { + g.setColor( FlatUIUtils.deriveColor( hoverOrPressedColor, splitPane.getBackground() ) ); + g.fillRect( 0, 0, getWidth(), getHeight() ); + } + super.paint( g ); + paintStyle( g, 0, 0, getWidth(), getHeight() ); + } + + /** @since 3.3 */ + protected void paintStyle( Graphics g, int x, int y, int width, int height ) { if( "plain".equals( style ) ) return; Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g ); g.setColor( gripColor ); - paintGrip( g, 0, 0, getWidth(), getHeight() ); + paintGrip( g, x, y, width, height ); FlatUIUtils.resetRenderingHints( g, oldRenderingHints ); } @@ -286,6 +348,29 @@ public class FlatSplitPaneUI : location == (splitPane.getWidth() - getWidth() - insets.right); } + @Override + protected void setMouseOver( boolean mouseOver ) { + super.setMouseOver( mouseOver ); + repaintIfNecessary(); + } + + @Override + protected void prepareForDragging() { + super.prepareForDragging(); + repaintIfNecessary(); + } + + @Override + protected void finishDraggingTo( int location ) { + super.finishDraggingTo( location ); + repaintIfNecessary(); + } + + private void repaintIfNecessary() { + if( hoverColor != null || pressedColor != null ) + repaint(); + } + //---- class FlatOneTouchButton --------------------------------------- protected class FlatOneTouchButton diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java index 7fe92c43..3960b2d5 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableInfo.java @@ -689,6 +689,9 @@ public class TestFlatStyleableInfo Map> expected = expectedMap( "arrowType", String.class, + "draggingColor", Color.class, + "hoverColor", Color.class, + "pressedColor", Color.class, "oneTouchArrowColor", Color.class, "oneTouchHoverArrowColor", Color.class, "oneTouchPressedArrowColor", Color.class, diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java index 6987fc74..47d32e63 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyleableValue.java @@ -699,6 +699,9 @@ public class TestFlatStyleableValue FlatSplitPaneUI ui = (FlatSplitPaneUI) c.getUI(); testString( c, ui, "arrowType", "chevron" ); + testColor( c, ui, "draggingColor", 0x123456 ); + testColor( c, ui, "hoverColor", 0x123456 ); + testColor( c, ui, "pressedColor", 0x123456 ); testColor( c, ui, "oneTouchArrowColor", 0x123456 ); testColor( c, ui, "oneTouchHoverArrowColor", 0x123456 ); testColor( c, ui, "oneTouchPressedArrowColor", 0x123456 ); diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java index dd185089..035e631a 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java @@ -870,6 +870,9 @@ public class TestFlatStyling FlatSplitPaneUI ui = (FlatSplitPaneUI) c.getUI(); ui.applyStyle( "arrowType: chevron" ); + ui.applyStyle( "draggingColor: #fff" ); + ui.applyStyle( "hoverColor: #fff" ); + ui.applyStyle( "pressedColor: #fff" ); ui.applyStyle( "oneTouchArrowColor: #fff" ); ui.applyStyle( "oneTouchHoverArrowColor: #fff" ); ui.applyStyle( "oneTouchPressedArrowColor: #fff" ); diff --git a/flatlaf-extras/src/main/resources/com/formdev/flatlaf/extras/resources/DerivedColorKeys.properties b/flatlaf-extras/src/main/resources/com/formdev/flatlaf/extras/resources/DerivedColorKeys.properties index 8f47973e..c7e0eccf 100644 --- a/flatlaf-extras/src/main/resources/com/formdev/flatlaf/extras/resources/DerivedColorKeys.properties +++ b/flatlaf-extras/src/main/resources/com/formdev/flatlaf/extras/resources/DerivedColorKeys.properties @@ -175,6 +175,9 @@ Spinner.buttonPressedArrowColor = Spinner.buttonArrowColor #---- SplitPaneDivider ---- +SplitPaneDivider.draggingColor = SplitPane.background +SplitPaneDivider.hoverColor = SplitPane.background +SplitPaneDivider.pressedColor = SplitPane.background SplitPaneDivider.oneTouchHoverArrowColor = SplitPaneDivider.oneTouchArrowColor SplitPaneDivider.oneTouchPressedArrowColor = SplitPaneDivider.oneTouchArrowColor diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt index 619881a0..dc851550 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt @@ -1050,9 +1050,11 @@ SplitPaneDivider.gripColor #afafaf HSL 0 0 69 javax.swing.plaf.Colo SplitPaneDivider.gripDotCount 3 SplitPaneDivider.gripDotSize 3 SplitPaneDivider.gripGap 2 +SplitPaneDivider.hoverColor #008800 HSL 120 100 27 javax.swing.plaf.ColorUIResource [UI] SplitPaneDivider.oneTouchArrowColor #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI] SplitPaneDivider.oneTouchHoverArrowColor #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI] SplitPaneDivider.oneTouchPressedArrowColor #0000ff HSL 240 100 50 javax.swing.plaf.ColorUIResource [UI] +SplitPaneDivider.pressedColor #000088 HSL 240 100 27 javax.swing.plaf.ColorUIResource [UI] SplitPaneDivider.style grip diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java index f30a845a..a8e421bf 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.java @@ -76,6 +76,13 @@ public class FlatContainerTest tabScrollChanged(); } + private void continuousLayoutChanged() { + boolean continuousLayout = continuousLayoutCheckBox.isSelected(); + splitPane1.setContinuousLayout( continuousLayout ); + splitPane2.setContinuousLayout( continuousLayout ); + splitPane3.setContinuousLayout( continuousLayout ); + } + private void showOnlyOne() { boolean showOnlyOne = showOnlyOneCheckBox.isSelected(); @@ -519,11 +526,12 @@ public class FlatContainerTest // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents JPanel panel9 = new JPanel(); JLabel splitPaneLabel = new JLabel(); - JSplitPane splitPane3 = new JSplitPane(); - JSplitPane splitPane1 = new JSplitPane(); + continuousLayoutCheckBox = new JCheckBox(); + splitPane3 = new JSplitPane(); + splitPane1 = new JSplitPane(); FlatContainerTest.Panel1 panel15 = new FlatContainerTest.Panel1(); FlatContainerTest.Panel2 panel21 = new FlatContainerTest.Panel2(); - JSplitPane splitPane2 = new JSplitPane(); + splitPane2 = new JSplitPane(); JPanel panel12 = new JPanel(); JLabel label3 = new JLabel(); JPanel panel13 = new JPanel(); @@ -601,6 +609,12 @@ public class FlatContainerTest splitPaneLabel.setText("JSplitPane:"); panel9.add(splitPaneLabel, cc.xy(1, 1)); + //---- continuousLayoutCheckBox ---- + continuousLayoutCheckBox.setText("Continuous Layout"); + continuousLayoutCheckBox.setSelected(true); + continuousLayoutCheckBox.addActionListener(e -> continuousLayoutChanged()); + panel9.add(continuousLayoutCheckBox, cc.xy(3, 1, CellConstraints.RIGHT, CellConstraints.DEFAULT)); + //======== splitPane3 ======== { splitPane3.setResizeWeight(0.5); @@ -929,6 +943,10 @@ public class FlatContainerTest } // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables + private JCheckBox continuousLayoutCheckBox; + private JSplitPane splitPane3; + private JSplitPane splitPane1; + private JSplitPane splitPane2; private JCheckBox showOnlyOneCheckBox; private FlatTabbedPane tabbedPane1; private FlatTabbedPane tabbedPane3; diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd index 771ebd6f..354fa128 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatContainerTest.jfd @@ -22,13 +22,32 @@ new FormModel { name: "splitPaneLabel" "text": "JSplitPane:" }, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "continuousLayoutCheckBox" + "text": "Continuous Layout" + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "continuousLayoutChanged", false ) ) + }, new FormLayoutConstraints( class com.jgoodies.forms.layout.CellConstraints ) { + "gridX": 3 + "gridY": 1 + "hAlign": sfield com.jgoodies.forms.layout.CellConstraints RIGHT + } ) add( new FormContainer( "javax.swing.JSplitPane", new FormLayoutManager( class javax.swing.JSplitPane ) ) { name: "splitPane3" "resizeWeight": 0.5 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } add( new FormContainer( "javax.swing.JSplitPane", new FormLayoutManager( class javax.swing.JSplitPane ) ) { name: "splitPane1" "resizeWeight": 0.5 "oneTouchExpandable": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } add( new FormComponent( "com.formdev.flatlaf.testing.FlatContainerTest$Panel1" ) { name: "panel15" "background": new java.awt.Color( 217, 163, 67, 255 ) @@ -49,6 +68,9 @@ new FormModel { "orientation": 0 "resizeWeight": 0.5 "oneTouchExpandable": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) { name: "panel12" "background": new java.awt.Color( 242, 101, 34, 255 ) diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties index 6a60b729..6bc61e14 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/FlatTestLaf.properties @@ -368,6 +368,8 @@ Spinner.focusedBackground = #ff8 #---- SplitPane ---- SplitPaneDivider.draggingColor = #800 +SplitPaneDivider.hoverColor = #080 +SplitPaneDivider.pressedColor = #008 SplitPaneDivider.oneTouchArrowColor = #0f0 SplitPaneDivider.oneTouchHoverArrowColor = #f00 SplitPaneDivider.oneTouchPressedArrowColor = #00f diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt index db43939e..efb174bb 100644 --- a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt @@ -827,9 +827,11 @@ SplitPaneDivider.gripColor SplitPaneDivider.gripDotCount SplitPaneDivider.gripDotSize SplitPaneDivider.gripGap +SplitPaneDivider.hoverColor SplitPaneDivider.oneTouchArrowColor SplitPaneDivider.oneTouchHoverArrowColor SplitPaneDivider.oneTouchPressedArrowColor +SplitPaneDivider.pressedColor SplitPaneDivider.style SplitPaneUI TabbedPane.ancestorInputMap