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)
This commit is contained in:
Karl Tauber
2021-03-13 17:08:47 +01:00
parent cee2211108
commit 30c7b442a8
10 changed files with 102 additions and 6 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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");

View File

@@ -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"

View File

@@ -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