From b7bcbccd4504aaa6a86b3d8becefb5fcb2ccfce6 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 13 Mar 2021 00:35:04 +0100 Subject: [PATCH 1/4] Window decorations: support right aligned extra components in `JFrame` title pane with embedded menu bar --- CHANGELOG.md | 2 + .../com/formdev/flatlaf/ui/FlatMenuBarUI.java | 23 ++++ .../formdev/flatlaf/ui/FlatRootPaneUI.java | 6 +- .../com/formdev/flatlaf/ui/FlatTitlePane.java | 107 ++++++++++++++---- .../com/formdev/flatlaf/FlatLaf.properties | 5 +- .../uidefaults/FlatDarkLaf_1.8.0_202.txt | 5 +- .../uidefaults/FlatLightLaf_1.8.0_202.txt | 5 +- .../uidefaults/FlatTestLaf_1.8.0_202.txt | 5 +- .../testing/FlatWindowDecorationsTest.java | 59 +++++++++- .../testing/FlatWindowDecorationsTest.jfd | 31 ++++- .../flatlaf/themeeditor/FlatLafUIKeys.txt | 1 - 11 files changed, 210 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 344f6716..7a0f54ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ FlatLaf Change Log and embedded menu bar with all JREs, while still having native Windows 10 border drop shadows, resize behavior, window snapping and system window menu. (PR #267) +- Support right aligned components in `JFrame` title bar with embedded menu bar + (using `Box.createHorizontalGlue()`). (PR #268) #### Fixed bugs diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java index 09af41dd..5c596185 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java @@ -16,18 +16,21 @@ package com.formdev.flatlaf.ui; +import java.awt.Graphics; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; +import javax.swing.LookAndFeel; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.SwingUtilities; import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicMenuBarUI; +import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.util.SystemInfo; @@ -55,6 +58,13 @@ public class FlatMenuBarUI * Do not add any functionality here. */ + @Override + protected void installDefaults() { + super.installDefaults(); + + LookAndFeel.installProperty( menuBar, "opaque", false ); + } + @Override protected void installKeyboardActions() { super.installKeyboardActions(); @@ -67,6 +77,19 @@ public class FlatMenuBarUI map.put( "takeFocus", new TakeFocus() ); } + @Override + public void update( Graphics g, JComponent c ) { + // do not fill background if menubar is embedded into title pane + if( c.isOpaque() || + !FlatClientProperties.clientPropertyBoolean( menuBar, "flatlaf.internal.menuBarEmbedded", false ) ) + { + g.setColor( c.getBackground() ); + g.fillRect( 0, 0, c.getWidth(), c.getHeight() ); + } + + paint( g, c ); + } + //---- class TakeFocus ---------------------------------------------------- /** 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 40ca3e98..888fbe8e 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 @@ -305,7 +305,8 @@ public class FlatRootPaneUI JMenuBar menuBar = rootPane.getJMenuBar(); if( menuBar != null && menuBar.isVisible() ) { - if( !isFullScreen && titlePane != null && titlePane.isMenuBarEmbedded() ) { + boolean embedded = !isFullScreen && titlePane != null && titlePane.isMenuBarEmbedded(); + if( embedded ) { titlePane.validate(); menuBar.setBounds( titlePane.getMenuBarBounds() ); } else { @@ -313,6 +314,9 @@ public class FlatRootPaneUI menuBar.setBounds( 0, nextY, width, prefSize.height ); nextY += prefSize.height; } + + // mark menubar as embedded, which is used when painting menubar background + menuBar.putClientProperty( "flatlaf.internal.menuBarEmbedded", embedded ? true : null ); } Container contentPane = rootPane.getContentPane(); 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 52d7a82f..ffe0df7f 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 @@ -47,6 +47,7 @@ import java.util.List; import java.util.Objects; import javax.accessibility.AccessibleContext; import javax.swing.BorderFactory; +import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.Icon; import javax.swing.ImageIcon; @@ -80,7 +81,6 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault TitlePane.iconSize Dimension * @uiDefault TitlePane.iconMargins Insets * @uiDefault TitlePane.titleMargins Insets - * @uiDefault TitlePane.menuBarMargins Insets * @uiDefault TitlePane.menuBarEmbedded boolean * @uiDefault TitlePane.buttonMaximizedHeight int * @uiDefault TitlePane.closeIcon Icon @@ -100,7 +100,6 @@ public class FlatTitlePane protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" ); protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" ); - protected final Insets menuBarMargins = UIManager.getInsets( "TitlePane.menuBarMargins" ); protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" ); protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" ); @@ -159,9 +158,7 @@ public class FlatTitlePane @Override public Dimension getPreferredSize() { JMenuBar menuBar = rootPane.getJMenuBar(); - return (menuBar != null && menuBar.isVisible() && isMenuBarEmbedded()) - ? FlatUIUtils.addInsets( menuBar.getPreferredSize(), UIScale.scale( menuBarMargins ) ) - : new Dimension(); + return hasVisibleEmbeddedMenuBar( menuBar ) ? menuBar.getPreferredSize() : new Dimension(); } }; leftPanel.add( menuBarPlaceholder ); @@ -184,6 +181,18 @@ public class FlatTitlePane if( !getComponentOrientation().isLeftToRight() ) leftPanel.setLocation( leftPanel.getX() + (oldWidth - newWidth), leftPanel.getY() ); } + + // If menu bar is embedded and contains a horizontal glue component, + // then move the title label to the same location as the glue component. + // This allows placing any component on the trailing side of the title pane. + JMenuBar menuBar = rootPane.getJMenuBar(); + if( hasVisibleEmbeddedMenuBar( menuBar ) ) { + Component horizontalGlue = findHorizontalGlue( menuBar ); + if( horizontalGlue != null ) { + Point glueLocation = SwingUtilities.convertPoint( horizontalGlue, 0, 0, titleLabel ); + titleLabel.setLocation( titleLabel.getX() + glueLocation.x, titleLabel.getY() ); + } + } } } ); @@ -240,7 +249,7 @@ public class FlatTitlePane } protected void activeChanged( boolean active ) { - boolean hasEmbeddedMenuBar = rootPane.getJMenuBar() != null && rootPane.getJMenuBar().isVisible() && isMenuBarEmbedded(); + boolean hasEmbeddedMenuBar = hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ); Color background = FlatUIUtils.nonUIResource( active ? activeBackground : inactiveBackground ); Color foreground = FlatUIUtils.nonUIResource( active ? activeForeground : inactiveForeground ); Color titleForeground = (hasEmbeddedMenuBar && active) ? FlatUIUtils.nonUIResource( embeddedForeground ) : foreground; @@ -394,6 +403,16 @@ public class FlatTitlePane window.removeComponentListener( handler ); } + /** + * Returns whether this title pane currently has an visible and embedded menubar. + */ + protected boolean hasVisibleEmbeddedMenuBar( JMenuBar menuBar ) { + return menuBar != null && menuBar.isVisible() && isMenuBarEmbedded(); + } + + /** + * Returns whether the menubar should be embedded into the title pane. + */ protected boolean isMenuBarEmbedded() { // not storing value of "TitlePane.menuBarEmbedded" in class to allow changing at runtime return UIManager.getBoolean( "TitlePane.menuBarEmbedded" ) && @@ -412,13 +431,30 @@ public class FlatTitlePane Insets borderInsets = getBorder().getBorderInsets( this ); bounds.height += borderInsets.bottom; - return FlatUIUtils.subtractInsets( bounds, UIScale.scale( getMenuBarMargins() ) ); + // If menu bar is embedded and contains a horizontal glue component, + // then make the menu bar wider so that it completely overlaps the title label. + // Since the menu bar is not opaque, the title label is still visible. + // The title label is moved to the location of the glue component by the layout manager. + // This allows placing any component on the trailing side of the title pane. + Component horizontalGlue = findHorizontalGlue( rootPane.getJMenuBar() ); + if( horizontalGlue != null ) { + int titleWidth = Math.max( titleLabel.getWidth(), 0 ); // title width may be negative + bounds.width += titleWidth; + if( !getComponentOrientation().isLeftToRight() ) + bounds.x -= titleWidth; + } + + return bounds; } - protected Insets getMenuBarMargins() { - return getComponentOrientation().isLeftToRight() - ? menuBarMargins - : new Insets( menuBarMargins.top, menuBarMargins.right, menuBarMargins.bottom, menuBarMargins.left ); + protected Component findHorizontalGlue( JMenuBar menuBar ) { + int count = menuBar.getComponentCount(); + for( int i = count - 1; i >= 0; i-- ) { + Component c = menuBar.getComponent( i ); + if( c instanceof Box.Filler && c.getMaximumSize().width >= Short.MAX_VALUE ) + return c; + } + return null; } protected void menuBarChanged() { @@ -654,8 +690,37 @@ debug*/ else appIconBounds = iconBounds; } - addNativeHitTestSpot( buttonPanel, false, hitTestSpots ); - addNativeHitTestSpot( menuBarPlaceholder, true, hitTestSpots ); + + Rectangle r = getNativeHitTestSpot( buttonPanel ); + if( r != null ) + hitTestSpots.add( r ); + + r = getNativeHitTestSpot( menuBarPlaceholder ); + if( r != null ) { + Component horizontalGlue = findHorizontalGlue( rootPane.getJMenuBar() ); + if( horizontalGlue != null ) { + // If menu bar is embedded and contains a horizontal glue component, + // then split the hit test spot into two spots so that + // the glue component area can used to move the window. + + Point glueLocation = SwingUtilities.convertPoint( horizontalGlue, 0, 0, window ); + Rectangle r2; + if( getComponentOrientation().isLeftToRight() ) { + int trailingWidth = (r.x + r.width - HIT_TEST_SPOT_GROW) - glueLocation.x; + r.width -= trailingWidth; + r2 = new Rectangle( glueLocation.x + horizontalGlue.getWidth(), r.y, trailingWidth, r.height ); + } else { + int leadingWidth = (glueLocation.x + horizontalGlue.getWidth()) - (r.x + HIT_TEST_SPOT_GROW); + r.x += leadingWidth; + r.width -= leadingWidth; + r2 = new Rectangle( glueLocation.x -leadingWidth, r.y, leadingWidth, r.height ); + } + r2.grow( HIT_TEST_SPOT_GROW, HIT_TEST_SPOT_GROW ); + hitTestSpots.add( r2 ); + } + + hitTestSpots.add( r ); + } FlatNativeWindowBorder.setTitleBarHeightAndHitTestSpots( window, titleBarHeight, hitTestSpots, appIconBounds ); @@ -667,27 +732,27 @@ debug*/ debug*/ } - protected void addNativeHitTestSpot( JComponent c, boolean subtractMenuBarMargins, List hitTestSpots ) { + protected Rectangle getNativeHitTestSpot( JComponent c ) { Dimension size = c.getSize(); if( size.width <= 0 || size.height <= 0 ) - return; + return null; Point location = SwingUtilities.convertPoint( c, 0, 0, window ); Rectangle r = new Rectangle( location, size ); - if( subtractMenuBarMargins ) - r = FlatUIUtils.subtractInsets( r, UIScale.scale( getMenuBarMargins() ) ); // slightly increase rectangle so that component receives mouseExit events - r.grow( 2, 2 ); - hitTestSpots.add( r ); + r.grow( HIT_TEST_SPOT_GROW, HIT_TEST_SPOT_GROW ); + return r; } + private static final int HIT_TEST_SPOT_GROW = 2; + /*debug private int debugTitleBarHeight; private List debugHitTestSpots; private Rectangle debugAppIconBounds; debug*/ - //---- class TitlePaneBorder ---------------------------------------------- + //---- class FlatTitlePaneBorder ------------------------------------------ protected class FlatTitlePaneBorder extends AbstractBorder @@ -729,7 +794,7 @@ debug*/ protected Border getMenuBarBorder() { JMenuBar menuBar = rootPane.getJMenuBar(); - return (menuBar != null && menuBar.isVisible() && isMenuBarEmbedded()) ? menuBar.getBorder() : null; + return hasVisibleEmbeddedMenuBar( menuBar ) ? menuBar.getBorder() : null; } } 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 580ff417..45a66b3e 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -688,9 +688,8 @@ TitledBorder.border = 1,1,1,1,$Separator.foreground TitlePane.useWindowDecorations = true TitlePane.menuBarEmbedded = true TitlePane.iconSize = 16,16 -TitlePane.iconMargins = 3,8,3,0 -TitlePane.menuBarMargins = 0,8,0,22 -TitlePane.titleMargins = 3,8,3,8 +TitlePane.iconMargins = 3,8,3,8 +TitlePane.titleMargins = 3,0,3,0 TitlePane.buttonSize = 44,30 TitlePane.buttonMaximizedHeight = 22 TitlePane.closeIcon = com.formdev.flatlaf.icons.FlatWindowCloseIcon diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt index 787ed4df..a4c45c88 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt @@ -1133,16 +1133,15 @@ TitlePane.closePressedBackground #e8112399 60% javax.swing.plaf.ColorUIResou TitlePane.closePressedForeground #ffffff javax.swing.plaf.ColorUIResource [UI] TitlePane.embeddedForeground #959595 javax.swing.plaf.ColorUIResource [UI] TitlePane.foreground #bbbbbb javax.swing.plaf.ColorUIResource [UI] -TitlePane.iconMargins 3,8,3,0 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.iconMargins 3,8,3,8 javax.swing.plaf.InsetsUIResource [UI] TitlePane.iconSize 16,16 javax.swing.plaf.DimensionUIResource [UI] TitlePane.iconifyIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowIconifyIcon [UI] TitlePane.inactiveBackground #303234 javax.swing.plaf.ColorUIResource [UI] TitlePane.inactiveForeground #888888 javax.swing.plaf.ColorUIResource [UI] TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] TitlePane.menuBarEmbedded true -TitlePane.menuBarMargins 0,8,0,22 javax.swing.plaf.InsetsUIResource [UI] TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] -TitlePane.titleMargins 3,8,3,8 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.useWindowDecorations true diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt index 578a317e..f8da0584 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt @@ -1138,16 +1138,15 @@ TitlePane.closePressedBackground #e8112399 60% javax.swing.plaf.ColorUIResou TitlePane.closePressedForeground #ffffff javax.swing.plaf.ColorUIResource [UI] TitlePane.embeddedForeground #595959 javax.swing.plaf.ColorUIResource [UI] TitlePane.foreground #000000 javax.swing.plaf.ColorUIResource [UI] -TitlePane.iconMargins 3,8,3,0 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.iconMargins 3,8,3,8 javax.swing.plaf.InsetsUIResource [UI] TitlePane.iconSize 16,16 javax.swing.plaf.DimensionUIResource [UI] TitlePane.iconifyIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowIconifyIcon [UI] TitlePane.inactiveBackground #ffffff javax.swing.plaf.ColorUIResource [UI] TitlePane.inactiveForeground #8c8c8c javax.swing.plaf.ColorUIResource [UI] TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] TitlePane.menuBarEmbedded true -TitlePane.menuBarMargins 0,8,0,22 javax.swing.plaf.InsetsUIResource [UI] TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] -TitlePane.titleMargins 3,8,3,8 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.useWindowDecorations true diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt index c89dd1a6..361f9b13 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt @@ -1130,16 +1130,15 @@ TitlePane.closeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWin TitlePane.closePressedBackground #e8112399 60% javax.swing.plaf.ColorUIResource [UI] TitlePane.closePressedForeground #ffffff javax.swing.plaf.ColorUIResource [UI] TitlePane.foreground #0000ff javax.swing.plaf.ColorUIResource [UI] -TitlePane.iconMargins 3,8,3,0 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.iconMargins 3,8,3,8 javax.swing.plaf.InsetsUIResource [UI] TitlePane.iconSize 16,16 javax.swing.plaf.DimensionUIResource [UI] TitlePane.iconifyIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowIconifyIcon [UI] TitlePane.inactiveBackground #008800 javax.swing.plaf.ColorUIResource [UI] TitlePane.inactiveForeground #ffffff javax.swing.plaf.ColorUIResource [UI] TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] TitlePane.menuBarEmbedded true -TitlePane.menuBarMargins 0,8,0,22 javax.swing.plaf.InsetsUIResource [UI] TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] -TitlePane.titleMargins 3,8,3,8 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.useWindowDecorations true 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 d3ed01a0..9a835539 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 @@ -128,13 +128,48 @@ public class FlatWindowDecorationsTest menuBar.setVisible( menuBarVisibleCheckBox.isSelected() ); } + private void colorizeMenuBar() { + boolean colorize = colorizeMenuBarCheckBox.isSelected(); + Color menuBarBackground = colorize ? new Color( 0xffccff ) : UIManager.getColor( "MenuBar.background" ); + + menuBar.setOpaque( colorize ); + menuBar.setBackground( menuBarBackground ); + } + + private void colorizeMenus() { + boolean colorize = colorizeMenusCheckBox.isSelected(); + Color menuBackground = colorize ? new Color( 0xaaffff ) : UIManager.getColor( "Menu.background" ); + + for( Component c : menuBar.getComponents() ) { + if( c instanceof JMenu ) { + ((JMenu)c).setOpaque( colorize ); + c.setBackground( menuBackground ); + } + } + } + private void addMenu() { JMenu menu = new JMenu( "Hello" ); menu.add( new JMenuItem( "world" ) ); + + if( colorizeMenusCheckBox.isSelected() ) { + menu.setOpaque( true ); + menu.setBackground( new Color( 0xaaffff ) ); + } + menuBar.add( menu ); menuBar.revalidate(); } + private void addGlue() { + for( Component c : menuBar.getComponents() ) { + if( c instanceof Box.Filler ) + return; + } + menuBar.add( Box.createGlue() ); + menuBar.revalidate(); + } + private void removeMenu() { int menuCount = menuBar.getMenuCount(); if( menuCount <= 0 ) @@ -264,10 +299,13 @@ public class FlatWindowDecorationsTest // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents menuBarCheckBox = new JCheckBox(); addMenuButton = new JButton(); + JButton addGlueButton = new JButton(); removeMenuButton = new JButton(); changeMenuButton = new JButton(); menuBarEmbeddedCheckBox = new JCheckBox(); menuBarVisibleCheckBox = new JCheckBox(); + colorizeMenuBarCheckBox = new JCheckBox(); + colorizeMenusCheckBox = new JCheckBox(); resizableCheckBox = new JCheckBox(); maximizedBoundsCheckBox = new JCheckBox(); undecoratedCheckBox = new JCheckBox(); @@ -325,9 +363,9 @@ public class FlatWindowDecorationsTest // rows "para[]0" + "[]0" + + "[]unrel" + "[]0" + - "[]0" + - "[]" + + "[]unrel" + "[]" + "[top]" + "[]")); @@ -343,6 +381,11 @@ public class FlatWindowDecorationsTest addMenuButton.addActionListener(e -> addMenu()); add(addMenuButton, "cell 1 0 1 2,align left top,grow 0 0"); + //---- addGlueButton ---- + addGlueButton.setText("Add glue"); + addGlueButton.addActionListener(e -> addGlue()); + add(addGlueButton, "cell 1 0 1 2,align left top,grow 0 0"); + //---- removeMenuButton ---- removeMenuButton.setText("Remove menu"); removeMenuButton.addActionListener(e -> removeMenu()); @@ -365,6 +408,16 @@ public class FlatWindowDecorationsTest menuBarVisibleCheckBox.addActionListener(e -> menuBarVisibleChanged()); add(menuBarVisibleCheckBox, "cell 0 2"); + //---- colorizeMenuBarCheckBox ---- + colorizeMenuBarCheckBox.setText("colorize menu bar"); + colorizeMenuBarCheckBox.addActionListener(e -> colorizeMenuBar()); + add(colorizeMenuBarCheckBox, "cell 1 2"); + + //---- colorizeMenusCheckBox ---- + colorizeMenusCheckBox.setText("colorize menus"); + colorizeMenusCheckBox.addActionListener(e -> colorizeMenus()); + add(colorizeMenusCheckBox, "cell 1 2"); + //---- resizableCheckBox ---- resizableCheckBox.setText("resizable"); resizableCheckBox.setSelected(true); @@ -688,6 +741,8 @@ public class FlatWindowDecorationsTest private JButton changeMenuButton; private JCheckBox menuBarEmbeddedCheckBox; private JCheckBox menuBarVisibleCheckBox; + private JCheckBox colorizeMenuBarCheckBox; + private JCheckBox colorizeMenusCheckBox; private JCheckBox resizableCheckBox; private JCheckBox maximizedBoundsCheckBox; private JCheckBox undecoratedCheckBox; 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 d536cc39..f1b87adc 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 @@ -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" @@ -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]para[left]" - "$rowConstraints": "para[]0[]0[]0[]0[][][top][]" + "$rowConstraints": "para[]0[]0[]unrel[]0[]unrel[][top][]" } ) { name: "this" add( new FormComponent( "javax.swing.JCheckBox" ) { @@ -33,6 +33,13 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 0 1 2,align left top,grow 0 0" } ) + add( new FormComponent( "javax.swing.JButton" ) { + name: "addGlueButton" + "text": "Add glue" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "addGlue", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 0 1 2,align left top,grow 0 0" + } ) add( new FormComponent( "javax.swing.JButton" ) { name: "removeMenuButton" "text": "Remove menu" @@ -75,6 +82,26 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 2" } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "colorizeMenuBarCheckBox" + "text": "colorize menu bar" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "colorizeMenuBar", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 2" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "colorizeMenusCheckBox" + "text": "colorize menus" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "colorizeMenus", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 2" + } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "resizableCheckBox" "text": "resizable" 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 dd90b82a..7a766b57 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 @@ -850,7 +850,6 @@ TitlePane.inactiveBackground TitlePane.inactiveForeground TitlePane.maximizeIcon TitlePane.menuBarEmbedded -TitlePane.menuBarMargins TitlePane.restoreIcon TitlePane.titleMargins TitlePane.useWindowDecorations From cee221110862d645d2b007f5209f072e216bb68e Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 13 Mar 2021 11:14:51 +0100 Subject: [PATCH 2/4] Demo: added "users" icon to right side of menu bar to demonstrate this feature --- .../main/java/com/formdev/flatlaf/demo/DemoFrame.java | 11 +++++++++++ .../com/formdev/flatlaf/demo/icons/users.svg | 1 + 2 files changed, 12 insertions(+) create mode 100644 flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/users.svg diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java index 876e3c8e..01f06382 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java @@ -32,6 +32,8 @@ import com.formdev.flatlaf.demo.intellijthemes.*; import com.formdev.flatlaf.extras.FlatAnimatedLafChange; import com.formdev.flatlaf.extras.FlatSVGIcon; import com.formdev.flatlaf.extras.FlatUIDefaultsInspector; +import com.formdev.flatlaf.extras.components.FlatButton; +import com.formdev.flatlaf.extras.components.FlatButton.ButtonType; import com.formdev.flatlaf.extras.FlatSVGUtils; import com.formdev.flatlaf.ui.FlatNativeWindowBorder; import com.formdev.flatlaf.ui.JBRCustomDecorations; @@ -707,6 +709,15 @@ class DemoFrame buttonGroup1.add(radioButtonMenuItem3); // JFormDesigner - End of component initialization //GEN-END:initComponents + // add "Users" button to menubar + FlatButton usersButton = new FlatButton(); + usersButton.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/users.svg" ) ); + usersButton.setButtonType( ButtonType.toolBarButton ); + usersButton.setFocusable( false ); + usersButton.addActionListener( e -> JOptionPane.showMessageDialog( null, "Hello User! How are you?", "User", JOptionPane.INFORMATION_MESSAGE ) ); + menuBar1.add( Box.createGlue() ); + menuBar1.add( usersButton ); + undoMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/undo.svg" ) ); redoMenuItem.setIcon( new FlatSVGIcon( "com/formdev/flatlaf/demo/icons/redo.svg" ) ); diff --git a/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/users.svg b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/users.svg new file mode 100644 index 00000000..135e8e60 --- /dev/null +++ b/flatlaf-demo/src/main/resources/com/formdev/flatlaf/demo/icons/users.svg @@ -0,0 +1 @@ + \ No newline at end of file From 30c7b442a8682ed2fe52e573f7f768c19b071211 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sat, 13 Mar 2021 17:08:47 +0100 Subject: [PATCH 3/4] Window decorations: - support customizing of window title alignment: left aligned or centered (default is left without embedded menubar and centered with embedded menubar) - improved centering of window title with embedded menubar (issue #252) --- CHANGELOG.md | 6 ++- .../com/formdev/flatlaf/ui/FlatTitlePane.java | 52 +++++++++++++++++-- .../com/formdev/flatlaf/ui/FlatUIUtils.java | 5 ++ .../com/formdev/flatlaf/FlatLaf.properties | 3 ++ .../uidefaults/FlatDarkLaf_1.8.0_202.txt | 3 ++ .../uidefaults/FlatLightLaf_1.8.0_202.txt | 3 ++ .../uidefaults/FlatTestLaf_1.8.0_202.txt | 3 ++ .../testing/FlatWindowDecorationsTest.java | 16 ++++++ .../testing/FlatWindowDecorationsTest.jfd | 14 ++++- .../flatlaf/themeeditor/FlatLafUIKeys.txt | 3 ++ 10 files changed, 102 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a0f54ca..04b73043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,10 @@ FlatLaf Change Log and embedded menu bar with all JREs, while still having native Windows 10 border drop shadows, resize behavior, window snapping and system window menu. (PR #267) -- Support right aligned components in `JFrame` title bar with embedded menu bar - (using `Box.createHorizontalGlue()`). (PR #268) +- Custom window decorations: Support right aligned components in `JFrame` title + bar with embedded menu bar (using `Box.createHorizontalGlue()`). (PR #268) +- Custom window decorations: Improved centering of window title with embedded + menu bar. (issue #252) #### 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 ffe0df7f..4c581be9 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,9 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault TitlePane.titleMargins Insets * @uiDefault TitlePane.menuBarEmbedded boolean * @uiDefault TitlePane.buttonMaximizedHeight int + * @uiDefault TitlePane.centerTitle boolean + * @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean + * @uiDefault TitlePane.menuBarTitleGap int * @uiDefault TitlePane.closeIcon Icon * @uiDefault TitlePane.iconifyIcon Icon * @uiDefault TitlePane.maximizeIcon Icon @@ -102,6 +105,9 @@ public class FlatTitlePane protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" ); 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 ); + protected final int menuBarTitleGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleGap", 20 ); protected final JRootPane rootPane; @@ -146,9 +152,15 @@ public class FlatTitlePane protected void addSubComponents() { leftPanel = new JPanel(); iconLabel = new JLabel(); - titleLabel = new JLabel(); + titleLabel = new JLabel() { + @Override + public void updateUI() { + setUI( new FlatTitleLabelUI() ); + } + }; iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) ); titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) ); + titleLabel.setHorizontalAlignment( SwingConstants.CENTER ); leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) ); leftPanel.setOpaque( false ); @@ -261,8 +273,6 @@ public class FlatTitlePane restoreButton.setForeground( foreground ); closeButton.setForeground( foreground ); - titleLabel.setHorizontalAlignment( hasEmbeddedMenuBar ? SwingConstants.CENTER : SwingConstants.LEADING ); - // this is necessary because hover/pressed colors are derived from background color iconifyButton.setBackground( background ); maximizeButton.setBackground( background ); @@ -472,6 +482,7 @@ public class FlatTitlePane protected void menuBarLayouted() { updateNativeTitleBarHeightAndHitTestSpotsLater(); + revalidate(); } /*debug @@ -798,6 +809,41 @@ debug*/ } } + //---- class FlatTitleLabelUI --------------------------------------------- + + protected class FlatTitleLabelUI + extends FlatLabelUI + { + @Override + protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) { + boolean hasEmbeddedMenuBar = hasVisibleEmbeddedMenuBar( rootPane.getJMenuBar() ); + int labelWidth = l.getWidth(); + int textWidth = labelWidth - (textX * 2); + int gap = UIScale.scale( menuBarTitleGap ); + + // The passed in textX coordinate is always to horizontally center the text within the label bounds. + // Modify textX so that the text is painted either centered within the window bounds or leading aligned. + boolean center = hasEmbeddedMenuBar ? centerTitleIfMenuBarEmbedded : centerTitle; + if( center ) { + // If window is wide enough, center title within window bounds. + // Otherwise leave it centered within free space (label bounds). + int centeredTextX = ((l.getParent().getWidth() - textWidth) / 2) - l.getX(); + if( centeredTextX >= gap && centeredTextX + textWidth <= labelWidth - gap ) + textX = centeredTextX; + } else { + // leading aligned + boolean leftToRight = getComponentOrientation().isLeftToRight(); + Insets insets = l.getInsets(); + int leadingInset = hasEmbeddedMenuBar ? gap : (leftToRight ? insets.left : insets.right); + int leadingTextX = leftToRight ? leadingInset : labelWidth - leadingInset - textWidth; + if( leftToRight ? leadingTextX < textX : leadingTextX > textX ) + textX = leadingTextX; + } + + super.paintEnabledText( l, g, s, textX, textY ); + } + } + //---- class Handler ------------------------------------------------------ protected class Handler diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java index 4030d43a..5e0eb5f8 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java @@ -119,6 +119,11 @@ public class FlatUIUtils return (color != null) ? color : UIManager.getColor( defaultKey ); } + public static boolean getUIBoolean( String key, boolean defaultValue ) { + Object value = UIManager.get( key ); + return (value instanceof Boolean) ? (Boolean) value : defaultValue; + } + public static int getUIInt( String key, int defaultValue ) { Object value = UIManager.get( key ); return (value instanceof Integer) ? (Integer) value : defaultValue; 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 45a66b3e..e055aa58 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -692,6 +692,9 @@ TitlePane.iconMargins = 3,8,3,8 TitlePane.titleMargins = 3,0,3,0 TitlePane.buttonSize = 44,30 TitlePane.buttonMaximizedHeight = 22 +TitlePane.centerTitle = false +TitlePane.centerTitleIfMenuBarEmbedded = true +TitlePane.menuBarTitleGap = 20 TitlePane.closeIcon = com.formdev.flatlaf.icons.FlatWindowCloseIcon TitlePane.iconifyIcon = com.formdev.flatlaf.icons.FlatWindowIconifyIcon TitlePane.maximizeIcon = com.formdev.flatlaf.icons.FlatWindowMaximizeIcon diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt index a4c45c88..8ac1f7b6 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt @@ -1126,6 +1126,8 @@ TitlePane.buttonHoverBackground #484c4f com.formdev.flatlaf.util.DerivedColor TitlePane.buttonMaximizedHeight 22 TitlePane.buttonPressedBackground #616569 com.formdev.flatlaf.util.DerivedColor [UI] lighten(20% autoInverse) TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] +TitlePane.centerTitle false +TitlePane.centerTitleIfMenuBarEmbedded true TitlePane.closeHoverBackground #e81123 javax.swing.plaf.ColorUIResource [UI] TitlePane.closeHoverForeground #ffffff javax.swing.plaf.ColorUIResource [UI] TitlePane.closeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowCloseIcon [UI] @@ -1140,6 +1142,7 @@ TitlePane.inactiveBackground #303234 javax.swing.plaf.ColorUIResource [UI] TitlePane.inactiveForeground #888888 javax.swing.plaf.ColorUIResource [UI] TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] TitlePane.menuBarEmbedded true +TitlePane.menuBarTitleGap 20 TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.useWindowDecorations true diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt index f8da0584..d4ba22a4 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt @@ -1131,6 +1131,8 @@ TitlePane.buttonHoverBackground #e6e6e6 com.formdev.flatlaf.util.DerivedColor TitlePane.buttonMaximizedHeight 22 TitlePane.buttonPressedBackground #cccccc com.formdev.flatlaf.util.DerivedColor [UI] darken(20% autoInverse) TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] +TitlePane.centerTitle false +TitlePane.centerTitleIfMenuBarEmbedded true TitlePane.closeHoverBackground #e81123 javax.swing.plaf.ColorUIResource [UI] TitlePane.closeHoverForeground #ffffff javax.swing.plaf.ColorUIResource [UI] TitlePane.closeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowCloseIcon [UI] @@ -1145,6 +1147,7 @@ TitlePane.inactiveBackground #ffffff javax.swing.plaf.ColorUIResource [UI] TitlePane.inactiveForeground #8c8c8c javax.swing.plaf.ColorUIResource [UI] TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] TitlePane.menuBarEmbedded true +TitlePane.menuBarTitleGap 20 TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.useWindowDecorations true diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt index 361f9b13..7b4676fa 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt @@ -1124,6 +1124,8 @@ TextPaneUI com.formdev.flatlaf.ui.FlatTextPaneUI TitlePane.background #00ff00 javax.swing.plaf.ColorUIResource [UI] TitlePane.buttonMaximizedHeight 22 TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] +TitlePane.centerTitle false +TitlePane.centerTitleIfMenuBarEmbedded true TitlePane.closeHoverBackground #e81123 javax.swing.plaf.ColorUIResource [UI] TitlePane.closeHoverForeground #ffffff javax.swing.plaf.ColorUIResource [UI] TitlePane.closeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowCloseIcon [UI] @@ -1137,6 +1139,7 @@ TitlePane.inactiveBackground #008800 javax.swing.plaf.ColorUIResource [UI] TitlePane.inactiveForeground #ffffff javax.swing.plaf.ColorUIResource [UI] TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] TitlePane.menuBarEmbedded true +TitlePane.menuBarTitleGap 20 TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.useWindowDecorations true 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 9a835539..f6971662 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 @@ -189,6 +189,14 @@ public class FlatWindowDecorationsTest menuBar.getMenu( menuCount - 1 ).setText( text ); } + private void changeTitle() { + Window window = SwingUtilities.windowForComponent( this ); + if( window instanceof Frame ) + ((Frame)window).setTitle( ((Frame)window).getTitle() + " bla" ); + else if( window instanceof Dialog ) + ((Dialog)window).setTitle( ((Dialog)window).getTitle() + " bla" ); + } + private void resizableChanged() { Window window = SwingUtilities.windowForComponent( this ); if( window instanceof Frame ) @@ -308,6 +316,8 @@ public class FlatWindowDecorationsTest colorizeMenusCheckBox = new JCheckBox(); resizableCheckBox = new JCheckBox(); maximizedBoundsCheckBox = new JCheckBox(); + JPanel hSpacer1 = new JPanel(null); + JButton changeTitleButton = new JButton(); undecoratedCheckBox = new JCheckBox(); fullScreenCheckBox = new JCheckBox(); JLabel label1 = new JLabel(); @@ -428,6 +438,12 @@ public class FlatWindowDecorationsTest maximizedBoundsCheckBox.setText("maximized bounds (50,100, 1000,700)"); maximizedBoundsCheckBox.addActionListener(e -> maximizedBoundsChanged()); add(maximizedBoundsCheckBox, "cell 1 3"); + add(hSpacer1, "cell 1 3,growx"); + + //---- changeTitleButton ---- + changeTitleButton.setText("Change title"); + changeTitleButton.addActionListener(e -> changeTitle()); + add(changeTitleButton, "cell 1 3"); //---- undecoratedCheckBox ---- undecoratedCheckBox.setText("undecorated"); 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 f1b87adc..91daff59 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 @@ -123,6 +123,18 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 3" } ) + add( new FormComponent( "com.jformdesigner.designer.wrapper.HSpacer" ) { + name: "hSpacer1" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 3,growx" + } ) + add( new FormComponent( "javax.swing.JButton" ) { + name: "changeTitleButton" + "text": "Change title" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeTitle", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 3" + } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "undecoratedCheckBox" "text": "undecorated" @@ -316,7 +328,7 @@ new FormModel { } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) - "size": new java.awt.Dimension( 550, 440 ) + "size": new java.awt.Dimension( 580, 440 ) } ) add( new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) { name: "menuBar" 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 7a766b57..4a388aa5 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 @@ -836,6 +836,8 @@ TitlePane.buttonHoverBackground TitlePane.buttonMaximizedHeight TitlePane.buttonPressedBackground TitlePane.buttonSize +TitlePane.centerTitle +TitlePane.centerTitleIfMenuBarEmbedded TitlePane.closeHoverBackground TitlePane.closeHoverForeground TitlePane.closeIcon @@ -850,6 +852,7 @@ TitlePane.inactiveBackground TitlePane.inactiveForeground TitlePane.maximizeIcon TitlePane.menuBarEmbedded +TitlePane.menuBarTitleGap TitlePane.restoreIcon TitlePane.titleMargins TitlePane.useWindowDecorations From 035a13df54f6217e539497bd228c2b7116adaa59 Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Sun, 14 Mar 2021 15:13:26 +0100 Subject: [PATCH 4/4] Window decorations: support unified backgrounds for window title bar, menu bar and main content (issue #254) --- CHANGELOG.md | 22 ++-- .../com/formdev/flatlaf/ui/FlatMenuBarUI.java | 31 ++++- .../formdev/flatlaf/ui/FlatRootPaneUI.java | 24 ++-- .../com/formdev/flatlaf/ui/FlatTitlePane.java | 8 +- .../com/formdev/flatlaf/FlatLaf.properties | 1 + .../com/formdev/flatlaf/demo/DemoFrame.java | 12 ++ .../com/formdev/flatlaf/demo/DemoFrame.jfd | 10 +- .../uidefaults/FlatDarkLaf_1.8.0_202.txt | 1 + .../uidefaults/FlatLightLaf_1.8.0_202.txt | 1 + .../uidefaults/FlatTestLaf_1.8.0_202.txt | 1 + .../testing/FlatWindowDecorationsTest.java | 92 ++++++++----- .../testing/FlatWindowDecorationsTest.jfd | 122 ++++++++++-------- .../flatlaf/themeeditor/FlatLafUIKeys.txt | 1 + 13 files changed, 217 insertions(+), 109 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04b73043..cd90e157 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,14 +5,20 @@ FlatLaf Change Log #### New features and improvements -- Native window decorations for Windows 10 enables dark frame/dialog title bar - and embedded menu bar with all JREs, while still having native Windows 10 - border drop shadows, resize behavior, window snapping and system window menu. - (PR #267) -- Custom window decorations: Support right aligned components in `JFrame` title - bar with embedded menu bar (using `Box.createHorizontalGlue()`). (PR #268) -- Custom window decorations: Improved centering of window title with embedded - menu bar. (issue #252) +- Windows 10 only: + - Native window decorations for Windows 10 enables dark frame/dialog title bar + and embedded menu bar with all JREs, while still having native Windows 10 + border drop shadows, resize behavior, window snapping and system window + menu. (PR #267) + - Custom window decorations: Support right aligned components in `JFrame` + title bar with embedded menu bar (using `Box.createHorizontalGlue()`). (PR + #268) + - Custom window decorations: Improved centering of window title with embedded + menu bar. (PR #268; issue #252) + - Custom window decorations: Support unified backgrounds for window title bar, + menu bar and main content. If enabled with `UIManager.put( + "TitlePane.unifiedBackground", true );` then window title bar and menu bar + use same background color as main content. (PR #268; issue #254) #### Fixed bugs diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java index 5c596185..d6aa88b1 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuBarUI.java @@ -23,14 +23,16 @@ import javax.swing.ActionMap; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuBar; +import javax.swing.JRootPane; import javax.swing.LookAndFeel; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.SwingUtilities; +import javax.swing.UIManager; import javax.swing.plaf.ActionMapUIResource; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicMenuBarUI; -import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.util.SystemInfo; @@ -43,12 +45,15 @@ import com.formdev.flatlaf.util.SystemInfo; * @uiDefault MenuBar.background Color * @uiDefault MenuBar.foreground Color * @uiDefault MenuBar.border Border + * @uiDefault TitlePane.unifiedBackground boolean * * @author Karl Tauber */ public class FlatMenuBarUI extends BasicMenuBarUI { + protected boolean unifiedBackground; + public static ComponentUI createUI( JComponent c ) { return new FlatMenuBarUI(); } @@ -63,6 +68,8 @@ public class FlatMenuBarUI super.installDefaults(); LookAndFeel.installProperty( menuBar, "opaque", false ); + + unifiedBackground = UIManager.getBoolean( "TitlePane.unifiedBackground" ); } @Override @@ -80,9 +87,7 @@ public class FlatMenuBarUI @Override public void update( Graphics g, JComponent c ) { // do not fill background if menubar is embedded into title pane - if( c.isOpaque() || - !FlatClientProperties.clientPropertyBoolean( menuBar, "flatlaf.internal.menuBarEmbedded", false ) ) - { + if( isFillBackground( c ) ) { g.setColor( c.getBackground() ); g.fillRect( 0, 0, c.getWidth(), c.getHeight() ); } @@ -90,6 +95,24 @@ public class FlatMenuBarUI paint( g, c ); } + protected boolean isFillBackground( JComponent c ) { + // paint background in opaque or having custom background color + if( c.isOpaque() || !(c.getBackground() instanceof UIResource) ) + return true; + + // do not paint background for unified title pane + if( unifiedBackground ) + return false; + + // paint background in full screen mode + JRootPane rootPane = SwingUtilities.getRootPane( c ); + if( rootPane == null || FlatUIUtils.isFullScreen( rootPane ) ) + return true; + + // do not paint background if menu bar is embedded into title pane + return rootPane.getJMenuBar() != c || !FlatRootPaneUI.isMenuBarEmbedded( rootPane ); + } + //---- class TakeFocus ---------------------------------------------------- /** 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 888fbe8e..417cd1e5 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 @@ -40,6 +40,7 @@ import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.plaf.BorderUIResource; import javax.swing.plaf.ComponentUI; +import javax.swing.plaf.RootPaneUI; import javax.swing.plaf.UIResource; import javax.swing.plaf.basic.BasicRootPaneUI; import com.formdev.flatlaf.FlatClientProperties; @@ -227,6 +228,13 @@ public class FlatRootPaneUI } } + protected static boolean isMenuBarEmbedded( JRootPane rootPane ) { + RootPaneUI ui = rootPane.getUI(); + return ui instanceof FlatRootPaneUI && + ((FlatRootPaneUI)ui).titlePane != null && + ((FlatRootPaneUI)ui).titlePane.isMenuBarEmbedded(); + } + //---- class FlatRootLayout ----------------------------------------------- protected class FlatRootLayout @@ -297,10 +305,10 @@ public class FlatRootPaneUI rootPane.getGlassPane().setBounds( x, y, width, height ); int nextY = 0; - if( !isFullScreen && titlePane != null ) { - Dimension prefSize = titlePane.getPreferredSize(); - titlePane.setBounds( 0, 0, width, prefSize.height ); - nextY += prefSize.height; + if( titlePane != null ) { + int prefHeight = !isFullScreen ? titlePane.getPreferredSize().height : 0; + titlePane.setBounds( 0, 0, width, prefHeight ); + nextY += prefHeight; } JMenuBar menuBar = rootPane.getJMenuBar(); @@ -314,9 +322,6 @@ public class FlatRootPaneUI menuBar.setBounds( 0, nextY, width, prefSize.height ); nextY += prefSize.height; } - - // mark menubar as embedded, which is used when painting menubar background - menuBar.putClientProperty( "flatlaf.internal.menuBarEmbedded", embedded ? true : null ); } Container contentPane = rootPane.getContentPane(); @@ -346,6 +351,9 @@ public class FlatRootPaneUI //---- class FlatWindowBorder --------------------------------------------- + /** + * Window border used for non-native window decorations. + */ public static class FlatWindowBorder extends BorderUIResource.EmptyBorderUIResource { @@ -360,7 +368,7 @@ public class FlatRootPaneUI @Override public Insets getBorderInsets( Component c, Insets insets ) { if( isWindowMaximized( c ) || FlatUIUtils.isFullScreen( c ) ) { - // hide border if window is maximized + // hide border if window is maximized or full screen insets.top = insets.left = insets.bottom = insets.right = 0; return insets; } else 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 4c581be9..af53d8b6 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 @@ -78,6 +78,7 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault TitlePane.inactiveForeground Color * @uiDefault TitlePane.embeddedForeground Color * @uiDefault TitlePane.borderColor Color optional + * @uiDefault TitlePane.unifiedBackground boolean * @uiDefault TitlePane.iconSize Dimension * @uiDefault TitlePane.iconMargins Insets * @uiDefault TitlePane.titleMargins Insets @@ -103,6 +104,7 @@ public class FlatTitlePane protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" ); protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" ); + protected final boolean unifiedBackground = UIManager.getBoolean( "TitlePane.unifiedBackground" ); protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" ); protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" ); protected final boolean centerTitle = UIManager.getBoolean( "TitlePane.centerTitle" ); @@ -511,8 +513,10 @@ debug*/ @Override protected void paintComponent( Graphics g ) { - g.setColor( getBackground() ); - g.fillRect( 0, 0, getWidth(), getHeight() ); + if( !unifiedBackground ) { + g.setColor( getBackground() ); + g.fillRect( 0, 0, getWidth(), getHeight() ); + } } protected void repaintWindowBorder() { 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 e055aa58..87949600 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -687,6 +687,7 @@ TitledBorder.border = 1,1,1,1,$Separator.foreground TitlePane.useWindowDecorations = true TitlePane.menuBarEmbedded = true +TitlePane.unifiedBackground = false TitlePane.iconSize = 16,16 TitlePane.iconMargins = 3,8,3,8 TitlePane.titleMargins = 3,0,3,0 diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java index 01f06382..3d61f6a7 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java @@ -170,6 +170,11 @@ class DemoFrame // repaint(); } + private void unifiedTitleBar() { + UIManager.put( "TitlePane.unifiedBackground", unifiedTitleBarMenuItem.isSelected() ); + FlatLaf.updateUI(); + } + private void underlineMenuSelection() { UIManager.put( "MenuItem.selectionType", underlineMenuSelectionMenuItem.isSelected() ? "underline" : null ); } @@ -334,6 +339,7 @@ class DemoFrame optionsMenu = new JMenu(); windowDecorationsCheckBoxMenuItem = new JCheckBoxMenuItem(); menuBarEmbeddedCheckBoxMenuItem = new JCheckBoxMenuItem(); + unifiedTitleBarMenuItem = new JCheckBoxMenuItem(); underlineMenuSelectionMenuItem = new JCheckBoxMenuItem(); alwaysShowMnemonicsMenuItem = new JCheckBoxMenuItem(); animatedLafChangeMenuItem = new JCheckBoxMenuItem(); @@ -595,6 +601,11 @@ class DemoFrame menuBarEmbeddedCheckBoxMenuItem.addActionListener(e -> menuBarEmbeddedChanged()); optionsMenu.add(menuBarEmbeddedCheckBoxMenuItem); + //---- unifiedTitleBarMenuItem ---- + unifiedTitleBarMenuItem.setText("Unified Title Bar"); + unifiedTitleBarMenuItem.addActionListener(e -> unifiedTitleBar()); + optionsMenu.add(unifiedTitleBarMenuItem); + //---- underlineMenuSelectionMenuItem ---- underlineMenuSelectionMenuItem.setText("Use underline menu selection"); underlineMenuSelectionMenuItem.addActionListener(e -> underlineMenuSelection()); @@ -760,6 +771,7 @@ class DemoFrame private JMenu optionsMenu; private JCheckBoxMenuItem windowDecorationsCheckBoxMenuItem; private JCheckBoxMenuItem menuBarEmbeddedCheckBoxMenuItem; + private JCheckBoxMenuItem unifiedTitleBarMenuItem; private JCheckBoxMenuItem underlineMenuSelectionMenuItem; private JCheckBoxMenuItem alwaysShowMnemonicsMenuItem; private JCheckBoxMenuItem animatedLafChangeMenuItem; diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd index ba2075b6..d04959a0 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.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" @@ -360,6 +360,14 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuBarEmbeddedChanged", false ) ) } ) + add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) { + name: "unifiedTitleBarMenuItem" + "text": "Unified Title Bar" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "unifiedTitleBar", false ) ) + } ) add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) { name: "underlineMenuSelectionMenuItem" "text": "Use underline menu selection" diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt index 8ac1f7b6..6394cd5d 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0_202.txt @@ -1145,6 +1145,7 @@ TitlePane.menuBarEmbedded true TitlePane.menuBarTitleGap 20 TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.unifiedBackground false TitlePane.useWindowDecorations true diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt index d4ba22a4..91ec37bb 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0_202.txt @@ -1150,6 +1150,7 @@ TitlePane.menuBarEmbedded true TitlePane.menuBarTitleGap 20 TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.unifiedBackground false TitlePane.useWindowDecorations true diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt index 7b4676fa..707004a2 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0_202.txt @@ -1142,6 +1142,7 @@ TitlePane.menuBarEmbedded true TitlePane.menuBarTitleGap 20 TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] +TitlePane.unifiedBackground false TitlePane.useWindowDecorations true 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 f6971662..7bdc8093 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 @@ -25,6 +25,7 @@ import java.util.List; import java.util.Random; import javax.swing.*; import com.formdev.flatlaf.FlatClientProperties; +import com.formdev.flatlaf.FlatLaf; import net.miginfocom.swing.*; /** @@ -109,6 +110,11 @@ public class FlatWindowDecorationsTest } } + private void unifiedBackgroundChanged() { + UIManager.put( "TitlePane.unifiedBackground", unifiedBackgroundCheckBox.isSelected() ); + FlatLaf.updateUI(); + } + private void menuBarChanged() { Window window = SwingUtilities.windowForComponent( this ); if( window instanceof JFrame ) { @@ -306,18 +312,19 @@ public class FlatWindowDecorationsTest private void initComponents() { // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents menuBarCheckBox = new JCheckBox(); + unifiedBackgroundCheckBox = new JCheckBox(); + JPanel panel3 = new JPanel(); addMenuButton = new JButton(); JButton addGlueButton = new JButton(); removeMenuButton = new JButton(); changeMenuButton = new JButton(); + JButton changeTitleButton = new JButton(); menuBarEmbeddedCheckBox = new JCheckBox(); - menuBarVisibleCheckBox = new JCheckBox(); colorizeMenuBarCheckBox = new JCheckBox(); + menuBarVisibleCheckBox = new JCheckBox(); colorizeMenusCheckBox = new JCheckBox(); resizableCheckBox = new JCheckBox(); maximizedBoundsCheckBox = new JCheckBox(); - JPanel hSpacer1 = new JPanel(null); - JButton changeTitleButton = new JButton(); undecoratedCheckBox = new JCheckBox(); fullScreenCheckBox = new JCheckBox(); JLabel label1 = new JLabel(); @@ -369,7 +376,8 @@ public class FlatWindowDecorationsTest "ltr,insets dialog,hidemode 3", // columns "[left]para" + - "[left]", + "[left]" + + "[fill]", // rows "para[]0" + "[]0" + @@ -386,25 +394,50 @@ public class FlatWindowDecorationsTest menuBarCheckBox.addActionListener(e -> menuBarChanged()); add(menuBarCheckBox, "cell 0 0"); - //---- addMenuButton ---- - addMenuButton.setText("Add menu"); - addMenuButton.addActionListener(e -> addMenu()); - add(addMenuButton, "cell 1 0 1 2,align left top,grow 0 0"); + //---- unifiedBackgroundCheckBox ---- + unifiedBackgroundCheckBox.setText("unified background"); + unifiedBackgroundCheckBox.addActionListener(e -> unifiedBackgroundChanged()); + add(unifiedBackgroundCheckBox, "cell 1 0"); - //---- addGlueButton ---- - addGlueButton.setText("Add glue"); - addGlueButton.addActionListener(e -> addGlue()); - add(addGlueButton, "cell 1 0 1 2,align left top,grow 0 0"); + //======== panel3 ======== + { + panel3.setLayout(new MigLayout( + "hidemode 3", + // columns + "[fill]", + // rows + "[]" + + "[]" + + "[]" + + "[]unrel" + + "[]")); - //---- removeMenuButton ---- - removeMenuButton.setText("Remove menu"); - removeMenuButton.addActionListener(e -> removeMenu()); - add(removeMenuButton, "cell 1 0 1 2,align left top,grow 0 0"); + //---- addMenuButton ---- + addMenuButton.setText("Add menu"); + addMenuButton.addActionListener(e -> addMenu()); + panel3.add(addMenuButton, "cell 0 0"); - //---- changeMenuButton ---- - changeMenuButton.setText("Change menu"); - changeMenuButton.addActionListener(e -> changeMenu()); - add(changeMenuButton, "cell 1 0 1 2,align left top,grow 0 0"); + //---- addGlueButton ---- + addGlueButton.setText("Add glue"); + addGlueButton.addActionListener(e -> addGlue()); + panel3.add(addGlueButton, "cell 0 1"); + + //---- removeMenuButton ---- + removeMenuButton.setText("Remove menu"); + removeMenuButton.addActionListener(e -> removeMenu()); + panel3.add(removeMenuButton, "cell 0 2"); + + //---- changeMenuButton ---- + changeMenuButton.setText("Change menu"); + changeMenuButton.addActionListener(e -> changeMenu()); + panel3.add(changeMenuButton, "cell 0 3"); + + //---- changeTitleButton ---- + changeTitleButton.setText("Change title"); + changeTitleButton.addActionListener(e -> changeTitle()); + panel3.add(changeTitleButton, "cell 0 4"); + } + add(panel3, "cell 2 0 1 6,aligny top,growy 0"); //---- menuBarEmbeddedCheckBox ---- menuBarEmbeddedCheckBox.setText("embedded menu bar"); @@ -412,17 +445,17 @@ public class FlatWindowDecorationsTest menuBarEmbeddedCheckBox.addActionListener(e -> menuBarEmbeddedChanged()); add(menuBarEmbeddedCheckBox, "cell 0 1"); + //---- colorizeMenuBarCheckBox ---- + colorizeMenuBarCheckBox.setText("colorize menu bar"); + colorizeMenuBarCheckBox.addActionListener(e -> colorizeMenuBar()); + add(colorizeMenuBarCheckBox, "cell 1 1"); + //---- menuBarVisibleCheckBox ---- menuBarVisibleCheckBox.setText("menu bar visible"); menuBarVisibleCheckBox.setSelected(true); menuBarVisibleCheckBox.addActionListener(e -> menuBarVisibleChanged()); add(menuBarVisibleCheckBox, "cell 0 2"); - //---- colorizeMenuBarCheckBox ---- - colorizeMenuBarCheckBox.setText("colorize menu bar"); - colorizeMenuBarCheckBox.addActionListener(e -> colorizeMenuBar()); - add(colorizeMenuBarCheckBox, "cell 1 2"); - //---- colorizeMenusCheckBox ---- colorizeMenusCheckBox.setText("colorize menus"); colorizeMenusCheckBox.addActionListener(e -> colorizeMenus()); @@ -438,12 +471,6 @@ public class FlatWindowDecorationsTest maximizedBoundsCheckBox.setText("maximized bounds (50,100, 1000,700)"); maximizedBoundsCheckBox.addActionListener(e -> maximizedBoundsChanged()); add(maximizedBoundsCheckBox, "cell 1 3"); - add(hSpacer1, "cell 1 3,growx"); - - //---- changeTitleButton ---- - changeTitleButton.setText("Change title"); - changeTitleButton.addActionListener(e -> changeTitle()); - add(changeTitleButton, "cell 1 3"); //---- undecoratedCheckBox ---- undecoratedCheckBox.setText("undecorated"); @@ -752,12 +779,13 @@ public class FlatWindowDecorationsTest // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables private JCheckBox menuBarCheckBox; + private JCheckBox unifiedBackgroundCheckBox; private JButton addMenuButton; private JButton removeMenuButton; private JButton changeMenuButton; private JCheckBox menuBarEmbeddedCheckBox; - private JCheckBox menuBarVisibleCheckBox; private JCheckBox colorizeMenuBarCheckBox; + private JCheckBox menuBarVisibleCheckBox; private JCheckBox colorizeMenusCheckBox; private JCheckBox resizableCheckBox; private JCheckBox maximizedBoundsCheckBox; 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 91daff59..64f877b7 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 @@ -8,7 +8,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]para[left]" + "$columnConstraints": "[left]para[left][fill]" "$rowConstraints": "para[]0[]0[]unrel[]0[]unrel[][top][]" } ) { name: "this" @@ -23,42 +23,68 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 0" } ) - add( new FormComponent( "javax.swing.JButton" ) { - name: "addMenuButton" - "text": "Add menu" + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "unifiedBackgroundCheckBox" + "text": "unified background" auxiliary() { "JavaCodeGenerator.variableLocal": false } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "addMenu", false ) ) + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "unifiedBackgroundChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 0 1 2,align left top,grow 0 0" + "value": "cell 1 0" } ) - add( new FormComponent( "javax.swing.JButton" ) { - name: "addGlueButton" - "text": "Add glue" - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "addGlue", false ) ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$layoutConstraints": "hidemode 3" + "$columnConstraints": "[fill]" + "$rowConstraints": "[][][][]unrel[]" + } ) { + name: "panel3" + add( new FormComponent( "javax.swing.JButton" ) { + name: "addMenuButton" + "text": "Add menu" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "addMenu", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JButton" ) { + name: "addGlueButton" + "text": "Add glue" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "addGlue", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormComponent( "javax.swing.JButton" ) { + name: "removeMenuButton" + "text": "Remove menu" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "removeMenu", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2" + } ) + add( new FormComponent( "javax.swing.JButton" ) { + name: "changeMenuButton" + "text": "Change menu" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeMenu", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 3" + } ) + add( new FormComponent( "javax.swing.JButton" ) { + name: "changeTitleButton" + "text": "Change title" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeTitle", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4" + } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 0 1 2,align left top,grow 0 0" - } ) - add( new FormComponent( "javax.swing.JButton" ) { - name: "removeMenuButton" - "text": "Remove menu" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "removeMenu", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 0 1 2,align left top,grow 0 0" - } ) - add( new FormComponent( "javax.swing.JButton" ) { - name: "changeMenuButton" - "text": "Change menu" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeMenu", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 0 1 2,align left top,grow 0 0" + "value": "cell 2 0 1 6,aligny top,growy 0" } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "menuBarEmbeddedCheckBox" @@ -71,6 +97,16 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 1" } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "colorizeMenuBarCheckBox" + "text": "colorize menu bar" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "colorizeMenuBar", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 1" + } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "menuBarVisibleCheckBox" "text": "menu bar visible" @@ -82,16 +118,6 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 2" } ) - add( new FormComponent( "javax.swing.JCheckBox" ) { - name: "colorizeMenuBarCheckBox" - "text": "colorize menu bar" - auxiliary() { - "JavaCodeGenerator.variableLocal": false - } - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "colorizeMenuBar", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 2" - } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "colorizeMenusCheckBox" "text": "colorize menus" @@ -123,18 +149,6 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 1 3" } ) - add( new FormComponent( "com.jformdesigner.designer.wrapper.HSpacer" ) { - name: "hSpacer1" - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 3,growx" - } ) - add( new FormComponent( "javax.swing.JButton" ) { - name: "changeTitleButton" - "text": "Change title" - addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "changeTitle", false ) ) - }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 3" - } ) add( new FormComponent( "javax.swing.JCheckBox" ) { name: "undecoratedCheckBox" "text": "undecorated" @@ -328,7 +342,7 @@ new FormModel { } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) - "size": new java.awt.Dimension( 580, 440 ) + "size": new java.awt.Dimension( 690, 440 ) } ) add( new FormContainer( "javax.swing.JMenuBar", new FormLayoutManager( class javax.swing.JMenuBar ) ) { name: "menuBar" 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 4a388aa5..a35f8b7d 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 @@ -855,6 +855,7 @@ TitlePane.menuBarEmbedded TitlePane.menuBarTitleGap TitlePane.restoreIcon TitlePane.titleMargins +TitlePane.unifiedBackground TitlePane.useWindowDecorations TitledBorder.border TitledBorder.font