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.getTextUIDrawing(c).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.getTextUIDrawing(c)
 270                             .drawString(c, g, keyString,
 271                                         acceleratorRect.x + acceleratorRect.width - emWidth,
 272                                         yAccel);
 273                 } else {
 274                     final int xAccel = acceleratorRect.x + emWidth;
 275                     g.setFont(acceleratorFont);
 276                     drawString(g, c, modifiersString, underlinedChar, xAccel, yAccel, isEnabled, isSelected);
 277                     g.setFont(f);
 278                     SwingUtilities2.getTextUIDrawing(c)
 279                             .drawString(c, g, keyString,
 280                                         xAccel - fm.stringWidth(keyString),
 281                                         yAccel);
 282                 }
 283             }
 284         }
 285 
 286         // Draw the Text
 287         if (text != null && !text.equals("")) {
 288             final View v = (View)c.getClientProperty(BasicHTML.propertyKey);
 289             if (v != null) {
 290                 v.paint(g, textRect);
 291             } else {
 292                 final int mnemonic = (AquaMnemonicHandler.isMnemonicHidden() ? -1 : model.getMnemonic());
 293                 drawString(g, c, text, mnemonic, textRect.x, textRect.y + fm.getAscent(), isEnabled, isSelected);
 294             }
 295         }
 296 
 297         // Paint the Arrow
 298         if (arrowIcon != null) {
 299             paintArrow(g, b, model, arrowIcon, arrowIconRect);
 300         }
 301 
 302         g.setColor(holdc);
 303         g.setFont(holdf);
 304     }
 305 
 306     // All this had to be copied from BasicMenuItemUI, just to get the right keyModifiersText fn
 307     // and a few Mac tweaks
 308     protected Dimension getPreferredMenuItemSize(final JComponent c, final Icon checkIcon, final Icon arrowIcon, final int defaultTextIconGap, final Font acceleratorFont) {
 309         final JMenuItem b = (JMenuItem)c;
 310         final Icon icon = b.getIcon();
 311         final String text = b.getText();
 312         final KeyStroke accelerator = b.getAccelerator();
 313         String keyString = "", modifiersString = "";
 314 
 315         if (accelerator != null) {
 316             final int modifiers = accelerator.getModifiers();
 317             if (modifiers > 0) {
 318                 modifiersString = getKeyModifiersText(modifiers, true); // doesn't matter, this is just for metrics
 319             }
 320             final int keyCode = accelerator.getKeyCode();
 321             if (keyCode != 0) {
 322                 keyString = KeyEvent.getKeyText(keyCode);
 323             } else {
 324                 keyString += accelerator.getKeyChar();
 325             }
 326         }
 327 
 328         final Font font = b.getFont();
 329         final FontMetrics fm = b.getFontMetrics(font);
 330         final FontMetrics fmAccel = b.getFontMetrics(acceleratorFont);
 331 
 332         Rectangle iconRect = new Rectangle();
 333         Rectangle textRect = new Rectangle();
 334         Rectangle acceleratorRect = new Rectangle();
 335         Rectangle checkIconRect = new Rectangle();
 336         Rectangle arrowIconRect = new Rectangle();
 337         Rectangle viewRect = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE);
 338 
 339         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);
 340         // find the union of the icon and text rects
 341         Rectangle r = new Rectangle();
 342         r.setBounds(textRect);
 343         r = SwingUtilities.computeUnion(iconRect.x, iconRect.y, iconRect.width, iconRect.height, r);
 344         //   r = iconRect.union(textRect);
 345 
 346         // Add in the accelerator
 347         boolean acceleratorTextIsEmpty = (keyString == null) || keyString.equals("");
 348 
 349         if (!acceleratorTextIsEmpty) {
 350             r.width += acceleratorRect.width;
 351         }
 352 
 353         if (!isTopLevelMenu(b)) {
 354             // Add in the checkIcon
 355             r.width += checkIconRect.width;
 356             r.width += defaultTextIconGap;
 357 
 358             // Add in the arrowIcon space
 359             r.width += defaultTextIconGap;
 360             r.width += arrowIconRect.width;
 361         }
 362 
 363         final Insets insets = b.getInsets();
 364         if (insets != null) {
 365             r.width += insets.left + insets.right;
 366             r.height += insets.top + insets.bottom;
 367         }
 368 
 369         // Tweak for Mac
 370         r.width += 4 + defaultTextIconGap;
 371         r.height = Math.max(r.height, 18);
 372 
 373         return r.getSize();
 374     }
 375 
 376     protected void paintCheck(final Graphics g, final JMenuItem item, Icon checkIcon, Rectangle checkIconRect) {
 377         if (isTopLevelMenu(item) || !item.isSelected()) return;
 378 
 379         if (item.isArmed() && checkIcon instanceof InvertableIcon) {
 380             ((InvertableIcon)checkIcon).getInvertedIcon().paintIcon(item, g, checkIconRect.x, checkIconRect.y);
 381         } else {
 382             checkIcon.paintIcon(item, g, checkIconRect.x, checkIconRect.y);
 383         }
 384     }
 385 
 386     protected void paintIcon(final Graphics g, final JMenuItem c, final Rectangle localIconRect, boolean isEnabled) {
 387         final ButtonModel model = c.getModel();
 388         Icon icon;
 389         if (!isEnabled) {
 390             icon = c.getDisabledIcon();
 391         } else if (model.isPressed() && model.isArmed()) {
 392             icon = c.getPressedIcon();
 393             if (icon == null) {
 394                 // Use default icon
 395                 icon = c.getIcon();
 396             }
 397         } else {
 398             icon = c.getIcon();
 399         }
 400 
 401         if (icon != null) icon.paintIcon(c, g, localIconRect.x, localIconRect.y);
 402     }
 403 
 404     protected void paintArrow(Graphics g, JMenuItem c, ButtonModel model, Icon arrowIcon, Rectangle arrowIconRect) {
 405         if (isTopLevelMenu(c)) return;
 406 
 407         if (c instanceof JMenu && (model.isArmed() || model.isSelected()) && arrowIcon instanceof InvertableIcon) {
 408             ((InvertableIcon)arrowIcon).getInvertedIcon().paintIcon(c, g, arrowIconRect.x, arrowIconRect.y);
 409         } else {
 410             arrowIcon.paintIcon(c, g, arrowIconRect.x, arrowIconRect.y);
 411         }
 412     }
 413 
 414     /** Draw a string with the graphics g at location (x,y) just like g.drawString() would.
 415      *  The first occurrence of underlineChar in text will be underlined. The matching is
 416      *  not case sensitive.
 417      */
 418     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) {
 419         char lc, uc;
 420         int index = -1, lci, uci;
 421 
 422         if (underlinedChar != '\0') {
 423             uc = Character.toUpperCase((char)underlinedChar);
 424             lc = Character.toLowerCase((char)underlinedChar);
 425 
 426             uci = text.indexOf(uc);
 427             lci = text.indexOf(lc);
 428 
 429             if (uci == -1) index = lci;
 430             else if (lci == -1) index = uci;
 431             else index = (lci < uci) ? lci : uci;
 432         }
 433 
 434         SwingUtilities2.getTextUIDrawing(c)
 435                 .drawStringUnderlineCharAt(c, g, text, index, x, y);
 436     }
 437 
 438     /*
 439      * Returns false if the component is a JMenu and it is a top
 440      * level menu (on the menubar).
 441      */
 442     private static boolean isTopLevelMenu(final JMenuItem menuItem) {
 443         return (menuItem instanceof JMenu) && (((JMenu)menuItem).isTopLevelMenu());
 444     }
 445 
 446     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) {
 447         // Force it to do "LEFT", then flip the rects if we're right-to-left
 448         SwingUtilities.layoutCompoundLabel(menuItem, fm, text, icon, verticalAlignment, SwingConstants.LEFT, verticalTextPosition, horizontalTextPosition, viewR, iconR, textR, textIconGap);
 449 
 450         final boolean acceleratorTextIsEmpty = (keyString == null) || keyString.equals("");
 451 
 452         if (acceleratorTextIsEmpty) {
 453             acceleratorR.width = acceleratorR.height = 0;
 454             keyString = "";
 455         } else {
 456             // Accel space doesn't overlap arrow space, even though items can't have both
 457             acceleratorR.width = SwingUtilities.computeStringWidth(fmAccel, modifiersString);
 458             // The keyStrings should all line up, so always adjust the width by the same amount
 459             // (if they're multi-char, they won't line up but at least they won't be cut off)
 460             acceleratorR.width += Math.max(fm.charWidth('M'), SwingUtilities.computeStringWidth(fm, keyString));
 461             acceleratorR.height = fmAccel.getHeight();
 462         }
 463 
 464         /* Initialize the checkIcon bounds rectangle checkIconR.
 465          */
 466 
 467         final boolean isTopLevelMenu = isTopLevelMenu(menuItem);
 468         if (!isTopLevelMenu) {
 469             if (checkIcon != null) {
 470                 checkIconR.width = checkIcon.getIconWidth();
 471                 checkIconR.height = checkIcon.getIconHeight();
 472             } else {
 473                 checkIconR.width = checkIconR.height = 16;
 474             }
 475 
 476             /* Initialize the arrowIcon bounds rectangle arrowIconR.
 477              */
 478 
 479             if (arrowIcon != null) {
 480                 arrowIconR.width = arrowIcon.getIconWidth();
 481                 arrowIconR.height = arrowIcon.getIconHeight();
 482             } else {
 483                 arrowIconR.width = arrowIconR.height = 16;
 484             }
 485 
 486             textR.x += 12;
 487             iconR.x += 12;
 488         }
 489 
 490         final Rectangle labelR = iconR.union(textR);
 491 
 492         // Position the Accelerator text rect
 493         // Menu shortcut text *ought* to have the letters left-justified - look at a menu with an "M" in it
 494         acceleratorR.x += (viewR.width - arrowIconR.width - acceleratorR.width);
 495         acceleratorR.y = viewR.y + (viewR.height / 2) - (acceleratorR.height / 2);
 496 
 497         if (!isTopLevelMenu) {
 498             //    if ( GetSysDirection() < 0 ) hierRect.right = hierRect.left + w + 4;
 499             //    else hierRect.left = hierRect.right - w - 4;
 500             arrowIconR.x = (viewR.width - arrowIconR.width) + 1;
 501             arrowIconR.y = viewR.y + (labelR.height / 2) - (arrowIconR.height / 2) + 1;
 502 
 503             checkIconR.y = viewR.y + (labelR.height / 2) - (checkIconR.height / 2);
 504             checkIconR.x = 5;
 505 
 506             textR.width += 8;
 507         }
 508 
 509         /*System.out.println("Layout: " +horizontalAlignment+ " v=" +viewR+"  c="+checkIconR+" i="+
 510          iconR+" t="+textR+" acc="+acceleratorR+" a="+arrowIconR);*/
 511 
 512         if (!AquaUtils.isLeftToRight(menuItem)) {
 513             // Flip the rectangles so that instead of [check][icon][text][accel/arrow] it's [accel/arrow][text][icon][check]
 514             final int w = viewR.width;
 515             checkIconR.x = w - (checkIconR.x + checkIconR.width);
 516             iconR.x = w - (iconR.x + iconR.width);
 517             textR.x = w - (textR.x + textR.width);
 518             acceleratorR.x = w - (acceleratorR.x + acceleratorR.width);
 519             arrowIconR.x = w - (arrowIconR.x + arrowIconR.width);
 520         }
 521         textR.x += menuItemGap;
 522         iconR.x += menuItemGap;
 523 
 524         return text;
 525     }
 526 
 527     public static Border getMenuBarPainter() {
 528         final AquaBorder border = new AquaBorder.Default();
 529         border.painter.state.set(Widget.MENU_BAR);
 530         return border;
 531     }
 532 
 533     public static Border getSelectedMenuBarItemPainter() {
 534         final AquaBorder border = new AquaBorder.Default();
 535         border.painter.state.set(Widget.MENU_TITLE);
 536         border.painter.state.set(State.PRESSED);
 537         return border;
 538     }
 539 
 540     public static Border getSelectedMenuItemPainter() {
 541         final AquaBorder border = new AquaBorder.Default();
 542         border.painter.state.set(Widget.MENU_ITEM);
 543         border.painter.state.set(State.PRESSED);
 544         return border;
 545     }
 546 }