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 e7e0812ec..3e591a442 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -346,7 +346,7 @@ public interface FlatClientProperties /** * Specifies whether the window icon should be shown in the window title bar - * (requires enabled window decorations). + * (requires enabled window decorations). Default is UI property {@code TitlePane.showIcon}. *

* Setting this shows/hides the windows icon * for the {@code JFrame} or {@code JDialog} that contains the root pane. @@ -362,6 +362,62 @@ public interface FlatClientProperties */ String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon"; + /** + * Specifies whether the window title should be shown in the window title bar + * (requires enabled window decorations). Default is {@code true}. + *

+ * Setting this shows/hides the windows title + * for the {@code JFrame} or {@code JDialog} that contains the root pane. + *

+ * Component {@link javax.swing.JRootPane}
+ * Value type {@link java.lang.Boolean} + * + * @since 3 + */ + String TITLE_BAR_SHOW_TITLE = "JRootPane.titleBarShowTitle"; + + /** + * Specifies whether the "iconfify" button should be shown in the window title bar + * (requires enabled window decorations). Default is {@code true}. + *

+ * Setting this shows/hides the "iconfify" button + * for the {@code JFrame} that contains the root pane. + *

+ * Component {@link javax.swing.JRootPane}
+ * Value type {@link java.lang.Boolean} + * + * @since 3 + */ + String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.titleBarShowIconify"; + + /** + * Specifies whether the "maximize/restore" button should be shown in the window title bar + * (requires enabled window decorations). Default is {@code true}. + *

+ * Setting this shows/hides the "maximize/restore" button + * for the {@code JFrame} that contains the root pane. + *

+ * Component {@link javax.swing.JRootPane}
+ * Value type {@link java.lang.Boolean} + * + * @since 3 + */ + String TITLE_BAR_SHOW_MAXIMIZE = "JRootPane.titleBarShowMaximize"; + + /** + * Specifies whether the "close" button should be shown in the window title bar + * (requires enabled window decorations). Default is {@code true}. + *

+ * Setting this shows/hides the "close" button + * for the {@code JFrame} or {@code JDialog} that contains the root pane. + *

+ * Component {@link javax.swing.JRootPane}
+ * Value type {@link java.lang.Boolean} + * + * @since 3 + */ + String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose"; + /** * Background color of window title bar (requires enabled window decorations). *

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 54640afd6..8177c4fe4 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 @@ -349,6 +349,14 @@ public void propertyChange( PropertyChangeEvent e ) { titlePane.updateIcon(); break; + case FlatClientProperties.TITLE_BAR_SHOW_TITLE: + case FlatClientProperties.TITLE_BAR_SHOW_ICONIFFY: + case FlatClientProperties.TITLE_BAR_SHOW_MAXIMIZE: + case FlatClientProperties.TITLE_BAR_SHOW_CLOSE: + if( titlePane != null ) + titlePane.updateVisibility(); + break; + case FlatClientProperties.TITLE_BAR_BACKGROUND: case FlatClientProperties.TITLE_BAR_FOREGROUND: if( titlePane != null ) 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 7194bee32..86d652fe4 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 @@ -107,6 +107,8 @@ public class FlatTitlePane extends JComponent { + private static final String KEY_DEBUG_SHOW_RECTANGLES = "FlatLaf.debug.titlebar.showRectangles"; + /** @since 2.5 */ protected final Font titleFont = UIManager.getFont( "TitlePane.font" ); protected final Color activeBackground = UIManager.getColor( "TitlePane.background" ); protected final Color inactiveBackground = UIManager.getColor( "TitlePane.inactiveBackground" ); @@ -354,15 +356,12 @@ protected void frameStateChanged() { if( window == null || rootPane.getWindowDecorationStyle() != JRootPane.FRAME ) return; + updateVisibility(); + if( window instanceof Frame ) { Frame frame = (Frame) window; - boolean resizable = frame.isResizable(); boolean maximized = ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0); - iconifyButton.setVisible( true ); - maximizeButton.setVisible( resizable && !maximized ); - restoreButton.setVisible( resizable && maximized ); - if( maximized && !(SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window )) && rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null ) @@ -383,14 +382,27 @@ protected void frameStateChanged() { frame.setExtendedState( oldExtendedState ); } } + } + } + + /** @since 3 */ + protected void updateVisibility() { + titleLabel.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_TITLE, true ) ); + closeButton.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_CLOSE, true ) ); + + if( window instanceof Frame ) { + Frame frame = (Frame) window; + boolean maximizable = frame.isResizable() && clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_MAXIMIZE, true ); + boolean maximized = ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0); + + iconifyButton.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_ICONIFFY, true ) ); + maximizeButton.setVisible( maximizable && !maximized ); + restoreButton.setVisible( maximizable && maximized ); } else { // hide buttons because they are only supported in frames iconifyButton.setVisible( false ); maximizeButton.setVisible( false ); restoreButton.setVisible( false ); - - revalidate(); - repaint(); } } @@ -566,11 +578,13 @@ protected void menuBarLayouted() { doLayout(); } -/*debug @Override public void paint( Graphics g ) { super.paint( g ); + if( !UIManager.getBoolean( KEY_DEBUG_SHOW_RECTANGLES ) ) + return; + if( debugTitleBarHeight > 0 ) { g.setColor( Color.green ); g.drawLine( 0, debugTitleBarHeight, getWidth(), debugTitleBarHeight ); @@ -594,7 +608,6 @@ private void paintRect( Graphics g, Color color, Rectangle r ) { Point offset = SwingUtilities.convertPoint( this, 0, 0, window ); g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 ); } -debug*/ @Override protected void paintComponent( Graphics g ) { @@ -923,15 +936,14 @@ protected void updateNativeTitleBarHeightAndHitTestSpots() { FlatNativeWindowBorder.setTitleBarHeightAndHitTestSpots( window, titleBarHeight, hitTestSpots, appIconBounds, minimizeButtonBounds, maximizeButtonBounds, closeButtonBounds ); -/*debug debugTitleBarHeight = titleBarHeight; debugHitTestSpots = hitTestSpots; debugAppIconBounds = appIconBounds; debugMinimizeButtonBounds = minimizeButtonBounds; debugMaximizeButtonBounds = maximizeButtonBounds; debugCloseButtonBounds = closeButtonBounds; - repaint(); -debug*/ + if( UIManager.getBoolean( KEY_DEBUG_SHOW_RECTANGLES ) ) + repaint(); } private Rectangle boundsInWindow( JComponent c ) { @@ -950,14 +962,12 @@ protected Rectangle getNativeHitTestSpot( JComponent c ) { return r; } -/*debug private int debugTitleBarHeight; private List debugHitTestSpots; private Rectangle debugAppIconBounds; private Rectangle debugMinimizeButtonBounds; private Rectangle debugMaximizeButtonBounds; private Rectangle debugCloseButtonBounds; -debug*/ //---- class FlatTitlePaneBorder ------------------------------------------ diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatNativeWindowBorderTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatNativeWindowBorderTest.java index 8e82f57e5..e59784fd7 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatNativeWindowBorderTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatNativeWindowBorderTest.java @@ -57,6 +57,7 @@ public static void main( String[] args ) { SwingUtilities.invokeLater( () -> { FlatLightLaf.setup(); FlatInspector.install( "ctrl shift alt X" ); + UIManager.put( "FlatLaf.debug.titlebar.showRectangles", true ); mainFrame = showFrame(); } ); 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 aeec1663e..203ebd403 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 @@ -49,6 +49,7 @@ public static void main( String[] args ) { FlatTestFrame frame = FlatTestFrame.create( args, "FlatWindowDecorationsTest" ); frame.applyComponentOrientationToFrame = true; + UIManager.put( "FlatLaf.debug.titlebar.showRectangles", true ); Class cls = FlatWindowDecorationsTest.class; List images = Arrays.asList( @@ -446,6 +447,30 @@ private void showIconChanged() { rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_ICON, showIconCheckBox.getChecked() ); } + private void showTitleChanged() { + JRootPane rootPane = getWindowRootPane(); + if( rootPane != null ) + rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_TITLE, showTitleCheckBox.isSelected() ? null : false ); + } + + private void showIconifyChanged() { + JRootPane rootPane = getWindowRootPane(); + if( rootPane != null ) + rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_ICONIFFY, showIconifyCheckBox.isSelected() ? null : false ); + } + + private void showMaximizeChanged() { + JRootPane rootPane = getWindowRootPane(); + if( rootPane != null ) + rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_MAXIMIZE, showMaximizeCheckBox.isSelected() ? null : false ); + } + + private void showCloseChanged() { + JRootPane rootPane = getWindowRootPane(); + if( rootPane != null ) + rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_CLOSE, showCloseCheckBox.isSelected() ? null : false ); + } + private JRootPane getWindowRootPane() { Window window = SwingUtilities.windowForComponent( this ); if( window instanceof JFrame ) @@ -495,7 +520,12 @@ private void initComponents() { iconTestRandomRadioButton = new JRadioButton(); iconTestMRIRadioButton = new JRadioButton(); iconTestDynMRIRadioButton = new JRadioButton(); + JPanel panel4 = new JPanel(); showIconCheckBox = new FlatTriStateCheckBox(); + showTitleCheckBox = new JCheckBox(); + showIconifyCheckBox = new JCheckBox(); + showMaximizeCheckBox = new JCheckBox(); + showCloseCheckBox = new JCheckBox(); JButton openDialogButton = new JButton(); JButton openFrameButton = new JButton(); menuBar = new JMenuBar(); @@ -771,13 +801,52 @@ private void initComponents() { iconTestDynMRIRadioButton.setText("test dynamic multi-resolution (Java 9+)"); iconTestDynMRIRadioButton.addActionListener(e -> iconChanged()); panel2.add(iconTestDynMRIRadioButton, "cell 0 4"); + } + add(panel2, "cell 1 8"); + + //======== panel4 ======== + { + panel4.setLayout(new MigLayout( + "ltr,insets 0,hidemode 3,gap 0 0", + // columns + "[grow,left]", + // rows + "[]" + + "[]" + + "[]" + + "[]" + + "[]")); //---- showIconCheckBox ---- showIconCheckBox.setText("show icon"); showIconCheckBox.addActionListener(e -> showIconChanged()); - panel2.add(showIconCheckBox, "cell 0 5"); + panel4.add(showIconCheckBox, "cell 0 0"); + + //---- showTitleCheckBox ---- + showTitleCheckBox.setText("show title"); + showTitleCheckBox.setSelected(true); + showTitleCheckBox.addActionListener(e -> showTitleChanged()); + panel4.add(showTitleCheckBox, "cell 0 1"); + + //---- showIconifyCheckBox ---- + showIconifyCheckBox.setText("show iconfiy"); + showIconifyCheckBox.setSelected(true); + showIconifyCheckBox.addActionListener(e -> showIconifyChanged()); + panel4.add(showIconifyCheckBox, "cell 0 2"); + + //---- showMaximizeCheckBox ---- + showMaximizeCheckBox.setText("show maximize"); + showMaximizeCheckBox.setSelected(true); + showMaximizeCheckBox.addActionListener(e -> showMaximizeChanged()); + panel4.add(showMaximizeCheckBox, "cell 0 3"); + + //---- showCloseCheckBox ---- + showCloseCheckBox.setText("show close"); + showCloseCheckBox.setSelected(true); + showCloseCheckBox.addActionListener(e -> showCloseChanged()); + panel4.add(showCloseCheckBox, "cell 0 4"); } - add(panel2, "cell 1 8"); + add(panel4, "cell 2 8"); //---- openDialogButton ---- openDialogButton.setText("Open Dialog"); @@ -1015,6 +1084,10 @@ private void initComponents() { private JRadioButton iconTestMRIRadioButton; private JRadioButton iconTestDynMRIRadioButton; private FlatTriStateCheckBox showIconCheckBox; + private JCheckBox showTitleCheckBox; + private JCheckBox showIconifyCheckBox; + private JCheckBox showMaximizeCheckBox; + private JCheckBox showCloseCheckBox; private JMenuBar menuBar; // JFormDesigner - End of variables declaration //GEN-END:variables } 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 048d768fe..3287cbd29 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.3.1.342" Java: "16" encoding: "UTF-8" +JFDML JFormDesigner: "8.0.0.0.194" Java: "17.0.2" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -398,6 +398,15 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 4" } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 8" + } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$layoutConstraints": "ltr,insets 0,hidemode 3,gap 0 0" + "$columnConstraints": "[grow,left]" + "$rowConstraints": "[][][][][]" + } ) { + name: "panel4" add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) { name: "showIconCheckBox" "text": "show icon" @@ -406,10 +415,54 @@ new FormModel { } addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showIconChanged", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 5" + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "showTitleCheckBox" + "text": "show title" + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showTitleChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "showIconifyCheckBox" + "text": "show iconfiy" + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showIconifyChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "showMaximizeCheckBox" + "text": "show maximize" + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showMaximizeChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 3" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "showCloseCheckBox" + "text": "show close" + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showCloseChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4" } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 1 8" + "value": "cell 2 8" } ) add( new FormComponent( "javax.swing.JButton" ) { name: "openDialogButton"