Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Window decorations: Title bar customizing #613

Merged
merged 2 commits into from Dec 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -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}.
* <p>
* Setting this shows/hides the windows icon
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
Expand All @@ -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}.
* <p>
* Setting this shows/hides the windows title
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@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}.
* <p>
* Setting this shows/hides the "iconfify" button
* for the {@code JFrame} that contains the root pane.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@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}.
* <p>
* Setting this shows/hides the "maximize/restore" button
* for the {@code JFrame} that contains the root pane.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@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}.
* <p>
* Setting this shows/hides the "close" button
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 3
*/
String TITLE_BAR_SHOW_CLOSE = "JRootPane.titleBarShowClose";

/**
* Background color of window title bar (requires enabled window decorations).
* <p>
Expand Down
Expand Up @@ -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 )
Expand Down
Expand Up @@ -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" );
Expand Down Expand Up @@ -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 )
Expand All @@ -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();
}
}

Expand Down Expand Up @@ -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 );
Expand All @@ -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 ) {
Expand Down Expand Up @@ -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 ) {
Expand All @@ -950,14 +962,12 @@ protected Rectangle getNativeHitTestSpot( JComponent c ) {
return r;
}

/*debug
private int debugTitleBarHeight;
private List<Rectangle> debugHitTestSpots;
private Rectangle debugAppIconBounds;
private Rectangle debugMinimizeButtonBounds;
private Rectangle debugMaximizeButtonBounds;
private Rectangle debugCloseButtonBounds;
debug*/

//---- class FlatTitlePaneBorder ------------------------------------------

Expand Down
Expand Up @@ -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();
} );
Expand Down
Expand Up @@ -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<Image> images = Arrays.asList(
Expand Down Expand Up @@ -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 )
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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
}