1 /*
   2  * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.apple.laf;
  27 
  28 import java.awt.*;
  29 import java.awt.event.*;
  30 
  31 import javax.swing.*;
  32 import javax.swing.border.Border;
  33 import javax.swing.plaf.basic.BasicHTML;
  34 import javax.swing.text.View;
  35 
  36 import sun.swing.SwingUtilities2;
  37 
  38 import apple.laf.JRSUIConstants.*;
  39 
  40 import com.apple.laf.AquaIcon.InvertableIcon;
  41 import com.apple.laf.AquaUtils.RecyclableSingleton;
  42 import com.apple.laf.AquaUtils.RecyclableSingletonFromDefaultConstructor;
  43 
  44 /**
  45  * AquaMenuPainter, implements paintMenuItem to avoid code duplication
  46  *
  47  * BasicMenuItemUI didn't factor out the various parts of the Menu, and
  48  * we subclass it and its subclasses BasicMenuUI
  49  * Our classes need an implementation of paintMenuItem
  50  * that allows them to paint their own backgrounds
  51  */
  52 
  53 public class AquaMenuPainter {
  54     // Glyph statics:
  55     // ASCII character codes
  56     static final byte
  57         kShiftGlyph = 0x05,
  58         kOptionGlyph = 0x07,
  59         kControlGlyph = 0x06,
  60         kPencilGlyph = 0x0F,
  61         kCommandMark = 0x11;
  62 
  63     // Unicode character codes
  64     static final char
  65         kUBlackDiamond = 0x25C6,
  66         kUCheckMark = 0x2713,
  67         kUControlGlyph = 0x2303,
  68         kUOptionGlyph = 0x2325,
  69         kUEnterGlyph = 0x2324,
  70         kUCommandGlyph = 0x2318,
  71         kULeftDeleteGlyph = 0x232B,
  72         kURightDeleteGlyph = 0x2326,
  73         kUShiftGlyph = 0x21E7,
  74         kUCapsLockGlyph = 0x21EA;
  75 
  76     static final int ALT_GRAPH_MASK = 1 << 5; // New to Java2
  77     @SuppressWarnings("deprecation")
  78     static final int sUnsupportedModifiersMask =
  79             ~(InputEvent.CTRL_MASK | InputEvent.ALT_MASK | InputEvent.SHIFT_MASK
  80                     | InputEvent.META_MASK | ALT_GRAPH_MASK);
  81 
  82     interface Client {
  83         public void paintBackground(Graphics g, JComponent c, int menuWidth, int menuHeight);
  84     }
  85 
  86     // Return a string with the proper modifier glyphs
  87     static String getKeyModifiersText(final int modifiers, final boolean isLeftToRight) {
  88         return getKeyModifiersUnicode(modifiers, isLeftToRight);
  89     }
  90 
  91     // Return a string with the proper modifier glyphs
  92     @SuppressWarnings("deprecation")
  93     private static String getKeyModifiersUnicode(final int modifiers, final boolean isLeftToRight) {
  94         final StringBuilder buf = new StringBuilder(2);
  95         // Order (from StandardMenuDef.c): control, option(alt), shift, cmd
  96         // reverse for right-to-left
  97         //$ check for substitute key glyphs for localization
  98         if (isLeftToRight) {
  99             if ((modifiers & InputEvent.CTRL_MASK) != 0) {
 100                 buf.append(kUControlGlyph);
 101             }
 102             if ((modifiers & (InputEvent.ALT_MASK | ALT_GRAPH_MASK)) != 0) {
 103                 buf.append(kUOptionGlyph);
 104             }
 105             if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
 106                 buf.append(kUShiftGlyph);
 107             }
 108             if ((modifiers & InputEvent.META_MASK) != 0) {
 109                 buf.append(kUCommandGlyph);
 110             }
 111         } else {
 112             if ((modifiers & InputEvent.META_MASK) != 0) {
 113                 buf.append(kUCommandGlyph);
 114             }
 115             if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
 116                 buf.append(kUShiftGlyph);
 117             }
 118             if ((modifiers & (InputEvent.ALT_MASK | ALT_GRAPH_MASK)) != 0) {
 119                 buf.append(kUOptionGlyph);
 120             }
 121             if ((modifiers & InputEvent.CTRL_MASK) != 0) {
 122                 buf.append(kUControlGlyph);
 123             }
 124         }
 125         return buf.toString();
 126     }
 127 
 128     private static final RecyclableSingleton<AquaMenuPainter> sPainter = new RecyclableSingletonFromDefaultConstructor<AquaMenuPainter>(AquaMenuPainter.class);
 129     static AquaMenuPainter instance() {
 130         return sPainter.get();
 131     }
 132 
 133     static final int defaultMenuItemGap = 2;
 134     static final int kAcceleratorArrowSpace = 16; // Accel space doesn't overlap arrow space, even though items can't have both
 135 
 136     static class RecyclableBorder extends RecyclableSingleton<Border> {
 137         final String borderName;
 138         RecyclableBorder(final String borderName) { this.borderName = borderName; }
 139         protected Border getInstance() { return UIManager.getBorder(borderName); }
 140     }
 141 
 142     private static final RecyclableBorder menuBarPainter = new RecyclableBorder("MenuBar.backgroundPainter");
 143     private static final RecyclableBorder selectedMenuBarItemPainter = new RecyclableBorder("MenuBar.selectedBackgroundPainter");
 144     private static final RecyclableBorder selectedMenuItemPainter = new RecyclableBorder("MenuItem.selectedBackgroundPainter");
 145 
 146     public void paintMenuBarBackground(final Graphics g, final int width, final int height, final JComponent c) {
 147         g.setColor(c == null ? Color.white : c.getBackground());
 148         g.fillRect(0, 0, width, height);
 149         menuBarPainter.get().paintBorder(null, g, 0, 0, width, height);
 150     }
 151 
 152     public void paintSelectedMenuTitleBackground(final Graphics g, final int width, final int height) {
 153         selectedMenuBarItemPainter.get().paintBorder(null, g, -1, 0, width + 2, height);
 154     }
 155 
 156     public void paintSelectedMenuItemBackground(final Graphics g, final int width, final int height) {
 157         selectedMenuItemPainter.get().paintBorder(null, g, 0, 0, width, height);
 158     }
 159 
 160     protected void paintMenuItem(final Client client, final Graphics g, final JComponent c, final Icon checkIcon, final Icon arrowIcon, final Color background, final Color foreground, final Color disabledForeground, final Color selectionForeground, final int defaultTextIconGap, final Font acceleratorFont) {
 161         final JMenuItem b = (JMenuItem)c;
 162         final ButtonModel model = b.getModel();
 163 
 164 //        Dimension size = b.getSize();
 165         final int menuWidth = b.getWidth();
 166         final int menuHeight = b.getHeight();
 167         final Insets i = c.getInsets();
 168 
 169         Rectangle viewRect = new Rectangle(0, 0, menuWidth, menuHeight);
 170 
 171         viewRect.x += i.left;
 172         viewRect.y += i.top;
 173         viewRect.width -= (i.right + viewRect.x);
 174         viewRect.height -= (i.bottom + viewRect.y);
 175 
 176         final Font holdf = g.getFont();
 177         final Color holdc = g.getColor();
 178         final Font f = c.getFont();
 179         g.setFont(f);
 180         final FontMetrics fm = g.getFontMetrics(f);
 181 
 182         final FontMetrics fmAccel = g.getFontMetrics(acceleratorFont);
 183 
 184         // Paint background (doesn't touch the Graphics object's color)
 185         if (c.isOpaque()) {
 186             client.paintBackground(g, c, menuWidth, menuHeight);
 187         }
 188 
 189         // get Accelerator text
 190         final KeyStroke accelerator = b.getAccelerator();
 191         String modifiersString = "", keyString = "";
 192         final boolean leftToRight = AquaUtils.isLeftToRight(c);
 193         if (accelerator != null) {
 194             final int modifiers = accelerator.getModifiers();
 195             if (modifiers > 0) {
 196                 modifiersString = getKeyModifiersText(modifiers, leftToRight);
 197             }
 198             final int keyCode = accelerator.getKeyCode();
 199             if (keyCode != 0) {
 200                 keyString = KeyEvent.getKeyText(keyCode);
 201             } else {
 202                 keyString += accelerator.getKeyChar();
 203             }
 204         }
 205 
 206         Rectangle iconRect = new Rectangle();
 207         Rectangle textRect = new Rectangle();
 208         Rectangle acceleratorRect = new Rectangle();
 209         Rectangle checkIconRect = new Rectangle();
 210         Rectangle arrowIconRect = new Rectangle();
 211 
 212         // layout the text and icon
 213         final String text = layoutMenuItem(b, fm, b.getText(), fmAccel, keyString, modifiersString, b.getIcon(), checkIcon, arrowIcon, b.getVerticalAlignment(), b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewRect, iconRect, textRect, acceleratorRect, checkIconRect, arrowIconRect, b.getText() == null ? 0 : defaultTextIconGap, defaultTextIconGap);
 214 
 215         // if this is in a AquaScreenMenuBar that's attached to a DialogPeer
 216         // the native menu will be disabled, though the awt Menu won't know about it
 217         // so the JPopupMenu will not have visibility set and the items should draw disabled
 218         // If it's not on a JPopupMenu then it should just use the model's enable state
 219         final Container parent = b.getParent();
 220         final boolean parentIsMenuBar = parent instanceof JMenuBar;
 221 
 222         Container ancestor = parent;
 223         while (ancestor != null && !(ancestor instanceof JPopupMenu)) ancestor = ancestor.getParent();
 224 
 225         boolean isEnabled = model.isEnabled() && (ancestor == null || ancestor.isVisible());
 226 
 227         // Set the accel/normal text color
 228         boolean isSelected = false;
 229         if (!isEnabled) {
 230             // *** paint the text disabled
 231             g.setColor(disabledForeground);
 232         } else {
 233             // *** paint the text normally
 234             if (model.isArmed() || (c instanceof JMenu && model.isSelected())) {
 235                 g.setColor(selectionForeground);
 236                 isSelected = true;
 237             } else {
 238                 g.setColor(parentIsMenuBar ? parent.getForeground() : b.getForeground()); // Which is either MenuItem.foreground or the user's choice
 239             }
 240         }
 241 
 242         // We want to paint the icon after the text color is set since some icon painting depends on the correct
 243         // graphics color being set
 244         // See <rdar://problem/3792383> Menu icons missing in Java2D's Lines.Joins demo
 245         // Paint the Icon
 246         if (b.getIcon() != null) {
 247             paintIcon(g, b, iconRect, isEnabled);
 248         }
 249 
 250         // Paint the Check using the current text color
 251         if (checkIcon != null) {
 252             paintCheck(g, b, checkIcon, checkIconRect);
 253         }
 254 
 255         // Draw the accelerator first in case the HTML renderer changes the color
 256         if (keyString != null && !keyString.isEmpty()) {
 257             final int yAccel = acceleratorRect.y + fm.getAscent();
 258             if (modifiersString.isEmpty()) {
 259                 // just draw the keyString
 260                 SwingUtilities2.drawString(c, g, keyString, acceleratorRect.x, yAccel);
 261             } else {
 262                 final int modifiers = accelerator.getModifiers();
 263                 int underlinedChar = 0;
 264                 if ((modifiers & ALT_GRAPH_MASK) > 0) underlinedChar = kUOptionGlyph; // This is a Java2 thing, we won't be getting kOptionGlyph
 265                 // The keyStrings should all line up, so always adjust the width by the same amount
 266                 // (if they're multi-char, they won't line up but at least they won't be cut off)
 267                 final int emWidth = Math.max(fm.charWidth('M'), SwingUtilities.computeStringWidth(fm, keyString));
 268 
 269                 if (leftToRight) {
 270                     g.setFont(acceleratorFont);
 271                     drawString(g, c, modifiersString, underlinedChar, acceleratorRect.x, yAccel, isEnabled, isSelected);
 272                     g.setFont(f);
 273                     SwingUtilities2.drawString(c, g, keyString, acceleratorRect.x + acceleratorRect.width - emWidth, yAccel);
 274                 } else {
 275                     final int xAccel = acceleratorRect.x + emWidth;
 276                     g.setFont(acceleratorFont);
 277                     drawString(g, c, modifiersString, underlinedChar, xAccel, yAccel, isEnabled, isSelected);
 278                     g.setFont(f);
 279                     SwingUtilities2.drawString(c, g, keyString, xAccel - fm.stringWidth(keyString), yAccel);
 280                 }
 281             }
 282         }
 283 
 284         // Draw the Text
 285         if (text != null && !text.isEmpty()) {
 286             final View v = (View)c.getClientProperty(BasicHTML.propertyKey);
 287             if (v != null) {
 288                 v.paint(g, textRect);
 289             } else {
 290                 final int mnemonic = (AquaMnemonicHandler.isMnemonicHidden() ? -1 : model.getMnemonic());
 291                 drawString(g, c, text, mnemonic, textRect.x, textRect.y + fm.getAscent(), isEnabled, isSelected);
 292             }
 293         }
 294 
 295         // Paint the Arrow
 296         if (arrowIcon != null) {
 297             paintArrow(g, b, model, arrowIcon, arrowIconRect);
 298         }
 299 
 300         g.setColor(holdc);
 301         g.setFont(holdf);
 302     }
 303 
 304     // All this had to be copied from BasicMenuItemUI, just to get the right keyModifiersText fn
 305     // and a few Mac tweaks
 306     protected Dimension getPreferredMenuItemSize(final JComponent c, final Icon checkIcon, final Icon arrowIcon, final int defaultTextIconGap, final Font acceleratorFont) {
 307         final JMenuItem b = (JMenuItem)c;
 308         final Icon icon = b.getIcon();
 309         final String text = b.getText();
 310         final KeyStroke accelerator = b.getAccelerator();
 311         String keyString = "", modifiersString = "";
 312 
 313         if (accelerator != null) {
 314             final int modifiers = accelerator.getModifiers();
 315             if (modifiers > 0) {
 316                 modifiersString = getKeyModifiersText(modifiers, true); // doesn't matter, this is just for metrics
 317             }
 318             final int keyCode = accelerator.getKeyCode();
 319             if (keyCode != 0) {
 320                 keyString = KeyEvent.getKeyText(keyCode);
 321             } else {
 322                 keyString += accelerator.getKeyChar();
 323             }
 324         }
 325 
 326         final Font font = b.getFont();
 327         final FontMetrics fm = b.getFontMetrics(font);
 328         final FontMetrics fmAccel = b.getFontMetrics(acceleratorFont);
 329 
 330         Rectangle iconRect = new Rectangle();
 331         Rectangle textRect = new Rectangle();
 332         Rectangle acceleratorRect = new Rectangle();
 333         Rectangle checkIconRect = new Rectangle();
 334         Rectangle arrowIconRect = new Rectangle();
 335         Rectangle viewRect = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE);
 336 
 337         layoutMenuItem(b, fm, text, fmAccel, keyString, modifiersString, icon, checkIcon, arrowIcon, b.getVerticalAlignment(), b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewRect, iconRect, textRect, acceleratorRect, checkIconRect, arrowIconRect, text == null ? 0 : defaultTextIconGap, defaultTextIconGap);
 338         // find the union of the icon and text rects
 339         Rectangle r = new Rectangle();
 340         r.setBounds(textRect);
 341         r = SwingUtilities.computeUnion(iconRect.x, iconRect.y, iconRect.width, iconRect.height, r);
 342         //   r = iconRect.union(textRect);
 343 
 344         // Add in the accelerator
 345         boolean acceleratorTextIsEmpty = (keyString == null) || keyString.isEmpty();
 346 
 347         if (!acceleratorTextIsEmpty) {
 348             r.width += acceleratorRect.width;
 349         }
 350 
 351         if (!isTopLevelMenu(b)) {
 352             // Add in the checkIcon
 353             r.width += checkIconRect.width;
 354             r.width += defaultTextIconGap;
 355 
 356             // Add in the arrowIcon space
 357             r.width += defaultTextIconGap;
 358             r.width += arrowIconRect.width;
 359         }
 360 
 361         final Insets insets = b.getInsets();
 362         if (insets != null) {
 363             r.width += insets.left + insets.right;
 364             r.height += insets.top + insets.bottom;
 365         }
 366 
 367         // Tweak for Mac
 368         r.width += 4 + defaultTextIconGap;
 369         r.height = Math.max(r.height, 18);
 370 
 371         return r.getSize();
 372     }
 373 
 374     protected void paintCheck(final Graphics g, final JMenuItem item, Icon checkIcon, Rectangle checkIconRect) {
 375         if (isTopLevelMenu(item) || !item.isSelected()) return;
 376 
 377         if (item.isArmed() && checkIcon instanceof InvertableIcon) {
 378             ((InvertableIcon)checkIcon).getInvertedIcon().paintIcon(item, g, checkIconRect.x, checkIconRect.y);
 379         } else {
 380             checkIcon.paintIcon(item, g, checkIconRect.x, checkIconRect.y);
 381         }
 382     }
 383 
 384     protected void paintIcon(final Graphics g, final JMenuItem c, final Rectangle localIconRect, boolean isEnabled) {
 385         final ButtonModel model = c.getModel();
 386         Icon icon;
 387         if (!isEnabled) {
 388             icon = c.getDisabledIcon();
 389         } else if (model.isPressed() && model.isArmed()) {
 390             icon = c.getPressedIcon();
 391             if (icon == null) {
 392                 // Use default icon
 393                 icon = c.getIcon();
 394             }
 395         } else {
 396             icon = c.getIcon();
 397         }
 398 
 399         if (icon != null) icon.paintIcon(c, g, localIconRect.x, localIconRect.y);
 400     }
 401 
 402     protected void paintArrow(Graphics g, JMenuItem c, ButtonModel model, Icon arrowIcon, Rectangle arrowIconRect) {
 403         if (isTopLevelMenu(c)) return;
 404 
 405         if (c instanceof JMenu && (model.isArmed() || model.isSelected()) && arrowIcon instanceof InvertableIcon) {
 406             ((InvertableIcon)arrowIcon).getInvertedIcon().paintIcon(c, g, arrowIconRect.x, arrowIconRect.y);
 407         } else {
 408             arrowIcon.paintIcon(c, g, arrowIconRect.x, arrowIconRect.y);
 409         }
 410     }
 411 
 412     /** Draw a string with the graphics g at location (x,y) just like g.drawString() would.
 413      *  The first occurrence of underlineChar in text will be underlined. The matching is
 414      *  not case sensitive.
 415      */
 416     public void drawString(final Graphics g, final JComponent c, final String text, final int underlinedChar, final int x, final int y, final boolean isEnabled, final boolean isSelected) {
 417         char lc, uc;
 418         int index = -1, lci, uci;
 419 
 420         if (underlinedChar != '\0') {
 421             uc = Character.toUpperCase((char)underlinedChar);
 422             lc = Character.toLowerCase((char)underlinedChar);
 423 
 424             uci = text.indexOf(uc);
 425             lci = text.indexOf(lc);
 426 
 427             if (uci == -1) index = lci;
 428             else if (lci == -1) index = uci;
 429             else index = (lci < uci) ? lci : uci;
 430         }
 431 
 432         SwingUtilities2.drawStringUnderlineCharAt(c, g, text, index, x, y);
 433     }
 434 
 435     /*
 436      * Returns false if the component is a JMenu and it is a top
 437      * level menu (on the menubar).
 438      */
 439     private static boolean isTopLevelMenu(final JMenuItem menuItem) {
 440         return (menuItem instanceof JMenu) && (((JMenu)menuItem).isTopLevelMenu());
 441     }
 442 
 443     private String layoutMenuItem(final JMenuItem menuItem, final FontMetrics fm, final String text, final FontMetrics fmAccel, String keyString, final String modifiersString, final Icon icon, final Icon checkIcon, final Icon arrowIcon, final int verticalAlignment, final int horizontalAlignment, final int verticalTextPosition, final int horizontalTextPosition, final Rectangle viewR, final Rectangle iconR, final Rectangle textR, final Rectangle acceleratorR, final Rectangle checkIconR, final Rectangle arrowIconR, final int textIconGap, final int menuItemGap) {
 444         // Force it to do "LEFT", then flip the rects if we're right-to-left
 445         SwingUtilities.layoutCompoundLabel(menuItem, fm, text, icon, verticalAlignment, SwingConstants.LEFT, verticalTextPosition, horizontalTextPosition, viewR, iconR, textR, textIconGap);
 446 
 447         final boolean acceleratorTextIsEmpty = (keyString == null) || keyString.isEmpty();
 448 
 449         if (acceleratorTextIsEmpty) {
 450             acceleratorR.width = acceleratorR.height = 0;
 451             keyString = "";
 452         } else {
 453             // Accel space doesn't overlap arrow space, even though items can't have both
 454             acceleratorR.width = SwingUtilities.computeStringWidth(fmAccel, modifiersString);
 455             // The keyStrings should all line up, so always adjust the width by the same amount
 456             // (if they're multi-char, they won't line up but at least they won't be cut off)
 457             acceleratorR.width += Math.max(fm.charWidth('M'), SwingUtilities.computeStringWidth(fm, keyString));
 458             acceleratorR.height = fmAccel.getHeight();
 459         }
 460 
 461         /* Initialize the checkIcon bounds rectangle checkIconR.
 462          */
 463 
 464         final boolean isTopLevelMenu = isTopLevelMenu(menuItem);
 465         if (!isTopLevelMenu) {
 466             if (checkIcon != null) {
 467                 checkIconR.width = checkIcon.getIconWidth();
 468                 checkIconR.height = checkIcon.getIconHeight();
 469             } else {
 470                 checkIconR.width = checkIconR.height = 16;
 471             }
 472 
 473             /* Initialize the arrowIcon bounds rectangle arrowIconR.
 474              */
 475 
 476             if (arrowIcon != null) {
 477                 arrowIconR.width = arrowIcon.getIconWidth();
 478                 arrowIconR.height = arrowIcon.getIconHeight();
 479             } else {
 480                 arrowIconR.width = arrowIconR.height = 16;
 481             }
 482 
 483             textR.x += 12;
 484             iconR.x += 12;
 485         }
 486 
 487         final Rectangle labelR = iconR.union(textR);
 488 
 489         // Position the Accelerator text rect
 490         // Menu shortcut text *ought* to have the letters left-justified - look at a menu with an "M" in it
 491         acceleratorR.x += (viewR.width - arrowIconR.width - acceleratorR.width);
 492         acceleratorR.y = viewR.y + (viewR.height / 2) - (acceleratorR.height / 2);
 493 
 494         if (!isTopLevelMenu) {
 495             //    if ( GetSysDirection() < 0 ) hierRect.right = hierRect.left + w + 4;
 496             //    else hierRect.left = hierRect.right - w - 4;
 497             arrowIconR.x = (viewR.width - arrowIconR.width) + 1;
 498             arrowIconR.y = viewR.y + (labelR.height / 2) - (arrowIconR.height / 2) + 1;
 499 
 500             checkIconR.y = viewR.y + (labelR.height / 2) - (checkIconR.height / 2);
 501             checkIconR.x = 5;
 502 
 503             textR.width += 8;
 504         }
 505 
 506         /*System.out.println("Layout: " +horizontalAlignment+ " v=" +viewR+"  c="+checkIconR+" i="+
 507          iconR+" t="+textR+" acc="+acceleratorR+" a="+arrowIconR);*/
 508 
 509         if (!AquaUtils.isLeftToRight(menuItem)) {
 510             // Flip the rectangles so that instead of [check][icon][text][accel/arrow] it's [accel/arrow][text][icon][check]
 511             final int w = viewR.width;
 512             checkIconR.x = w - (checkIconR.x + checkIconR.width);
 513             iconR.x = w - (iconR.x + iconR.width);
 514             textR.x = w - (textR.x + textR.width);
 515             acceleratorR.x = w - (acceleratorR.x + acceleratorR.width);
 516             arrowIconR.x = w - (arrowIconR.x + arrowIconR.width);
 517         }
 518         textR.x += menuItemGap;
 519         iconR.x += menuItemGap;
 520 
 521         return text;
 522     }
 523 
 524     public static Border getMenuBarPainter() {
 525         final AquaBorder border = new AquaBorder.Default();
 526         border.painter.state.set(Widget.MENU_BAR);
 527         return border;
 528     }
 529 
 530     public static Border getSelectedMenuBarItemPainter() {
 531         final AquaBorder border = new AquaBorder.Default();
 532         border.painter.state.set(Widget.MENU_TITLE);
 533         border.painter.state.set(State.PRESSED);
 534         return border;
 535     }
 536 
 537     public static Border getSelectedMenuItemPainter() {
 538         final AquaBorder border = new AquaBorder.Default();
 539         border.painter.state.set(Widget.MENU_ITEM);
 540         border.painter.state.set(State.PRESSED);
 541         return border;
 542     }
 543 }