3535import java .text .AttributedCharacterIterator ;
3636import java .util .Map ;
3737import javax .swing .Icon ;
38+ import javax .swing .JCheckBoxMenuItem ;
3839import javax .swing .JComponent ;
3940import javax .swing .JMenu ;
4041import javax .swing .JMenuBar ;
4142import javax .swing .JMenuItem ;
43+ import javax .swing .JRadioButtonMenuItem ;
4244import javax .swing .KeyStroke ;
45+ import javax .swing .MenuElement ;
4346import javax .swing .SwingUtilities ;
4447import javax .swing .UIManager ;
4548import javax .swing .plaf .basic .BasicHTML ;
7376 * @uiDefault MenuItem.underlineSelectionCheckBackground Color
7477 * @uiDefault MenuItem.underlineSelectionColor Color
7578 * @uiDefault MenuItem.underlineSelectionHeight int
79+ * @uiDefault MenuItem.checkIconSeparated boolean
7680 *
7781 * @author Karl Tauber
7882 */
@@ -103,6 +107,7 @@ public class FlatMenuItemRenderer
103107 @ Styleable protected Color underlineSelectionCheckBackground = UIManager .getColor ( "MenuItem.underlineSelectionCheckBackground" );
104108 @ Styleable protected Color underlineSelectionColor = UIManager .getColor ( "MenuItem.underlineSelectionColor" );
105109 @ Styleable protected int underlineSelectionHeight = UIManager .getInt ( "MenuItem.underlineSelectionHeight" );
110+ @ Styleable protected boolean checkIconSeparated = UIManager .getBoolean ( "MenuItem.checkIconSeparated" );
106111
107112 private boolean iconsShared = true ;
108113 private final Font menuFont = UIManager .getFont ( "Menu.font" );
@@ -195,6 +200,7 @@ protected Dimension getPreferredMenuItemSize() {
195200 int width = 0 ;
196201 int height = 0 ;
197202 boolean isTopLevelMenu = isTopLevelMenu ( menuItem );
203+ boolean isIconSeparated = isIconSeparated ( menuItem );
198204
199205 Rectangle viewRect = new Rectangle ( 0 , 0 , Integer .MAX_VALUE , Integer .MAX_VALUE );
200206 Rectangle iconRect = new Rectangle ();
@@ -237,6 +243,11 @@ protected Dimension getPreferredMenuItemSize() {
237243 height = Math .max ( arrowIcon .getIconHeight (), height );
238244 }
239245
246+ if ( isIconSeparated ) {
247+ // gap between check and icon
248+ width += iconRect .width + scale ( menuItem .getIconTextGap () );
249+ }
250+
240251 // add insets
241252 Insets insets = menuItem .getInsets ();
242253 width += insets .left + insets .right ;
@@ -251,10 +262,11 @@ protected Dimension getPreferredMenuItemSize() {
251262 return new Dimension ( width , height );
252263 }
253264
254- private void layout ( Rectangle viewRect , Rectangle iconRect , Rectangle textRect ,
255- Rectangle accelRect , Rectangle arrowRect , Rectangle labelRect )
265+ private void layout ( Rectangle viewRect , Rectangle checkRect , Rectangle iconRect ,
266+ Rectangle textRect , Rectangle accelRect , Rectangle arrowRect , Rectangle labelRect )
256267 {
257268 boolean isTopLevelMenu = isTopLevelMenu ( menuItem );
269+ boolean isIconSeparated = isIconSeparated ( menuItem );
258270
259271 // layout arrow
260272 boolean showArrowIcon = (arrowIcon != null && (!isTopLevelMenu || isInVerticalMenuBar ( menuItem )));
@@ -311,6 +323,16 @@ private void layout( Rectangle viewRect, Rectangle iconRect, Rectangle textRect,
311323 menuItem .getVerticalAlignment (), menuItem .getHorizontalAlignment (),
312324 menuItem .getVerticalTextPosition (), menuItem .getHorizontalTextPosition (),
313325 labelRect , iconRect , textRect , scale ( menuItem .getIconTextGap () ) );
326+
327+ checkRect .setBounds ( iconRect );
328+
329+ if ( isIconSeparated ) {
330+ int width = checkRect .width + scale ( menuItem .getIconTextGap () );
331+ iconRect .x += width ;
332+ textRect .x += width ;
333+ labelRect .x += width ;
334+ textRect .width -= width ;
335+ }
314336 }
315337
316338 private static int centerOffset ( int wh1 , int wh2 ) {
@@ -329,15 +351,17 @@ protected void paintMenuItem( Graphics g, Color selectionBackground, Color selec
329351 viewRect .width -= (insets .left + insets .right );
330352 viewRect .height -= (insets .top + insets .bottom );
331353
354+ Rectangle checkRect = new Rectangle ();
332355 Rectangle iconRect = new Rectangle ();
333356 Rectangle textRect = new Rectangle ();
334357 Rectangle accelRect = new Rectangle ();
335358 Rectangle arrowRect = new Rectangle ();
336359 Rectangle labelRect = new Rectangle ();
337360
338- layout ( viewRect , iconRect , textRect , accelRect , arrowRect , labelRect );
361+ layout ( viewRect , checkRect , iconRect , textRect , accelRect , arrowRect , labelRect );
339362
340363/*debug
364+ g.setColor( Color.pink ); g.drawRect( checkRect.x, checkRect.y, checkRect.width - 1, checkRect.height - 1 );
341365 g.setColor( Color.green ); g.drawRect( viewRect.x, viewRect.y, viewRect.width - 1, viewRect.height - 1 );
342366 g.setColor( Color.red ); g.drawRect( labelRect.x, labelRect.y, labelRect.width - 1, labelRect.height - 1 );
343367 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
356380 else
357381 paintSelection ( g , selectionBackground , selectionInsets , selectionArc );
358382 }
359- paintIcon ( g , iconRect , getIconForPainting (), underlineSelection ? underlineSelectionCheckBackground : checkBackground , selectionBackground );
383+
384+ if ( isIconSeparated ( menuItem ) ) {
385+ if ( menuItem instanceof JCheckBoxMenuItem ) {
386+ paintIcon ( g , checkRect , UIManager .getIcon ( "CheckBox.icon" ) );
387+ } else if ( menuItem instanceof JRadioButtonMenuItem ) {
388+ paintIcon ( g , checkRect , UIManager .getIcon ( "RadioButton.icon" ) );
389+ }
390+
391+ paintIcon ( g , iconRect , getIconForPainting (false ) );
392+ } else {
393+ paintIcon ( g , iconRect , getIconForPainting (true ), underlineSelection ? underlineSelectionCheckBackground : checkBackground , selectionBackground );
394+ }
395+
360396 paintText ( g , textRect , menuItem .getText (), selectionForeground , disabledForeground );
361397 paintAccelerator ( g , accelRect , getAcceleratorText (), acceleratorForeground , acceleratorSelectionForeground , disabledForeground );
362398 if ( arrowIcon != null && (!isTopLevelMenu ( menuItem ) || isInVerticalMenuBar ( menuItem )) )
@@ -429,6 +465,10 @@ protected void paintIcon( Graphics g, Rectangle iconRect, Icon icon, Color check
429465 paintIcon ( g , menuItem , icon , iconRect );
430466 }
431467
468+ protected void paintIcon ( Graphics g , Rectangle iconRect , Icon icon ) {
469+ paintIcon ( g , menuItem , icon , iconRect );
470+ }
471+
432472 protected void paintText ( Graphics g , Rectangle textRect , String text , Color selectionForeground , Color disabledForeground ) {
433473 View htmlView = (View ) menuItem .getClientProperty ( BasicHTML .propertyKey );
434474 if ( htmlView != null ) {
@@ -537,6 +577,24 @@ protected boolean isUnderlineSelection() {
537577 return "underline" .equals ( UIManager .getString ( "MenuItem.selectionType" ) );
538578 }
539579
580+ protected boolean isIconSeparated ( JMenuItem item ) {
581+ if ( !checkIconSeparated )
582+ return false ;
583+
584+ Container parent = item .getParent ();
585+ if ( !(parent instanceof MenuElement ) )
586+ return false ;
587+
588+ for ( MenuElement element : ((MenuElement ) parent ).getSubElements () ) {
589+ Component c = element .getComponent ();
590+ if ( c instanceof JCheckBoxMenuItem && ((JCheckBoxMenuItem ) c ).getIcon () != null )
591+ return true ;
592+ if ( c instanceof JRadioButtonMenuItem && ((JRadioButtonMenuItem ) c ).getIcon () != null )
593+ return true ;
594+ }
595+ return false ;
596+ }
597+
540598 private Font getTopLevelFont () {
541599 Font font = menuItem .getFont ();
542600 // menu item parent may be null if JMenu.isTopLevelMenu() is overridden
@@ -546,10 +604,10 @@ private Font getTopLevelFont() {
546604 : menuItem .getParent ().getFont ();
547605 }
548606
549- private Icon getIconForPainting () {
607+ private Icon getIconForPainting (boolean canUseCheckIcon ) {
550608 Icon icon = menuItem .getIcon ();
551609
552- if ( icon == null && checkIcon != null && !isTopLevelMenu ( menuItem ) )
610+ if ( icon == null && canUseCheckIcon && checkIcon != null && !isTopLevelMenu ( menuItem ) )
553611 return checkIcon ;
554612
555613 if ( icon == null )
0 commit comments