From 570cf6fc510a271ab6e6a360ff7e3da64c7e1087 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Thu, 17 Oct 2024 19:58:58 +0200 Subject: [PATCH] FlatLaf window decorations: added client property `JRootPane.titleBarHeight` to allow specifying a (larger) preferred height for the title bar (issue #897) --- CHANGELOG.md | 3 ++ .../formdev/flatlaf/FlatClientProperties.java | 12 ++++++ .../formdev/flatlaf/ui/FlatRootPaneUI.java | 5 +++ .../com/formdev/flatlaf/ui/FlatTitlePane.java | 4 ++ .../testing/FlatWindowDecorationsTest.java | 39 +++++++++++++++-- .../testing/FlatWindowDecorationsTest.jfd | 43 ++++++++++++++++--- 6 files changed, 96 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc4b67edb..f062c2b3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,9 @@ FlatLaf Change Log #### Other Changes +- FlatLaf window decorations: Added client property `JRootPane.titleBarHeight` + to allow specifying a (larger) preferred height for the title bar. (issue + #897) - Added system property `flatlaf.useRoundedPopupBorder` to allow disabling native rounded popup borders on Windows 11 and macOS. On macOS 14.4+, where rounded popup borders are disabled since FlatLaf 3.5 because of occasional diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java index 2f1728db5..bfd0f1509 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -626,6 +626,18 @@ public interface FlatClientProperties */ String TITLE_BAR_FOREGROUND = "JRootPane.titleBarForeground"; + /** + * Specifies the preferred height of title bar (requires enabled window decorations). + *

+ * (requires Windows 10/11) + *

+ * Component {@link javax.swing.JRootPane}
+ * Value type {@link java.lang.Integer} + * + * @since 3.5.2 + */ + String TITLE_BAR_HEIGHT = "JRootPane.titleBarHeight"; + /** * Specifies whether the glass pane should have full height and overlap the title bar, * if FlatLaf window decorations are enabled. Default is {@code false}. diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java index 5dafefce9..3cb17f340 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java @@ -448,6 +448,11 @@ public void propertyChange( PropertyChangeEvent e ) { titlePane.titleBarColorsChanged(); break; + case FlatClientProperties.TITLE_BAR_HEIGHT: + if( titlePane != null ) + titlePane.revalidate(); + break; + case FlatClientProperties.FULL_WINDOW_CONTENT: if( titlePane != null ) { rootPane.getLayeredPane().setLayer( titlePane, getLayerForTitlePane() ); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java index f00d9d6ad..ba0bd2a7d 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java @@ -359,6 +359,10 @@ protected void createButtons() { @Override public Dimension getPreferredSize() { Dimension size = super.getPreferredSize(); + int titleBarHeight = clientPropertyInt( rootPane, TITLE_BAR_HEIGHT, -1 ); + if( titleBarHeight >= 0 ) + return new Dimension( size.width, UIScale.scale( titleBarHeight ) ); + if( buttonMaximizedHeight > 0 && isWindowMaximized() && !hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ) ) { // make title pane height smaller when frame is maximized size = new Dimension( size.width, Math.min( size.height, UIScale.scale( buttonMaximizedHeight ) ) ); diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java index ef31a999f..5e659bc27 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java @@ -127,6 +127,9 @@ else if( window instanceof Dialog ) + " @ " + bounds.x + ", " + bounds.y ); } else fullWindowContentButtonsBoundsField.setText( "null" ); + + fullWindowContentButtonsBoundsLabel.setEnabled( bounds != null ); + fullWindowContentButtonsBoundsField.setEnabled( bounds != null ); } ); } } @@ -562,6 +565,16 @@ private void fullWindowContentChanged() { } } + private void titleBarHeightChanged() { + JRootPane rootPane = getWindowRootPane(); + if( rootPane != null ) { + boolean enabled = titleBarHeightCheckBox.isSelected(); + titleBarHeightField.setEnabled( enabled ); + + rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_HEIGHT, enabled ? titleBarHeightField.getValue() : null ); + } + } + private JRootPane getWindowRootPane() { Window window = SwingUtilities.windowForComponent( this ); return (window instanceof RootPaneContainer) @@ -588,12 +601,14 @@ private void initComponents() { maximizedBoundsCheckBox = new JCheckBox(); JPanel panel4 = new JPanel(); showIconCheckBox = new FlatTriStateCheckBox(); + titleBarHeightCheckBox = new JCheckBox(); showTitleCheckBox = new JCheckBox(); + titleBarHeightField = new JSpinner(); showIconifyCheckBox = new JCheckBox(); showMaximizeCheckBox = new JCheckBox(); showCloseCheckBox = new JCheckBox(); fullWindowContentCheckBox = new JCheckBox(); - JLabel fullWindowContentButtonsBoundsLabel = new JLabel(); + fullWindowContentButtonsBoundsLabel = new JLabel(); fullWindowContentButtonsBoundsField = new JLabel(); JPanel panel6 = new JPanel(); menuBarCheckBox = new JCheckBox(); @@ -677,7 +692,8 @@ private void initComponents() { "[fill]" + "[fill]" + "[]" + - "[]")); + "[]" + + "[40]")); //======== panel7 ======== { @@ -728,7 +744,8 @@ private void initComponents() { panel4.setLayout(new MigLayout( "ltr,hidemode 3,gap 0 0", // columns - "[grow,left]", + "[grow,left]" + + "[fill]", // rows "[]" + "[]" + @@ -743,12 +760,23 @@ private void initComponents() { showIconCheckBox.addActionListener(e -> showIconChanged()); panel4.add(showIconCheckBox, "cell 0 0"); + //---- titleBarHeightCheckBox ---- + titleBarHeightCheckBox.setText("Height:"); + titleBarHeightCheckBox.addActionListener(e -> titleBarHeightChanged()); + panel4.add(titleBarHeightCheckBox, "cell 1 0"); + //---- showTitleCheckBox ---- showTitleCheckBox.setText("show title"); showTitleCheckBox.setSelected(true); showTitleCheckBox.addActionListener(e -> showTitleChanged()); panel4.add(showTitleCheckBox, "cell 0 1"); + //---- titleBarHeightField ---- + titleBarHeightField.setEnabled(false); + titleBarHeightField.setModel(new SpinnerNumberModel(44, null, null, 2)); + titleBarHeightField.addChangeListener(e -> titleBarHeightChanged()); + panel4.add(titleBarHeightField, "cell 1 1"); + //---- showIconifyCheckBox ---- showIconifyCheckBox.setText("show iconfiy"); showIconifyCheckBox.setSelected(true); @@ -774,10 +802,12 @@ private void initComponents() { //---- fullWindowContentButtonsBoundsLabel ---- fullWindowContentButtonsBoundsLabel.setText("Buttons bounds:"); + fullWindowContentButtonsBoundsLabel.setEnabled(false); panel4.add(fullWindowContentButtonsBoundsLabel, "cell 0 6"); //---- fullWindowContentButtonsBoundsField ---- fullWindowContentButtonsBoundsField.setText("null"); + fullWindowContentButtonsBoundsField.setEnabled(false); panel4.add(fullWindowContentButtonsBoundsField, "cell 0 6"); } add(panel4, "cell 1 0"); @@ -1266,11 +1296,14 @@ private void initComponents() { private JCheckBox fullScreenCheckBox; private JCheckBox maximizedBoundsCheckBox; private FlatTriStateCheckBox showIconCheckBox; + private JCheckBox titleBarHeightCheckBox; private JCheckBox showTitleCheckBox; + private JSpinner titleBarHeightField; private JCheckBox showIconifyCheckBox; private JCheckBox showMaximizeCheckBox; private JCheckBox showCloseCheckBox; private JCheckBox fullWindowContentCheckBox; + private JLabel fullWindowContentButtonsBoundsLabel; private JLabel fullWindowContentButtonsBoundsField; private JCheckBox menuBarCheckBox; private JCheckBox menuBarEmbeddedCheckBox; diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd index a05293da6..78e40bebc 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd @@ -9,7 +9,7 @@ new FormModel { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "ltr,insets dialog,hidemode 3" "$columnConstraints": "[left][fill][fill][fill]" - "$rowConstraints": "[fill][fill][][]" + "$rowConstraints": "[fill][fill][][][40]" } ) { name: "this" add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { @@ -76,7 +76,7 @@ new FormModel { } ) add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "ltr,hidemode 3,gap 0 0" - "$columnConstraints": "[grow,left]" + "$columnConstraints": "[grow,left][fill]" "$rowConstraints": "[][][][][]rel[]rel[]" } ) { name: "panel4" @@ -91,6 +91,16 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 0" } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "titleBarHeightCheckBox" + "text": "Height:" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "titleBarHeightChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 0" + } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "showTitleCheckBox" "text": "show title" @@ -102,6 +112,20 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 1" } ) + add( new FormComponent( "javax.swing.JSpinner" ) { + name: "titleBarHeightField" + "enabled": false + "model": new javax.swing.SpinnerNumberModel { + stepSize: 2 + value: 44 + } + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "titleBarHeightChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 1" + } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "showIconifyCheckBox" "text": "show iconfiy" @@ -148,12 +172,17 @@ new FormModel { add( new FormComponent( "javax.swing.JLabel" ) { name: "fullWindowContentButtonsBoundsLabel" "text": "Buttons bounds:" + "enabled": false + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 6" } ) add( new FormComponent( "javax.swing.JLabel" ) { name: "fullWindowContentButtonsBoundsField" "text": "null" + "enabled": false auxiliary() { "JavaCodeGenerator.variableLocal": false } @@ -610,7 +639,7 @@ new FormModel { } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) - "size": new java.awt.Dimension( 960, 495 ) + "size": new java.awt.Dimension( 960, 570 ) } ) add( new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) { name: "menuBar" @@ -776,23 +805,23 @@ new FormModel { } ) } ) }, new FormLayoutConstraints( null ) { - "location": new java.awt.Point( 0, 515 ) + "location": new java.awt.Point( 0, 585 ) "size": new java.awt.Dimension( 255, 30 ) } ) add( new FormNonVisual( "javax.swing.ButtonGroup" ) { name: "styleButtonGroup" }, new FormLayoutConstraints( null ) { - "location": new java.awt.Point( 0, 565 ) + "location": new java.awt.Point( 0, 635 ) } ) add( new FormNonVisual( "javax.swing.ButtonGroup" ) { name: "iconButtonGroup" }, new FormLayoutConstraints( null ) { - "location": new java.awt.Point( 0, 615 ) + "location": new java.awt.Point( 0, 685 ) } ) add( new FormNonVisual( "javax.swing.ButtonGroup" ) { name: "typeButtonGroup" }, new FormLayoutConstraints( null ) { - "location": new java.awt.Point( 0, 669 ) + "location": new java.awt.Point( 0, 740 ) } ) } }