1 /*
   2  * Copyright (c) 2011, 2013, 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     static final int sUnsupportedModifiersMask = ~(InputEvent.CTRL_MASK | InputEvent.ALT_MASK | InputEvent.SHIFT_MASK | InputEvent.META_MASK | ALT_GRAPH_MASK);
  78 
  79     interface Client {
  80         public void paintBackground(Graphics g, JComponent c, int menuWidth, int menuHeight);
  81     }
  82 
  83     // Return a string with the proper modifier glyphs
  84     static String getKeyModifiersText(final int modifiers, final boolean isLeftToRight) {
  85         return getKeyModifiersUnicode(modifiers, isLeftToRight);
  86     }
  87 
  88     // Return a string with the proper modifier glyphs
  89     private static String getKeyModifiersUnicode(final int modifiers, final boolean isLeftToRight) {
  90         final StringBuilder buf = new StringBuilder(2);
  91         // Order (from StandardMenuDef.c): control, option(alt), shift, cmd
  92         // reverse for right-to-left
  93         //$ check for substitute key glyphs for localization
  94         if (isLeftToRight) {
  95             if ((modifiers & InputEvent.CTRL_MASK) != 0) {
  96                 buf.append(kUControlGlyph);
  97             }
  98             if ((modifiers & (InputEvent.ALT_MASK | ALT_GRAPH_MASK)) != 0) {
  99                 buf.append(kUOptionGlyph);
 100             }
 101             if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
 102                 buf.append(kUShiftGlyph);
 103             }
 104             if ((modifiers & InputEvent.META_MASK) != 0) {
 105                 buf.append(kUCommandGlyph);
 106             }
 107         } else {
 108             if ((modifiers & InputEvent.META_MASK) != 0) {
 109                 buf.append(kUCommandGlyph);
 110             }
 111             if ((modifiers & InputEvent.SHIFT_MASK) != 0) {
 112                 buf.append(kUShiftGlyph);
 113             }
 114             if ((modifiers & (InputEvent.ALT_MASK | ALT_GRAPH_MASK)) != 0) {
 115                 buf.append(kUOptionGlyph);
 116             }
 117             if ((modifiers & InputEvent.CTRL_MASK) != 0) {
 118                 buf.append(kUControlGlyph);
 119             }
 120         }
 121         return buf.toString();
 122     }
 123 
 124     static final RecyclableSingleton<AquaMenuPainter> sPainter = new RecyclableSingletonFromDefaultConstructor<AquaMenuPainter>(AquaMenuPainter.class);
 125     static AquaMenuPainter instance() {
 126         return sPainter.get();
 127     }
 128 
 129     static final int defaultMenuItemGap = 2;
 130     static final int kAcceleratorArrowSpace = 16; // Accel space doesn't overlap arrow space, even though items can't have both
 131 
 132     static class RecyclableBorder extends RecyclableSingleton<Border> {
 133         final String borderName;
 134         RecyclableBorder(final String borderName) { this.borderName = borderName; }
 135         protected Border getInstance() { return UIManager.getBorder(borderName); }
 136     }
 137 
 138     protected final RecyclableBorder menuBarPainter = new RecyclableBorder("MenuBar.backgroundPainter");
 139     protected final RecyclableBorder selectedMenuBarItemPainter = new RecyclableBorder("MenuBar.selectedBackgroundPainter");
 140     protected final RecyclableBorder selectedMenuItemPainter = new RecyclableBorder("MenuItem.selectedBackgroundPainter");
 141 
 142     public void paintMenuBarBackground(final Graphics g, final int width, final int height, final JComponent c) {
 143         g.setColor(c == null ? Color.white : c.getBackground());
 144         g.fillRect(0, 0, width, height);
 145         menuBarPainter.get().paintBorder(null, g, 0, 0, width, height);
 146     }
 147 
 148     public void paintSelectedMenuTitleBackground(final Graphics g, final int width, final int height) {
 149         selectedMenuBarItemPainter.get().paintBorder(null, g, -1, 0, width + 2, height);
 150     }
 151 
 152     public void paintSelectedMenuItemBackground(final Graphics g, final int width, final int height) {
 153         selectedMenuItemPainter.get().paintBorder(null, g, 0, 0, width, height);
 154     }
 155 
 156     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) {
 157         final JMenuItem b = (JMenuItem)c;
 158         final ButtonModel model = b.getModel();
 159 
 160 //        Dimension size = b.getSize();
 161         final int menuWidth = b.getWidth();
 162         final int menuHeight = b.getHeight();
 163         final Insets i = c.getInsets();
 164 
 165         Rectangle viewRect = new Rectangle(0, 0, menuWidth, menuHeight);
 166 
 167         viewRect.x += i.left;
 168         viewRect.y += i.top;
 169         viewRect.width -= (i.right + viewRect.x);
 170         viewRect.height -= (i.bottom + viewRect.y);
 171 
 172         final Font holdf = g.getFont();
 173         final Color holdc = g.getColor();
 174         final Font f = c.getFont();
 175         g.setFont(f);
 176         final FontMetrics fm = g.getFontMetrics(f);
 177 
 178         final FontMetrics fmAccel = g.getFontMetrics(acceleratorFont);
 179 
 180         // Paint background (doesn't touch the Graphics object's color)
 181         if (c.isOpaque()) {
 182             client.paintBackground(g, c, menuWidth, menuHeight);
 183         }
 184 
 185         // get Accelerator text
 186         final KeyStroke accelerator = b.getAccelerator();
 187         String modifiersString = "", keyString = "";
 188         final boolean leftToRight = AquaUtils.isLeftToRight(c);
 189         if (accelerator != null) {
 190             final int modifiers = accelerator.getModifiers();
 191             if (modifiers > 0) {
 192                 modifiersString = getKeyModifiersText(modifiers, leftToRight);
 193             }
 194             final int keyCode = accelerator.getKeyCode();
 195             if (keyCode != 0) {
 196                 keyString = KeyEvent.getKeyText(keyCode);
 197             } else {
 198                 keyString += accelerator.getKeyChar();
 199             }
 200         }
 201 
 202         Rectangle iconRect = new Rectangle();
 203         Rectangle textRect = new Rectangle();
 204         Rectangle acceleratorRect = new Rectangle();
 205         Rectangle checkIconRect = new Rectangle();
 206         Rectangle arrowIconRect = new Rectangle();
 207 
 208         // layout the text and icon
 209         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);
 210 
 211         // if this is in a AquaScreenMenuBar that's attached to a DialogPeer
 212         // the native menu will be disabled, though the awt Menu won't know about it
 213         // so the JPopupMenu will not have visibility set and the items should draw disabled
 214         // If it's not on a JPopupMenu then it should just use the model's enable state
 215         final Container parent = b.getParent();
 216         final boolean parentIsMenuBar = parent instanceof JMenuBar;
 217 
 218         Container ancestor = parent;
 219         while (ancestor != null && !(ancestor instanceof JPopupMenu)) ancestor = ancestor.getParent();
 220 
 221         boolean isEnabled = model.isEnabled() && (ancestor == null || ancestor.isVisible());
 222 
 223         // Set the accel/normal text color
 224         boolean isSelected = false;
 225         if (!isEnabled) {
 226             // *** paint the text disabled
 227             g.setColor(disabledForeground);
 228         } else {
 229             // *** paint the text normally
 230             if (model.isArmed() || (c instanceof JMenu && model.isSelected())) {
 231                 g.setColor(selectionForeground);
 232                 isSelected = true;
 233             } else {
 234                 g.setColor(parentIsMenuBar ? parent.getForeground() : b.getForeground()); // Which is either MenuItem.foreground or the user's choice
 235             }
 236         }
 237 
 238         // We want to paint the icon after the text color is set since some icon painting depends on the correct
 239         // graphics color being set
 240         // See <rdar://problem/3792383> Menu icons missing in Java2D's Lines.Joins demo
 241         // Paint the Icon
 242         if (b.getIcon() != null) {
 243             paintIcon(g, b, iconRect, isEnabled);
 244         }
 245 
 246         // Paint the Check using the current text color
 247         if (checkIcon != null) {
 248             paintCheck(g, b, checkIcon, checkIconRect);
 249         }
 250 
 251         // Draw the accelerator first in case the HTML renderer changes the color
 252         if (keyString != null && !keyString.equals("")) {
 253             final int yAccel = acceleratorRect.y + fm.getAscent();
 254             if (modifiersString.equals("")) {
 255                 // just draw the keyString
 256                 SwingUtilities2.drawString(c, g, keyString, acceleratorRect.x, yAccel);
 257             } else {
 258                 final int modifiers = accelerator.getModifiers();
 259                 int underlinedChar = 0;
 260                 if ((modifiers & ALT_GRAPH_MASK) > 0) underlinedChar = kUOptionGlyph; // This is a Java2 thing, we won't be getting kOptionGlyph
 261                 // The keyStrings should all line up, so always adjust the width by the same amount
 262                 // (if they're multi-char, they won't line up but at least they won't be cut off)
 263                 final int emWidth = Math.max(fm.charWidth('M'), SwingUtilities.computeStringWidth(fm, keyString));
 264 
 265                 if (leftToRight) {
 266                     g.setFont(acceleratorFont);
 267                     drawString(g, c, modifiersString, underlinedChar, acceleratorRect.x, yAccel, isEnabled, isSelected);
 268                     g.setFont(f);
 269                     SwingUtilities2.drawString(c, g, keyString, acceleratorRect.x + acceleratorRect.width - emWidth, yAccel);
 270                 } else {
 271                     final int xAccel = acceleratorRect.x + emWidth;
 272                     g.setFont(acceleratorFont);
 273                     drawString(g, c, modifiersString, underlinedChar, xAccel, yAccel, isEnabled, isSelected);
 274                     g.setFont(f);
 275                     SwingUtilities2.drawString(c, g, keyString, xAccel - fm.stringWidth(keyString), yAccel);
 276                 }
 277             }
 278         }
 279 
 280         // Draw the Text
 281         if (text != null && !text.equals("")) {
 282             final View v = (View)c.getClientProperty(BasicHTML.propertyKey);
 283             if (v != null) {
 284                 v.paint(g, textRect);
 285             } else {
 286                 final int mnemonic = (AquaMnemonicHandler.isMnemonicHidden() ? -1 : model.getMnemonic());
 287                 drawString(g, c, text, mnemonic, textRect.x, textRect.y + fm.getAscent(), isEnabled, isSelected);
 288             }
 289         }
 290 
 291         // Paint the Arrow
 292         if (arrowIcon != null) {
 293             paintArrow(g, b, model, arrowIcon, arrowIconRect);
 294         }
 295 
 296         g.setColor(holdc);
 297         g.setFont(holdf);
 298     }
 299 
 300     // All this had to be copied from BasicMenuItemUI, just to get the right keyModifiersText fn
 301     // and a few Mac tweaks
 302     protected Dimension getPreferredMenuItemSize(final JComponent c, final Icon checkIcon, final Icon arrowIcon, final int defaultTextIconGap, final Font acceleratorFont) {
 303         final JMenuItem b = (JMenuItem)c;
 304         final Icon icon = b.getIcon();
 305         final String text = b.getText();
 306         final KeyStroke accelerator = b.getAccelerator();
 307         String keyString = "", modifiersString = "";
 308 
 309         if (accelerator != null) {
 310             final int modifiers = accelerator.getModifiers();
 311             if (modifiers > 0) {
 312                 modifiersString = getKeyModifiersText(modifiers, true); // doesn't matter, this is just for metrics
 313             }
 314             final int keyCode = accelerator.getKeyCode();
 315             if (keyCode != 0) {
 316                 keyString = KeyEvent.getKeyText(keyCode);
 317             } else {
 318                 keyString += accelerator.getKeyChar();
 319             }
 320         }
 321 
 322         final Font font = b.getFont();
 323         final FontMetrics fm = b.getFontMetrics(font);
 324         final FontMetrics fmAccel = b.getFontMetrics(acceleratorFont);
 325 
 326         Rectangle iconRect = new Rectangle();
 327         Rectangle textRect = new Rectangle();
 328         Rectangle acceleratorRect = new Rectangle();
 329         Rectangle checkIconRect = new Rectangle();
 330         Rectangle arrowIconRect = new Rectangle();
 331         Rectangle viewRect = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE);
 332 
 333         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);
 334         // find the union of the icon and text rects
 335         Rectangle r = new Rectangle();
 336         r.setBounds(textRect);
 337         r = SwingUtilities.computeUnion(iconRect.x, iconRect.y, iconRect.width, iconRect.height, r);
 338         //   r = iconRect.union(textRect);
 339 
 340         // Add in the accelerator
 341         boolean acceleratorTextIsEmpty = (keyString == null) || keyString.equals("");
 342 
 343         if (!acceleratorTextIsEmpty) {
 344             r.width += acceleratorRect.width;
 345         }
 346 
 347         if (!isTopLevelMenu(b)) {
 348             // Add in the checkIcon
 349             r.width += checkIconRect.width;
 350             r.width += defaultTextIconGap;
 351 
 352             // Add in the arrowIcon space
 353             r.width += defaultTextIconGap;
 354             r.width += arrowIconRect.width;
 355         }
 356 
 357         final Insets insets = b.getInsets();
 358         if (insets != null) {
 359             r.width += insets.left + insets.right;
 360             r.height += insets.top + insets.bottom;
 361         }
 362 
 363         // Tweak for Mac
 364         r.width += 4 + defaultTextIconGap;
 365         r.height = Math.max(r.height, 18);
 366 
 367         return r.getSize();
 368     }
 369 
 370     protected void paintCheck(final Graphics g, final JMenuItem item, Icon checkIcon, Rectangle checkIconRect) {
 371         if (isTopLevelMenu(item) || !item.isSelected()) return;
 372 
 373         if (item.isArmed() && checkIcon instanceof InvertableIcon) {
 374             ((InvertableIcon)checkIcon).getInvertedIcon().paintIcon(item, g, checkIconRect.x, checkIconRect.y);
 375         } else {
 376             checkIcon.paintIcon(item, g, checkIconRect.x, checkIconRect.y);
 377         }
 378     }
 379 
 380     protected void paintIcon(final Graphics g, final JMenuItem c, final Rectangle localIconRect, boolean isEnabled) {
 381         final ButtonModel model = c.getModel();
 382         Icon icon;
 383         if (!isEnabled) {
 384             icon = c.getDisabledIcon();
 385         } else if (model.isPressed() && model.isArmed()) {
 386             icon = c.getPressedIcon();
 387             if (icon == null) {
 388                 // Use default icon
 389                 icon = c.getIcon();
 390             }
 391         } else {
 392             icon = c.getIcon();
 393         }
 394 
 395         if (icon != null) icon.paintIcon(c, g, localIconRect.x, localIconRect.y);
 396     }
 397 
 398     protected void paintArrow(Graphics g, JMenuItem c, ButtonModel model, Icon arrowIcon, Rectangle arrowIconRect) {
 399         if (isTopLevelMenu(c)) return;
 400 
 401         if (c instanceof JMenu && (model.isArmed() || model.isSelected()) && arrowIcon instanceof InvertableIcon) {
 402             ((InvertableIcon)arrowIcon).getInvertedIcon().paintIcon(c, g, arrowIconRect.x, arrowIconRect.y);
 403         } else {
 404             arrowIcon.paintIcon(c, g, arrowIconRect.x, arrowIconRect.y);
 405         }
 406     }
 407 
 408     /** Draw a string with the graphics g at location (x,y) just like g.drawString() would.
 409      *  The first occurrence of underlineChar in text will be underlined. The matching is
 410      *  not case sensitive.
 411      */
 412     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) {
 413         char lc, uc;
 414         int index = -1, lci, uci;
 415 
 416         if (underlinedChar != '\0') {
 417             uc = Character.toUpperCase((char)underlinedChar);
 418             lc = Character.toLowerCase((char)underlinedChar);
 419 
 420             uci = text.indexOf(uc);
 421             lci = text.indexOf(lc);
 422 
 423             if (uci == -1) index = lci;
 424             else if (lci == -1) index = uci;
 425             else index = (lci < uci) ? lci : uci;
 426         }
 427 
 428         SwingUtilities2.drawStringUnderlineCharAt(c, g, text, index, x, y);
 429     }
 430 
 431     /*
 432      * Returns false if the component is a JMenu and it is a top
 433      * level menu (on the menubar).
 434      */
 435     private static boolean isTopLevelMenu(final JMenuItem menuItem) {
 436         return (menuItem instanceof JMenu) && (((JMenu)menuItem).isTopLevelMenu());
 437     }
 438 
 439     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) {
 440         // Force it to do "LEFT", then flip the rects if we're right-to-left
 441         SwingUtilities.layoutCompoundLabel(menuItem, fm, text, icon, verticalAlignment, SwingConstants.LEFT, verticalTextPosition, horizontalTextPosition, viewR, iconR, textR, textIconGap);
 442 
 443         final boolean acceleratorTextIsEmpty = (keyString == null) || keyString.equals("");
 444 
 445         if (acceleratorTextIsEmpty) {
 446             acceleratorR.width = acceleratorR.height = 0;
 447             keyString = "";
 448         } else {
 449             // Accel space doesn't overlap arrow space, even though items can't have both
 450             acceleratorR.width = SwingUtilities.computeStringWidth(fmAccel, modifiersString);
 451             // The keyStrings should all line up, so always adjust the width by the same amount
 452             // (if they're multi-char, they won't line up but at least they won't be cut off)
 453             acceleratorR.width += Math.max(fm.charWidth('M'), SwingUtilities.computeStringWidth(fm, keyString));
 454             acceleratorR.height = fmAccel.getHeight();
 455         }
 456 
 457         /* Initialize the checkIcon bounds rectangle checkIconR.
 458          */
 459 
 460         final boolean isTopLevelMenu = isTopLevelMenu(menuItem);
 461         if (!isTopLevelMenu) {
 462             if (checkIcon != null) {
 463                 checkIconR.width = checkIcon.getIconWidth();
 464                 checkIconR.height = checkIcon.getIconHeight();
 465             } else {
 466                 checkIconR.width = checkIconR.height = 16;
 467             }
 468 
 469             /* Initialize the arrowIcon bounds rectangle arrowIconR.
 470              */
 471 
 472             if (arrowIcon != null) {
 473                 arrowIconR.width = arrowIcon.getIconWidth();
 474                 arrowIconR.height = arrowIcon.getIconHeight();
 475             } else {
 476                 arrowIconR.width = arrowIconR.height = 16;
 477             }
 478 
 479             textR.x += 12;
 480             iconR.x += 12;
 481         }
 482 
 483         final Rectangle labelR = iconR.union(textR);
 484 
 485         // Position the Accelerator text rect
 486         // Menu shortcut text *ought* to have the letters left-justified - look at a menu with an "M" in it
 487         acceleratorR.x += (viewR.width - arrowIconR.width - acceleratorR.width);
 488         acceleratorR.y = viewR.y + (viewR.height / 2) - (acceleratorR.height / 2);
 489 
 490         if (!isTopLevelMenu) {
 491             //    if ( GetSysDirection() < 0 ) hierRect.right = hierRect.left + w + 4;
 492             //    else hierRect.left = hierRect.right - w - 4;
 493             arrowIconR.x = (viewR.width - arrowIconR.width) + 1;
 494             arrowIconR.y = viewR.y + (labelR.height / 2) - (arrowIconR.height / 2) + 1;
 495 
 496             checkIconR.y = viewR.y + (labelR.height / 2) - (checkIconR.height / 2);
 497             checkIconR.x = 5;
 498 
 499             textR.width += 8;
 500         }
 501 
 502         /*System.out.println("Layout: " +horizontalAlignment+ " v=" +viewR+"  c="+checkIconR+" i="+
 503          iconR+" t="+textR+" acc="+acceleratorR+" a="+arrowIconR);*/
 504 
 505         if (!AquaUtils.isLeftToRight(menuItem)) {
 506             // Flip the rectangles so that instead of [check][icon][text][accel/arrow] it's [accel/arrow][text][icon][check]
 507             final int w = viewR.width;
 508             checkIconR.x = w - (checkIconR.x + checkIconR.width);
 509             iconR.x = w - (iconR.x + iconR.width);
 510             textR.x = w - (textR.x + textR.width);
 511             acceleratorR.x = w - (acceleratorR.x + acceleratorR.width);
 512             arrowIconR.x = w - (arrowIconR.x + arrowIconR.width);
 513         }
 514         textR.x += menuItemGap;
 515         iconR.x += menuItemGap;
 516 
 517         return text;
 518     }
 519 
 520     public static Border getMenuBarPainter() {
 521         final AquaBorder border = new AquaBorder.Default();
 522         border.painter.state.set(Widget.MENU_BAR);
 523         return border;
 524     }
 525 
 526     public static Border getSelectedMenuBarItemPainter() {
 527         final AquaBorder border = new AquaBorder.Default();
 528         border.painter.state.set(Widget.MENU_TITLE);
 529         border.painter.state.set(State.PRESSED);
 530         return border;
 531     }
 532 
 533     public static Border getSelectedMenuItemPainter() {
 534         final AquaBorder border = new AquaBorder.Default();
 535         border.painter.state.set(Widget.MENU_ITEM);
 536         border.painter.state.set(State.PRESSED);
 537         return border;
 538     }
 539 }