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 ebc393cd..f2fc9fea 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/FlatClientProperties.java @@ -282,20 +282,24 @@ public interface FlatClientProperties * You're responsible to layout that panel at the top-left or top-right corner, * depending on platform, where the iconfify/maximize/close buttons are located. *

- * Syntax of the value string is: {@code "win|mac [horizontal|vertical]"}. + * Syntax of the value string is: {@code "win|mac [horizontal|vertical] [zeroInFullScreen] [leftToRight|rightToLeft]"}. *

* The string must start with {@code "win"} (for Windows or Linux) or * with {@code "mac"} (for macOS) and specifies the platform where the placeholder * should be used. On macOS, you need the placeholder in the top-left corner, - * but on Windows/Linux you need it in the top-right corner. So if fullWindowContent mode - * is supported on both platforms, you can add two placeholders to your layout + * but on Windows/Linux you need it in the top-right corner. So if your application supports + * fullWindowContent mode on both platforms, you can add two placeholders to your layout * and FlatLaf automatically uses only one of them. The other gets size {@code 0,0}. *

- * Optionally, you can append {@code " horizontal"} or {@code " vertical"} to the value string - * to specify that the placeholder preferred size should be limited to one orientation. - * E.g. {@code "win horizontal"} means that the placeholder preferred width is - * equal to iconfify/maximize/close buttons width, but preferred height is zero. - *

+ * Optionally, you can append following options to the value string (separated by space characters): + *

+ * * Example for adding placeholder to top-left corner on macOS: *
{@code
 	 * JPanel placeholder = new JPanel();
@@ -1350,41 +1354,39 @@ public interface FlatClientProperties
 	//---- macOS --------------------------------------------------------------
 
 	/**
-	 * Specifies the style of macOS window close/minimize/zoom buttons.
-	 * This does not change visual appearance but adds extra space around the buttons.
+	 * Specifies the spacing around the macOS window close/minimize/zoom buttons.
 	 * Useful if full window content
 	 * is enabled.
 	 * 

- * (requires macOS 10.14+ or 11+ for style 'large', Java 17+ and client property {@code apple.awt.fullWindowContent} set to {@code true}) + * (requires macOS 10.14+ for "medium" spacing and macOS 11+ for "large" spacing, requires Java 17+) *

* Component {@link javax.swing.JRootPane}
- * Value type {@link java.lang.String} or {@link java.lang.Boolean}
+ * Value type {@link java.lang.String}
* Allowed Values - * {@link #MACOS_WINDOW_BUTTON_STYLE_MEDIUM}, - * {@link #MACOS_WINDOW_BUTTON_STYLE_LARGE} (requires macOS 11+) or - * {@code true} (equal to 'large') + * {@link #MACOS_WINDOW_BUTTONS_SPACING_MEDIUM} or + * {@link #MACOS_WINDOW_BUTTONS_SPACING_LARGE} (requires macOS 11+) * - * @since 3.3 + * @since 3.4 */ - String MACOS_WINDOW_BUTTON_STYLE = "FlatLaf.macOS.windowButtonStyle"; + String MACOS_WINDOW_BUTTONS_SPACING = "FlatLaf.macOS.windowButtonsSpacing"; /** - * Add medium space around the macOS window close/minimize/zoom buttons. + * Add medium spacing around the macOS window close/minimize/zoom buttons. * - * @see #MACOS_WINDOW_BUTTON_STYLE - * @since 3.3 + * @see #MACOS_WINDOW_BUTTONS_SPACING + * @since 3.4 */ - String MACOS_WINDOW_BUTTON_STYLE_MEDIUM = "medium"; + String MACOS_WINDOW_BUTTONS_SPACING_MEDIUM = "medium"; /** - * Add large space around the macOS window close/minimize/zoom buttons. + * Add large spacing around the macOS window close/minimize/zoom buttons. *

- * (requires macOS 11+; 'medium' is used on older systems) + * (requires macOS 11+; "medium" is used on older systems) * - * @see #MACOS_WINDOW_BUTTON_STYLE - * @since 3.3 + * @see #MACOS_WINDOW_BUTTONS_SPACING + * @since 3.4 */ - String MACOS_WINDOW_BUTTON_STYLE_LARGE = "large"; + String MACOS_WINDOW_BUTTONS_SPACING_LARGE = "large"; //---- helper methods ----------------------------------------------------- diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java index 6a7858b2..0ef75f50 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeMacLibrary.java @@ -18,6 +18,7 @@ package com.formdev.flatlaf.ui; import java.awt.Rectangle; import java.awt.Window; +import com.formdev.flatlaf.util.SystemInfo; /** * Native methods for macOS. @@ -50,18 +51,18 @@ public class FlatNativeMacLibrary * method of this class. Otherwise, the native library may not be loaded. */ public static boolean isLoaded() { - return FlatNativeLibrary.isLoaded(); + return SystemInfo.isMacOS && FlatNativeLibrary.isLoaded(); } public native static boolean setWindowRoundedBorder( Window window, float radius, float borderWidth, int borderColor ); /** @since 3.4 */ public static final int - BUTTON_STYLE_DEFAULT = 0, - BUTTON_STYLE_MEDIUM = 1, - BUTTON_STYLE_LARGE = 2; + BUTTONS_SPACING_DEFAULT = 0, + BUTTONS_SPACING_MEDIUM = 1, + BUTTONS_SPACING_LARGE = 2; - /** @since 3.4 */ public native static boolean setWindowButtonStyle( Window window, int buttonStyle ); + /** @since 3.4 */ public native static boolean setWindowButtonsSpacing( Window window, int buttonsSpacing ); /** @since 3.4 */ public native static Rectangle getWindowButtonsBounds( Window window ); /** @since 3.4 */ public native static boolean isWindowFullScreen( Window window ); /** @since 3.4 */ public native static boolean toggleWindowFullScreen( Window window ); 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 c4bc0001..5664f8c7 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 @@ -381,35 +381,49 @@ public class FlatRootPaneUI throw new IllegalComponentStateException( "The client property 'Window.style' must be set before the window becomes displayable." ); break; - case FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE: case "ancestor": - if( SystemInfo.isMacFullWindowContentSupported && - rootPane.isDisplayable() && - FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.fullWindowContent", false ) ) - { - // set window button style - if( SystemInfo.isJava_17_orLater && FlatNativeMacLibrary.isLoaded() ) { - int buttonStyle = FlatNativeMacLibrary.BUTTON_STYLE_DEFAULT; - Object value = rootPane.getClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE ); - switch( String.valueOf( value ) ) { - case FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE_MEDIUM: - buttonStyle = FlatNativeMacLibrary.BUTTON_STYLE_MEDIUM; - break; + // FlatNativeMacLibrary.setWindowButtonsSpacing() and + // FullWindowContentSupport.macUpdateFullWindowContentButtonsBoundsProperty() + // require a native window, but setting the client properties + // "apple.awt.fullWindowContent" or FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING + // is usually done before the native window is created + // --> try again when native window is created + if( !SystemInfo.isMacOS || e.getNewValue() == null ) + break; - case "true": - case FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE_LARGE: - buttonStyle = FlatNativeMacLibrary.BUTTON_STYLE_LARGE; - break; + // fall through + + case FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING: + if( SystemInfo.isMacOS ) { + // set window buttons spacing + if( SystemInfo.isJava_17_orLater && rootPane.isDisplayable() && FlatNativeMacLibrary.isLoaded() ) { + int buttonsSpacing = FlatNativeMacLibrary.BUTTONS_SPACING_DEFAULT; + String value = (String) rootPane.getClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING ); + if( value != null ) { + switch( value ) { + case FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_MEDIUM: + buttonsSpacing = FlatNativeMacLibrary.BUTTONS_SPACING_MEDIUM; + break; + + case FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_LARGE: + buttonsSpacing = FlatNativeMacLibrary.BUTTONS_SPACING_LARGE; + break; + } } Window window = SwingUtilities.windowForComponent( rootPane ); - FlatNativeMacLibrary.setWindowButtonStyle( window, buttonStyle ); + FlatNativeMacLibrary.setWindowButtonsSpacing( window, buttonsSpacing ); } // update buttons bounds client property FullWindowContentSupport.macUpdateFullWindowContentButtonsBoundsProperty( rootPane ); } break; + + case "apple.awt.fullWindowContent": + if( SystemInfo.isMacOS ) + FullWindowContentSupport.macUpdateFullWindowContentButtonsBoundsProperty( rootPane ); + break; } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FullWindowContentSupport.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FullWindowContentSupport.java index 65bfe8b9..5665ce5c 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FullWindowContentSupport.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FullWindowContentSupport.java @@ -48,32 +48,41 @@ class FullWindowContentSupport JRootPane rootPane; Rectangle bounds; - if( options.startsWith( SystemInfo.isMacOS ? "mac" : "win" ) && - c.isDisplayable() && - (rootPane = SwingUtilities.getRootPane( c )) != null && - (bounds = (Rectangle) rootPane.getClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS )) != null ) - { - // On macOS, the client property is updated very late when toggling full screen, - // which results in "jumping" layout after full screen toggle finished. - // To avoid that, get up-to-date buttons bounds from macOS. - if( SystemInfo.isMacFullWindowContentSupported && FlatNativeMacLibrary.isLoaded() ) { - Rectangle r = FlatNativeMacLibrary.getWindowButtonsBounds( SwingUtilities.windowForComponent( c ) ); - if( r != null ) - bounds = r; - } + if( !options.startsWith( SystemInfo.isMacOS ? "mac" : "win" ) || + !c.isDisplayable() || + (rootPane = SwingUtilities.getRootPane( c )) == null || + (bounds = (Rectangle) rootPane.getClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS )) == null ) + return new Dimension( 0, 0 ); - if( options.length() > 3 ) { - if( options.contains( "horizontal" ) ) - return new Dimension( bounds.width, 0 ); - if( options.contains( "vertical" ) ) - return new Dimension( 0, bounds.height ); - } - - return bounds.getSize(); + if( options.length() > 3 ) { + if( (options.contains( "leftToRight" ) && !c.getComponentOrientation().isLeftToRight()) || + (options.contains( "rightToLeft" ) && c.getComponentOrientation().isLeftToRight()) ) + return new Dimension( 0, 0 ); } - // default to 0,0 - return new Dimension(); + // On macOS, the client property is updated very late when toggling full screen, + // which results in "jumping" layout after full screen toggle finished. + // To avoid that, get up-to-date buttons bounds from macOS. + if( SystemInfo.isMacFullWindowContentSupported && FlatNativeMacLibrary.isLoaded() ) { + Rectangle r = FlatNativeMacLibrary.getWindowButtonsBounds( SwingUtilities.windowForComponent( c ) ); + if( r != null ) + bounds = r; + } + + int width = bounds.width; + int height = bounds.height; + + if( options.length() > 3 ) { + if( width == 0 && options.contains( "zeroInFullScreen" ) ) + height = 0; + + if( options.contains( "horizontal" ) ) + height = 0; + if( options.contains( "vertical" ) ) + width = 0; + } + + return new Dimension( width, height ); } static void registerPlaceholder( JComponent c ) { @@ -151,14 +160,15 @@ class FullWindowContentSupport } static void macUpdateFullWindowContentButtonsBoundsProperty( JRootPane rootPane ) { - if( !SystemInfo.isMacFullWindowContentSupported || - !rootPane.isDisplayable() || - !FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.fullWindowContent", false ) ) - return; + if( !SystemInfo.isMacFullWindowContentSupported || !rootPane.isDisplayable() ) + return; - Rectangle bounds = FlatNativeMacLibrary.isLoaded() - ? FlatNativeMacLibrary.getWindowButtonsBounds( SwingUtilities.windowForComponent( rootPane ) ) - : new Rectangle( 68, 28 ); // default size + Rectangle bounds = null; + if( FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.fullWindowContent", false ) ) { + bounds = FlatNativeMacLibrary.isLoaded() + ? FlatNativeMacLibrary.getWindowButtonsBounds( SwingUtilities.windowForComponent( rootPane ) ) + : new Rectangle( 68, 28 ); // default size + } rootPane.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS, bounds ); } @@ -166,18 +176,35 @@ class FullWindowContentSupport if( !UIManager.getBoolean( KEY_DEBUG_SHOW_PLACEHOLDERS ) ) return; - int width = c.getWidth() - 1; - int height = c.getHeight() - 1; + int width = c.getWidth(); + int height = c.getHeight(); if( width <= 0 || height <= 0 ) return; + // draw red figure g.setColor( Color.red ); - g.drawRect( 0, 0, width, height ); + debugPaintRect( g, new Rectangle( width, height ) ); + + // draw magenta figure if buttons bounds are not equal to placeholder bounds + JRootPane rootPane; + Rectangle bounds; + if( (rootPane = SwingUtilities.getRootPane( c )) != null && + (bounds = (Rectangle) rootPane.getClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS )) != null && + (bounds.width != width || bounds.height != height) ) + { + g.setColor( Color.magenta ); + debugPaintRect( g, SwingUtilities.convertRectangle( rootPane, bounds, c ) ); + } + } + + private static void debugPaintRect( Graphics g, Rectangle r ) { + // draw rectangle + g.drawRect( r.x, r.y, r.width - 1, r.height - 1 ); // draw diagonal cross Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g ); - g.drawLine( 0, 0, width, height ); - g.drawLine( 0, height, width, 0 ); + g.drawLine( r.x, r.y, r.width - 1, r.height - 1 ); + g.drawLine( r.x, r.height - 1, r.width - 1, r.y ); FlatUIUtils.resetRenderingHints( g, oldRenderingHints ); } } diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-arm64.dylib b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-arm64.dylib index 34d85495..cf1677cb 100755 Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-arm64.dylib and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-arm64.dylib differ diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-x86_64.dylib b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-x86_64.dylib index 25d9db4f..77cf3e03 100755 Binary files a/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-x86_64.dylib and b/flatlaf-core/src/main/resources/com/formdev/flatlaf/natives/libflatlaf-macos-x86_64.dylib differ diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java index c982a2de..8f701a66 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java @@ -95,7 +95,7 @@ class DemoFrame // expand window content into window title bar and make title bar transparent rootPane.putClientProperty( "apple.awt.fullWindowContent", true ); rootPane.putClientProperty( "apple.awt.transparentTitleBar", true ); - rootPane.putClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE, true ); + rootPane.putClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING, FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_LARGE ); // hide window title if( SystemInfo.isJava_17_orLater ) @@ -922,13 +922,13 @@ class DemoFrame //TODO remove backButton.addActionListener( e -> { - rootPane.putClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE, FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE_LARGE ); + rootPane.putClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING, FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_LARGE ); }); forwardButton.addActionListener( e -> { - rootPane.putClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE, FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE_MEDIUM ); + rootPane.putClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING, FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_MEDIUM ); }); cutButton.addActionListener( e -> { - rootPane.putClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTON_STYLE, null ); + rootPane.putClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING, null ); }); copyButton.addActionListener( e -> System.out.println( e ) ); @@ -1025,7 +1025,7 @@ class DemoFrame animatedLafChangeMenuItem.setSelected( false ); // on macOS, panel left to toolBar is a placeholder for title bar buttons in fullWindowContent mode - macFullWindowContentButtonsPlaceholder.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER, "mac" ); + macFullWindowContentButtonsPlaceholder.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER, "mac zeroInFullScreen" ); // remove contentPanel bottom insets MigLayout layout = (MigLayout) contentPanel.getLayout(); diff --git a/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h b/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h index 0e39445c..f99549e5 100644 --- a/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h +++ b/flatlaf-natives/flatlaf-natives-macos/src/main/headers/com_formdev_flatlaf_ui_FlatNativeMacLibrary.h @@ -7,12 +7,12 @@ #ifdef __cplusplus extern "C" { #endif -#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTON_STYLE_DEFAULT -#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTON_STYLE_DEFAULT 0L -#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTON_STYLE_MEDIUM -#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTON_STYLE_MEDIUM 1L -#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTON_STYLE_LARGE -#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTON_STYLE_LARGE 2L +#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_DEFAULT +#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_DEFAULT 0L +#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_MEDIUM +#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_MEDIUM 1L +#undef com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_LARGE +#define com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_LARGE 2L /* * Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary * Method: setWindowRoundedBorder @@ -23,10 +23,10 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW /* * Class: com_formdev_flatlaf_ui_FlatNativeMacLibrary - * Method: setWindowButtonStyle + * Method: setWindowButtonsSpacing * Signature: (Ljava/awt/Window;I)Z */ -JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowButtonStyle +JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowButtonsSpacing (JNIEnv *, jclass, jobject, jint); /* diff --git a/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacWindow.mm b/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacWindow.mm index 2edd4cc6..919c4ec8 100644 --- a/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacWindow.mm +++ b/flatlaf-natives/flatlaf-natives-macos/src/main/objcpp/MacWindow.mm @@ -32,6 +32,7 @@ // full screen observers @property (nonatomic) id willEnterFullScreenObserver; + @property (nonatomic) id willExitFullScreenObserver; @property (nonatomic) id didExitFullScreenObserver; @end @@ -41,6 +42,7 @@ // declare internal methods NSWindow* getNSWindow( JNIEnv* env, jclass cls, jobject window ); WindowData* getWindowData( NSWindow* nsWindow, bool allocate ); +void setWindowButtonsHidden( NSWindow* nsWindow, bool hidden ); int getWindowButtonAreaWidth( NSWindow* nsWindow ); int getWindowTitleBarHeight( NSWindow* nsWindow ); bool isWindowFullScreen( NSWindow* nsWindow ); @@ -121,8 +123,8 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW } extern "C" -JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowButtonStyle - ( JNIEnv* env, jclass cls, jobject window, jint buttonStyle ) +JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setWindowButtonsSpacing + ( JNIEnv* env, jclass cls, jobject window, jint buttonsSpacing ) { JNI_COCOA_ENTER() @@ -130,20 +132,20 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW if( nsWindow == NULL ) return FALSE; - #define STYLE_DEFAULT com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTON_STYLE_DEFAULT - #define STYLE_MEDIUM com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTON_STYLE_MEDIUM - #define STYLE_LARGE com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTON_STYLE_LARGE + #define SPACING_DEFAULT com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_DEFAULT + #define SPACING_MEDIUM com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_MEDIUM + #define SPACING_LARGE com_formdev_flatlaf_ui_FlatNativeMacLibrary_BUTTONS_SPACING_LARGE bool isMacOS_11_orLater = @available( macOS 11, * ); - if( !isMacOS_11_orLater && buttonStyle == STYLE_LARGE ) - buttonStyle = STYLE_MEDIUM; - int oldButtonStyle = (nsWindow.toolbar != NULL) + if( !isMacOS_11_orLater && buttonsSpacing == SPACING_LARGE ) + buttonsSpacing = SPACING_MEDIUM; + int oldButtonsSpacing = (nsWindow.toolbar != NULL) ? ((isMacOS_11_orLater && nsWindow.toolbarStyle == NSWindowToolbarStyleUnified) - ? STYLE_LARGE - : STYLE_MEDIUM) - : STYLE_DEFAULT; + ? SPACING_LARGE + : SPACING_MEDIUM) + : SPACING_DEFAULT; - if( buttonStyle == oldButtonStyle ) + if( buttonsSpacing == oldButtonsSpacing ) return TRUE; WindowData* windowData = getWindowData( nsWindow, true ); @@ -153,8 +155,8 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW // add/remove toolbar NSToolbar* toolbar = NULL; - bool hasToolbar = (buttonStyle != STYLE_DEFAULT); - if( hasToolbar ) { + bool needsToolbar = (buttonsSpacing != SPACING_DEFAULT); + if( needsToolbar ) { toolbar = [NSToolbar new]; toolbar.showsBaselineSeparator = NO; // necessary for older macOS versions if( isWindowFullScreen( nsWindow ) ) @@ -163,9 +165,9 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW nsWindow.toolbar = toolbar; if( isMacOS_11_orLater ) { - nsWindow.toolbarStyle = (buttonStyle == STYLE_LARGE) + nsWindow.toolbarStyle = (buttonsSpacing == SPACING_LARGE) ? NSWindowToolbarStyleUnified - : (buttonStyle == STYLE_MEDIUM) + : (buttonsSpacing == SPACING_MEDIUM) ? NSWindowToolbarStyleUnifiedCompact : NSWindowToolbarStyleAutomatic; } @@ -178,7 +180,7 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW // when window becomes full screen, it is necessary to hide the toolbar // because it otherwise is shown non-transparent and hides Swing components NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; - if( hasToolbar ) { + if( needsToolbar && windowData.willEnterFullScreenObserver == NULL ) { // NSLog( @"add observers %@", nsWindow ); windowData.willEnterFullScreenObserver = [center addObserverForName:NSWindowWillEnterFullScreenNotification object:nsWindow queue:nil usingBlock:^(NSNotification *note) { @@ -188,26 +190,40 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW // remembar title bar height so that "main" JToolBar keeps its height in full screen windowData.lastWindowButtonAreaWidth = getWindowButtonAreaWidth( nsWindow ); windowData.lastWindowTitleBarHeight = getWindowTitleBarHeight( nsWindow ); -// NSLog(@"%d %d",windowData.lastWindowButtonAreaWidth,windowData.lastWindowTitleBarHeight); +// NSLog( @"%d %d", windowData.lastWindowButtonAreaWidth, windowData.lastWindowTitleBarHeight ); nsWindow.toolbar.visible = NO; } }]; + + windowData.willExitFullScreenObserver = [center addObserverForName:NSWindowWillExitFullScreenNotification + object:nsWindow queue:nil usingBlock:^(NSNotification *note) { +// NSLog( @"will exit full screen %@", nsWindow ); + if( nsWindow.toolbar != NULL ) + setWindowButtonsHidden( nsWindow, true ); + }]; + windowData.didExitFullScreenObserver = [center addObserverForName:NSWindowDidExitFullScreenNotification object:nsWindow queue:nil usingBlock:^(NSNotification *note) { // NSLog( @"exit full screen %@", nsWindow ); - if( nsWindow.toolbar != NULL ) + if( nsWindow.toolbar != NULL ) { + setWindowButtonsHidden( nsWindow, false ); nsWindow.toolbar.visible = YES; + } windowData.lastWindowButtonAreaWidth = 0; windowData.lastWindowTitleBarHeight = 0; }]; - } else { + } else if( !needsToolbar ) { // NSLog( @"remove observers %@", nsWindow ); if( windowData.willEnterFullScreenObserver != NULL ) { [center removeObserver:windowData.willEnterFullScreenObserver]; windowData.willEnterFullScreenObserver = nil; } + if( windowData.willExitFullScreenObserver != NULL ) { + [center removeObserver:windowData.willExitFullScreenObserver]; + windowData.willExitFullScreenObserver = nil; + } if( windowData.didExitFullScreenObserver != NULL ) { [center removeObserver:windowData.didExitFullScreenObserver]; windowData.didExitFullScreenObserver = nil; @@ -221,6 +237,21 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_setW return FALSE; } +void setWindowButtonsHidden( NSWindow* nsWindow, bool hidden ) { + // get buttons + NSView* buttons[3] = { + [nsWindow standardWindowButton:NSWindowCloseButton], + [nsWindow standardWindowButton:NSWindowMiniaturizeButton], + [nsWindow standardWindowButton:NSWindowZoomButton] + }; + + for( int i = 0; i < 3; i++ ) { + NSView* button = buttons[i]; + if( button != NULL ) + button.hidden = hidden; + } +} + extern "C" JNIEXPORT jobject JNICALL Java_com_formdev_flatlaf_ui_FlatNativeMacLibrary_getWindowButtonsBounds ( JNIEnv* env, jclass cls, jobject window ) diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMacOSTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMacOSTest.java new file mode 100644 index 00000000..226392d0 --- /dev/null +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMacOSTest.java @@ -0,0 +1,283 @@ +/* + * Copyright 2024 FormDev Software GmbH + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.formdev.flatlaf.testing; + +import java.awt.*; +import javax.swing.*; +import com.formdev.flatlaf.FlatClientProperties; +import com.formdev.flatlaf.ui.FlatNativeMacLibrary; +import com.formdev.flatlaf.util.SystemInfo; +import net.miginfocom.swing.*; + +/** + * @author Karl Tauber + */ +public class FlatMacOSTest + extends FlatTestPanel +{ + public static void main( String[] args ) { + SwingUtilities.invokeLater( () -> { + FlatTestFrame frame = FlatTestFrame.create( args, FlatMacOSTest.class.getSimpleName() ); + frame.applyComponentOrientationToFrame = true; + + JRootPane rootPane = frame.getRootPane(); + rootPane.putClientProperty( "apple.awt.fullWindowContent", true ); + rootPane.putClientProperty( "apple.awt.transparentTitleBar", true ); + rootPane.putClientProperty( "apple.awt.windowTitleVisible", false ); + + frame.showFrame( FlatMacOSTest::new ); + } ); + } + + FlatMacOSTest() { + initComponents(); + + if( SystemInfo.isMacFullWindowContentSupported ) { + fullWindowContentHint.setVisible( false ); + transparentTitleBarHint.setVisible( false ); + } + if( SystemInfo.isJava_17_orLater ) { + windowTitleVisibleHint.setVisible( false ); + buttonsSpacingHint.setVisible( false ); + } + + placeholderPanel.putClientProperty( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_PLACEHOLDER, "mac zeroInFullScreen" ); + UIManager.put( "FlatLaf.debug.panel.showPlaceholders", true ); + } + + @Override + public void addNotify() { + super.addNotify(); + + JRootPane rootPane = getRootPane(); + fullWindowContentCheckBox.setSelected( FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.fullWindowContent", false ) ); + transparentTitleBarCheckBox.setSelected( FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.transparentTitleBar", false ) ); + windowTitleVisibleCheckBox.setSelected( FlatClientProperties.clientPropertyBoolean( rootPane, "apple.awt.windowTitleVisible", true ) ); + + rootPane.addPropertyChangeListener( FlatClientProperties.FULL_WINDOW_CONTENT_BUTTONS_BOUNDS, e -> { + Rectangle bounds = (Rectangle) e.getNewValue(); + fullWindowContentButtonsBoundsField.setText( bounds2string( bounds ) ); + } ); + updateNativeButtonBounds(); + } + + private void fullWindowContentChanged() { + getRootPane().putClientProperty( "apple.awt.fullWindowContent", fullWindowContentCheckBox.isSelected() ); + } + + private void transparentTitleBarChanged() { + getRootPane().putClientProperty( "apple.awt.transparentTitleBar", transparentTitleBarCheckBox.isSelected() ); + } + + private void windowTitleVisibleChanged() { + getRootPane().putClientProperty( "apple.awt.windowTitleVisible", windowTitleVisibleCheckBox.isSelected() ); + } + + private void buttonsSpacingChanged() { + String buttonsSpacing = null; + if( buttonsSpacingMediumRadioButton.isSelected() ) + buttonsSpacing = FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_MEDIUM; + else if( buttonsSpacingLargeRadioButton.isSelected() ) + buttonsSpacing = FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING_LARGE; + + getRootPane().putClientProperty( FlatClientProperties.MACOS_WINDOW_BUTTONS_SPACING, buttonsSpacing ); + + updateNativeButtonBounds(); + } + + private void updateNativeButtonBounds() { + if( !FlatNativeMacLibrary.isLoaded() ) + return; + + Window window = SwingUtilities.windowForComponent( this ); + Rectangle bounds = FlatNativeMacLibrary.getWindowButtonsBounds( window ); + nativeButtonsBoundsField.setText( bounds2string( bounds ) ); + } + + private String bounds2string( Rectangle bounds ) { + return (bounds != null) + ? bounds.width + ", " + bounds.height + " @ " + bounds.x + ", " + bounds.y + : "null"; + } + + private void toggleFullScreen() { + if( !FlatNativeMacLibrary.isLoaded() ) + return; + + Window window = SwingUtilities.windowForComponent( this ); + FlatNativeMacLibrary.toggleWindowFullScreen( window ); + } + + private void initComponents() { + // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents + JPanel panel1 = new JPanel(); + placeholderPanel = new JPanel(); + JPanel panel2 = new JPanel(); + fullWindowContentCheckBox = new JCheckBox(); + fullWindowContentHint = new JLabel(); + transparentTitleBarCheckBox = new JCheckBox(); + transparentTitleBarHint = new JLabel(); + windowTitleVisibleCheckBox = new JCheckBox(); + windowTitleVisibleHint = new JLabel(); + JLabel buttonsSpacingLabel = new JLabel(); + buttonsSpacingDefaultRadioButton = new JRadioButton(); + buttonsSpacingMediumRadioButton = new JRadioButton(); + buttonsSpacingLargeRadioButton = new JRadioButton(); + buttonsSpacingHint = new JLabel(); + JLabel fullWindowContentButtonsBoundsLabel = new JLabel(); + fullWindowContentButtonsBoundsField = new JLabel(); + JLabel nativeButtonsBoundsLabel = new JLabel(); + nativeButtonsBoundsField = new JLabel(); + JButton toggleFullScreenButton = new JButton(); + + //======== this ======== + setLayout(new BorderLayout()); + + //======== panel1 ======== + { + panel1.setLayout(new BorderLayout()); + + //======== placeholderPanel ======== + { + placeholderPanel.setBackground(Color.green); + placeholderPanel.setLayout(new FlowLayout()); + } + panel1.add(placeholderPanel, BorderLayout.WEST); + } + add(panel1, BorderLayout.PAGE_START); + + //======== panel2 ======== + { + panel2.setLayout(new MigLayout( + "ltr,insets dialog,hidemode 3", + // columns + "[left]" + + "[left]" + + "[left]" + + "[left]para" + + "[fill]", + // rows + "[]" + + "[]" + + "[]" + + "[fill]" + + "[]" + + "[]para" + + "[]")); + + //---- fullWindowContentCheckBox ---- + fullWindowContentCheckBox.setText("fullWindowContent"); + fullWindowContentCheckBox.addActionListener(e -> fullWindowContentChanged()); + panel2.add(fullWindowContentCheckBox, "cell 0 0"); + + //---- fullWindowContentHint ---- + fullWindowContentHint.setText("requires Java 12, 11.0.8 or 8u292"); + fullWindowContentHint.setForeground(Color.red); + panel2.add(fullWindowContentHint, "cell 4 0"); + + //---- transparentTitleBarCheckBox ---- + transparentTitleBarCheckBox.setText("transparentTitleBar"); + transparentTitleBarCheckBox.addActionListener(e -> transparentTitleBarChanged()); + panel2.add(transparentTitleBarCheckBox, "cell 0 1"); + + //---- transparentTitleBarHint ---- + transparentTitleBarHint.setText("requires Java 12, 11.0.8 or 8u292"); + transparentTitleBarHint.setForeground(Color.red); + panel2.add(transparentTitleBarHint, "cell 4 1"); + + //---- windowTitleVisibleCheckBox ---- + windowTitleVisibleCheckBox.setText("windowTitleVisible"); + windowTitleVisibleCheckBox.addActionListener(e -> windowTitleVisibleChanged()); + panel2.add(windowTitleVisibleCheckBox, "cell 0 2"); + + //---- windowTitleVisibleHint ---- + windowTitleVisibleHint.setText("requires Java 17"); + windowTitleVisibleHint.setForeground(Color.red); + panel2.add(windowTitleVisibleHint, "cell 4 2"); + + //---- buttonsSpacingLabel ---- + buttonsSpacingLabel.setText("Buttons spacing:"); + panel2.add(buttonsSpacingLabel, "cell 0 3"); + + //---- buttonsSpacingDefaultRadioButton ---- + buttonsSpacingDefaultRadioButton.setText("Default"); + buttonsSpacingDefaultRadioButton.setSelected(true); + buttonsSpacingDefaultRadioButton.addActionListener(e -> buttonsSpacingChanged()); + panel2.add(buttonsSpacingDefaultRadioButton, "cell 1 3"); + + //---- buttonsSpacingMediumRadioButton ---- + buttonsSpacingMediumRadioButton.setText("Medium"); + buttonsSpacingMediumRadioButton.addActionListener(e -> buttonsSpacingChanged()); + panel2.add(buttonsSpacingMediumRadioButton, "cell 2 3"); + + //---- buttonsSpacingLargeRadioButton ---- + buttonsSpacingLargeRadioButton.setText("Large"); + buttonsSpacingLargeRadioButton.addActionListener(e -> buttonsSpacingChanged()); + panel2.add(buttonsSpacingLargeRadioButton, "cell 3 3"); + + //---- buttonsSpacingHint ---- + buttonsSpacingHint.setText("requires Java 17"); + buttonsSpacingHint.setForeground(Color.red); + panel2.add(buttonsSpacingHint, "cell 4 3"); + + //---- fullWindowContentButtonsBoundsLabel ---- + fullWindowContentButtonsBoundsLabel.setText("Buttons bounds:"); + panel2.add(fullWindowContentButtonsBoundsLabel, "cell 0 4"); + + //---- fullWindowContentButtonsBoundsField ---- + fullWindowContentButtonsBoundsField.setText("null"); + panel2.add(fullWindowContentButtonsBoundsField, "cell 1 4 3 1"); + + //---- nativeButtonsBoundsLabel ---- + nativeButtonsBoundsLabel.setText("Native buttons bounds:"); + panel2.add(nativeButtonsBoundsLabel, "cell 0 5"); + + //---- nativeButtonsBoundsField ---- + nativeButtonsBoundsField.setText("null"); + panel2.add(nativeButtonsBoundsField, "cell 1 5 3 1"); + + //---- toggleFullScreenButton ---- + toggleFullScreenButton.setText("Toggle Full Screen"); + toggleFullScreenButton.addActionListener(e -> toggleFullScreen()); + panel2.add(toggleFullScreenButton, "cell 0 6"); + } + add(panel2, BorderLayout.CENTER); + + //---- buttonsSpacingButtonGroup ---- + ButtonGroup buttonsSpacingButtonGroup = new ButtonGroup(); + buttonsSpacingButtonGroup.add(buttonsSpacingDefaultRadioButton); + buttonsSpacingButtonGroup.add(buttonsSpacingMediumRadioButton); + buttonsSpacingButtonGroup.add(buttonsSpacingLargeRadioButton); + // JFormDesigner - End of component initialization //GEN-END:initComponents + } + + // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables + private JPanel placeholderPanel; + private JCheckBox fullWindowContentCheckBox; + private JLabel fullWindowContentHint; + private JCheckBox transparentTitleBarCheckBox; + private JLabel transparentTitleBarHint; + private JCheckBox windowTitleVisibleCheckBox; + private JLabel windowTitleVisibleHint; + private JRadioButton buttonsSpacingDefaultRadioButton; + private JRadioButton buttonsSpacingMediumRadioButton; + private JRadioButton buttonsSpacingLargeRadioButton; + private JLabel buttonsSpacingHint; + private JLabel fullWindowContentButtonsBoundsField; + private JLabel nativeButtonsBoundsField; + // JFormDesigner - End of variables declaration //GEN-END:variables +} diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMacOSTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMacOSTest.jfd new file mode 100644 index 00000000..f580097b --- /dev/null +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMacOSTest.jfd @@ -0,0 +1,191 @@ +JFDML JFormDesigner: "8.2.1.0.348" Java: "21.0.1" encoding: "UTF-8" + +new FormModel { + contentType: "form/swing" + root: new FormRoot { + auxiliary() { + "JavaCodeGenerator.defaultVariableLocal": true + } + add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) { + name: "this" + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.BorderLayout ) ) { + name: "panel1" + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class java.awt.FlowLayout ) ) { + name: "placeholderPanel" + "background": sfield java.awt.Color green + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class java.lang.String ) { + "value": "West" + } ) + }, new FormLayoutConstraints( class java.lang.String ) { + "value": "First" + } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$layoutConstraints": "ltr,insets dialog,hidemode 3" + "$columnConstraints": "[left][left][left][left]para[fill]" + "$rowConstraints": "[][][][fill][][]para[]" + } ) { + name: "panel2" + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "fullWindowContentCheckBox" + "text": "fullWindowContent" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "fullWindowContentChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "fullWindowContentHint" + "text": "requires Java 12, 11.0.8 or 8u292" + "foreground": sfield java.awt.Color red + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 4 0" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "transparentTitleBarCheckBox" + "text": "transparentTitleBar" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "transparentTitleBarChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "transparentTitleBarHint" + "text": "requires Java 12, 11.0.8 or 8u292" + "foreground": sfield java.awt.Color red + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 4 1" + } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "windowTitleVisibleCheckBox" + "text": "windowTitleVisible" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "windowTitleVisibleChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "windowTitleVisibleHint" + "text": "requires Java 17" + "foreground": sfield java.awt.Color red + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 4 2" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "buttonsSpacingLabel" + "text": "Buttons spacing:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 3" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "buttonsSpacingDefaultRadioButton" + "text": "Default" + "$buttonGroup": new FormReference( "buttonsSpacingButtonGroup" ) + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "buttonsSpacingChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 3" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "buttonsSpacingMediumRadioButton" + "text": "Medium" + "$buttonGroup": new FormReference( "buttonsSpacingButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "buttonsSpacingChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 3" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "buttonsSpacingLargeRadioButton" + "text": "Large" + "$buttonGroup": new FormReference( "buttonsSpacingButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "buttonsSpacingChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 3 3" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "buttonsSpacingHint" + "text": "requires Java 17" + "foreground": sfield java.awt.Color red + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 4 3" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "fullWindowContentButtonsBoundsLabel" + "text": "Buttons bounds:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "fullWindowContentButtonsBoundsField" + "text": "null" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 4 3 1" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "nativeButtonsBoundsLabel" + "text": "Native buttons bounds:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 5" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "nativeButtonsBoundsField" + "text": "null" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 5 3 1" + } ) + add( new FormComponent( "javax.swing.JButton" ) { + name: "toggleFullScreenButton" + "text": "Toggle Full Screen" + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "toggleFullScreen", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 6" + } ) + }, new FormLayoutConstraints( class java.lang.String ) { + "value": "Center" + } ) + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 0 ) + "size": new java.awt.Dimension( 725, 350 ) + } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "buttonsSpacingButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 360 ) + } ) + } +}