From 626601f6aa4cc84048e25301d18d9e6592e9c7fd Mon Sep 17 00:00:00 2001 From: Karl Tauber Date: Wed, 27 May 2020 11:36:11 +0200 Subject: [PATCH] Window decorations: added window icon (issues #47 and #82) --- .../com/formdev/flatlaf/ui/FlatTitlePane.java | 40 ++++++- .../formdev/flatlaf/ui/FlatTitlePaneIcon.java | 70 ++++++++++++ .../formdev/flatlaf/util/ScaledImageIcon.java | 28 +++-- .../com/formdev/flatlaf/FlatLaf.properties | 2 + .../Window Icon Test Images.sketch | Bin 0 -> 14593 bytes .../testing/FlatWindowDecorationsTest.java | 104 +++++++++++++++++- .../testing/FlatWindowDecorationsTest.jfd | 58 +++++++++- .../com/formdev/flatlaf/testing/test128.png | Bin 0 -> 3934 bytes .../com/formdev/flatlaf/testing/test16.png | Bin 0 -> 428 bytes .../com/formdev/flatlaf/testing/test24.png | Bin 0 -> 624 bytes .../com/formdev/flatlaf/testing/test32.png | Bin 0 -> 1128 bytes .../com/formdev/flatlaf/testing/test48.png | Bin 0 -> 1494 bytes .../com/formdev/flatlaf/testing/test64.png | Bin 0 -> 1985 bytes 13 files changed, 286 insertions(+), 16 deletions(-) create mode 100644 flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePaneIcon.java create mode 100644 flatlaf-testing/Window Icon Test Images.sketch create mode 100644 flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/test128.png create mode 100644 flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/test16.png create mode 100644 flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/test24.png create mode 100644 flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/test32.png create mode 100644 flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/test48.png create mode 100644 flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/test64.png 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 014b5d53..568d9594 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 @@ -19,8 +19,10 @@ package com.formdev.flatlaf.ui; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dialog; +import java.awt.Dimension; import java.awt.Frame; import java.awt.Graphics; +import java.awt.Image; import java.awt.Window; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; @@ -29,6 +31,7 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.List; import javax.accessibility.AccessibleContext; import javax.swing.BorderFactory; import javax.swing.BoxLayout; @@ -39,7 +42,6 @@ import javax.swing.JPanel; import javax.swing.JRootPane; import javax.swing.SwingUtilities; import javax.swing.UIManager; -import com.formdev.flatlaf.util.UIScale; /** * Provides the Flat LaF title bar. @@ -48,6 +50,9 @@ import com.formdev.flatlaf.util.UIScale; * @uiDefault TitlePane.inactiveBackground Color * @uiDefault TitlePane.foreground Color * @uiDefault TitlePane.inactiveForeground Color + * @uiDefault TitlePane.iconSize Dimension + * @uiDefault TitlePane.iconMargins Insets + * @uiDefault TitlePane.titleMargins Insets * @uiDefault TitlePane.closeIcon Icon * @uiDefault TitlePane.iconifyIcon Icon * @uiDefault TitlePane.maximizeIcon Icon @@ -63,8 +68,11 @@ class FlatTitlePane private final Color activeForeground = UIManager.getColor( "TitlePane.foreground" ); private final Color inactiveForeground = UIManager.getColor( "TitlePane.inactiveForeground" ); + private final Dimension iconSize = UIManager.getDimension( "TitlePane.iconSize" ); + private final JRootPane rootPane; + private JLabel iconLabel; private JLabel titleLabel; private JPanel buttonPanel; private JButton iconifyButton; @@ -85,12 +93,15 @@ class FlatTitlePane } private void addSubComponents() { + iconLabel = new JLabel(); titleLabel = new JLabel(); + iconLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.iconMargins" ) ) ); titleLabel.setBorder( new FlatEmptyBorder( UIManager.getInsets( "TitlePane.titleMargins" ) ) ); createButtons(); - setLayout( new BorderLayout( UIScale.scale( 4 ), 0 ) ); + setLayout( new BorderLayout() ); + add( iconLabel, BorderLayout.WEST ); add( titleLabel, BorderLayout.CENTER ); add( buttonPanel, BorderLayout.EAST ); } @@ -157,6 +168,26 @@ class FlatTitlePane } } + private void updateIcon() { + // get window images + List images = window.getIconImages(); + if( images.isEmpty() ) { + // search in owners + for( Window owner = window.getOwner(); owner != null; owner = owner.getOwner() ) { + images = owner.getIconImages(); + if( !images.isEmpty() ) + break; + } + } + + // show/hide icon + boolean hasImages = !images.isEmpty(); + iconLabel.setVisible( hasImages ); + + if( hasImages ) + iconLabel.setIcon( FlatTitlePaneIcon.create( images, iconSize ) ); + } + @Override public void addNotify() { super.addNotify(); @@ -167,6 +198,7 @@ class FlatTitlePane if( window != null ) { frameStateChanged(); activeChanged( window.isActive() ); + updateIcon(); titleLabel.setText( getWindowTitle() ); installWindowListeners(); } @@ -260,6 +292,10 @@ class FlatTitlePane if( window instanceof Frame ) frameStateChanged(); break; + + case "iconImage": + updateIcon(); + break; } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePaneIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePaneIcon.java new file mode 100644 index 00000000..93084ccc --- /dev/null +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTitlePaneIcon.java @@ -0,0 +1,70 @@ +/* + * Copyright 2020 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.ui; + +import java.awt.Dimension; +import java.awt.Image; +import java.util.ArrayList; +import java.util.List; +import javax.swing.Icon; +import javax.swing.ImageIcon; +import com.formdev.flatlaf.util.MultiResolutionImageSupport; +import com.formdev.flatlaf.util.ScaledImageIcon; + +/** + * @author Karl Tauber + */ +class FlatTitlePaneIcon + extends ScaledImageIcon +{ + static Icon create( List images, Dimension size ) { + // collect all images including multi-resolution variants + List allImages = new ArrayList<>(); + for( Image image : images ) { + if( MultiResolutionImageSupport.isMultiResolutionImage( image ) ) + allImages.addAll( MultiResolutionImageSupport.getResolutionVariants( image ) ); + else + allImages.add( image ); + } + + // sort images by size + allImages.sort( (image1, image2) -> { + return image1.getWidth( null ) - image2.getWidth( null ); + } ); + + // create icon + return new FlatTitlePaneIcon( allImages, size ); + } + + private final List images; + + FlatTitlePaneIcon( List images, Dimension size ) { + super( new ImageIcon( images.get( 0 ) ), size.width, size.height ); + this.images = images; + } + + @Override + protected Image getResolutionVariant( int destImageWidth, int destImageHeight ) { + for( Image image : images ) { + if( destImageWidth <= image.getWidth( null ) && + destImageHeight <= image.getHeight( null ) ) + return image; + } + + return images.get( images.size() - 1 ); + } +} diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/ScaledImageIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/ScaledImageIcon.java index 91c5549f..cb503c31 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/util/ScaledImageIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/util/ScaledImageIcon.java @@ -37,30 +37,38 @@ public class ScaledImageIcon implements Icon { private final ImageIcon imageIcon; + private final int iconWidth; + private final int iconHeight; private double lastSystemScaleFactor; private float lastUserScaleFactor; private Image lastImage; public ScaledImageIcon( ImageIcon imageIcon ) { + this( imageIcon, imageIcon.getIconWidth(), imageIcon.getIconHeight() ); + } + + public ScaledImageIcon( ImageIcon imageIcon, int iconWidth, int iconHeight ) { this.imageIcon = imageIcon; + this.iconWidth = iconWidth; + this.iconHeight = iconHeight; } @Override public int getIconWidth() { - return UIScale.scale( imageIcon.getIconWidth() ); + return UIScale.scale( iconWidth ); } @Override public int getIconHeight() { - return UIScale.scale( imageIcon.getIconHeight() ); + return UIScale.scale( iconHeight ); } @Override public void paintIcon( Component c, Graphics g, int x, int y ) { /*debug g.setColor( Color.red ); - g.drawRect( x, y, getIconWidth(), getIconHeight() ); + g.drawRect( x, y, getIconWidth() - 1, getIconHeight() - 1 ); debug*/ // scale factor @@ -69,7 +77,7 @@ debug*/ double scaleFactor = systemScaleFactor * userScaleFactor; // paint input image icon if not necessary to scale - if( scaleFactor == 1 ) { + if( scaleFactor == 1 && iconWidth == imageIcon.getIconWidth() && iconHeight == imageIcon.getIconHeight() ) { imageIcon.paintIcon( c, g, x, y ); return; } @@ -84,12 +92,11 @@ debug*/ } // destination image size - int destImageWidth = (int) Math.round( imageIcon.getIconWidth() * scaleFactor ); - int destImageHeight = (int) Math.round( imageIcon.getIconHeight() * scaleFactor ); + int destImageWidth = (int) Math.round( iconWidth * scaleFactor ); + int destImageHeight = (int) Math.round( iconHeight * scaleFactor ); // get resolution variant of image if it is a multi-resolution image - Image image = MultiResolutionImageSupport.getResolutionVariant( - imageIcon.getImage(), destImageWidth, destImageHeight ); + Image image = getResolutionVariant( destImageWidth, destImageHeight ); // size of image int imageWidth = image.getWidth( null ); @@ -124,6 +131,11 @@ debug*/ paintLastImage( g, x, y ); } + protected Image getResolutionVariant( int destImageWidth, int destImageHeight ) { + return MultiResolutionImageSupport.getResolutionVariant( + imageIcon.getImage(), destImageWidth, destImageHeight ); + } + private void paintLastImage( Graphics g, int x, int y ) { if( lastSystemScaleFactor > 1 ) { HiDPIUtils.paintAtScale1x( (Graphics2D) g, x, y, 100, 100, // width and height are not used 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 98094770..5b6f4d2a 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -576,6 +576,8 @@ TitledBorder.border=1,1,1,1,$Separator.foreground #---- TitlePane ---- +TitlePane.iconSize=16,16 +TitlePane.iconMargins=3,8,3,0 TitlePane.titleMargins=3,8,3,8 TitlePane.closeIcon=$InternalFrame.closeIcon TitlePane.iconifyIcon=$InternalFrame.iconifyIcon diff --git a/flatlaf-testing/Window Icon Test Images.sketch b/flatlaf-testing/Window Icon Test Images.sketch new file mode 100644 index 0000000000000000000000000000000000000000..3fa6d1df56f50ed39d2ce3e845349a10dc9cf990 GIT binary patch literal 14593 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 LpX}zbeLejjp|~*| literal 0 HcmV?d00001 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 6d4efdab..58f35611 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 @@ -17,7 +17,11 @@ package com.formdev.flatlaf.testing; import java.awt.*; +import java.awt.Dialog.ModalityType; import java.awt.event.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; import javax.swing.*; import net.miginfocom.swing.*; @@ -39,10 +43,25 @@ public class FlatWindowDecorationsTest // frame.setUndecorated( true ); // frame.getRootPane().setWindowDecorationStyle( JRootPane.FRAME ); + Class cls = FlatWindowDecorationsTest.class; + List images = Arrays.asList( + new ImageIcon( cls.getResource( "/com/formdev/flatlaf/testing/test16.png" ) ).getImage(), + new ImageIcon( cls.getResource( "/com/formdev/flatlaf/testing/test24.png" ) ).getImage(), + new ImageIcon( cls.getResource( "/com/formdev/flatlaf/testing/test32.png" ) ).getImage(), + new ImageIcon( cls.getResource( "/com/formdev/flatlaf/testing/test48.png" ) ).getImage(), + new ImageIcon( cls.getResource( "/com/formdev/flatlaf/testing/test64.png" ) ).getImage(), + new ImageIcon( cls.getResource( "/com/formdev/flatlaf/testing/test128.png" ) ).getImage() + ); + // shuffle to test whether FlatLaf chooses the right size + Collections.shuffle( images ); + frame.setIconImages( images ); + frame.showFrame( FlatWindowDecorationsTest::new, panel -> ((FlatWindowDecorationsTest)panel).menuBar ); } ); } + private List images; + FlatWindowDecorationsTest() { initComponents(); } @@ -51,6 +70,14 @@ public class FlatWindowDecorationsTest public void addNotify() { super.addNotify(); + Window window = SwingUtilities.windowForComponent( this ); + menuBarCheckBox.setEnabled( window instanceof JFrame ); + + boolean windowHasIcons = (window != null && !window.getIconImages().isEmpty()); + iconNoneRadioButton.setEnabled( windowHasIcons ); + iconTestAllRadioButton.setEnabled( windowHasIcons ); + iconTestRandomRadioButton.setEnabled( windowHasIcons ); + JRootPane rootPane = getWindowRootPane(); if( rootPane != null ) { int style = rootPane.getWindowDecorationStyle(); @@ -89,7 +116,12 @@ public class FlatWindowDecorationsTest } private void openDialog() { - JOptionPane.showMessageDialog( this, new FlatWindowDecorationsTest() ); + Window owner = SwingUtilities.windowForComponent( this ); + JDialog dialog = new JDialog( owner, "Dialog", ModalityType.APPLICATION_MODAL ); + dialog.add( new FlatWindowDecorationsTest() ); + dialog.pack(); + dialog.setLocationRelativeTo( this ); + dialog.setVisible( true ); } private void decorationStyleChanged() { @@ -118,6 +150,22 @@ public class FlatWindowDecorationsTest rootPane.setWindowDecorationStyle( style ); } + private void iconChanged() { + Window window = SwingUtilities.windowForComponent( this ); + if( window == null ) + return; + + if( images == null ) + images = window.getIconImages(); + + if( iconNoneRadioButton.isSelected() ) + window.setIconImage( null ); + else if( iconTestAllRadioButton.isSelected() ) + window.setIconImages( images ); + else if( iconTestRandomRadioButton.isSelected() ) + window.setIconImage( images.get( (int) (Math.random() * images.size()) ) ); + } + private JRootPane getWindowRootPane() { Window window = SwingUtilities.windowForComponent( this ); if( window instanceof JFrame ) @@ -132,6 +180,7 @@ public class FlatWindowDecorationsTest menuBarCheckBox = new JCheckBox(); resizableCheckBox = new JCheckBox(); JLabel label1 = new JLabel(); + JLabel label2 = new JLabel(); JPanel panel1 = new JPanel(); styleNoneRadioButton = new JRadioButton(); styleFrameRadioButton = new JRadioButton(); @@ -142,6 +191,10 @@ public class FlatWindowDecorationsTest styleWarningRadioButton = new JRadioButton(); styleColorChooserRadioButton = new JRadioButton(); styleFileChooserRadioButton = new JRadioButton(); + JPanel panel2 = new JPanel(); + iconNoneRadioButton = new JRadioButton(); + iconTestAllRadioButton = new JRadioButton(); + iconTestRandomRadioButton = new JRadioButton(); JButton openDialogButton = new JButton(); menuBar = new JMenuBar(); JMenu fileMenu = new JMenu(); @@ -174,12 +227,13 @@ public class FlatWindowDecorationsTest setLayout(new MigLayout( "ltr,insets dialog,hidemode 3", // columns - "[left]para", + "[left]para" + + "[fill]", // rows - "para[]" + - "[]" + + "para[]0" + "[]" + "[]" + + "[top]" + "[]")); //---- menuBarCheckBox ---- @@ -198,6 +252,10 @@ public class FlatWindowDecorationsTest label1.setText("Style:"); add(label1, "cell 0 2"); + //---- label2 ---- + label2.setText("Icon:"); + add(label2, "cell 1 2"); + //======== panel1 ======== { panel1.setLayout(new MigLayout( @@ -263,6 +321,35 @@ public class FlatWindowDecorationsTest } add(panel1, "cell 0 3"); + //======== panel2 ======== + { + panel2.setLayout(new MigLayout( + "ltr,insets 0,hidemode 3,gap 0 0", + // columns + "[fill]", + // rows + "[]" + + "[]" + + "[]")); + + //---- iconNoneRadioButton ---- + iconNoneRadioButton.setText("none"); + iconNoneRadioButton.addActionListener(e -> iconChanged()); + panel2.add(iconNoneRadioButton, "cell 0 0"); + + //---- iconTestAllRadioButton ---- + iconTestAllRadioButton.setText("test all"); + iconTestAllRadioButton.setSelected(true); + iconTestAllRadioButton.addActionListener(e -> iconChanged()); + panel2.add(iconTestAllRadioButton, "cell 0 1"); + + //---- iconTestRandomRadioButton ---- + iconTestRandomRadioButton.setText("test random"); + iconTestRandomRadioButton.addActionListener(e -> iconChanged()); + panel2.add(iconTestRandomRadioButton, "cell 0 2"); + } + add(panel2, "cell 1 3"); + //---- openDialogButton ---- openDialogButton.setText("Open Dialog"); openDialogButton.addActionListener(e -> openDialog()); @@ -447,6 +534,12 @@ public class FlatWindowDecorationsTest styleButtonGroup.add(styleWarningRadioButton); styleButtonGroup.add(styleColorChooserRadioButton); styleButtonGroup.add(styleFileChooserRadioButton); + + //---- iconButtonGroup ---- + ButtonGroup iconButtonGroup = new ButtonGroup(); + iconButtonGroup.add(iconNoneRadioButton); + iconButtonGroup.add(iconTestAllRadioButton); + iconButtonGroup.add(iconTestRandomRadioButton); // JFormDesigner - End of component initialization //GEN-END:initComponents } @@ -462,6 +555,9 @@ public class FlatWindowDecorationsTest private JRadioButton styleWarningRadioButton; private JRadioButton styleColorChooserRadioButton; private JRadioButton styleFileChooserRadioButton; + private JRadioButton iconNoneRadioButton; + private JRadioButton iconTestAllRadioButton; + private JRadioButton iconTestRandomRadioButton; 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 dfaee803..a9824228 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 @@ -8,8 +8,8 @@ new FormModel { } add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "ltr,insets dialog,hidemode 3" - "$columnConstraints": "[left]para" - "$rowConstraints": "para[][][][][]" + "$columnConstraints": "[left]para[fill]" + "$rowConstraints": "para[]0[][][top][]" } ) { name: "this" add( new FormComponent( "javax.swing.JCheckBox" ) { @@ -40,6 +40,12 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 2" } ) + add( new FormComponent( "javax.swing.JLabel" ) { + name: "label2" + "text": "Icon:" + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 2" + } ) add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$columnConstraints": "[fill]" "$rowConstraints": "[][][][][][][][][]" @@ -149,6 +155,49 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 3" } ) + add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { + "$columnConstraints": "[fill]" + "$rowConstraints": "[][][]" + "$layoutConstraints": "ltr,insets 0,hidemode 3,gap 0 0" + } ) { + name: "panel2" + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "iconNoneRadioButton" + "text": "none" + "$buttonGroup": new FormReference( "iconButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "iconChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 0" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "iconTestAllRadioButton" + "text": "test all" + "selected": true + "$buttonGroup": new FormReference( "iconButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "iconChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 1" + } ) + add( new FormComponent( "javax.swing.JRadioButton" ) { + name: "iconTestRandomRadioButton" + "text": "test random" + "$buttonGroup": new FormReference( "iconButtonGroup" ) + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "iconChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 2" + } ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 1 3" + } ) add( new FormComponent( "javax.swing.JButton" ) { name: "openDialogButton" "text": "Open Dialog" @@ -332,5 +381,10 @@ new FormModel { }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 450 ) } ) + add( new FormNonVisual( "javax.swing.ButtonGroup" ) { + name: "iconButtonGroup" + }, new FormLayoutConstraints( null ) { + "location": new java.awt.Point( 0, 502 ) + } ) } } diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/test128.png b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/test128.png new file mode 100644 index 0000000000000000000000000000000000000000..b26ffcea6b442087894dbb1f5e34a7401bc1824f GIT binary patch literal 3934 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 literal 0 HcmV?d00001 diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/test64.png b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/test64.png new file mode 100644 index 0000000000000000000000000000000000000000..ad67439b8db856341bd4a96b37460916693e07b5 GIT binary patch literal 1985 zcmV;y2R`_TP)Px+dr3q=RCodH8)Gtn&HLW9E!Vzdfer(B@B{el#?f;M$XUPu*Ff$H3~&R0oCV}8V1R2NcLfHx z0py%up!XKQ0be*C_{cEeg2l#iTJ$t%o%Nu{8W7K3ttFJs0WOedJX24!fZFn>@8k4X z0h}}hf@2;6q3m|xrNNF5*3|^ar?x?|_G17w>d4bmqEL1#glE1;#g*niuATzK^2HDw z_ZVtFOgG>JaDoKE%B2t(z7Uc%n?X7EofDgH8nLv{u>Xwfsq zo#YFvATVqph{NVH50$2@0kyprbo3ED9b);t5Gc8^r{XDco)y3sj0Lgs0cHWMqYh&G z*MOe9Na=d=5~vsUb$yz4gEVC|a6-tK=K>K3O@9Gmdsb3@KLDRs0l}&#{fM~odQ5~k zkS47{^A_lWTIZ>h!_&#jfYR_IBu{+EkOhnwTzEJ`^Mr5#kfyCiWd=R5du8&Z0HI_y z2!kduYsL?4V%|J6X+h*uTR}@STPOg5(wiCF3qr1+P&kgVYOzKN_XhB!fWXiN%roSM zpFnG^W@z0ax`zJYH)dKWxrxEu5Ml5P5J%rn+0>T5K|b>}#k+u>^dZr#b2P%GgGKlZtLuFJnQT;aP@$(e#E#P_u_<}LaGkTJ4G7I=X$knrk zQl)VxC}+R*v4T6Rs|E1+mCP#S{yC07KJek|0E94T9sdEKsrF`Y_|~OK&(b9{%=P0( zUZ;4b0CxoxunJ(zPb>s+_#z|K6)b!tBQ(sutp*fynCkgmKKIK(XzKI8iTPA6arjjL z^dFfX?h1&oF`GCsGKA8(5SsEFrlf;X_Cy>OhjKiA#G&)hWAA`O^;=jF#Zq{k2;%6a zAQVrhQ*!-wOsw`&Jd;3rAArdRhf%;fbh#bGG0Px4YlGwAt-K~Ij#vbdx$hZevq|gj zn=crLh1R2Vnxxl>ns+IlX&}7?VCrfgBq@?C8`Lq*layF%KW@|ld}IXh1y#W3S77M6 zqF-VSp_wm1bl39kOJh_vNtHRiYg@XmLj0eN$RD?FBV%}41(-R!^=ZOlGDy3x$NUH!) zoV|A9*k%k#t)BKoYJa(IE5j>bzrZ?3G_khTk~QyR&!FDQk~KK30`zYBcuM0hzBXj< z0+IMmdWvKOM&60F#w~O`rTGBJ_1h?(Z6K`^bc)+X8R{{fo0}(HV*4P?4GkM5()g$7 zl#bp$dHe$mug*nN2sTK7G^CECIIW6AgO*YG1>8}7jTx&bQY=Mi61i&K5PhrA^@mC{DR!A1q4F%|+ zUOLRI?-d~mwe|@}ciP^k@X~m3Re*9~4~F9;ZANmufL{AHP|keib*~^`R%jh0kI*_! z0<@oiSkoTslxJA1d=R9n<&nQFOaJ>Sgu2-?WZ5_eUOVAaFR#NvcntyQY z!_2(W@H3i#!qBc2;;sPPnS6RXvp+s>6dr0BL+cI^E0%OMN-PZW+3zjbwFNyXfV9En zb3ZUUB|nS?$3DW)>VU{NTGNZ<^;ti$uMnU$PJJ@`6;OQ z>#UJDVQWk%nh4^kyO|7+2$5VMar6x;-xmPS3LsuTwr@3rXK!M>uP|sb{h8Y676l4u z3)^}?;-%vUH~5MkR{3nfp00rTa8lUB_O1e@W^!H~#yLiw_ z?h~+g3%I;p(iDy352Asg^Fge*56wNbwl_~k8YXi6m)H~h#&bW=l)YNtTyOthfRjqm zH_R}qJ5r43N{7)A)}m*#-p$E`l6+f${h@lI3IFn=?}Rn`{@ie1KEQ3U{y3jgK!1E| zncQ>E0y3%1{PvlCqY TGQLQf00000NkvXXu0mjflUTaU literal 0 HcmV?d00001