diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fbe39b2..cd47512c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ FlatLaf Change Log - Native window decorations (Windows 10/11 only): - There is now a small area at top of the embedded menu bar to resize the window. + - Improved window title bar layout for small window widths: + - Width of iconify/maximize/close buttons is reduced (if necessary) to give + more space to embedded menu bar and title. + - Window title now has a minimum width to always allow moving window + (click-and-drag on window title). Instead, embedded menu bar is made + smaller. #### Fixed bugs 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 742f1012..ba51272b 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 @@ -83,6 +83,8 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault TitlePane.iconMargins Insets * @uiDefault TitlePane.titleMargins Insets * @uiDefault TitlePane.menuBarEmbedded boolean + * @uiDefault TitlePane.titleMinimumWidth int + * @uiDefault TitlePane.buttonMinimumWidth int * @uiDefault TitlePane.buttonMaximizedHeight int * @uiDefault TitlePane.centerTitle boolean * @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean @@ -108,6 +110,8 @@ public class FlatTitlePane /** @since 2 */ protected final boolean showIcon = FlatUIUtils.getUIBoolean( "TitlePane.showIcon", true ); /** @since 2 */ protected final int noIconLeftGap = FlatUIUtils.getUIInt( "TitlePane.noIconLeftGap", 8 ); protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" ); + /** @since 2.4 */ protected final int titleMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.titleMinimumWidth", 30 ); + /** @since 2.4 */ protected final int buttonMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.buttonMinimumWidth", 22 ); protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" ); protected final boolean centerTitle = UIManager.getBoolean( "TitlePane.centerTitle" ); protected final boolean centerTitleIfMenuBarEmbedded = FlatUIUtils.getUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", true ); @@ -185,18 +189,44 @@ public class FlatTitlePane setLayout( new BorderLayout() { @Override public void layoutContainer( Container target ) { - super.layoutContainer( target ); - - // make left panel (with embedded menu bar) smaller if horizontal space is rare - // to avoid that embedded menu bar overlaps button bar + // compute available bounds Insets insets = target.getInsets(); - int width = target.getWidth() - insets.left - insets.right; - if( leftPanel.getWidth() + buttonPanel.getWidth() > width ) { - int oldWidth = leftPanel.getWidth(); - int newWidth = Math.max( width - buttonPanel.getWidth(), 0 ); - leftPanel.setSize( newWidth, leftPanel.getHeight() ); - if( !getComponentOrientation().isLeftToRight() ) - leftPanel.setLocation( leftPanel.getX() + (oldWidth - newWidth), leftPanel.getY() ); + int x = insets.left; + int y = insets.top; + int w = target.getWidth() - insets.left - insets.right; + int h = target.getHeight() - insets.top - insets.bottom; + + // compute widths + int leftWidth = leftPanel.getPreferredSize().width; + int buttonsWidth = buttonPanel.getPreferredSize().width; + int titleWidth = w - leftWidth - buttonsWidth; + int minTitleWidth = UIScale.scale( titleMinimumWidth ); + + // if title is too small, reduce width of buttons + if( titleWidth < minTitleWidth ) { + buttonsWidth = Math.max( buttonsWidth - (minTitleWidth - titleWidth), buttonPanel.getMinimumSize().width ); + titleWidth = w - leftWidth - buttonsWidth; + } + + // if title is still too small, reduce width of left panel (icon and embedded menu bar) + if( titleWidth < minTitleWidth ) { + int minLeftWidth = iconLabel.isVisible() + ? iconLabel.getWidth() - iconLabel.getInsets().right + : UIScale.scale( noIconLeftGap ); + leftWidth = Math.max( leftWidth - (minTitleWidth - titleWidth), minLeftWidth ); + titleWidth = w - leftWidth - buttonsWidth; + } + + if( target.getComponentOrientation().isLeftToRight() ) { + // left-to-right + leftPanel.setBounds( x, y, leftWidth, h ); + titleLabel.setBounds( x + leftWidth, y, titleWidth, h ); + buttonPanel.setBounds( x + leftWidth + titleWidth, y, buttonsWidth, h ); + } else { + // right-to-left + buttonPanel.setBounds( x, y, buttonsWidth, h ); + titleLabel.setBounds( x + buttonsWidth, y, titleWidth, h ); + leftPanel.setBounds( x + buttonsWidth + titleWidth, y, leftWidth, h ); } // If menu bar is embedded and contains a horizontal glue component, @@ -258,7 +288,13 @@ public class FlatTitlePane } protected JButton createButton( String iconKey, String accessibleName, ActionListener action ) { - JButton button = new JButton( UIManager.getIcon( iconKey ) ); + JButton button = new JButton( UIManager.getIcon( iconKey ) ) { + @Override + public Dimension getMinimumSize() { + // allow the button to shrink if space is rare + return new Dimension( UIScale.scale( buttonMinimumWidth ), super.getMinimumSize().height ); + } + }; button.setFocusable( false ); button.setContentAreaFilled( false ); button.setBorder( BorderFactory.createEmptyBorder() ); diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties index 621e6473..66e1b015 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -789,7 +789,9 @@ TitlePane.noIconLeftGap = 8 TitlePane.iconSize = 16,16 TitlePane.iconMargins = 3,8,3,8 TitlePane.titleMargins = 3,0,3,0 +TitlePane.titleMinimumWidth = 30 TitlePane.buttonSize = 44,30 +TitlePane.buttonMinimumWidth = 22 TitlePane.buttonMaximizedHeight = 22 TitlePane.centerTitle = false TitlePane.centerTitleIfMenuBarEmbedded = true diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt index 628f7fd9..e0f90f62 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt @@ -1214,6 +1214,7 @@ TextPaneUI com.formdev.flatlaf.ui.FlatTextPaneUI TitlePane.background #303234 HSL 210 4 20 javax.swing.plaf.ColorUIResource [UI] TitlePane.buttonHoverBackground #55585c HSL 214 4 35 com.formdev.flatlaf.util.DerivedColor [UI] lighten(15% autoInverse) TitlePane.buttonMaximizedHeight 22 +TitlePane.buttonMinimumWidth 22 TitlePane.buttonPressedBackground #484c4f HSL 206 5 30 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10% autoInverse) TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] TitlePane.centerTitle false @@ -1239,6 +1240,7 @@ TitlePane.noIconLeftGap 8 TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.showIcon true TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.titleMinimumWidth 30 TitlePane.unifiedBackground true TitlePane.useWindowDecorations true diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt index 17e0d6cd..1e32e40b 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt @@ -1219,6 +1219,7 @@ TextPaneUI com.formdev.flatlaf.ui.FlatTextPaneUI TitlePane.background #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI] TitlePane.buttonHoverBackground #e6e6e6 HSL 0 0 90 com.formdev.flatlaf.util.DerivedColor [UI] darken(10% autoInverse) TitlePane.buttonMaximizedHeight 22 +TitlePane.buttonMinimumWidth 22 TitlePane.buttonPressedBackground #ebebeb HSL 0 0 92 com.formdev.flatlaf.util.DerivedColor [UI] darken(8% autoInverse) TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] TitlePane.centerTitle false @@ -1244,6 +1245,7 @@ TitlePane.noIconLeftGap 8 TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.showIcon true TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.titleMinimumWidth 30 TitlePane.unifiedBackground true TitlePane.useWindowDecorations true diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt index 4c691646..11ba3707 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt @@ -1249,6 +1249,7 @@ TextPaneUI com.formdev.flatlaf.ui.FlatTextPaneUI TitlePane.background #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI] TitlePane.borderColor #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI] TitlePane.buttonMaximizedHeight 22 +TitlePane.buttonMinimumWidth 22 TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] TitlePane.centerTitle false TitlePane.centerTitleIfMenuBarEmbedded true @@ -1272,6 +1273,7 @@ TitlePane.noIconLeftGap 8 TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.showIcon true TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.titleMinimumWidth 30 TitlePane.unifiedBackground true TitlePane.useWindowDecorations true 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 1c6fa061..7bb5a8f9 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 @@ -980,6 +980,7 @@ TitlePane.background TitlePane.borderColor TitlePane.buttonHoverBackground TitlePane.buttonMaximizedHeight +TitlePane.buttonMinimumWidth TitlePane.buttonPressedBackground TitlePane.buttonSize TitlePane.centerTitle @@ -1005,6 +1006,7 @@ TitlePane.noIconLeftGap TitlePane.restoreIcon TitlePane.showIcon TitlePane.titleMargins +TitlePane.titleMinimumWidth TitlePane.unifiedBackground TitlePane.useWindowDecorations TitledBorder.border