diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemRenderer.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemRenderer.java
index 463ebe428..e4285b87b 100644
--- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemRenderer.java
+++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemRenderer.java
@@ -35,11 +35,14 @@
import java.text.AttributedCharacterIterator;
import java.util.Map;
import javax.swing.Icon;
+import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
+import javax.swing.JRadioButtonMenuItem;
import javax.swing.KeyStroke;
+import javax.swing.MenuElement;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.basic.BasicHTML;
@@ -73,6 +76,7 @@
* @uiDefault MenuItem.underlineSelectionCheckBackground Color
* @uiDefault MenuItem.underlineSelectionColor Color
* @uiDefault MenuItem.underlineSelectionHeight int
+ * @uiDefault MenuItem.checkIconSeparated boolean
*
* @author Karl Tauber
*/
@@ -103,6 +107,7 @@ public class FlatMenuItemRenderer
@Styleable protected Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" );
@Styleable protected Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" );
@Styleable protected int underlineSelectionHeight = UIManager.getInt( "MenuItem.underlineSelectionHeight" );
+ @Styleable protected boolean checkIconSeparated = UIManager.getBoolean( "MenuItem.checkIconSeparated" );
private boolean iconsShared = true;
private final Font menuFont = UIManager.getFont( "Menu.font" );
@@ -195,6 +200,7 @@ protected Dimension getPreferredMenuItemSize() {
int width = 0;
int height = 0;
boolean isTopLevelMenu = isTopLevelMenu( menuItem );
+ boolean isIconSeparated = isIconSeparated( menuItem );
Rectangle viewRect = new Rectangle( 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE );
Rectangle iconRect = new Rectangle();
@@ -237,6 +243,11 @@ protected Dimension getPreferredMenuItemSize() {
height = Math.max( arrowIcon.getIconHeight(), height );
}
+ if( isIconSeparated ) {
+ // gap between check and icon
+ width += iconRect.width + scale( menuItem.getIconTextGap() );
+ }
+
// add insets
Insets insets = menuItem.getInsets();
width += insets.left + insets.right;
@@ -251,10 +262,11 @@ protected Dimension getPreferredMenuItemSize() {
return new Dimension( width, height );
}
- private void layout( Rectangle viewRect, Rectangle iconRect, Rectangle textRect,
- Rectangle accelRect, Rectangle arrowRect, Rectangle labelRect )
+ private void layout( Rectangle viewRect, Rectangle checkRect, Rectangle iconRect,
+ Rectangle textRect, Rectangle accelRect, Rectangle arrowRect, Rectangle labelRect )
{
boolean isTopLevelMenu = isTopLevelMenu( menuItem );
+ boolean isIconSeparated = isIconSeparated( menuItem );
// layout arrow
boolean showArrowIcon = (arrowIcon != null && (!isTopLevelMenu || isInVerticalMenuBar( menuItem )));
@@ -311,6 +323,16 @@ private void layout( Rectangle viewRect, Rectangle iconRect, Rectangle textRect,
menuItem.getVerticalAlignment(), menuItem.getHorizontalAlignment(),
menuItem.getVerticalTextPosition(), menuItem.getHorizontalTextPosition(),
labelRect, iconRect, textRect, scale( menuItem.getIconTextGap() ) );
+
+ checkRect.setBounds( iconRect );
+
+ if( isIconSeparated ) {
+ int width = checkRect.width + scale( menuItem.getIconTextGap() );
+ iconRect.x += width;
+ textRect.x += width;
+ labelRect.x += width;
+ textRect.width -= width;
+ }
}
private static int centerOffset( int wh1, int wh2 ) {
@@ -329,15 +351,17 @@ protected void paintMenuItem( Graphics g, Color selectionBackground, Color selec
viewRect.width -= (insets.left + insets.right);
viewRect.height -= (insets.top + insets.bottom);
+ Rectangle checkRect = new Rectangle();
Rectangle iconRect = new Rectangle();
Rectangle textRect = new Rectangle();
Rectangle accelRect = new Rectangle();
Rectangle arrowRect = new Rectangle();
Rectangle labelRect = new Rectangle();
- layout( viewRect, iconRect, textRect, accelRect, arrowRect, labelRect );
+ layout( viewRect, checkRect, iconRect, textRect, accelRect, arrowRect, labelRect );
/*debug
+ g.setColor( Color.pink ); g.drawRect( checkRect.x, checkRect.y, checkRect.width - 1, checkRect.height - 1 );
g.setColor( Color.green ); g.drawRect( viewRect.x, viewRect.y, viewRect.width - 1, viewRect.height - 1 );
g.setColor( Color.red ); g.drawRect( labelRect.x, labelRect.y, labelRect.width - 1, labelRect.height - 1 );
g.setColor( Color.blue ); g.drawRect( iconRect.x, iconRect.y, iconRect.width - 1, iconRect.height - 1 );
@@ -356,7 +380,19 @@ protected void paintMenuItem( Graphics g, Color selectionBackground, Color selec
else
paintSelection( g, selectionBackground, selectionInsets, selectionArc );
}
- paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground );
+
+ if( isIconSeparated( menuItem ) ) {
+ if( menuItem instanceof JCheckBoxMenuItem ) {
+ paintIcon( g, checkRect, UIManager.getIcon( "CheckBox.icon" ) );
+ } else if( menuItem instanceof JRadioButtonMenuItem ) {
+ paintIcon( g, checkRect, UIManager.getIcon( "RadioButton.icon" ) );
+ }
+
+ paintIcon( g, iconRect, getIconForPainting(false) );
+ } else {
+ paintIcon( g, iconRect, getIconForPainting(true), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground );
+ }
+
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
if( arrowIcon != null && (!isTopLevelMenu( menuItem ) || isInVerticalMenuBar( menuItem )) )
@@ -429,6 +465,10 @@ protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon, Color check
paintIcon( g, menuItem, icon, iconRect );
}
+ protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon ) {
+ paintIcon( g, menuItem, icon, iconRect );
+ }
+
protected void paintText( Graphics g, Rectangle textRect, String text, Color selectionForeground, Color disabledForeground ) {
View htmlView = (View) menuItem.getClientProperty( BasicHTML.propertyKey );
if( htmlView != null ) {
@@ -537,6 +577,24 @@ protected boolean isUnderlineSelection() {
return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) );
}
+ protected boolean isIconSeparated( JMenuItem item ) {
+ if( !checkIconSeparated )
+ return false;
+
+ Container parent = item.getParent();
+ if( !(parent instanceof MenuElement) )
+ return false;
+
+ for( MenuElement element : ((MenuElement) parent).getSubElements() ) {
+ Component c = element.getComponent();
+ if( c instanceof JCheckBoxMenuItem && ((JCheckBoxMenuItem) c).getIcon() != null )
+ return true;
+ if( c instanceof JRadioButtonMenuItem && ((JRadioButtonMenuItem) c).getIcon() != null )
+ return true;
+ }
+ return false;
+ }
+
private Font getTopLevelFont() {
Font font = menuItem.getFont();
// menu item parent may be null if JMenu.isTopLevelMenu() is overridden
@@ -546,10 +604,10 @@ private Font getTopLevelFont() {
: menuItem.getParent().getFont();
}
- private Icon getIconForPainting() {
+ private Icon getIconForPainting(boolean canUseCheckIcon) {
Icon icon = menuItem.getIcon();
- if( icon == null && checkIcon != null && !isTopLevelMenu( menuItem ) )
+ if( icon == null && canUseCheckIcon && checkIcon != null && !isTopLevelMenu( menuItem ) )
return checkIcon;
if( icon == null )
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 b0cb557cb..16d5d7453 100644
--- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties
+++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties
@@ -447,6 +447,7 @@ MenuItem.verticallyAlignText = true
MenuItem.background = @menuBackground
MenuItem.checkBackground = @menuCheckBackground
MenuItem.checkMargins = 2,2,2,2
+MenuItem.checkIconSeparated = false
MenuItem.minimumWidth = 72
MenuItem.minimumIconSize = 16,16
MenuItem.iconTextGap = 6
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 ccb0073d2..6b6601a8c 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
@@ -635,6 +635,11 @@ private boolean supportsFlatLafWindowDecorations() {
return FlatLaf.supportsNativeWindowDecorations() || SystemInfo.isLinux;
}
+ private void showCheckMenuIconsSeparately() {
+ UIManager.put( "MenuItem.checkIconSeparated", showMenuCheckIconsSeparately.isSelected() );
+ FlatLaf.updateUI();
+ }
+
private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
menuBar = new JMenuBar();
@@ -667,6 +672,10 @@ private void initComponents() {
scrollingPopupMenu = new JMenu();
JMenuItem menuItem2 = new JMenuItem();
htmlMenuItem = new JMenuItem();
+ JCheckBoxMenuItem checkBoxMenuItem2 = new JCheckBoxMenuItem();
+ JCheckBoxMenuItem checkBoxMenuItem3 = new JCheckBoxMenuItem();
+ JRadioButtonMenuItem radioButtonMenuItem4 = new JRadioButtonMenuItem();
+ JRadioButtonMenuItem radioButtonMenuItem5 = new JRadioButtonMenuItem();
JRadioButtonMenuItem radioButtonMenuItem1 = new JRadioButtonMenuItem();
JRadioButtonMenuItem radioButtonMenuItem2 = new JRadioButtonMenuItem();
JRadioButtonMenuItem radioButtonMenuItem3 = new JRadioButtonMenuItem();
@@ -686,6 +695,7 @@ private void initComponents() {
underlineMenuSelectionMenuItem = new JCheckBoxMenuItem();
alwaysShowMnemonicsMenuItem = new JCheckBoxMenuItem();
animatedLafChangeMenuItem = new JCheckBoxMenuItem();
+ showMenuCheckIconsSeparately = new JCheckBoxMenuItem();
JMenuItem showHintsMenuItem = new JMenuItem();
JMenuItem showUIDefaultsInspectorMenuItem = new JMenuItem();
JMenu helpMenu = new JMenu();
@@ -915,6 +925,28 @@ private void initComponents() {
//---- htmlMenuItem ----
htmlMenuItem.setText("some HTML text");
viewMenu.add(htmlMenuItem);
+
+ //---- checkBoxMenuItem2 ----
+ checkBoxMenuItem2.setText("Check Box");
+ checkBoxMenuItem2.setSelected(true);
+ viewMenu.add(checkBoxMenuItem2);
+
+ //---- checkBoxMenuItem3 ----
+ checkBoxMenuItem3.setText("Check Box with Icon");
+ checkBoxMenuItem3.setSelected(true);
+ checkBoxMenuItem3.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/show.svg"));
+ viewMenu.add(checkBoxMenuItem3);
+
+ //---- radioButtonMenuItem4 ----
+ radioButtonMenuItem4.setText("Radio Button");
+ radioButtonMenuItem4.setSelected(true);
+ viewMenu.add(radioButtonMenuItem4);
+
+ //---- radioButtonMenuItem5 ----
+ radioButtonMenuItem5.setText("Radio Button with Icon");
+ radioButtonMenuItem5.setSelected(true);
+ radioButtonMenuItem5.setIcon(new FlatSVGIcon("com/formdev/flatlaf/demo/icons/show.svg"));
+ viewMenu.add(radioButtonMenuItem5);
viewMenu.addSeparator();
//---- radioButtonMenuItem1 ----
@@ -1026,6 +1058,11 @@ private void initComponents() {
animatedLafChangeMenuItem.addActionListener(e -> animatedLafChangeChanged());
optionsMenu.add(animatedLafChangeMenuItem);
+ //---- showMenuCheckIconsSeparately ----
+ showMenuCheckIconsSeparately.setText("Show check menu icons separately");
+ showMenuCheckIconsSeparately.addActionListener(e -> showCheckMenuIconsSeparately());
+ optionsMenu.add(showMenuCheckIconsSeparately);
+
//---- showHintsMenuItem ----
showHintsMenuItem.setText("Show hints");
showHintsMenuItem.addActionListener(e -> showHintsChanged());
@@ -1239,6 +1276,7 @@ private void unsupported( JCheckBoxMenuItem menuItem ) {
private JCheckBoxMenuItem underlineMenuSelectionMenuItem;
private JCheckBoxMenuItem alwaysShowMnemonicsMenuItem;
private JCheckBoxMenuItem animatedLafChangeMenuItem;
+ private JCheckBoxMenuItem showMenuCheckIconsSeparately;
private JMenuItem aboutMenuItem;
private JToolBar toolBar;
private JTabbedPane tabbedPane;
diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd
index 0db8f3fba..3c479ab99 100644
--- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd
+++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd
@@ -357,6 +357,28 @@ new FormModel {
"JavaCodeGenerator.variableLocal": false
}
} )
+ add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
+ name: "checkBoxMenuItem2"
+ "text": "Check Box"
+ "selected": true
+ } )
+ add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
+ name: "checkBoxMenuItem3"
+ "text": "Check Box with Icon"
+ "selected": true
+ "icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/show.svg" )
+ } )
+ add( new FormComponent( "javax.swing.JRadioButtonMenuItem" ) {
+ name: "radioButtonMenuItem4"
+ "text": "Radio Button"
+ "selected": true
+ } )
+ add( new FormComponent( "javax.swing.JRadioButtonMenuItem" ) {
+ name: "radioButtonMenuItem5"
+ "text": "Radio Button with Icon"
+ "selected": true
+ "icon": new com.jformdesigner.model.SwingIcon( 0, "/com/formdev/flatlaf/demo/icons/show.svg" )
+ } )
add( new FormComponent( "javax.swing.JPopupMenu$Separator" ) {
name: "separator8"
} )
@@ -496,6 +518,14 @@ new FormModel {
}
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "animatedLafChangeChanged", false ) )
} )
+ add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) {
+ name: "showMenuCheckIconsSeparately"
+ "text": "Show check menu icons separately"
+ auxiliary() {
+ "JavaCodeGenerator.variableLocal": false
+ }
+ addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showCheckMenuIconsSeparately", false ) )
+ } )
add( new FormComponent( "javax.swing.JMenuItem" ) {
name: "showHintsMenuItem"
"text": "Show hints"
diff --git a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt
index d4c750f74..c5b4f32b8 100644
--- a/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt
+++ b/flatlaf-theme-editor/src/main/resources/com/formdev/flatlaf/themeeditor/FlatLafUIKeys.txt
@@ -550,6 +550,7 @@ MenuItem.border
MenuItem.borderPainted
MenuItem.checkBackground
MenuItem.checkMargins
+MenuItem.checkIconSeparated
MenuItem.disabledForeground
MenuItem.font
MenuItem.foreground