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 )
} )
}
}