diff --git a/CHANGELOG.md b/CHANGELOG.md index 772d3e7c..6c9e9258 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ FlatLaf Change Log #### New features and improvements +- FlatLaf window decorations: Support toolbox-style "small" window title bar. + (issue #659) - Extras: Class `FlatSVGIcon` now uses [JSVG](https://github.com/weisJ/jsvg) library (instead of svgSalamander) for rendering. JSVG provides improved SVG rendering and uses less memory compared to svgSalamander. (PR #684) diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java index ee16de4c..1aad7959 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -17,6 +17,8 @@ package com.formdev.flatlaf; import java.awt.Color; +import java.awt.IllegalComponentStateException; +import java.awt.Window; import java.util.Objects; import javax.swing.JComponent; import javax.swing.SwingConstants; @@ -124,6 +126,7 @@ public interface FlatClientProperties */ String SQUARE_SIZE = "JButton.squareSize"; + //---- JComponent --------------------------------------------------------- /** @@ -266,6 +269,7 @@ public interface FlatClientProperties */ String COMPONENT_TITLE_BAR_CAPTION = "JComponent.titleBarCaption"; + //---- Popup -------------------------------------------------------------- /** @@ -305,6 +309,7 @@ public interface FlatClientProperties */ String POPUP_FORCE_HEAVY_WEIGHT = "Popup.forceHeavyWeight"; + //---- JProgressBar ------------------------------------------------------- /** @@ -323,6 +328,7 @@ public interface FlatClientProperties */ String PROGRESS_BAR_SQUARE = "JProgressBar.square"; + //---- JRootPane ---------------------------------------------------------- /** @@ -472,6 +478,37 @@ public interface FlatClientProperties */ String GLASS_PANE_FULL_HEIGHT = "JRootPane.glassPaneFullHeight"; + /** + * Specifies the style of the window title bar. + * Besides the default title bar style, you can use a Utility-style title bar, + * which is smaller than the default title bar. + *

+ * On Windows 10/11, this requires FlatLaf window decorations. + * On macOS, Java supports this out of the box. + *

+ * Note that this client property must be set before the window becomes displayable. + * Otherwise an {@link IllegalComponentStateException} is thrown. + *

+ * Component {@link javax.swing.JRootPane}
+ * Value type {@link java.lang.String}
+ * Allowed Values + * {@link #WINDOW_STYLE_SMALL} + * + * @since 3.2 + */ + String WINDOW_STYLE = "Window.style"; + + /** + * The window has Utility-style title bar, which is smaller than default title bar. + *

+ * This is the same as using {@link Window#setType}( {@link Window.Type#UTILITY} ). + * + * @see #WINDOW_STYLE + * @since 3.2 + */ + String WINDOW_STYLE_SMALL = "small"; + + //---- JScrollBar / JScrollPane ------------------------------------------- /** @@ -490,6 +527,7 @@ public interface FlatClientProperties */ String SCROLL_PANE_SMOOTH_SCROLLING = "JScrollPane.smoothScrolling"; + //---- JSplitPane --------------------------------------------------------- /** @@ -524,6 +562,7 @@ public interface FlatClientProperties */ String SPLIT_PANE_EXPANDABLE_SIDE_RIGHT = "right"; + //---- JTabbedPane -------------------------------------------------------- /** @@ -919,6 +958,7 @@ public interface FlatClientProperties */ String TABBED_PANE_TRAILING_COMPONENT = "JTabbedPane.trailingComponent"; + //---- JTextField --------------------------------------------------------- /** @@ -1088,6 +1128,7 @@ public interface FlatClientProperties */ String TEXT_FIELD_CLEAR_CALLBACK = "JTextField.clearCallback"; + //---- JToggleButton ------------------------------------------------------ /** @@ -1129,6 +1170,7 @@ public interface FlatClientProperties */ String TAB_BUTTON_SELECTED_BACKGROUND = "JToggleButton.tab.selectedBackground"; + //---- JTree -------------------------------------------------------------- /** @@ -1148,6 +1190,7 @@ public interface FlatClientProperties */ String TREE_PAINT_SELECTION = "JTree.paintSelection"; + //---- helper methods ----------------------------------------------------- /** diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java index b820f000..79345841 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/UIDefaultsLoader.java @@ -27,8 +27,12 @@ import java.io.IOException; import java.io.InputStream; import java.io.StreamTokenizer; import java.io.StringReader; +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -548,7 +552,7 @@ class UIDefaultsLoader case INTEGERORFLOAT:return parseIntegerOrFloat( value ); case FLOAT: return parseFloat( value ); case BORDER: return parseBorder( value, resolver, addonClassLoaders ); - case ICON: return parseInstance( value, addonClassLoaders ); + case ICON: return parseInstance( value, resolver, addonClassLoaders ); case INSETS: return parseInsets( value ); case DIMENSION: return parseDimension( value ); case COLOR: return parseColorOrFunction( value, resolver ); @@ -557,7 +561,7 @@ class UIDefaultsLoader case SCALEDFLOAT: return parseScaledFloat( value ); case SCALEDINSETS: return parseScaledInsets( value ); case SCALEDDIMENSION:return parseScaledDimension( value ); - case INSTANCE: return parseInstance( value, addonClassLoaders ); + case INSTANCE: return parseInstance( value, resolver, addonClassLoaders ); case CLASS: return parseClass( value, addonClassLoaders ); case GRAYFILTER: return parseGrayFilter( value ); case UNKNOWN: @@ -623,7 +627,7 @@ class UIDefaultsLoader throws IllegalArgumentException { if( value.indexOf( ',' ) >= 0 ) { - // top,left,bottom,right[,lineColor[,lineThickness[,arc]]] + // Syntax: top,left,bottom,right[,lineColor[,lineThickness[,arc]]] List parts = splitFunctionParams( value, ',' ); Insets insets = parseInsets( value ); ColorUIResource lineColor = (parts.size() >= 5) @@ -638,13 +642,29 @@ class UIDefaultsLoader : new FlatEmptyBorder( insets ); }; } else - return parseInstance( value, addonClassLoaders ); + return parseInstance( value, resolver, addonClassLoaders ); } - private static Object parseInstance( String value, List addonClassLoaders ) { + private static Object parseInstance( String value, Function resolver, List addonClassLoaders ) { return (LazyValue) t -> { try { - return findClass( value, addonClassLoaders ).getDeclaredConstructor().newInstance(); + if( value.indexOf( ',' ) >= 0 ) { + // Syntax: className,param1,param2,... + List parts = splitFunctionParams( value, ',' ); + String className = parts.get( 0 ); + Class cls = findClass( className, addonClassLoaders ); + + Constructor[] constructors = cls.getDeclaredConstructors(); + Object result = invokeConstructorOrStaticMethod( constructors, parts, resolver ); + if( result != null ) + return result; + + LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + className + + "': no constructor found for parameters '" + + value.substring( value.indexOf( ',' + 1 ) ) + "'.", null ); + return null; + } else + return findClass( value, addonClassLoaders ).getDeclaredConstructor().newInstance(); } catch( Exception ex ) { LoggingFacade.INSTANCE.logSevere( "FlatLaf: Failed to instantiate '" + value + "'.", ex ); return null; @@ -1466,6 +1486,86 @@ class UIDefaultsLoader return strs; } + private static Object invokeConstructorOrStaticMethod( Executable[] constructorsOrMethods, + List parts, Function resolver ) + throws Exception + { + // order constructors/methods by parameter types: + // - String parameters to the end + // - int before float parameters + constructorsOrMethods = constructorsOrMethods.clone(); + Arrays.sort( constructorsOrMethods, (c1, c2) -> { + Class[] ptypes1 = c1.getParameterTypes(); + Class[] ptypes2 = c2.getParameterTypes(); + if( ptypes1.length != ptypes2.length ) + return ptypes1.length - ptypes2.length; + + for( int i = 0; i < ptypes1.length; i++ ) { + Class pt1 = ptypes1[i]; + Class pt2 = ptypes2[i]; + + if( pt1 == pt2 ) + continue; + + // order methods with String parameters to the end + if( pt1 == String.class ) + return 2; + if( pt2 == String.class ) + return -2; + + // order int before float + if( pt1 == int.class ) + return -1; + if( pt2 == int.class ) + return 1; + } + return 0; + } ); + + // search for best constructor/method for given parameter values + for( Executable cm : constructorsOrMethods ) { + if( cm.getParameterCount() != parts.size() - 1 ) + continue; + + Object[] params = parseMethodParams( cm.getParameterTypes(), parts, resolver ); + if( params == null ) + continue; + + // invoke constructor or static method + if( cm instanceof Constructor ) + return ((Constructor)cm).newInstance( params ); + else + return ((Method)cm).invoke( null, params ); + } + + return null; + } + + private static Object[] parseMethodParams( Class[] paramTypes, List parts, Function resolver ) { + Object[] params = new Object[paramTypes.length]; + try { + for( int i = 0; i < params.length; i++ ) { + Class paramType = paramTypes[i]; + String paramValue = parts.get( i + 1 ); + if( paramType == String.class ) + params[i] = paramValue; + else if( paramType == boolean.class ) + params[i] = parseBoolean( paramValue ); + else if( paramType == int.class ) + params[i] = parseInteger( paramValue ); + else if( paramType == float.class ) + params[i] = parseFloat( paramValue ); + else if( paramType == Color.class ) + params[i] = parseColorOrFunction( resolver.apply( paramValue ), resolver ); + else + return null; // unsupported parameter type + } + } catch( IllegalArgumentException ex ) { + return null; // failed to parse parameter for expected parameter type + } + return params; + } + /** * For use in LazyValue to get value for given key from UIManager and report error * if not found. If key is prefixed by '?', then no error is reported. diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowAbstractIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowAbstractIcon.java index fcea0da8..bf0122d4 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowAbstractIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowAbstractIcon.java @@ -21,7 +21,6 @@ import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.RenderingHints; -import javax.swing.UIManager; import com.formdev.flatlaf.ui.FlatButtonUI; import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.util.HiDPIUtils; @@ -30,6 +29,7 @@ import com.formdev.flatlaf.util.HiDPIUtils; * Base class for window icons. * * @uiDefault TitlePane.buttonSize Dimension + * @uiDefault TitlePane.buttonSymbolHeight int * @uiDefault TitlePane.buttonHoverBackground Color * @uiDefault TitlePane.buttonPressedBackground Color * @@ -38,17 +38,22 @@ import com.formdev.flatlaf.util.HiDPIUtils; public abstract class FlatWindowAbstractIcon extends FlatAbstractIcon { + private final int symbolHeight; private final Color hoverBackground; private final Color pressedBackground; - public FlatWindowAbstractIcon() { - this( UIManager.getDimension( "TitlePane.buttonSize" ), - UIManager.getColor( "TitlePane.buttonHoverBackground" ), - UIManager.getColor( "TitlePane.buttonPressedBackground" ) ); + /** @since 3.2 */ + protected FlatWindowAbstractIcon( String windowStyle ) { + this( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ), + FlatUIUtils.getSubUIInt( "TitlePane.buttonSymbolHeight", windowStyle, 10 ), + FlatUIUtils.getSubUIColor( "TitlePane.buttonHoverBackground", windowStyle ), + FlatUIUtils.getSubUIColor( "TitlePane.buttonPressedBackground", windowStyle ) ); } - public FlatWindowAbstractIcon( Dimension size, Color hoverBackground, Color pressedBackground ) { + /** @since 3.2 */ + protected FlatWindowAbstractIcon( Dimension size, int symbolHeight, Color hoverBackground, Color pressedBackground ) { super( size.width, size.height, null ); + this.symbolHeight = symbolHeight; this.hoverBackground = hoverBackground; this.pressedBackground = pressedBackground; } @@ -80,4 +85,9 @@ public abstract class FlatWindowAbstractIcon protected Color getForeground( Component c ) { return c.getForeground(); } + + /** @since 3.2 */ + protected int getSymbolHeight() { + return symbolHeight; + } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowCloseIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowCloseIcon.java index ef6e3b1b..99625d75 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowCloseIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowCloseIcon.java @@ -21,8 +21,8 @@ import java.awt.Color; import java.awt.Component; import java.awt.Graphics2D; import java.awt.geom.Path2D; -import javax.swing.UIManager; import com.formdev.flatlaf.ui.FlatButtonUI; +import com.formdev.flatlaf.ui.FlatUIUtils; import com.formdev.flatlaf.util.SystemInfo; /** @@ -38,18 +38,27 @@ import com.formdev.flatlaf.util.SystemInfo; public class FlatWindowCloseIcon extends FlatWindowAbstractIcon { - private final Color hoverForeground = UIManager.getColor( "TitlePane.closeHoverForeground" ); - private final Color pressedForeground = UIManager.getColor( "TitlePane.closePressedForeground" ); + private final Color hoverForeground; + private final Color pressedForeground; public FlatWindowCloseIcon() { - super( UIManager.getDimension( "TitlePane.buttonSize" ), - UIManager.getColor( "TitlePane.closeHoverBackground" ), - UIManager.getColor( "TitlePane.closePressedBackground" ) ); + this( null ); + } + + /** @since 3.2 */ + public FlatWindowCloseIcon( String windowStyle ) { + super( FlatUIUtils.getSubUIDimension( "TitlePane.buttonSize", windowStyle ), + FlatUIUtils.getSubUIInt( "TitlePane.buttonSymbolHeight", windowStyle, 10 ), + FlatUIUtils.getSubUIColor( "TitlePane.closeHoverBackground", windowStyle ), + FlatUIUtils.getSubUIColor( "TitlePane.closePressedBackground", windowStyle ) ); + + hoverForeground = FlatUIUtils.getSubUIColor( "TitlePane.closeHoverForeground", windowStyle ); + pressedForeground = FlatUIUtils.getSubUIColor( "TitlePane.closePressedForeground", windowStyle ); } @Override protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { - int iwh = (int) (10 * scaleFactor); + int iwh = (int) (getSymbolHeight() * scaleFactor); int ix = x + ((width - iwh) / 2); int iy = y + ((height - iwh) / 2); int ix2 = ix + iwh - 1; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowIconifyIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowIconifyIcon.java index 54cab7d7..35d32c20 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowIconifyIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowIconifyIcon.java @@ -27,11 +27,17 @@ public class FlatWindowIconifyIcon extends FlatWindowAbstractIcon { public FlatWindowIconifyIcon() { + this( null ); + } + + /** @since 3.2 */ + public FlatWindowIconifyIcon( String windowStyle ) { + super( windowStyle ); } @Override protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { - int iw = (int) (10 * scaleFactor); + int iw = (int) (getSymbolHeight() * scaleFactor); int ih = (int) scaleFactor; int ix = x + ((width - iw) / 2); int iy = y + ((height - ih) / 2); diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowMaximizeIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowMaximizeIcon.java index 85016c18..f95f379d 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowMaximizeIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowMaximizeIcon.java @@ -29,11 +29,17 @@ public class FlatWindowMaximizeIcon extends FlatWindowAbstractIcon { public FlatWindowMaximizeIcon() { + this( null ); + } + + /** @since 3.2 */ + public FlatWindowMaximizeIcon( String windowStyle ) { + super( windowStyle ); } @Override protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { - int iwh = (int) (10 * scaleFactor); + int iwh = (int) (getSymbolHeight() * scaleFactor); int ix = x + ((width - iwh) / 2); int iy = y + ((height - iwh) / 2); float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor; diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowRestoreIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowRestoreIcon.java index c4407e90..da2e18bb 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowRestoreIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatWindowRestoreIcon.java @@ -32,18 +32,24 @@ public class FlatWindowRestoreIcon extends FlatWindowAbstractIcon { public FlatWindowRestoreIcon() { + this( null ); + } + + /** @since 3.2 */ + public FlatWindowRestoreIcon( String windowStyle ) { + super( windowStyle ); } @Override protected void paintIconAt1x( Graphics2D g, int x, int y, int width, int height, double scaleFactor ) { - int iwh = (int) (10 * scaleFactor); + int iwh = (int) (getSymbolHeight() * scaleFactor); int ix = x + ((width - iwh) / 2); int iy = y + ((height - iwh) / 2); float thickness = SystemInfo.isWindows_11_orLater ? (float) scaleFactor : (int) scaleFactor; int arc = Math.max( (int) (1.5 * scaleFactor), 2 ); int arcOuter = (int) (arc + (1.5 * scaleFactor)); - int rwh = (int) (8 * scaleFactor); + int rwh = (int) ((getSymbolHeight() - 2) * scaleFactor); int ro2 = iwh - rwh; // upper-right rectangle diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java index 2478b34e..86125101 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatRootPaneUI.java @@ -23,6 +23,7 @@ import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.IllegalComponentStateException; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.LayoutManager2; @@ -366,6 +367,11 @@ public class FlatRootPaneUI case FlatClientProperties.GLASS_PANE_FULL_HEIGHT: rootPane.revalidate(); break; + + case FlatClientProperties.WINDOW_STYLE: + if( rootPane.isDisplayable() ) + throw new IllegalComponentStateException( "The client property 'Window.style' must be set before the window becomes displayable." ); + break; } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java index a49a5835..3de0e068 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePane.java @@ -97,6 +97,7 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault TitlePane.centerTitleIfMenuBarEmbedded boolean * @uiDefault TitlePane.showIconBesideTitle boolean * @uiDefault TitlePane.menuBarTitleGap int + * @uiDefault TitlePane.menuBarTitleMinimumGap int * @uiDefault TitlePane.menuBarResizeHeight int * @uiDefault TitlePane.closeIcon Icon * @uiDefault TitlePane.iconifyIcon Icon @@ -110,29 +111,30 @@ public class FlatTitlePane { 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" ); - protected final Color activeForeground = UIManager.getColor( "TitlePane.foreground" ); - protected final Color inactiveForeground = UIManager.getColor( "TitlePane.inactiveForeground" ); - protected final Color embeddedForeground = UIManager.getColor( "TitlePane.embeddedForeground" ); - protected final Color borderColor = UIManager.getColor( "TitlePane.borderColor" ); + /** @since 2.5 */ protected final Font titleFont; + protected final Color activeBackground; + protected final Color inactiveBackground; + protected final Color activeForeground; + protected final Color inactiveForeground; + protected final Color embeddedForeground; + protected final Color borderColor; - /** @since 2 */ protected final boolean showIcon = FlatUIUtils.getUIBoolean( "TitlePane.showIcon", true ); - /** @since 2.5 */ protected final boolean showIconInDialogs = FlatUIUtils.getUIBoolean( "TitlePane.showIconInDialogs", true ); - /** @since 2 */ protected final int noIconLeftGap = FlatUIUtils.getUIInt( "TitlePane.noIconLeftGap", 8 ); - protected final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" ); - /** @since 2.4 */ protected final int titleMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.titleMinimumWidth", 60 ); - /** @since 2.4 */ protected final int buttonMinimumWidth = FlatUIUtils.getUIInt( "TitlePane.buttonMinimumWidth", 30 ); - 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 ); - /** @since 2.4 */ protected final boolean showIconBesideTitle = UIManager.getBoolean( "TitlePane.showIconBesideTitle" ); - 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 */ protected final boolean showIcon; + /** @since 2.5 */ protected final boolean showIconInDialogs; + /** @since 2 */ protected final int noIconLeftGap; + protected final Dimension iconSize; + /** @since 2.4 */ protected final int titleMinimumWidth; + /** @since 2.4 */ protected final int buttonMinimumWidth; + protected final int buttonMaximizedHeight; + protected final boolean centerTitle; + protected final boolean centerTitleIfMenuBarEmbedded; + /** @since 2.4 */ protected final boolean showIconBesideTitle; + protected final int menuBarTitleGap; + /** @since 2.4 */ protected final int menuBarTitleMinimumGap; + /** @since 2.4 */ protected final int menuBarResizeHeight; protected final JRootPane rootPane; + protected final String windowStyle; protected JPanel leftPanel; protected JLabel iconLabel; @@ -151,6 +153,34 @@ public class FlatTitlePane public FlatTitlePane( JRootPane rootPane ) { this.rootPane = rootPane; + Window w = SwingUtilities.getWindowAncestor( rootPane ); + String defaultWindowStyle = (w != null && w.getType() == Window.Type.UTILITY) ? WINDOW_STYLE_SMALL : null; + windowStyle = clientProperty( rootPane, WINDOW_STYLE, defaultWindowStyle, String.class ); + + titleFont = FlatUIUtils.getSubUIFont( "TitlePane.font", windowStyle ); + activeBackground = FlatUIUtils.getSubUIColor( "TitlePane.background", windowStyle ); + inactiveBackground = FlatUIUtils.getSubUIColor( "TitlePane.inactiveBackground", windowStyle ); + activeForeground = FlatUIUtils.getSubUIColor( "TitlePane.foreground", windowStyle ); + inactiveForeground = FlatUIUtils.getSubUIColor( "TitlePane.inactiveForeground", windowStyle ); + embeddedForeground = FlatUIUtils.getSubUIColor( "TitlePane.embeddedForeground", windowStyle ); + // not using windowStyle here because TitlePane.borderColor is also used in FlatRootPaneUI + borderColor = UIManager.getColor( "TitlePane.borderColor" ); + + showIcon = FlatUIUtils.getSubUIBoolean( "TitlePane.showIcon", windowStyle, true ); + showIconInDialogs = FlatUIUtils.getSubUIBoolean( "TitlePane.showIconInDialogs", windowStyle, true ); + noIconLeftGap = FlatUIUtils.getSubUIInt( "TitlePane.noIconLeftGap", windowStyle, 8 ); + iconSize = FlatUIUtils.getSubUIDimension( "TitlePane.iconSize", windowStyle ); + titleMinimumWidth = FlatUIUtils.getSubUIInt( "TitlePane.titleMinimumWidth", windowStyle, 60 ); + buttonMinimumWidth = FlatUIUtils.getSubUIInt( "TitlePane.buttonMinimumWidth", windowStyle, 30 ); + buttonMaximizedHeight = FlatUIUtils.getSubUIInt( "TitlePane.buttonMaximizedHeight", windowStyle, 0 ); + centerTitle = FlatUIUtils.getSubUIBoolean( "TitlePane.centerTitle", windowStyle, false ); + centerTitleIfMenuBarEmbedded = FlatUIUtils.getSubUIBoolean( "TitlePane.centerTitleIfMenuBarEmbedded", windowStyle, true ); + showIconBesideTitle = FlatUIUtils.getSubUIBoolean( "TitlePane.showIconBesideTitle", windowStyle, false ); + menuBarTitleGap = FlatUIUtils.getSubUIInt( "TitlePane.menuBarTitleGap", windowStyle, 40 ); + menuBarTitleMinimumGap = FlatUIUtils.getSubUIInt( "TitlePane.menuBarTitleMinimumGap", windowStyle, 12 ); + menuBarResizeHeight = FlatUIUtils.getSubUIInt( "TitlePane.menuBarResizeHeight", windowStyle, 4 ); + + handler = createHandler(); setBorder( createTitlePaneBorder() ); @@ -183,8 +213,8 @@ public class FlatTitlePane setUI( new FlatTitleLabelUI() ); } }; - iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) ); - titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) ); + iconLabel.setBorder( new FlatEmptyBorder( FlatUIUtils.getSubUIInsets( "TitlePane.iconMargins", windowStyle ) ) ); + titleLabel.setBorder( new FlatEmptyBorder( FlatUIUtils.getSubUIInsets( "TitlePane.titleMargins", windowStyle ) ) ); leftPanel.setLayout( new BoxLayout( leftPanel, BoxLayout.LINE_AXIS ) ); leftPanel.setOpaque( false ); @@ -311,7 +341,7 @@ public class FlatTitlePane } protected JButton createButton( String iconKey, String accessibleName, ActionListener action ) { - JButton button = new JButton( UIManager.getIcon( iconKey ) ) { + JButton button = new JButton( FlatUIUtils.getSubUIIcon( iconKey, windowStyle ) ) { @Override public Dimension getMinimumSize() { // allow the button to shrink if space is rare diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarUI.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarUI.java index ccd83c00..1eca1479 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarUI.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatToolBarUI.java @@ -39,10 +39,12 @@ import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JToolBar; import javax.swing.LayoutFocusTraversalPolicy; +import javax.swing.RootPaneContainer; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.basic.BasicToolBarUI; +import com.formdev.flatlaf.FlatClientProperties; import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable; import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI; import com.formdev.flatlaf.util.LoggingFacade; @@ -156,6 +158,13 @@ public class FlatToolBarUI } } + @Override + protected RootPaneContainer createFloatingWindow( JToolBar toolbar ) { + RootPaneContainer floatingWindow = super.createFloatingWindow( toolbar ); + floatingWindow.getRootPane().putClientProperty( FlatClientProperties.WINDOW_STYLE, FlatClientProperties.WINDOW_STYLE_SMALL ); + return floatingWindow; + } + @Override protected ContainerListener createToolBarContListener() { return new ToolBarContListener() { diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java index b50ba470..2d56d887 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatUIUtils.java @@ -46,6 +46,7 @@ import java.util.IdentityHashMap; import java.util.WeakHashMap; import java.util.function.Predicate; import java.util.function.Supplier; +import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JScrollPane; import javax.swing.JTable; @@ -166,6 +167,88 @@ public class FlatUIUtils return defaultValue; } + /** @since 3.2 */ + public static Color getSubUIColor( String key, String subKey ) { + if( subKey != null ) { + Color value = UIManager.getColor( buildSubKey( key, subKey ) ); + if( value != null ) + return value; + } + return UIManager.getColor( key ); + } + + /** @since 3.2 */ + public static boolean getSubUIBoolean( String key, String subKey, boolean defaultValue ) { + if( subKey != null ) { + Object value = UIManager.get( buildSubKey( key, subKey ) ); + if( value instanceof Boolean ) + return (Boolean) value; + } + return getUIBoolean( key, defaultValue ); + } + + /** @since 3.2 */ + public static int getSubUIInt( String key, String subKey, int defaultValue ) { + if( subKey != null ) { + Object value = UIManager.get( buildSubKey( key, subKey ) ); + if( value instanceof Integer ) + return (Integer) value; + } + return getUIInt( key, defaultValue ); + } + + /** @since 3.2 */ + public static Insets getSubUIInsets( String key, String subKey ) { + if( subKey != null ) { + Insets value = UIManager.getInsets( buildSubKey( key, subKey ) ); + if( value != null ) + return value; + } + return UIManager.getInsets( key ); + } + + /** @since 3.2 */ + public static Dimension getSubUIDimension( String key, String subKey ) { + if( subKey != null ) { + Dimension value = UIManager.getDimension( buildSubKey( key, subKey ) ); + if( value != null ) + return value; + } + return UIManager.getDimension( key ); + } + + /** @since 3.2 */ + public static Icon getSubUIIcon( String key, String subKey ) { + if( subKey != null ) { + Icon value = UIManager.getIcon( buildSubKey( key, subKey ) ); + if( value != null ) + return value; + } + return UIManager.getIcon( key ); + } + + /** @since 3.2 */ + public static Font getSubUIFont( String key, String subKey ) { + if( subKey != null ) { + Font value = UIManager.getFont( buildSubKey( key, subKey ) ); + if( value != null ) + return value; + } + return UIManager.getFont( key ); + } + + /** + * Inserts {@code subKey} at last dot in {@code key}. + *

+ * E.g. {@code buildSubKey( "TitlePane.font", "small" )} returns {@code "TitlePane.small.font"}. + */ + private static String buildSubKey( String key, String subKey ) { + int dot = key.lastIndexOf( '.' ); + return (dot >= 0) + ? key.substring( 0, dot ) + '.' + subKey + '.' + key.substring( dot + 1 ) + : key; + } + /** @since 1.1.2 */ public static boolean getBoolean( JComponent c, String systemPropertyKey, String clientPropertyKey, String uiKey, boolean defaultValue ) diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties index 358c3cec..e4a724ce 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -808,6 +808,7 @@ TitlePane.titleMinimumWidth = 60 TitlePane.buttonSize = 44,30 TitlePane.buttonMinimumWidth = 30 TitlePane.buttonMaximizedHeight = 22 +TitlePane.buttonSymbolHeight = 10 TitlePane.centerTitle = false TitlePane.centerTitleIfMenuBarEmbedded = true TitlePane.showIconBesideTitle = false @@ -829,6 +830,16 @@ TitlePane.closePressedBackground = fade($TitlePane.closeHoverBackground,90%) TitlePane.closeHoverForeground = #fff TitlePane.closePressedForeground = #fff +# window style "small" +TitlePane.small.font = -1 +TitlePane.small.showIcon = false +TitlePane.small.buttonSize = 30,20 +TitlePane.small.buttonSymbolHeight = 8 +TitlePane.small.closeIcon = com.formdev.flatlaf.icons.FlatWindowCloseIcon, small +TitlePane.small.iconifyIcon = com.formdev.flatlaf.icons.FlatWindowIconifyIcon, small +TitlePane.small.maximizeIcon = com.formdev.flatlaf.icons.FlatWindowMaximizeIcon, small +TitlePane.small.restoreIcon = com.formdev.flatlaf.icons.FlatWindowRestoreIcon, small + #---- ToggleButton ---- diff --git a/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java b/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java index 65d50ae5..3541a883 100644 --- a/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java +++ b/flatlaf-core/src/test/java/com/formdev/flatlaf/TestUIDefaultsLoader.java @@ -21,6 +21,7 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Insets; +import java.util.Objects; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.UIDefaults.ActiveValue; @@ -153,4 +154,102 @@ public class TestUIDefaultsLoader new Font( name, style, size ), ((ActiveValue)UIDefaultsLoader.parseValue( "dummyFont", actualStyle, null )).createValue( null ) ); } + + @Test + void parseInstance() { + String className = TestInstance.class.getName(); + assertEquals( new TestInstance(), ((LazyValue)UIDefaultsLoader.parseValue( "dummyIcon", className, null )).createValue( null ) ); + assertInstanceEquals( new TestInstance(), null ); + assertInstanceEquals( new TestInstance( "some string" ), "some string" ); + assertInstanceEquals( new TestInstance( false ), "false" ); + assertInstanceEquals( new TestInstance( true ), "true" ); + assertInstanceEquals( new TestInstance( 123 ), "123" ); + assertInstanceEquals( new TestInstance( 123.456f ), "123.456" ); + assertInstanceEquals( new TestInstance( Color.red ), "#f00" ); + assertInstanceEquals( new TestInstance( "some string", true ), "some string, true" ); + assertInstanceEquals( new TestInstance( "some string", true, 123 ), "some string, true, 123" ); + assertInstanceEquals( new TestInstance( "some string", 123, true ), "some string, 123, true" ); + assertInstanceEquals( new TestInstance( "some string", 123.456f, true ), "some string, 123.456, true" ); + assertInstanceEquals( new TestInstance( 123, "some string" ), "123, some string" ); + } + + private void assertInstanceEquals( TestInstance expected, String params ) { + String value = TestInstance.class.getName() + (params != null ? "," + params : ""); + assertEquals( expected, ((LazyValue)UIDefaultsLoader.parseValue( "dummyIcon", value, null )).createValue( null ) ); + } + + //---- class TestInstance ------------------------------------------------- + + public static class TestInstance + { + private String s; + private boolean b; + private int i; + private float f; + private Color color; + + public TestInstance() { + } + + public TestInstance( String s ) { + this.s = s; + } + + public TestInstance( boolean b ) { + this.b = b; + } + + public TestInstance( int i ) { + this.i = i; + } + + public TestInstance( float f ) { + this.f = f; + } + + public TestInstance( Color color ) { + this.color = color; + } + + public TestInstance( String s, boolean b ) { + this.s = s; + this.b = b; + } + + public TestInstance( String s, boolean b, int i ) { + this.s = s; + this.b = b; + this.i = i; + } + + public TestInstance( String s, int i, boolean b ) { + this.s = s; + this.b = b; + this.i = i; + } + + public TestInstance( String s, float f, boolean b ) { + this.s = s; + this.b = b; + this.f = f; + } + + protected TestInstance( int i, String s ) { + this.s = s; + this.i = i; + } + + @Override + public boolean equals( Object obj ) { + if( !(obj instanceof TestInstance) ) + return false; + + TestInstance inst = (TestInstance) obj; + return Objects.equals( s, inst.s ) && + b == inst.b && + i == inst.i && + f == inst.f && + Objects.equals( color, inst.color ); + } + } } diff --git a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt index 016a5f46..2fd045b7 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt @@ -1238,6 +1238,7 @@ TitlePane.buttonMaximizedHeight 22 TitlePane.buttonMinimumWidth 30 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.buttonSymbolHeight 10 TitlePane.centerTitle false TitlePane.centerTitleIfMenuBarEmbedded true TitlePane.closeHoverBackground #c42b1c HSL 5 75 44 javax.swing.plaf.ColorUIResource [UI] @@ -1264,6 +1265,14 @@ TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWin TitlePane.showIcon true TitlePane.showIconBesideTitle false TitlePane.showIconInDialogs true +TitlePane.small.buttonSize 30,20 javax.swing.plaf.DimensionUIResource [UI] +TitlePane.small.buttonSymbolHeight 8 +TitlePane.small.closeIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowCloseIcon [UI] +TitlePane.small.font [active] Segoe UI plain 11 javax.swing.plaf.FontUIResource [UI] +TitlePane.small.iconifyIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowIconifyIcon [UI] +TitlePane.small.maximizeIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] +TitlePane.small.restoreIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] +TitlePane.small.showIcon false TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.titleMinimumWidth 60 TitlePane.unifiedBackground true diff --git a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt index 36c6d31c..e3055c9a 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt @@ -1243,6 +1243,7 @@ TitlePane.buttonMaximizedHeight 22 TitlePane.buttonMinimumWidth 30 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.buttonSymbolHeight 10 TitlePane.centerTitle false TitlePane.centerTitleIfMenuBarEmbedded true TitlePane.closeHoverBackground #c42b1c HSL 5 75 44 javax.swing.plaf.ColorUIResource [UI] @@ -1269,6 +1270,14 @@ TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWin TitlePane.showIcon true TitlePane.showIconBesideTitle false TitlePane.showIconInDialogs true +TitlePane.small.buttonSize 30,20 javax.swing.plaf.DimensionUIResource [UI] +TitlePane.small.buttonSymbolHeight 8 +TitlePane.small.closeIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowCloseIcon [UI] +TitlePane.small.font [active] Segoe UI plain 11 javax.swing.plaf.FontUIResource [UI] +TitlePane.small.iconifyIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowIconifyIcon [UI] +TitlePane.small.maximizeIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] +TitlePane.small.restoreIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] +TitlePane.small.showIcon false TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.titleMinimumWidth 60 TitlePane.unifiedBackground true diff --git a/flatlaf-testing/dumps/uidefaults/FlatMacDarkLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatMacDarkLaf_1.8.0.txt index d82d54d8..2a75c86c 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatMacDarkLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatMacDarkLaf_1.8.0.txt @@ -1248,6 +1248,7 @@ TitlePane.buttonMaximizedHeight 22 TitlePane.buttonMinimumWidth 30 TitlePane.buttonPressedBackground #4c4c4c HSL 0 0 30 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10% autoInverse) TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] +TitlePane.buttonSymbolHeight 10 TitlePane.centerTitle false TitlePane.centerTitleIfMenuBarEmbedded true TitlePane.closeHoverBackground #c42b1c HSL 5 75 44 javax.swing.plaf.ColorUIResource [UI] @@ -1274,6 +1275,14 @@ TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWin TitlePane.showIcon true TitlePane.showIconBesideTitle false TitlePane.showIconInDialogs true +TitlePane.small.buttonSize 30,20 javax.swing.plaf.DimensionUIResource [UI] +TitlePane.small.buttonSymbolHeight 8 +TitlePane.small.closeIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowCloseIcon [UI] +TitlePane.small.font [active] Segoe UI plain 11 javax.swing.plaf.FontUIResource [UI] +TitlePane.small.iconifyIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowIconifyIcon [UI] +TitlePane.small.maximizeIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] +TitlePane.small.restoreIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] +TitlePane.small.showIcon false TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.titleMinimumWidth 60 TitlePane.unifiedBackground true diff --git a/flatlaf-testing/dumps/uidefaults/FlatMacLightLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatMacLightLaf_1.8.0.txt index b678cad6..5aa571ca 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatMacLightLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatMacLightLaf_1.8.0.txt @@ -1252,6 +1252,7 @@ TitlePane.buttonMaximizedHeight 22 TitlePane.buttonMinimumWidth 30 TitlePane.buttonPressedBackground #d8d8d8 HSL 0 0 85 com.formdev.flatlaf.util.DerivedColor [UI] darken(8% autoInverse) TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] +TitlePane.buttonSymbolHeight 10 TitlePane.centerTitle false TitlePane.centerTitleIfMenuBarEmbedded true TitlePane.closeHoverBackground #c42b1c HSL 5 75 44 javax.swing.plaf.ColorUIResource [UI] @@ -1278,6 +1279,14 @@ TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWin TitlePane.showIcon true TitlePane.showIconBesideTitle false TitlePane.showIconInDialogs true +TitlePane.small.buttonSize 30,20 javax.swing.plaf.DimensionUIResource [UI] +TitlePane.small.buttonSymbolHeight 8 +TitlePane.small.closeIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowCloseIcon [UI] +TitlePane.small.font [active] Segoe UI plain 11 javax.swing.plaf.FontUIResource [UI] +TitlePane.small.iconifyIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowIconifyIcon [UI] +TitlePane.small.maximizeIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] +TitlePane.small.restoreIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] +TitlePane.small.showIcon false TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.titleMinimumWidth 60 TitlePane.unifiedBackground true diff --git a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt index 164661ef..3a48cc9d 100644 --- a/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt +++ b/flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt @@ -1278,6 +1278,7 @@ TitlePane.borderColor #ff0000 HSL 0 100 50 javax.swing.plaf.Colo TitlePane.buttonMaximizedHeight 22 TitlePane.buttonMinimumWidth 30 TitlePane.buttonSize 44,30 javax.swing.plaf.DimensionUIResource [UI] +TitlePane.buttonSymbolHeight 10 TitlePane.centerTitle false TitlePane.centerTitleIfMenuBarEmbedded true TitlePane.closeHoverBackground #c42b1c HSL 5 75 44 javax.swing.plaf.ColorUIResource [UI] @@ -1303,6 +1304,14 @@ TitlePane.restoreIcon [lazy] 44,30 com.formdev.flatlaf.icons.FlatWin TitlePane.showIcon true TitlePane.showIconBesideTitle false TitlePane.showIconInDialogs true +TitlePane.small.buttonSize 30,20 javax.swing.plaf.DimensionUIResource [UI] +TitlePane.small.buttonSymbolHeight 8 +TitlePane.small.closeIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowCloseIcon [UI] +TitlePane.small.font [active] Segoe UI plain 11 javax.swing.plaf.FontUIResource [UI] +TitlePane.small.iconifyIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowIconifyIcon [UI] +TitlePane.small.maximizeIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowMaximizeIcon [UI] +TitlePane.small.restoreIcon [lazy] 30,20 com.formdev.flatlaf.icons.FlatWindowRestoreIcon [UI] +TitlePane.small.showIcon false TitlePane.titleMargins 3,0,3,0 javax.swing.plaf.InsetsUIResource [UI] TitlePane.titleMinimumWidth 60 TitlePane.unifiedBackground true diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java index 3b847dca..efacf6fc 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.java @@ -361,6 +361,7 @@ debug*/ private void openDialog() { Window owner = SwingUtilities.windowForComponent( this ); JDialog dialog = new JDialog( owner, "Dialog", ModalityType.DOCUMENT_MODAL ); + initWindowType( dialog ); dialog.setDefaultCloseOperation( JDialog.DISPOSE_ON_CLOSE ); dialog.add( new FlatWindowDecorationsTest() ); dialog.pack(); @@ -371,6 +372,7 @@ debug*/ private void openFrame() { FlatWindowDecorationsTest comp = new FlatWindowDecorationsTest(); JFrame frame = new JFrame( "Frame" ); + initWindowType( frame ); frame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE ); frame.add( comp ); frame.setJMenuBar( comp.menuBar ); @@ -379,6 +381,13 @@ debug*/ frame.setVisible( true ); } + private void initWindowType( Window window ) { + if( typeUtilityRadioButton.isSelected() ) + window.setType( Window.Type.UTILITY ); + else if( typeSmallRadioButton.isSelected() ) + ((RootPaneContainer)window).getRootPane().putClientProperty( "Window.style", "small" ); + } + private void decorationStyleChanged() { int style; if( styleFrameRadioButton.isSelected() ) @@ -536,6 +545,9 @@ debug*/ colorizeMenusCheckBox = new JCheckBox(); JButton openDialogButton = new JButton(); JButton openFrameButton = new JButton(); + typeNormalRadioButton = new JRadioButton(); + typeUtilityRadioButton = new JRadioButton(); + typeSmallRadioButton = new JRadioButton(); menuBar = new JMenuBar(); JMenu fileMenu = new JMenu(); JMenuItem newMenuItem = new JMenuItem(); @@ -567,7 +579,7 @@ debug*/ setLayout(new MigLayout( "ltr,insets dialog,hidemode 3", // columns - "[fill]" + + "[left]" + "[fill]" + "[fill]" + "[fill]", @@ -617,7 +629,7 @@ debug*/ maximizedBoundsCheckBox.addActionListener(e -> maximizedBoundsChanged()); panel7.add(maximizedBoundsCheckBox, "cell 0 4"); } - add(panel7, "cell 0 0"); + add(panel7, "cell 0 0,growx"); //======== panel4 ======== { @@ -818,7 +830,7 @@ debug*/ styleFileChooserRadioButton.addActionListener(e -> decorationStyleChanged()); panel1.add(styleFileChooserRadioButton, "cell 0 8"); } - add(panel1, "cell 0 1"); + add(panel1, "cell 0 1,growx"); //======== panel2 ======== { @@ -900,13 +912,26 @@ debug*/ //---- openDialogButton ---- openDialogButton.setText("Open Dialog"); openDialogButton.addActionListener(e -> openDialog()); - add(openDialogButton, "cell 0 2"); + add(openDialogButton, "cell 0 2 3 1"); //---- openFrameButton ---- openFrameButton.setText("Open Frame"); openFrameButton.setMnemonic('A'); openFrameButton.addActionListener(e -> openFrame()); - add(openFrameButton, "cell 0 2"); + add(openFrameButton, "cell 0 2 3 1"); + + //---- typeNormalRadioButton ---- + typeNormalRadioButton.setText("Normal"); + typeNormalRadioButton.setSelected(true); + add(typeNormalRadioButton, "cell 0 2 3 1"); + + //---- typeUtilityRadioButton ---- + typeUtilityRadioButton.setText("Utility"); + add(typeUtilityRadioButton, "cell 0 2 3 1"); + + //---- typeSmallRadioButton ---- + typeSmallRadioButton.setText("Small"); + add(typeSmallRadioButton, "cell 0 2 3 1"); //======== menuBar ======== { @@ -1095,6 +1120,12 @@ debug*/ iconButtonGroup.add(iconTestRandomRadioButton); iconButtonGroup.add(iconTestMRIRadioButton); iconButtonGroup.add(iconTestDynMRIRadioButton); + + //---- typeButtonGroup ---- + ButtonGroup typeButtonGroup = new ButtonGroup(); + typeButtonGroup.add(typeNormalRadioButton); + typeButtonGroup.add(typeUtilityRadioButton); + typeButtonGroup.add(typeSmallRadioButton); // JFormDesigner - End of component initialization //GEN-END:initComponents } @@ -1138,6 +1169,9 @@ debug*/ private JCheckBox colorizeTitleBarCheckBox; private JCheckBox colorizeMenuBarCheckBox; private JCheckBox colorizeMenusCheckBox; + private JRadioButton typeNormalRadioButton; + private JRadioButton typeUtilityRadioButton; + private JRadioButton typeSmallRadioButton; private JMenuBar menuBar; // JFormDesigner - End of variables declaration //GEN-END:variables } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd index acfcc68a..c7c40684 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindowDecorationsTest.jfd @@ -1,4 +1,4 @@ -JFDML JFormDesigner: "8.0.0.0.194" Java: "17.0.2" encoding: "UTF-8" +JFDML JFormDesigner: "8.1.0.0.283" Java: "19.0.2" encoding: "UTF-8" new FormModel { contentType: "form/swing" @@ -8,7 +8,7 @@ new FormModel { } add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "ltr,insets dialog,hidemode 3" - "$columnConstraints": "[fill][fill][fill][fill]" + "$columnConstraints": "[left][fill][fill][fill]" "$rowConstraints": "[fill][fill][]" } ) { name: "this" @@ -72,7 +72,7 @@ new FormModel { "value": "cell 0 4" } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 0" + "value": "cell 0 0,growx" } ) add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "ltr,hidemode 3,gap 0 0" @@ -378,7 +378,7 @@ new FormModel { "value": "cell 0 8" } ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 1" + "value": "cell 0 1,growx" } ) add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$columnConstraints": "[left]" @@ -501,7 +501,7 @@ new FormModel { "text": "Open Dialog" addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "openDialog", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 2" + "value": "cell 0 2 3 1" } ) add( new FormComponent( "javax.swing.JButton" ) { name: "openFrameButton" @@ -509,7 +509,38 @@ new FormModel { "mnemonic": 65 addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "openFrame", false ) ) }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { - "value": "cell 0 2" + "value": "cell 0 2 3 1" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "typeNormalRadioButton" + "text": "Normal" + "selected": true + "$buttonGroup": new FormReference( "typeButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2 3 1" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "typeUtilityRadioButton" + "text": "Utility" + "$buttonGroup": new FormReference( "typeButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2 3 1" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "typeSmallRadioButton" + "text": "Small" + "$buttonGroup": new FormReference( "typeButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2 3 1" } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) @@ -692,5 +723,10 @@ new FormModel { }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 615 ) } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "typeButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 669 ) + } ) } } diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt index 3071f5a1..489de222 100644 --- a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt +++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt @@ -1012,6 +1012,7 @@ TitlePane.buttonMaximizedHeight TitlePane.buttonMinimumWidth TitlePane.buttonPressedBackground TitlePane.buttonSize +TitlePane.buttonSymbolHeight TitlePane.centerTitle TitlePane.centerTitleIfMenuBarEmbedded TitlePane.closeHoverBackground @@ -1038,6 +1039,40 @@ TitlePane.restoreIcon TitlePane.showIcon TitlePane.showIconBesideTitle TitlePane.showIconInDialogs +TitlePane.small.background +TitlePane.small.buttonHoverBackground +TitlePane.small.buttonMaximizedHeight +TitlePane.small.buttonMinimumWidth +TitlePane.small.buttonPressedBackground +TitlePane.small.buttonSize +TitlePane.small.buttonSymbolHeight +TitlePane.small.centerTitle +TitlePane.small.centerTitleIfMenuBarEmbedded +TitlePane.small.closeHoverBackground +TitlePane.small.closeHoverForeground +TitlePane.small.closeIcon +TitlePane.small.closePressedBackground +TitlePane.small.closePressedForeground +TitlePane.small.embeddedForeground +TitlePane.small.font +TitlePane.small.foreground +TitlePane.small.icon +TitlePane.small.iconMargins +TitlePane.small.iconSize +TitlePane.small.iconifyIcon +TitlePane.small.inactiveBackground +TitlePane.small.inactiveForeground +TitlePane.small.maximizeIcon +TitlePane.small.menuBarResizeHeight +TitlePane.small.menuBarTitleGap +TitlePane.small.menuBarTitleMinimumGap +TitlePane.small.noIconLeftGap +TitlePane.small.restoreIcon +TitlePane.small.showIcon +TitlePane.small.showIconBesideTitle +TitlePane.small.showIconInDialogs +TitlePane.small.titleMargins +TitlePane.small.titleMinimumWidth TitlePane.titleMargins TitlePane.titleMinimumWidth TitlePane.unifiedBackground