Window decorations:

- option to hide window icon (via client property or UI default)
- no longer show the Java "duke/cup" icon if no window icon image is set (issue #416)
This commit is contained in:
Karl Tauber
2021-11-10 14:09:32 +01:00
parent b40532a830
commit 005c9f471e
12 changed files with 91 additions and 33 deletions

View File

@@ -12,8 +12,14 @@ FlatLaf Change Log
- Style classes allow defining style rules at a single place (in UI defaults) - Style classes allow defining style rules at a single place (in UI defaults)
and use them in any component. (PR #388)\ and use them in any component. (PR #388)\
E.g.: `mySlider.putClientProperty( "FlatLaf.styleClass", "myclass" );` E.g.: `mySlider.putClientProperty( "FlatLaf.styleClass", "myclass" );`
- Native window decorations: Show Windows 11 snap layouts menu when hovering the - Native window decorations (Windows 10/11 only):
mouse over the maximize button. (issues #397 and #407) - Show Windows 11 snap layouts menu when hovering the mouse over the maximize
button. (issues #397 and #407)
- Option to hide window icon (for single window set client property
`JRootPane.titleBarShowIcon` to `false`; for all windows set UI value
`TitlePane.showIcon` to `false`).
- No longer show the Java "duke/cup" icon if no window icon image is set.
(issue #416)
- TextField, FormattedTextField and PasswordField: Support leading and trailing - TextField, FormattedTextField and PasswordField: Support leading and trailing
icons (set client property `JTextField.leadingIcon` or icons (set client property `JTextField.leadingIcon` or
`JTextField.trailingIcon` to an `Icon`). (PR #378; issue #368) `JTextField.trailingIcon` to an `Icon`). (PR #378; issue #368)

View File

@@ -331,6 +331,24 @@ public interface FlatClientProperties
*/ */
String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded"; String MENU_BAR_EMBEDDED = "JRootPane.menuBarEmbedded";
/**
* Specifies whether the window icon should be shown in the window title bar
* (requires enabled window decorations).
* <p>
* Setting this shows/hides the windows icon
* for the {@code JFrame} or {@code JDialog} that contains the root pane.
* <p>
* This client property has higher priority than UI default {@code TitlePane.showIcon}.
* <p>
* (requires Window 10)
* <p>
* <strong>Component</strong> {@link javax.swing.JRootPane}<br>
* <strong>Value type</strong> {@link java.lang.Boolean}
*
* @since 2
*/
String TITLE_BAR_SHOW_ICON = "JRootPane.titleBarShowIcon";
/** /**
* Background color of window title bar (requires enabled window decorations). * Background color of window title bar (requires enabled window decorations).
* <p> * <p>

View File

@@ -421,7 +421,7 @@ public abstract class FlatLaf
// (using defaults.remove() to avoid that lazy value is resolved and icon loaded here) // (using defaults.remove() to avoid that lazy value is resolved and icon loaded here)
Object icon = defaults.remove( "InternalFrame.icon" ); Object icon = defaults.remove( "InternalFrame.icon" );
defaults.put( "InternalFrame.icon", icon ); defaults.put( "InternalFrame.icon", icon );
defaults.put( "TitlePane.icon", icon ); defaults.put( "TitlePane.icon", icon ); // no longer used, but keep for compatibility
// get addons and sort them by priority // get addons and sort them by priority
ServiceLoader<FlatDefaultsAddon> addonLoader = ServiceLoader.load( FlatDefaultsAddon.class ); ServiceLoader<FlatDefaultsAddon> addonLoader = ServiceLoader.load( FlatDefaultsAddon.class );

View File

@@ -313,6 +313,11 @@ public class FlatRootPaneUI
} }
break; break;
case FlatClientProperties.TITLE_BAR_SHOW_ICON:
if( titlePane != null )
titlePane.updateIcon();
break;
case FlatClientProperties.TITLE_BAR_BACKGROUND: case FlatClientProperties.TITLE_BAR_BACKGROUND:
case FlatClientProperties.TITLE_BAR_FOREGROUND: case FlatClientProperties.TITLE_BAR_FOREGROUND:
if( titlePane != null ) if( titlePane != null )

View File

@@ -50,8 +50,6 @@ 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.ImageIcon;
import javax.swing.JButton; import javax.swing.JButton;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLabel; import javax.swing.JLabel;
@@ -66,7 +64,6 @@ import javax.swing.border.Border;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatSystemProperties; import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.ui.FlatNativeWindowBorder.WindowTopBorder; import com.formdev.flatlaf.ui.FlatNativeWindowBorder.WindowTopBorder;
import com.formdev.flatlaf.util.ScaledImageIcon;
import com.formdev.flatlaf.util.SystemInfo; import com.formdev.flatlaf.util.SystemInfo;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
@@ -80,6 +77,8 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TitlePane.embeddedForeground Color * @uiDefault TitlePane.embeddedForeground Color
* @uiDefault TitlePane.borderColor Color optional * @uiDefault TitlePane.borderColor Color optional
* @uiDefault TitlePane.unifiedBackground boolean * @uiDefault TitlePane.unifiedBackground boolean
* @uiDefault TitlePane.showIcon boolean
* @uiDefault TitlePane.noIconLeftGap int
* @uiDefault TitlePane.iconSize Dimension * @uiDefault TitlePane.iconSize Dimension
* @uiDefault TitlePane.iconMargins Insets * @uiDefault TitlePane.iconMargins Insets
* @uiDefault TitlePane.titleMargins Insets * @uiDefault TitlePane.titleMargins Insets
@@ -88,7 +87,6 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TitlePane.centerTitle boolean * @uiDefault TitlePane.centerTitle boolean
* @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean * @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean
* @uiDefault TitlePane.menuBarTitleGap int * @uiDefault TitlePane.menuBarTitleGap int
* @uiDefault TitlePane.icon Icon
* @uiDefault TitlePane.closeIcon Icon * @uiDefault TitlePane.closeIcon Icon
* @uiDefault TitlePane.iconifyIcon Icon * @uiDefault TitlePane.iconifyIcon Icon
* @uiDefault TitlePane.maximizeIcon Icon * @uiDefault TitlePane.maximizeIcon Icon
@@ -106,6 +104,8 @@ public class FlatTitlePane
protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" ); protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" );
protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" ); protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" );
/** @since 2 */ protected final boolean showIcon = FlatUIUtils.getUIBoolean( "TitlePane.showIcon", true );
/** @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" );
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" );
@@ -340,36 +340,27 @@ public class FlatTitlePane
protected void updateIcon() { protected void updateIcon() {
// get window images // get window images
List<Image> images = window.getIconImages(); List<Image> images = null;
if( images.isEmpty() ) { if( clientPropertyBoolean( rootPane, TITLE_BAR_SHOW_ICON, showIcon ) ) {
// search in owners images = window.getIconImages();
for( Window owner = window.getOwner(); owner != null; owner = owner.getOwner() ) { if( images.isEmpty() ) {
images = owner.getIconImages(); // search in owners
if( !images.isEmpty() ) for( Window owner = window.getOwner(); owner != null; owner = owner.getOwner() ) {
break; images = owner.getIconImages();
if( !images.isEmpty() )
break;
}
} }
} }
boolean hasIcon = true; boolean hasIcon = (images != null && !images.isEmpty());
// set icon // set icon
if( !images.isEmpty() ) iconLabel.setIcon( hasIcon ? new FlatTitlePaneIcon( images, iconSize ) : null );
iconLabel.setIcon( new FlatTitlePaneIcon( images, iconSize ) );
else {
// no icon set on window --> use default icon
Icon defaultIcon = UIManager.getIcon( "TitlePane.icon" );
if( defaultIcon != null && (defaultIcon.getIconWidth() == 0 || defaultIcon.getIconHeight() == 0) )
defaultIcon = null;
if( defaultIcon != null ) {
if( defaultIcon instanceof ImageIcon )
defaultIcon = new ScaledImageIcon( (ImageIcon) defaultIcon, iconSize.width, iconSize.height );
iconLabel.setIcon( defaultIcon );
} else
hasIcon = false;
}
// show/hide icon // show/hide icon
iconLabel.setVisible( hasIcon ); iconLabel.setVisible( hasIcon );
leftPanel.setBorder( hasIcon ? null : new FlatEmptyBorder( 0, noIconLeftGap, 0, 0 ) );
updateNativeTitleBarHeightAndHitTestSpotsLater(); updateNativeTitleBarHeightAndHitTestSpotsLater();
} }
@@ -739,7 +730,7 @@ debug*/
Rectangle appIconBounds = null; Rectangle appIconBounds = null;
if( iconLabel.isVisible() ) { if( iconLabel.isVisible() ) {
// compute real icon size (without insets; 1px wider for easier hitting) // compute real icon size (without insets; 1px larger for easier hitting)
Point location = SwingUtilities.convertPoint( iconLabel, 0, 0, window ); Point location = SwingUtilities.convertPoint( iconLabel, 0, 0, window );
Insets iconInsets = iconLabel.getInsets(); Insets iconInsets = iconLabel.getInsets();
Rectangle iconBounds = new Rectangle( Rectangle iconBounds = new Rectangle(

View File

@@ -710,6 +710,8 @@ TitledBorder.border = 1,1,1,1,$Separator.foreground
TitlePane.useWindowDecorations = true TitlePane.useWindowDecorations = true
TitlePane.menuBarEmbedded = true TitlePane.menuBarEmbedded = true
TitlePane.unifiedBackground = false TitlePane.unifiedBackground = false
TitlePane.showIcon = true
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

View File

@@ -1213,7 +1213,9 @@ 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.menuBarTitleGap 20 TitlePane.menuBarTitleGap 20
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.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI]
TitlePane.unifiedBackground false TitlePane.unifiedBackground false
TitlePane.useWindowDecorations true TitlePane.useWindowDecorations true

View File

@@ -1218,7 +1218,9 @@ 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.menuBarTitleGap 20 TitlePane.menuBarTitleGap 20
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.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI]
TitlePane.unifiedBackground false TitlePane.unifiedBackground false
TitlePane.useWindowDecorations true TitlePane.useWindowDecorations true

View File

@@ -1233,7 +1233,9 @@ 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.menuBarTitleGap 20 TitlePane.menuBarTitleGap 20
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.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI]
TitlePane.unifiedBackground false TitlePane.unifiedBackground false
TitlePane.useWindowDecorations true TitlePane.useWindowDecorations true

View File

@@ -27,6 +27,7 @@ import java.util.List;
import java.util.Random; import java.util.Random;
import javax.swing.*; import javax.swing.*;
import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.extras.components.FlatTriStateCheckBox;
import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.ui.FlatUIUtils;
import com.formdev.flatlaf.util.MultiResolutionImageSupport; import com.formdev.flatlaf.util.MultiResolutionImageSupport;
import net.miginfocom.swing.*; import net.miginfocom.swing.*;
@@ -73,6 +74,9 @@ public class FlatWindowDecorationsTest
menuBarCheckBox.setSelected( window instanceof JFrame ); menuBarCheckBox.setSelected( window instanceof JFrame );
maximizedBoundsCheckBox.setEnabled( window instanceof Frame ); maximizedBoundsCheckBox.setEnabled( window instanceof Frame );
menuBarEmbeddedCheckBox.setSelected( UIManager.getBoolean( "TitlePane.menuBarEmbedded" ) );
unifiedBackgroundCheckBox.setSelected( UIManager.getBoolean( "TitlePane.unifiedBackground" ) );
addMenuButton.setEnabled( menuBarCheckBox.isEnabled() ); addMenuButton.setEnabled( menuBarCheckBox.isEnabled() );
addGlueButton.setEnabled( menuBarCheckBox.isEnabled() ); addGlueButton.setEnabled( menuBarCheckBox.isEnabled() );
removeMenuButton.setEnabled( menuBarCheckBox.isEnabled() ); removeMenuButton.setEnabled( menuBarCheckBox.isEnabled() );
@@ -402,6 +406,12 @@ public class FlatWindowDecorationsTest
} }
} }
private void showIconChanged() {
JRootPane rootPane = getWindowRootPane();
if( rootPane != null )
rootPane.putClientProperty( FlatClientProperties.TITLE_BAR_SHOW_ICON, showIconCheckBox.getChecked() );
}
private JRootPane getWindowRootPane() { private JRootPane getWindowRootPane() {
Window window = SwingUtilities.windowForComponent( this ); Window window = SwingUtilities.windowForComponent( this );
if( window instanceof JFrame ) if( window instanceof JFrame )
@@ -450,6 +460,7 @@ public class FlatWindowDecorationsTest
iconTestRandomRadioButton = new JRadioButton(); iconTestRandomRadioButton = new JRadioButton();
iconTestMRIRadioButton = new JRadioButton(); iconTestMRIRadioButton = new JRadioButton();
iconTestDynMRIRadioButton = new JRadioButton(); iconTestDynMRIRadioButton = new JRadioButton();
showIconCheckBox = new FlatTriStateCheckBox();
JButton openDialogButton = new JButton(); JButton openDialogButton = new JButton();
JButton openFrameButton = new JButton(); JButton openFrameButton = new JButton();
menuBar = new JMenuBar(); menuBar = new JMenuBar();
@@ -685,12 +696,13 @@ public class FlatWindowDecorationsTest
panel2.setLayout(new MigLayout( panel2.setLayout(new MigLayout(
"ltr,insets 0,hidemode 3,gap 0 0", "ltr,insets 0,hidemode 3,gap 0 0",
// columns // columns
"[fill]", "[left]",
// rows // rows
"[]" + "[]" +
"[]" + "[]" +
"[]" + "[]" +
"[]" + "[]" +
"[]rel" +
"[]")); "[]"));
//---- iconNoneRadioButton ---- //---- iconNoneRadioButton ----
@@ -718,6 +730,11 @@ public class FlatWindowDecorationsTest
iconTestDynMRIRadioButton.setText("test dynamic multi-resolution (Java 9+)"); iconTestDynMRIRadioButton.setText("test dynamic multi-resolution (Java 9+)");
iconTestDynMRIRadioButton.addActionListener(e -> iconChanged()); iconTestDynMRIRadioButton.addActionListener(e -> iconChanged());
panel2.add(iconTestDynMRIRadioButton, "cell 0 4"); panel2.add(iconTestDynMRIRadioButton, "cell 0 4");
//---- showIconCheckBox ----
showIconCheckBox.setText("show icon");
showIconCheckBox.addActionListener(e -> showIconChanged());
panel2.add(showIconCheckBox, "cell 0 5");
} }
add(panel2, "cell 1 8"); add(panel2, "cell 1 8");
@@ -955,6 +972,7 @@ public class FlatWindowDecorationsTest
private JRadioButton iconTestRandomRadioButton; private JRadioButton iconTestRandomRadioButton;
private JRadioButton iconTestMRIRadioButton; private JRadioButton iconTestMRIRadioButton;
private JRadioButton iconTestDynMRIRadioButton; private JRadioButton iconTestDynMRIRadioButton;
private FlatTriStateCheckBox showIconCheckBox;
private JMenuBar menuBar; private JMenuBar menuBar;
// JFormDesigner - End of variables declaration //GEN-END:variables // JFormDesigner - End of variables declaration //GEN-END:variables
} }

View File

@@ -327,8 +327,8 @@ new FormModel {
"value": "cell 0 8" "value": "cell 0 8"
} ) } )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$columnConstraints": "[fill]" "$columnConstraints": "[left]"
"$rowConstraints": "[][][][][]" "$rowConstraints": "[][][][][]rel[]"
"$layoutConstraints": "ltr,insets 0,hidemode 3,gap 0 0" "$layoutConstraints": "ltr,insets 0,hidemode 3,gap 0 0"
} ) { } ) {
name: "panel2" name: "panel2"
@@ -388,6 +388,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 4" "value": "cell 0 4"
} ) } )
add( new FormComponent( "com.formdev.flatlaf.extras.components.FlatTriStateCheckBox" ) {
name: "showIconCheckBox"
"text": "show icon"
auxiliary() {
"JavaCodeGenerator.variableLocal": false
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showIconChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 5"
} )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 8" "value": "cell 1 8"
} ) } )

View File

@@ -969,7 +969,9 @@ TitlePane.inactiveForeground
TitlePane.maximizeIcon TitlePane.maximizeIcon
TitlePane.menuBarEmbedded TitlePane.menuBarEmbedded
TitlePane.menuBarTitleGap TitlePane.menuBarTitleGap
TitlePane.noIconLeftGap
TitlePane.restoreIcon TitlePane.restoreIcon
TitlePane.showIcon
TitlePane.titleMargins TitlePane.titleMargins
TitlePane.unifiedBackground TitlePane.unifiedBackground
TitlePane.useWindowDecorations TitlePane.useWindowDecorations