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 }