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     @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 {
paintBackground(Graphics g, JComponent c, int menuWidth, int menuHeight)83         public void paintBackground(Graphics g, JComponent c, int menuWidth, int menuHeight);
84     }
85 
86     // Return a string with the proper modifier glyphs
getKeyModifiersText(final int modifiers, final boolean isLeftToRight)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")
getKeyModifiersUnicode(final int modifiers, final boolean isLeftToRight)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);
instance()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;
RecyclableBorder(final String borderName)138         RecyclableBorder(final String borderName) { this.borderName = borderName; }
getInstance()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 
paintMenuBarBackground(final Graphics g, final int width, final int height, final JComponent c)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 
paintSelectedMenuTitleBackground(final Graphics g, final int width, final int height)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 
paintSelectedMenuItemBackground(final Graphics g, final int width, final int height)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 
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)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.equals("")) {
257             final int yAccel = acceleratorRect.y + fm.getAscent();
258             if (modifiersString.equals("")) {
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.equals("")) {
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
getPreferredMenuItemSize(final JComponent c, final Icon checkIcon, final Icon arrowIcon, final int defaultTextIconGap, final Font acceleratorFont)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.equals("");
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 
paintCheck(final Graphics g, final JMenuItem item, Icon checkIcon, Rectangle checkIconRect)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 
paintIcon(final Graphics g, final JMenuItem c, final Rectangle localIconRect, boolean isEnabled)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 
paintArrow(Graphics g, JMenuItem c, ButtonModel model, Icon arrowIcon, Rectangle arrowIconRect)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      */
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)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      */
isTopLevelMenu(final JMenuItem menuItem)439     private static boolean isTopLevelMenu(final JMenuItem menuItem) {
440         return (menuItem instanceof JMenu) && (((JMenu)menuItem).isTopLevelMenu());
441     }
442 
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)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.equals("");
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 
getMenuBarPainter()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 
getSelectedMenuBarItemPainter()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 
getSelectedMenuItemPainter()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 }
544