Skip to content

Commit d286550

Browse files
committed
Merge PR #613: Window decorations: Title bar customizing
2 parents 4e44e25 + 4d175da commit d286550

6 files changed

Lines changed: 222 additions & 21 deletions

File tree

flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ public interface FlatClientProperties
346346

347347
/**
348348
* Specifies whether the window icon should be shown in the window title bar
349-
* (requires enabled window decorations).
349+
* (requires enabled window decorations). Default is UI property {@code TitlePane.showIcon}.
350350
* <p>
351351
* Setting this shows/hides the windows icon
352352
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
@@ -362,6 +362,62 @@ public interface FlatClientProperties
362362
*/
363363
String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon";
364364

365+
/**
366+
* Specifies whether the window title should be shown in the window title bar
367+
* (requires enabled window decorations). Default is {@code true}.
368+
* <p>
369+
* Setting this shows/hides the windows title
370+
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
371+
* <p>
372+
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
373+
* <strong>Value type</strong> {@link java.lang.Boolean}
374+
*
375+
* @since 3
376+
*/
377+
String TITLE_BAR_SHOW_TITLE = "JRootPane.titleBarShowTitle";
378+
379+
/**
380+
* Specifies whether the "iconfify" button should be shown in the window title bar
381+
* (requires enabled window decorations). Default is {@code true}.
382+
* <p>
383+
* Setting this shows/hides the "iconfify" button
384+
* for the {@code JFrame} that contains the root pane.
385+
* <p>
386+
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
387+
* <strong>Value type</strong> {@link java.lang.Boolean}
388+
*
389+
* @since 3
390+
*/
391+
String TITLE_BAR_SHOW_ICONIFFY = "JRootPane.titleBarShowIconify";
392+
393+
/**
394+
* Specifies whether the "maximize/restore" button should be shown in the window title bar
395+
* (requires enabled window decorations). Default is {@code true}.
396+
* <p>
397+
* Setting this shows/hides the "maximize/restore" button
398+
* for the {@code JFrame} that contains the root pane.
399+
* <p>
400+
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
401+
* <strong>Value type</strong> {@link java.lang.Boolean}
402+
*
403+
* @since 3
404+
*/
405+
String TITLE_BAR_SHOW_MAXIMIZE = "JRootPane.titleBarShowMaximize";
406+
407+
/**
408+
* Specifies whether the "close" button should be shown in the window title bar
409+
* (requires enabled window decorations). Default is {@code true}.
410+
* <p>
411+
* Setting this shows/hides the "close" button
412+
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
413+
* <p>
414+
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
415+
* <strong>Value type</strong> {@link java.lang.Boolean}
416+
*
417+
* @since 3
418+
*/
419+
String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose";
420+
365421
/**
366422
* Background color of window title bar (requires enabled window decorations).
367423
* <p>

flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,14 @@ public void propertyChange( PropertyChangeEvent e ) {
349349
titlePane.updateIcon();
350350
break;
351351

352+
case FlatClientProperties.TITLE_BAR_SHOW_TITLE:
353+
case FlatClientProperties.TITLE_BAR_SHOW_ICONIFFY:
354+
case FlatClientProperties.TITLE_BAR_SHOW_MAXIMIZE:
355+
case FlatClientProperties.TITLE_BAR_SHOW_CLOSE:
356+
if( titlePane != null )
357+
titlePane.updateVisibility();
358+
break;
359+
352360
case FlatClientProperties.TITLE_BAR_BACKGROUND:
353361
case FlatClientProperties.TITLE_BAR_FOREGROUND:
354362
if( titlePane != null )

flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@
107107
public class FlatTitlePane
108108
extends JComponent
109109
{
110+
private static final String KEY_DEBUG_SHOW_RECTANGLES = "FlatLaf.debug.titlebar.showRectangles";
111+
110112
/** @since 2.5 */ protected final Font titleFont = UIManager.getFont( "TitlePane.font" );
111113
protected final Color activeBackground = UIManager.getColor( "TitlePane.background" );
112114
protected final Color inactiveBackground = UIManager.getColor( "TitlePane.inactiveBackground" );
@@ -354,15 +356,12 @@ protected void frameStateChanged() {
354356
if( window == null || rootPane.getWindowDecorationStyle() != JRootPane.FRAME )
355357
return;
356358

359+
updateVisibility();
360+
357361
if( window instanceof Frame ) {
358362
Frame frame = (Frame) window;
359-
boolean resizable = frame.isResizable();
360363
boolean maximized = ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0);
361364

362-
iconifyButton.setVisible( true );
363-
maximizeButton.setVisible( resizable && !maximized );
364-
restoreButton.setVisible( resizable && maximized );
365-
366365
if( maximized &&
367366
!(SystemInfo.isLinux && FlatNativeLinuxLibrary.isWMUtilsSupported( window )) &&
368367
rootPane.getClientProperty( "_flatlaf.maximizedBoundsUpToDate" ) == null )
@@ -383,14 +382,27 @@ protected void frameStateChanged() {
383382
frame.setExtendedState( oldExtendedState );
384383
}
385384
}
385+
}
386+
}
387+
388+
/** @since 3 */
389+
protected void updateVisibility() {
390+
titleLabel.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_TITLE, true ) );
391+
closeButton.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_CLOSE, true ) );
392+
393+
if( window instanceof Frame ) {
394+
Frame frame = (Frame) window;
395+
boolean maximizable = frame.isResizable() && clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_MAXIMIZE, true );
396+
boolean maximized = ((frame.getExtendedState() & Frame.MAXIMIZED_BOTH) != 0);
397+
398+
iconifyButton.setVisible( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_ICONIFFY, true ) );
399+
maximizeButton.setVisible( maximizable && !maximized );
400+
restoreButton.setVisible( maximizable && maximized );
386401
} else {
387402
// hide buttons because they are only supported in frames
388403
iconifyButton.setVisible( false );
389404
maximizeButton.setVisible( false );
390405
restoreButton.setVisible( false );
391-
392-
revalidate();
393-
repaint();
394406
}
395407
}
396408

@@ -566,11 +578,13 @@ protected void menuBarLayouted() {
566578
doLayout();
567579
}
568580

569-
/*debug
570581
@Override
571582
public void paint( Graphics g ) {
572583
super.paint( g );
573584

585+
if( !UIManager.getBoolean( KEY_DEBUG_SHOW_RECTANGLES ) )
586+
return;
587+
574588
if( debugTitleBarHeight > 0 ) {
575589
g.setColor( Color.green );
576590
g.drawLine( 0, debugTitleBarHeight, getWidth(), debugTitleBarHeight );
@@ -594,7 +608,6 @@ private void paintRect( Graphics g, Color color, Rectangle r ) {
594608
Point offset = SwingUtilities.convertPoint( this, 0, 0, window );
595609
g.drawRect( r.x - offset.x, r.y - offset.y, r.width - 1, r.height - 1 );
596610
}
597-
debug*/
598611

599612
@Override
600613
protected void paintComponent( Graphics g ) {
@@ -923,15 +936,14 @@ protected void updateNativeTitleBarHeightAndHitTestSpots() {
923936
FlatNativeWindowBorder.setTitleBarHeightAndHitTestSpots( window, titleBarHeight,
924937
hitTestSpots, appIconBounds, minimizeButtonBounds, maximizeButtonBounds, closeButtonBounds );
925938

926-
/*debug
927939
debugTitleBarHeight = titleBarHeight;
928940
debugHitTestSpots = hitTestSpots;
929941
debugAppIconBounds = appIconBounds;
930942
debugMinimizeButtonBounds = minimizeButtonBounds;
931943
debugMaximizeButtonBounds = maximizeButtonBounds;
932944
debugCloseButtonBounds = closeButtonBounds;
933-
repaint();
934-
debug*/
945+
if( UIManager.getBoolean( KEY_DEBUG_SHOW_RECTANGLES ) )
946+
repaint();
935947
}
936948

937949
private Rectangle boundsInWindow( JComponent c ) {
@@ -950,14 +962,12 @@ protected Rectangle getNativeHitTestSpot( JComponent c ) {
950962
return r;
951963
}
952964

953-
/*debug
954965
private int debugTitleBarHeight;
955966
private List<Rectangle> debugHitTestSpots;
956967
private Rectangle debugAppIconBounds;
957968
private Rectangle debugMinimizeButtonBounds;
958969
private Rectangle debugMaximizeButtonBounds;
959970
private Rectangle debugCloseButtonBounds;
960-
debug*/
961971

962972
//---- class FlatTitlePaneBorder ------------------------------------------
963973

flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatNativeWindowBorderTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public static void main( String[] args ) {
5757
SwingUtilities.invokeLater( () -> {
5858
FlatLightLaf.setup();
5959
FlatInspector.install( "ctrl shift alt X" );
60+
UIManager.put( "FlatLaf.debug.titlebar.showRectangles", true );
6061

6162
mainFrame = showFrame();
6263
} );

flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java

Lines changed: 75 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public static void main( String[] args ) {
4949

5050
FlatTestFrame frame = FlatTestFrame.create( args, "FlatWindowDecorationsTest" );
5151
frame.applyComponentOrientationToFrame = true;
52+
UIManager.put( "FlatLaf.debug.titlebar.showRectangles", true );
5253

5354
Class<?> cls = FlatWindowDecorationsTest.class;
5455
List<Image> images = Arrays.asList(
@@ -446,6 +447,30 @@ private void showIconChanged() {
446447
rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_ICON, showIconCheckBox.getChecked() );
447448
}
448449

450+
private void showTitleChanged() {
451+
JRootPane rootPane = getWindowRootPane();
452+
if( rootPane != null )
453+
rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_TITLE, showTitleCheckBox.isSelected() ? null : false );
454+
}
455+
456+
private void showIconifyChanged() {
457+
JRootPane rootPane = getWindowRootPane();
458+
if( rootPane != null )
459+
rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_ICONIFFY, showIconifyCheckBox.isSelected() ? null : false );
460+
}
461+
462+
private void showMaximizeChanged() {
463+
JRootPane rootPane = getWindowRootPane();
464+
if( rootPane != null )
465+
rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_MAXIMIZE, showMaximizeCheckBox.isSelected() ? null : false );
466+
}
467+
468+
private void showCloseChanged() {
469+
JRootPane rootPane = getWindowRootPane();
470+
if( rootPane != null )
471+
rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_CLOSE, showCloseCheckBox.isSelected() ? null : false );
472+
}
473+
449474
private JRootPane getWindowRootPane() {
450475
Window window = SwingUtilities.windowForComponent( this );
451476
if( window instanceof JFrame )
@@ -495,7 +520,12 @@ private void initComponents() {
495520
iconTestRandomRadioButton = new JRadioButton();
496521
iconTestMRIRadioButton = new JRadioButton();
497522
iconTestDynMRIRadioButton = new JRadioButton();
523+
JPanel panel4 = new JPanel();
498524
showIconCheckBox = new FlatTriStateCheckBox();
525+
showTitleCheckBox = new JCheckBox();
526+
showIconifyCheckBox = new JCheckBox();
527+
showMaximizeCheckBox = new JCheckBox();
528+
showCloseCheckBox = new JCheckBox();
499529
JButton openDialogButton = new JButton();
500530
JButton openFrameButton = new JButton();
501531
menuBar = new JMenuBar();
@@ -771,13 +801,52 @@ private void initComponents() {
771801
iconTestDynMRIRadioButton.setText("test dynamic multi-resolution (Java 9+)");
772802
iconTestDynMRIRadioButton.addActionListener(e -> iconChanged());
773803
panel2.add(iconTestDynMRIRadioButton, "cell 0 4");
804+
}
805+
add(panel2, "cell 1 8");
806+
807+
//======== panel4 ========
808+
{
809+
panel4.setLayout(new MigLayout(
810+
"ltr,insets 0,hidemode 3,gap 0 0",
811+
// columns
812+
"[grow,left]",
813+
// rows
814+
"[]" +
815+
"[]" +
816+
"[]" +
817+
"[]" +
818+
"[]"));
774819

775820
//---- showIconCheckBox ----
776821
showIconCheckBox.setText("show icon");
777822
showIconCheckBox.addActionListener(e -> showIconChanged());
778-
panel2.add(showIconCheckBox, "cell 0 5");
823+
panel4.add(showIconCheckBox, "cell 0 0");
824+
825+
//---- showTitleCheckBox ----
826+
showTitleCheckBox.setText("show title");
827+
showTitleCheckBox.setSelected(true);
828+
showTitleCheckBox.addActionListener(e -> showTitleChanged());
829+
panel4.add(showTitleCheckBox, "cell 0 1");
830+
831+
//---- showIconifyCheckBox ----
832+
showIconifyCheckBox.setText("show iconfiy");
833+
showIconifyCheckBox.setSelected(true);
834+
showIconifyCheckBox.addActionListener(e -> showIconifyChanged());
835+
panel4.add(showIconifyCheckBox, "cell 0 2");
836+
837+
//---- showMaximizeCheckBox ----
838+
showMaximizeCheckBox.setText("show maximize");
839+
showMaximizeCheckBox.setSelected(true);
840+
showMaximizeCheckBox.addActionListener(e -> showMaximizeChanged());
841+
panel4.add(showMaximizeCheckBox, "cell 0 3");
842+
843+
//---- showCloseCheckBox ----
844+
showCloseCheckBox.setText("show close");
845+
showCloseCheckBox.setSelected(true);
846+
showCloseCheckBox.addActionListener(e -> showCloseChanged());
847+
panel4.add(showCloseCheckBox, "cell 0 4");
779848
}
780-
add(panel2, "cell 1 8");
849+
add(panel4, "cell 2 8");
781850

782851
//---- openDialogButton ----
783852
openDialogButton.setText("Open Dialog");
@@ -1015,6 +1084,10 @@ private void initComponents() {
10151084
private JRadioButton iconTestMRIRadioButton;
10161085
private JRadioButton iconTestDynMRIRadioButton;
10171086
private FlatTriStateCheckBox showIconCheckBox;
1087+
private JCheckBox showTitleCheckBox;
1088+
private JCheckBox showIconifyCheckBox;
1089+
private JCheckBox showMaximizeCheckBox;
1090+
private JCheckBox showCloseCheckBox;
10181091
private JMenuBar menuBar;
10191092
// JFormDesigner - End of variables declaration //GEN-END:variables
10201093
}

0 commit comments

Comments
 (0)