From 7f6f366744331df4ca144a47a922472450a8a9ae Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Thu, 7 Dec 2023 18:53:45 +0100 Subject: [PATCH] flatlaf-natives-windows: support DWM attributes DWMWA_USE_IMMERSIVE_DARK_MODE, DWMWA_CAPTION_COLOR and DWMWA_TEXT_COLOR (all unused in FlatLaf core) --- .../flatlaf/ui/FlatNativeWindowsLibrary.java | 66 +++- .../formdev/flatlaf/ui/FlatPopupFactory.java | 15 +- .../src/main/cpp/WinWrapper.cpp | 48 +-- ...mdev_flatlaf_ui_FlatNativeWindowsLibrary.h | 28 +- .../flatlaf/testing/FlatWindows11DwmTest.java | 336 ++++++++++++++++++ .../flatlaf/testing/FlatWindows11DwmTest.jfd | 278 +++++++++++++++ 6 files changed, 715 insertions(+), 56 deletions(-) create mode 100644 flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindows11DwmTest.java create mode 100644 flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindows11DwmTest.jfd diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java index 17ffa839..669271e6 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatNativeWindowsLibrary.java @@ -16,6 +16,7 @@ package com.formdev.flatlaf.ui; +import java.awt.Color; import java.awt.Window; import com.formdev.flatlaf.util.SystemInfo; @@ -31,6 +32,12 @@ public class FlatNativeWindowsLibrary { private static long osBuildNumber = Long.MIN_VALUE; + /** + * Checks whether native library is loaded/available. + *

+ * Note: It is required to invoke this method before invoking any other + * method of this class. Otherwise, the native library may not be loaded. + */ public static boolean isLoaded() { return SystemInfo.isWindows && FlatNativeLibrary.isLoaded(); } @@ -93,15 +100,60 @@ public class FlatNativeWindowsLibrary public native static boolean setWindowCornerPreference( long hwnd, int cornerPreference ); /** - * Sets the color of the window border. - * The red/green/blue values must be in range {@code 0 - 255}. - * If red is {@code -1}, then the system default border color is used (useful to reset the border color). - * If red is {@code -2}, then no border is painted. - *

- * Invokes Win32 API method {@code DwmSetWindowAttribute(DWMWA_BORDER_COLOR)}. + * DWMWINDOWATTRIBUTE + * see https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute + * + * @since 3.3 + */ + public static final int + DWMWA_USE_IMMERSIVE_DARK_MODE = 20, + DWMWA_BORDER_COLOR = 34, + DWMWA_CAPTION_COLOR = 35, + DWMWA_TEXT_COLOR = 36; + + /** + * Invokes Win32 API method {@code DwmSetWindowAttribute()} with a {@code BOOL} attribute value. + * See https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute + * + * @since 3.3 + */ + public native static boolean dwmSetWindowAttributeBOOL( long hwnd, int attribute, boolean value ); + + /** + * Invokes Win32 API method {@code DwmSetWindowAttribute()} with a {@code DWORD} attribute value. + * See https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute + * + * @since 3.3 + */ + public native static boolean dwmSetWindowAttributeDWORD( long hwnd, int attribute, int value ); + + /** @since 3.3 */ + public static final int + // use this constant to reset any window part colors to the system default behavior + DWMWA_COLOR_DEFAULT = 0xFFFFFFFF, + // use this constant to specify that a window part should not be rendered + DWMWA_COLOR_NONE = 0xFFFFFFFE; + + /** @since 3.3 */ + public static final Color COLOR_NONE = new Color( 0, true ); + + /** + * Invokes Win32 API method {@code DwmSetWindowAttribute()} with a {@code COLORREF} attribute value. * See https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/nf-dwmapi-dwmsetwindowattribute *

* Supported since Windows 11 Build 22000. + * + * @since 3.3 */ - public native static boolean setWindowBorderColor( long hwnd, int red, int green, int blue ); + public static boolean dwmSetWindowAttributeCOLORREF( long hwnd, int attribute, Color color ) { + // convert color to Windows RGB value + int rgb = (color == COLOR_NONE) + ? DWMWA_COLOR_NONE + : (color != null + ? (color.getRed() | (color.getGreen() << 8) | (color.getBlue() << 16)) + : DWMWA_COLOR_DEFAULT); + + // DwmSetWindowAttribute() expects COLORREF as attribute value, which is defined as DWORD + return dwmSetWindowAttributeDWORD( hwnd, attribute, rgb ); + } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java index eeca80ef..7a25b907 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatPopupFactory.java @@ -361,29 +361,20 @@ public class FlatPopupFactory FlatNativeWindowsLibrary.setWindowCornerPreference( hwnd, cornerPreference ); // set border color - int red = -1; // use system default color - int green = 0; - int blue = 0; + Color borderColor = null; // use system default color if( contents instanceof JComponent ) { Border border = ((JComponent)contents).getBorder(); border = FlatUIUtils.unwrapNonUIResourceBorder( border ); // get color from border of contents (e.g. JPopupMenu or JToolTip) - Color borderColor = null; if( border instanceof FlatLineBorder ) borderColor = ((FlatLineBorder)border).getLineColor(); else if( border instanceof LineBorder ) borderColor = ((LineBorder)border).getLineColor(); else if( border instanceof EmptyBorder ) - red = -2; // do not paint border - - if( borderColor != null ) { - red = borderColor.getRed(); - green = borderColor.getGreen(); - blue = borderColor.getBlue(); - } + borderColor = FlatNativeWindowsLibrary.COLOR_NONE; // do not paint border } - FlatNativeWindowsLibrary.setWindowBorderColor( hwnd, red, green, blue ); + FlatNativeWindowsLibrary.dwmSetWindowAttributeCOLORREF( hwnd, FlatNativeWindowsLibrary.DWMWA_BORDER_COLOR, borderColor ); } private static void resetWindows11Border( Window popupWindow ) { diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinWrapper.cpp b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinWrapper.cpp index 37fc9e84..1983a075 100644 --- a/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinWrapper.cpp +++ b/flatlaf-natives/flatlaf-natives-windows/src/main/cpp/WinWrapper.cpp @@ -50,29 +50,6 @@ JNIEXPORT jlong JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_get //---- Desktop Window Manager (DWM) ------------------------------------------- -// define constants that may not available in older development environments - -#ifndef DWMWA_COLOR_DEFAULT - -#define DWMWA_WINDOW_CORNER_PREFERENCE 33 -#define DWMWA_BORDER_COLOR 34 - -typedef enum { - DWMWCP_DEFAULT = 0, - DWMWCP_DONOTROUND = 1, - DWMWCP_ROUND = 2, - DWMWCP_ROUNDSMALL = 3 -} DWM_WINDOW_CORNER_PREFERENCE; - -// Use this constant to reset any window part colors to the system default behavior -#define DWMWA_COLOR_DEFAULT 0xFFFFFFFF - -// Use this constant to specify that a window part should not be rendered -#define DWMWA_COLOR_NONE 0xFFFFFFFE - -#endif - - extern "C" JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_setWindowCornerPreference ( JNIEnv* env, jclass cls, jlong hwnd, jint cornerPreference ) @@ -85,18 +62,23 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_ } extern "C" -JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_setWindowBorderColor - ( JNIEnv* env, jclass cls, jlong hwnd, jint red, jint green, jint blue ) +JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_dwmSetWindowAttributeBOOL + ( JNIEnv* env, jclass cls, jlong hwnd, jint attribute, jboolean value ) { if( hwnd == 0 ) return FALSE; - COLORREF attr; - if( red == -1 ) - attr = DWMWA_COLOR_DEFAULT; - else if( red == -2 ) - attr = DWMWA_COLOR_NONE; - else - attr = RGB( red, green, blue ); - return ::DwmSetWindowAttribute( reinterpret_cast( hwnd ), DWMWA_BORDER_COLOR, &attr, sizeof( attr ) ) == S_OK; + BOOL attr = value; + return ::DwmSetWindowAttribute( reinterpret_cast( hwnd ), attribute, &attr, sizeof( attr ) ) == S_OK; +} + +extern "C" +JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_dwmSetWindowAttributeDWORD + ( JNIEnv* env, jclass cls, jlong hwnd, jint attribute, jint value ) +{ + if( hwnd == 0 ) + return FALSE; + + DWORD attr = value; + return ::DwmSetWindowAttribute( reinterpret_cast( hwnd ), attribute, &attr, sizeof( attr ) ) == S_OK; } diff --git a/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h b/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h index 921c7a99..1701cb3b 100644 --- a/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h +++ b/flatlaf-natives/flatlaf-natives-windows/src/main/headers/com_formdev_flatlaf_ui_FlatNativeWindowsLibrary.h @@ -15,6 +15,18 @@ extern "C" { #define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWCP_ROUND 2L #undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWCP_ROUNDSMALL #define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWCP_ROUNDSMALL 3L +#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_USE_IMMERSIVE_DARK_MODE +#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_USE_IMMERSIVE_DARK_MODE 20L +#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_BORDER_COLOR +#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_BORDER_COLOR 34L +#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_CAPTION_COLOR +#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_CAPTION_COLOR 35L +#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_TEXT_COLOR +#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_TEXT_COLOR 36L +#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_COLOR_DEFAULT +#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_COLOR_DEFAULT -1L +#undef com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_COLOR_NONE +#define com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_DWMWA_COLOR_NONE -2L /* * Class: com_formdev_flatlaf_ui_FlatNativeWindowsLibrary * Method: getOSBuildNumberImpl @@ -41,11 +53,19 @@ JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_ /* * Class: com_formdev_flatlaf_ui_FlatNativeWindowsLibrary - * Method: setWindowBorderColor - * Signature: (JIII)Z + * Method: dwmSetWindowAttributeBOOL + * Signature: (JIZ)Z */ -JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_setWindowBorderColor - (JNIEnv *, jclass, jlong, jint, jint, jint); +JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_dwmSetWindowAttributeBOOL + (JNIEnv *, jclass, jlong, jint, jboolean); + +/* + * Class: com_formdev_flatlaf_ui_FlatNativeWindowsLibrary + * Method: dwmSetWindowAttributeDWORD + * Signature: (JII)Z + */ +JNIEXPORT jboolean JNICALL Java_com_formdev_flatlaf_ui_FlatNativeWindowsLibrary_dwmSetWindowAttributeDWORD + (JNIEnv *, jclass, jlong, jint, jint); #ifdef __cplusplus } diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindows11DwmTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindows11DwmTest.java new file mode 100644 index 00000000..df9a30fc --- /dev/null +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindows11DwmTest.java @@ -0,0 +1,336 @@ +/* + * Copyright 2023 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.Color; +import javax.swing.*; +import com.formdev.flatlaf.FlatSystemProperties; +import com.formdev.flatlaf.ui.FlatNativeWindowsLibrary; +import net.miginfocom.swing.*; + +/** + * @author Karl Tauber + */ +public class FlatWindows11DwmTest + extends FlatTestPanel +{ + public static void main( String[] args ) { + SwingUtilities.invokeLater( () -> { + System.setProperty( FlatSystemProperties.USE_WINDOW_DECORATIONS, "false" ); + + FlatTestFrame frame = FlatTestFrame.create( args, FlatWindows11DwmTest.class.getSimpleName() ); + frame.showFrame( FlatWindows11DwmTest::new ); + } ); + } + + FlatWindows11DwmTest() { + initComponents(); + } + + private void modeChanged() { + if( !checkNativeLibraryLoaded() ) + return; + + boolean dark = darkModeRadioButton.isSelected(); + FlatNativeWindowsLibrary.dwmSetWindowAttributeBOOL( getHWND(), FlatNativeWindowsLibrary.DWMWA_USE_IMMERSIVE_DARK_MODE, dark ); + } + + private void borderColorChanged() { + if( !checkNativeLibraryLoaded() ) + return; + + Color color = null; + if( borderRedRadioButton.isSelected() ) + color = Color.red; + else if( borderGreenRadioButton.isSelected() ) + color = Color.green; + else if( borderNoneRadioButton.isSelected() ) + color = FlatNativeWindowsLibrary.COLOR_NONE; + + FlatNativeWindowsLibrary.dwmSetWindowAttributeCOLORREF( getHWND(), FlatNativeWindowsLibrary.DWMWA_BORDER_COLOR, color ); + } + + private void captionColorChanged() { + if( !checkNativeLibraryLoaded() ) + return; + + Color color = null; + if( captionGreenRadioButton.isSelected() ) + color = Color.green; + else if( captionYellowRadioButton.isSelected() ) + color = Color.yellow; + else if( captionBlackRadioButton.isSelected() ) + color = Color.black; + + FlatNativeWindowsLibrary.dwmSetWindowAttributeCOLORREF( getHWND(), FlatNativeWindowsLibrary.DWMWA_CAPTION_COLOR, color ); + } + + private void textColorChanged() { + if( !checkNativeLibraryLoaded() ) + return; + + Color color = null; + if( textRedRadioButton.isSelected() ) + color = Color.red; + else if( textBlueRadioButton.isSelected() ) + color = Color.blue; + else if( textWhiteRadioButton.isSelected() ) + color = Color.white; + + FlatNativeWindowsLibrary.dwmSetWindowAttributeCOLORREF( getHWND(), FlatNativeWindowsLibrary.DWMWA_TEXT_COLOR, color ); + } + + private void cornerChanged() { + if( !checkNativeLibraryLoaded() ) + return; + + int cornerPreference = FlatNativeWindowsLibrary.DWMWCP_DEFAULT; + if( cornerDontRoundRadioButton.isSelected() ) + cornerPreference = FlatNativeWindowsLibrary.DWMWCP_DONOTROUND; + else if( cornerRoundRadioButton.isSelected() ) + cornerPreference = FlatNativeWindowsLibrary.DWMWCP_ROUND; + else if( cornerRoundSmallRadioButton.isSelected() ) + cornerPreference = FlatNativeWindowsLibrary.DWMWCP_ROUNDSMALL; + + FlatNativeWindowsLibrary.setWindowCornerPreference( getHWND(), cornerPreference ); + } + + private long getHWND() { + return FlatNativeWindowsLibrary.getHWND( SwingUtilities.getWindowAncestor( this ) ); + } + + private boolean checkNativeLibraryLoaded() { + if( FlatNativeWindowsLibrary.isLoaded() ) + return true; + + JOptionPane.showMessageDialog( this, "FlatLaf native windows library not loaded/available." ); + return false; + } + + private void initComponents() { + // JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents + JLabel modeLabel = new JLabel(); + lightModeRadioButton = new JRadioButton(); + darkModeRadioButton = new JRadioButton(); + JLabel borderLabel = new JLabel(); + borderDefaultRadioButton = new JRadioButton(); + borderRedRadioButton = new JRadioButton(); + borderGreenRadioButton = new JRadioButton(); + borderNoneRadioButton = new JRadioButton(); + JLabel captionLabel = new JLabel(); + captionDefaultRadioButton = new JRadioButton(); + captionGreenRadioButton = new JRadioButton(); + captionYellowRadioButton = new JRadioButton(); + captionBlackRadioButton = new JRadioButton(); + JLabel textLabel = new JLabel(); + textDefaultRadioButton = new JRadioButton(); + textRedRadioButton = new JRadioButton(); + textBlueRadioButton = new JRadioButton(); + textWhiteRadioButton = new JRadioButton(); + JLabel cornerLabel = new JLabel(); + cornerDefaultRadioButton = new JRadioButton(); + cornerDontRoundRadioButton = new JRadioButton(); + cornerRoundRadioButton = new JRadioButton(); + cornerRoundSmallRadioButton = new JRadioButton(); + + //======== this ======== + setLayout(new MigLayout( + "ltr,insets dialog,hidemode 3", + // columns + "[fill]" + + "[left]" + + "[left]" + + "[left]" + + "[left]", + // rows + "[fill]para" + + "[]" + + "[]" + + "[]" + + "[]")); + + //---- modeLabel ---- + modeLabel.setText("Mode:"); + add(modeLabel, "cell 0 0"); + + //---- lightModeRadioButton ---- + lightModeRadioButton.setText("Light"); + lightModeRadioButton.setSelected(true); + lightModeRadioButton.addActionListener(e -> modeChanged()); + add(lightModeRadioButton, "cell 1 0"); + + //---- darkModeRadioButton ---- + darkModeRadioButton.setText("Dark"); + darkModeRadioButton.addActionListener(e -> modeChanged()); + add(darkModeRadioButton, "cell 2 0"); + + //---- borderLabel ---- + borderLabel.setText("Border Color:"); + add(borderLabel, "cell 0 1"); + + //---- borderDefaultRadioButton ---- + borderDefaultRadioButton.setText("Default"); + borderDefaultRadioButton.setSelected(true); + borderDefaultRadioButton.addActionListener(e -> borderColorChanged()); + add(borderDefaultRadioButton, "cell 1 1"); + + //---- borderRedRadioButton ---- + borderRedRadioButton.setText("Red"); + borderRedRadioButton.addActionListener(e -> borderColorChanged()); + add(borderRedRadioButton, "cell 2 1"); + + //---- borderGreenRadioButton ---- + borderGreenRadioButton.setText("Green"); + borderGreenRadioButton.addActionListener(e -> borderColorChanged()); + add(borderGreenRadioButton, "cell 3 1"); + + //---- borderNoneRadioButton ---- + borderNoneRadioButton.setText("None"); + borderNoneRadioButton.addActionListener(e -> borderColorChanged()); + add(borderNoneRadioButton, "cell 4 1"); + + //---- captionLabel ---- + captionLabel.setText("Caption Color:"); + add(captionLabel, "cell 0 2"); + + //---- captionDefaultRadioButton ---- + captionDefaultRadioButton.setText("Default"); + captionDefaultRadioButton.setSelected(true); + captionDefaultRadioButton.addActionListener(e -> captionColorChanged()); + add(captionDefaultRadioButton, "cell 1 2"); + + //---- captionGreenRadioButton ---- + captionGreenRadioButton.setText("Green"); + captionGreenRadioButton.addActionListener(e -> captionColorChanged()); + add(captionGreenRadioButton, "cell 2 2"); + + //---- captionYellowRadioButton ---- + captionYellowRadioButton.setText("Yellow"); + captionYellowRadioButton.addActionListener(e -> captionColorChanged()); + add(captionYellowRadioButton, "cell 3 2"); + + //---- captionBlackRadioButton ---- + captionBlackRadioButton.setText("Black"); + captionBlackRadioButton.addActionListener(e -> captionColorChanged()); + add(captionBlackRadioButton, "cell 4 2"); + + //---- textLabel ---- + textLabel.setText("Text Color:"); + add(textLabel, "cell 0 3"); + + //---- textDefaultRadioButton ---- + textDefaultRadioButton.setText("Default"); + textDefaultRadioButton.setSelected(true); + textDefaultRadioButton.addActionListener(e -> textColorChanged()); + add(textDefaultRadioButton, "cell 1 3"); + + //---- textRedRadioButton ---- + textRedRadioButton.setText("Red"); + textRedRadioButton.addActionListener(e -> textColorChanged()); + add(textRedRadioButton, "cell 2 3"); + + //---- textBlueRadioButton ---- + textBlueRadioButton.setText("Blue"); + textBlueRadioButton.addActionListener(e -> textColorChanged()); + add(textBlueRadioButton, "cell 3 3"); + + //---- textWhiteRadioButton ---- + textWhiteRadioButton.setText("White"); + textWhiteRadioButton.addActionListener(e -> textColorChanged()); + add(textWhiteRadioButton, "cell 4 3"); + + //---- cornerLabel ---- + cornerLabel.setText("Corner:"); + add(cornerLabel, "cell 0 4"); + + //---- cornerDefaultRadioButton ---- + cornerDefaultRadioButton.setText("Default"); + cornerDefaultRadioButton.setSelected(true); + cornerDefaultRadioButton.addActionListener(e -> cornerChanged()); + add(cornerDefaultRadioButton, "cell 1 4 4 1"); + + //---- cornerDontRoundRadioButton ---- + cornerDontRoundRadioButton.setText("Don't Round"); + cornerDontRoundRadioButton.addActionListener(e -> cornerChanged()); + add(cornerDontRoundRadioButton, "cell 1 4 4 1"); + + //---- cornerRoundRadioButton ---- + cornerRoundRadioButton.setText("Round"); + cornerRoundRadioButton.addActionListener(e -> cornerChanged()); + add(cornerRoundRadioButton, "cell 1 4 4 1"); + + //---- cornerRoundSmallRadioButton ---- + cornerRoundSmallRadioButton.setText("Round Small"); + cornerRoundSmallRadioButton.addActionListener(e -> cornerChanged()); + add(cornerRoundSmallRadioButton, "cell 1 4 4 1"); + + //---- modeButtonGroup ---- + ButtonGroup modeButtonGroup = new ButtonGroup(); + modeButtonGroup.add(lightModeRadioButton); + modeButtonGroup.add(darkModeRadioButton); + + //---- borderColorButtonGroup ---- + ButtonGroup borderColorButtonGroup = new ButtonGroup(); + borderColorButtonGroup.add(borderDefaultRadioButton); + borderColorButtonGroup.add(borderRedRadioButton); + borderColorButtonGroup.add(borderGreenRadioButton); + borderColorButtonGroup.add(borderNoneRadioButton); + + //---- captionColorButtonGroup ---- + ButtonGroup captionColorButtonGroup = new ButtonGroup(); + captionColorButtonGroup.add(captionDefaultRadioButton); + captionColorButtonGroup.add(captionGreenRadioButton); + captionColorButtonGroup.add(captionYellowRadioButton); + captionColorButtonGroup.add(captionBlackRadioButton); + + //---- textColorButtonGroup ---- + ButtonGroup textColorButtonGroup = new ButtonGroup(); + textColorButtonGroup.add(textDefaultRadioButton); + textColorButtonGroup.add(textRedRadioButton); + textColorButtonGroup.add(textBlueRadioButton); + textColorButtonGroup.add(textWhiteRadioButton); + + //---- cornerButtonGroup ---- + ButtonGroup cornerButtonGroup = new ButtonGroup(); + cornerButtonGroup.add(cornerDefaultRadioButton); + cornerButtonGroup.add(cornerDontRoundRadioButton); + cornerButtonGroup.add(cornerRoundRadioButton); + cornerButtonGroup.add(cornerRoundSmallRadioButton); + // JFormDesigner - End of component initialization //GEN-END:initComponents + } + + // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables + private JRadioButton lightModeRadioButton; + private JRadioButton darkModeRadioButton; + private JRadioButton borderDefaultRadioButton; + private JRadioButton borderRedRadioButton; + private JRadioButton borderGreenRadioButton; + private JRadioButton borderNoneRadioButton; + private JRadioButton captionDefaultRadioButton; + private JRadioButton captionGreenRadioButton; + private JRadioButton captionYellowRadioButton; + private JRadioButton captionBlackRadioButton; + private JRadioButton textDefaultRadioButton; + private JRadioButton textRedRadioButton; + private JRadioButton textBlueRadioButton; + private JRadioButton textWhiteRadioButton; + private JRadioButton cornerDefaultRadioButton; + private JRadioButton cornerDontRoundRadioButton; + private JRadioButton cornerRoundRadioButton; + private JRadioButton cornerRoundSmallRadioButton; + // JFormDesigner - End of variables declaration //GEN-END:variables +} diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindows11DwmTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindows11DwmTest.jfd new file mode 100644 index 00000000..36f01e3c --- /dev/null +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatWindows11DwmTest.jfd @@ -0,0 +1,278 @@ +JFDML JFormDesigner: "8.1.0.0.283" Java: "19.0.2" 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 net.miginfocom.swing.MigLayout ) { + "$layoutConstraints": "ltr,insets dialog,hidemode 3" + "$columnConstraints": "[fill][left][left][left][left]" + "$rowConstraints": "[fill]para[][][][]" + } ) { + name: "this" + add( new FormComponent( "javax.swing.JLabel" ) { + name: "modeLabel" + "text": "Mode:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "lightModeRadioButton" + "text": "Light" + "$buttonGroup": new FormReference( "modeButtonGroup" ) + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "modeChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 0" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "darkModeRadioButton" + "text": "Dark" + "$buttonGroup": new FormReference( "modeButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "modeChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 0" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "borderLabel" + "text": "Border Color:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "borderDefaultRadioButton" + "text": "Default" + "$buttonGroup": new FormReference( "borderColorButtonGroup" ) + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "borderColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 1" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "borderRedRadioButton" + "text": "Red" + "$buttonGroup": new FormReference( "borderColorButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "borderColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 1" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "borderGreenRadioButton" + "text": "Green" + "$buttonGroup": new FormReference( "borderColorButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "borderColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 3 1" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "borderNoneRadioButton" + "text": "None" + "$buttonGroup": new FormReference( "borderColorButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "borderColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 4 1" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "captionLabel" + "text": "Caption Color:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "captionDefaultRadioButton" + "text": "Default" + "$buttonGroup": new FormReference( "captionColorButtonGroup" ) + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "captionColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 2" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "captionGreenRadioButton" + "text": "Green" + "$buttonGroup": new FormReference( "captionColorButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "captionColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 2" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "captionYellowRadioButton" + "text": "Yellow" + "$buttonGroup": &FormReference0 new FormReference( "captionColorButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "captionColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 3 2" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "captionBlackRadioButton" + "text": "Black" + "$buttonGroup": #FormReference0 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "captionColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 4 2" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "textLabel" + "text": "Text Color:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 3" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "textDefaultRadioButton" + "text": "Default" + "$buttonGroup": new FormReference( "textColorButtonGroup" ) + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "textColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 3" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "textRedRadioButton" + "text": "Red" + "$buttonGroup": new FormReference( "textColorButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "textColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 2 3" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "textBlueRadioButton" + "text": "Blue" + "$buttonGroup": &FormReference1 new FormReference( "textColorButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "textColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 3 3" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "textWhiteRadioButton" + "text": "White" + "$buttonGroup": #FormReference1 + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "textColorChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 4 3" + } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "cornerLabel" + "text": "Corner:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "cornerDefaultRadioButton" + "text": "Default" + "$buttonGroup": new FormReference( "cornerButtonGroup" ) + "selected": true + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "cornerChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 4 4 1" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "cornerDontRoundRadioButton" + "text": "Don't Round" + "$buttonGroup": new FormReference( "cornerButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "cornerChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 4 4 1" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "cornerRoundRadioButton" + "text": "Round" + "$buttonGroup": new FormReference( "cornerButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "cornerChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 4 4 1" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "cornerRoundSmallRadioButton" + "text": "Round Small" + "$buttonGroup": new FormReference( "cornerButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "cornerChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 4 4 1" + } ) + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 0 ) + "size": new java.awt.Dimension( 415, 350 ) + } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "modeButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 360 ) + } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "borderColorButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 414 ) + } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "captionColorButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 468 ) + } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "textColorButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 522 ) + } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "cornerButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 576 ) + } ) + } +}