Window decorations:

- improved title bar usability by using larger gaps and minimum sizes
- added minimum gap between embedded menu bar and window title
- fixed oscillating title while resizing window width
- fixed lost right-to-left component orientation in title bar when switching Laf
This commit is contained in:
Karl Tauber
2022-07-11 17:28:30 +02:00
parent 52feaac92a
commit ef151c68f4
7 changed files with 77 additions and 41 deletions

View File

@@ -34,6 +34,8 @@ FlatLaf Change Log
`true` on Windows 10. (issue #540) `true` on Windows 10. (issue #540)
- Fixed missing top window border in dark themes if window drop shadows are - Fixed missing top window border in dark themes if window drop shadows are
disabled in system settings. (issue #554; Windows 10 only) disabled in system settings. (issue #554; Windows 10 only)
- Right-to-left component orientation of title bar was lost when switching
theme.
## 2.3 ## 2.3

View File

@@ -24,6 +24,7 @@ import java.awt.Container;
import java.awt.Dialog; import java.awt.Dialog;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Frame; import java.awt.Frame;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.GraphicsConfiguration; import java.awt.GraphicsConfiguration;
@@ -50,13 +51,13 @@ import javax.accessibility.AccessibleContext;
import javax.swing.BorderFactory; import javax.swing.BorderFactory;
import javax.swing.Box; import javax.swing.Box;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLabel; import javax.swing.JLabel;
import javax.swing.JMenuBar; import javax.swing.JMenuBar;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.JRootPane; import javax.swing.JRootPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.AbstractBorder; import javax.swing.border.AbstractBorder;
@@ -110,12 +111,13 @@ public class FlatTitlePane
/** @since 2 */ protected final boolean showIcon = FlatUIUtils.getUIBoolean( "TitlePane.showIcon", true ); /** @since 2 */ protected final boolean showIcon = FlatUIUtils.getUIBoolean( "TitlePane.showIcon", true );
/** @since 2 */ protected final int noIconLeftGap = FlatUIUtils.getUIInt( "TitlePane.noIconLeftGap", 8 ); /** @since 2 */ protected final int noIconLeftGap = FlatUIUtils.getUIInt( "TitlePane.noIconLeftGap", 8 );
protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" ); protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" );
/** @since 2.4 */ protected final int titleMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.titleMinimumWidth", 30 ); /** @since 2.4 */ protected final int titleMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.titleMinimumWidth", 60 );
/** @since 2.4 */ protected final int buttonMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.buttonMinimumWidth", 22 ); /** @since 2.4 */ protected final int buttonMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.buttonMinimumWidth", 30 );
protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" ); protected final int buttonMaximizedHeight = UIManager.getInt( "TitlePane.buttonMaximizedHeight" );
protected final boolean centerTitle = UIManager.getBoolean( "TitlePane.centerTitle" ); protected final boolean centerTitle = UIManager.getBoolean( "TitlePane.centerTitle" );
protected final boolean centerTitleIfMenuBarEmbedded = FlatUIUtils.getUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", true ); protected final boolean centerTitleIfMenuBarEmbedded = FlatUIUtils.getUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", true );
protected final int menuBarTitleGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleGap", 20 ); protected final int menuBarTitleGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleGap", 40 );
/** @since 2.4 */ protected final int menuBarTitleMinimumGap = FlatUIUtils.getUIInt( "TitlePane.menuBarTitleMinimumGap", 12 );
/** @since 2.4 */ protected final int menuBarResizeHeight = FlatUIUtils.getUIInt( "TitlePane.menuBarResizeHeight", 4 ); /** @since 2.4 */ protected final int menuBarResizeHeight = FlatUIUtils.getUIInt( "TitlePane.menuBarResizeHeight", 4 );
protected final JRootPane rootPane; protected final JRootPane rootPane;
@@ -148,6 +150,8 @@ public class FlatTitlePane
// necessary for closing window with double-click on icon // necessary for closing window with double-click on icon
iconLabel.addMouseListener( handler ); iconLabel.addMouseListener( handler );
applyComponentOrientation( rootPane.getComponentOrientation() );
} }
protected FlatTitlePaneBorder createTitlePaneBorder() { protected FlatTitlePaneBorder createTitlePaneBorder() {
@@ -169,7 +173,6 @@ public class FlatTitlePane
}; };
iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) ); iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) );
titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) ); titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) );
titleLabel.setHorizontalAlignment( SwingConstants.CENTER );
leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) ); leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) );
leftPanel.setOpaque( false ); leftPanel.setOpaque( false );
@@ -941,36 +944,62 @@ debug*/
} }
@Override @Override
protected void paintEnabledText( JLabel l, Graphics g, String s, int textX, int textY ) { protected String layoutCL( JLabel label, FontMetrics fontMetrics, String text, Icon icon,
Rectangle viewR, Rectangle iconR, Rectangle textR )
{
JMenuBar menuBar = rootPane.getJMenuBar(); JMenuBar menuBar = rootPane.getJMenuBar();
boolean hasEmbeddedMenuBar = hasVisibleEmbeddedMenuBar( menuBar ) && hasMenus( menuBar ); boolean hasEmbeddedMenuBar = hasVisibleEmbeddedMenuBar( menuBar );
int labelWidth = l.getWidth(); boolean hasEmbeddedLeadingMenus = hasEmbeddedMenuBar && hasLeadingMenus( menuBar );
int textWidth = labelWidth - (textX * 2); boolean leftToRight = getComponentOrientation().isLeftToRight();
int gap = UIScale.scale( menuBarTitleGap );
// The passed in textX coordinate is always to horizontally center the text within the label bounds. if( hasEmbeddedMenuBar ) {
// Modify textX so that the text is painted either centered within the window bounds or leading aligned. int minGap = UIScale.scale( menuBarTitleMinimumGap );
boolean center = hasEmbeddedMenuBar ? centerTitleIfMenuBarEmbedded : centerTitle;
if( center ) { // apply minimum leading gap (between embedded menu bar and title)
// If window is wide enough, center title within window bounds. if( hasEmbeddedLeadingMenus ) {
// Otherwise, leave it centered within free space (label bounds). if( leftToRight )
int centeredTextX = ((l.getParent().getWidth() - textWidth) / 2) - l.getX(); viewR.x += minGap;
if( centeredTextX >= gap && centeredTextX + textWidth <= labelWidth - gap ) viewR.width -= minGap;
textX = centeredTextX; }
} else {
// leading aligned // apply minimum trailing gap (between title and right aligned components of embedded menu bar)
boolean leftToRight = getComponentOrientation().isLeftToRight(); Component horizontalGlue = findHorizontalGlue( menuBar );
Insets insets = l.getInsets(); if( horizontalGlue != null && menuBar.getComponent( menuBar.getComponentCount() - 1 ) != horizontalGlue ) {
int leadingInset = hasEmbeddedMenuBar ? gap : (leftToRight ? insets.left : insets.right); if( !leftToRight )
int leadingTextX = leftToRight ? leadingInset : labelWidth - leadingInset - textWidth; viewR.x += minGap;
if( leftToRight ? leadingTextX < textX : leadingTextX > textX ) viewR.width -= minGap;
textX = leadingTextX; }
} }
super.paintEnabledText( l, g, s, textX, textY ); String clippedText = super.layoutCL( label, fontMetrics, text, icon, viewR, iconR, textR );
if( !clippedText.equals( text ) ) {
// if text is clipped, align to left (or right)
textR.x = leftToRight ? viewR.x : viewR.x + viewR.width - textR.width;
} else {
int leadingGap = hasEmbeddedLeadingMenus ? UIScale.scale( menuBarTitleGap - menuBarTitleMinimumGap ) : 0;
boolean center = hasEmbeddedLeadingMenus ? centerTitleIfMenuBarEmbedded : centerTitle;
if( center ) {
// If window is wide enough, center title within window bounds.
// Otherwise, center within free space (label bounds).
Container parent = label.getParent();
int centeredTextX = (parent != null) ? ((parent.getWidth() - textR.width) / 2) - label.getX() : -1;
textR.x = (centeredTextX >= viewR.x + leadingGap && centeredTextX + textR.width <= viewR.x + viewR.width - leadingGap)
? centeredTextX
: viewR.x + ((viewR.width - textR.width) / 2);
} else {
// leading aligned with leading gap, which is reduced is space is rare
textR.x = leftToRight
? Math.min( viewR.x + leadingGap, viewR.x + viewR.width - textR.width )
: Math.max( viewR.x + viewR.width - textR.width - leadingGap, viewR.x );
}
}
return clippedText;
} }
private boolean hasMenus( JMenuBar menuBar ) { private boolean hasLeadingMenus( JMenuBar menuBar ) {
// check whether menu bar is empty // check whether menu bar is empty
if( menuBar.getComponentCount() == 0 || menuBar.getWidth() == 0 ) if( menuBar.getComponentCount() == 0 || menuBar.getWidth() == 0 )
return false; return false;

View File

@@ -789,13 +789,14 @@ TitlePane.noIconLeftGap = 8
TitlePane.iconSize = 16,16 TitlePane.iconSize = 16,16
TitlePane.iconMargins = 3,8,3,8 TitlePane.iconMargins = 3,8,3,8
TitlePane.titleMargins = 3,0,3,0 TitlePane.titleMargins = 3,0,3,0
TitlePane.titleMinimumWidth = 30 TitlePane.titleMinimumWidth = 60
TitlePane.buttonSize = 44,30 TitlePane.buttonSize = 44,30
TitlePane.buttonMinimumWidth = 22 TitlePane.buttonMinimumWidth = 30
TitlePane.buttonMaximizedHeight = 22 TitlePane.buttonMaximizedHeight = 22
TitlePane.centerTitle = false TitlePane.centerTitle = false
TitlePane.centerTitleIfMenuBarEmbedded = true TitlePane.centerTitleIfMenuBarEmbedded = true
TitlePane.menuBarTitleGap = 20 TitlePane.menuBarTitleGap = 40
TitlePane.menuBarTitleMinimumGap = 12
TitlePane.menuBarResizeHeight = 4 TitlePane.menuBarResizeHeight = 4
TitlePane.closeIcon = com.formdev.flatlaf.icons.FlatWindowCloseIcon TitlePane.closeIcon = com.formdev.flatlaf.icons.FlatWindowCloseIcon
TitlePane.iconifyIcon = com.formdev.flatlaf.icons.FlatWindowIconifyIcon TitlePane.iconifyIcon = com.formdev.flatlaf.icons.FlatWindowIconifyIcon

View File

@@ -1214,7 +1214,7 @@ TextPaneUI com.formdev.flatlaf.ui.FlatTextPaneUI
TitlePane.background #303234 HSL 210 4 20 javax.swing.plaf.ColorUIResource [UI] TitlePane.background #303234 HSL 210 4 20 javax.swing.plaf.ColorUIResource [UI]
TitlePane.buttonHoverBackground #55585c HSL 214 4 35 com.formdev.flatlaf.util.DerivedColor [UI] lighten(15% autoInverse) TitlePane.buttonHoverBackground #55585c HSL 214 4 35 com.formdev.flatlaf.util.DerivedColor [UI] lighten(15% autoInverse)
TitlePane.buttonMaximizedHeight 22 TitlePane.buttonMaximizedHeight 22
TitlePane.buttonMinimumWidth 22 TitlePane.buttonMinimumWidth 30
TitlePane.buttonPressedBackground #484c4f HSL 206 5 30 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10% autoInverse) TitlePane.buttonPressedBackground #484c4f HSL 206 5 30 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10% autoInverse)
TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI]
TitlePane.centerTitle false TitlePane.centerTitle false
@@ -1235,12 +1235,13 @@ TitlePane.inactiveForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.Colo
TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI]
TitlePane.menuBarEmbedded true TitlePane.menuBarEmbedded true
TitlePane.menuBarResizeHeight 4 TitlePane.menuBarResizeHeight 4
TitlePane.menuBarTitleGap 20 TitlePane.menuBarTitleGap 40
TitlePane.menuBarTitleMinimumGap 12
TitlePane.noIconLeftGap 8 TitlePane.noIconLeftGap 8
TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI]
TitlePane.showIcon true TitlePane.showIcon true
TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI]
TitlePane.titleMinimumWidth 30 TitlePane.titleMinimumWidth 60
TitlePane.unifiedBackground true TitlePane.unifiedBackground true
TitlePane.useWindowDecorations true TitlePane.useWindowDecorations true

View File

@@ -1219,7 +1219,7 @@ TextPaneUI com.formdev.flatlaf.ui.FlatTextPaneUI
TitlePane.background #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI] TitlePane.background #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
TitlePane.buttonHoverBackground #e6e6e6 HSL 0 0 90 com.formdev.flatlaf.util.DerivedColor [UI] darken(10% autoInverse) TitlePane.buttonHoverBackground #e6e6e6 HSL 0 0 90 com.formdev.flatlaf.util.DerivedColor [UI] darken(10% autoInverse)
TitlePane.buttonMaximizedHeight 22 TitlePane.buttonMaximizedHeight 22
TitlePane.buttonMinimumWidth 22 TitlePane.buttonMinimumWidth 30
TitlePane.buttonPressedBackground #ebebeb HSL 0 0 92 com.formdev.flatlaf.util.DerivedColor [UI] darken(8% autoInverse) TitlePane.buttonPressedBackground #ebebeb HSL 0 0 92 com.formdev.flatlaf.util.DerivedColor [UI] darken(8% autoInverse)
TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI]
TitlePane.centerTitle false TitlePane.centerTitle false
@@ -1240,12 +1240,13 @@ TitlePane.inactiveForeground #8c8c8c HSL 0 0 55 javax.swing.plaf.Colo
TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI]
TitlePane.menuBarEmbedded true TitlePane.menuBarEmbedded true
TitlePane.menuBarResizeHeight 4 TitlePane.menuBarResizeHeight 4
TitlePane.menuBarTitleGap 20 TitlePane.menuBarTitleGap 40
TitlePane.menuBarTitleMinimumGap 12
TitlePane.noIconLeftGap 8 TitlePane.noIconLeftGap 8
TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI]
TitlePane.showIcon true TitlePane.showIcon true
TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI]
TitlePane.titleMinimumWidth 30 TitlePane.titleMinimumWidth 60
TitlePane.unifiedBackground true TitlePane.unifiedBackground true
TitlePane.useWindowDecorations true TitlePane.useWindowDecorations true

View File

@@ -1249,7 +1249,7 @@ TextPaneUI com.formdev.flatlaf.ui.FlatTextPaneUI
TitlePane.background #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI] TitlePane.background #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI]
TitlePane.borderColor #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI] TitlePane.borderColor #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
TitlePane.buttonMaximizedHeight 22 TitlePane.buttonMaximizedHeight 22
TitlePane.buttonMinimumWidth 22 TitlePane.buttonMinimumWidth 30
TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI]
TitlePane.centerTitle false TitlePane.centerTitle false
TitlePane.centerTitleIfMenuBarEmbedded true TitlePane.centerTitleIfMenuBarEmbedded true
@@ -1268,12 +1268,13 @@ TitlePane.inactiveForeground #ffffff HSL 0 0 100 javax.swing.plaf.Colo
TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] TitlePane.maximizeIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI]
TitlePane.menuBarEmbedded true TitlePane.menuBarEmbedded true
TitlePane.menuBarResizeHeight 4 TitlePane.menuBarResizeHeight 4
TitlePane.menuBarTitleGap 20 TitlePane.menuBarTitleGap 40
TitlePane.menuBarTitleMinimumGap 12
TitlePane.noIconLeftGap 8 TitlePane.noIconLeftGap 8
TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI]
TitlePane.showIcon true TitlePane.showIcon true
TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI]
TitlePane.titleMinimumWidth 30 TitlePane.titleMinimumWidth 60
TitlePane.unifiedBackground true TitlePane.unifiedBackground true
TitlePane.useWindowDecorations true TitlePane.useWindowDecorations true

View File

@@ -1002,6 +1002,7 @@ TitlePane.maximizeIcon
TitlePane.menuBarEmbedded TitlePane.menuBarEmbedded
TitlePane.menuBarResizeHeight TitlePane.menuBarResizeHeight
TitlePane.menuBarTitleGap TitlePane.menuBarTitleGap
TitlePane.menuBarTitleMinimumGap
TitlePane.noIconLeftGap TitlePane.noIconLeftGap
TitlePane.restoreIcon TitlePane.restoreIcon
TitlePane.showIcon TitlePane.showIcon