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 { 83 public void paintBackground(Graphics g, JComponent c, int menuWidth, int menuHeight); 84 } 85 86 // Return a string with the proper modifier glyphs 87 static String getKeyModifiersText(final int modifiers, final boolean isLeftToRight) { 88 return getKeyModifiersUnicode(modifiers, isLeftToRight); 89 } 90 91 // Return a string with the proper modifier glyphs 92 @SuppressWarnings("deprecation") 93 private static String getKeyModifiersUnicode(final int modifiers, final boolean isLeftToRight) { 94 final StringBuilder buf = new StringBuilder(2); 95 // Order (from StandardMenuDef.c): control, option(alt), shift, cmd 96 // reverse for right-to-left 97 //$ check for substitute key glyphs for localization 98 if (isLeftToRight) { 99 if ((modifiers & InputEvent.CTRL_MASK) != 0) { 100 buf.append(kUControlGlyph); 101 } 102 if ((modifiers & (InputEvent.ALT_MASK | ALT_GRAPH_MASK)) != 0) { 103 buf.append(kUOptionGlyph); 104 } 105 if ((modifiers & InputEvent.SHIFT_MASK) != 0) { 106 buf.append(kUShiftGlyph); 107 } 108 if ((modifiers & InputEvent.META_MASK) != 0) { 109 buf.append(kUCommandGlyph); 110 } 111 } else { 112 if ((modifiers & InputEvent.META_MASK) != 0) { 113 buf.append(kUCommandGlyph); 114 } 115 if ((modifiers & InputEvent.SHIFT_MASK) != 0) { 116 buf.append(kUShiftGlyph); 117 } 118 if ((modifiers & (InputEvent.ALT_MASK | ALT_GRAPH_MASK)) != 0) { 119 buf.append(kUOptionGlyph); 120 } 121 if ((modifiers & InputEvent.CTRL_MASK) != 0) { 122 buf.append(kUControlGlyph); 123 } 124 } 125 return buf.toString(); 126 } 127 128 static final RecyclableSingleton<AquaMenuPainter> sPainter = new RecyclableSingletonFromDefaultConstructor<AquaMenuPainter>(AquaMenuPainter.class); 129 static AquaMenuPainter instance() { 130 return sPainter.get(); 131 } 132 133 static final int defaultMenuItemGap = 2; 134 static final int kAcceleratorArrowSpace = 16; // Accel space doesn't overlap arrow space, even though items can't have both 135 136 static class RecyclableBorder extends RecyclableSingleton<Border> { 137 final String borderName; 138 RecyclableBorder(final String borderName) { this.borderName = borderName; } 139 protected Border getInstance() { return UIManager.getBorder(borderName); } 140 } 141 142 protected final RecyclableBorder menuBarPainter = new RecyclableBorder("MenuBar.backgroundPainter"); 143 protected final RecyclableBorder selectedMenuBarItemPainter = new RecyclableBorder("MenuBar.selectedBackgroundPainter"); 144 protected final RecyclableBorder selectedMenuItemPainter = new RecyclableBorder("MenuItem.selectedBackgroundPainter"); 145 146 public void paintMenuBarBackground(final Graphics g, final int width, final int height, final JComponent c) { 147 g.setColor(c == null ? Color.white : c.getBackground()); 148 g.fillRect(0, 0, width, height); 149 menuBarPainter.get().paintBorder(null, g, 0, 0, width, height); 150 } 151 152 public void paintSelectedMenuTitleBackground(final Graphics g, final int width, final int height) { 153 selectedMenuBarItemPainter.get().paintBorder(null, g, -1, 0, width + 2, height); 154 } 155 156 public void paintSelectedMenuItemBackground(final Graphics g, final int width, final int height) { 157 selectedMenuItemPainter.get().paintBorder(null, g, 0, 0, width, height); 158 } 159 160 protected void paintMenuItem(final Client client, final Graphics g, final JComponent c, final Icon checkIcon, final Icon arrowIcon, final Color background, final Color foreground, final Color disabledForeground, final Color selectionForeground, final int defaultTextIconGap, final Font acceleratorFont) { 161 final JMenuItem b = (JMenuItem)c; 162 final ButtonModel model = b.getModel(); 163 164 // Dimension size = b.getSize(); 165 final int menuWidth = b.getWidth(); 166 final int menuHeight = b.getHeight(); 167 final Insets i = c.getInsets(); 168 169 Rectangle viewRect = new Rectangle(0, 0, menuWidth, menuHeight); 170 171 viewRect.x += i.left; 172 viewRect.y += i.top; 173 viewRect.width -= (i.right + viewRect.x); 174 viewRect.height -= (i.bottom + viewRect.y); 175 176 final Font holdf = g.getFont(); 177 final Color holdc = g.getColor(); 178 final Font f = c.getFont(); 179 g.setFont(f); 180 final FontMetrics fm = g.getFontMetrics(f); 181 182 final FontMetrics fmAccel = g.getFontMetrics(acceleratorFont); 183 184 // Paint background (doesn't touch the Graphics object's color) 185 if (c.isOpaque()) { 186 client.paintBackground(g, c, menuWidth, menuHeight); 187 } 188 189 // get Accelerator text 190 final KeyStroke accelerator = b.getAccelerator(); 191 String modifiersString = "", keyString = ""; 192 final boolean leftToRight = AquaUtils.isLeftToRight(c); 193 if (accelerator != null) { 194 final int modifiers = accelerator.getModifiers(); 195 if (modifiers > 0) { 196 modifiersString = getKeyModifiersText(modifiers, leftToRight); 197 } 198 final int keyCode = accelerator.getKeyCode(); 199 if (keyCode != 0) { 200 keyString = KeyEvent.getKeyText(keyCode); 201 } else { 202 keyString += accelerator.getKeyChar(); 203 } 204 } 205 206 Rectangle iconRect = new Rectangle(); 207 Rectangle textRect = new Rectangle(); 208 Rectangle acceleratorRect = new Rectangle(); 209 Rectangle checkIconRect = new Rectangle(); 210 Rectangle arrowIconRect = new Rectangle(); 211 212 // layout the text and icon 213 final String text = layoutMenuItem(b, fm, b.getText(), fmAccel, keyString, modifiersString, b.getIcon(), checkIcon, arrowIcon, b.getVerticalAlignment(), b.getHorizontalAlignment(), b.getVerticalTextPosition(), b.getHorizontalTextPosition(), viewRect, iconRect, textRect, acceleratorRect, checkIconRect, arrowIconRect, b.getText() == null ? 0 : defaultTextIconGap, defaultTextIconGap); 214 215 // if this is in a AquaScreenMenuBar that's attached to a DialogPeer 216 // the native menu will be disabled, though the awt Menu won't know about it 217 // so the JPopupMenu will not have visibility set and the items should draw disabled 218 // If it's not on a JPopupMenu then it should just use the model's enable state 219 final Container parent = b.getParent(); 220 final boolean parentIsMenuBar = parent instanceof JMenuBar; 221 222 Container ancestor = parent; 223 while (ancestor != null && !(ancestor instanceof JPopupMenu)) ancestor = ancestor.getParent(); 224 225 boolean isEnabled = model.isEnabled() && (ancestor == null || ancestor.isVisible()); 226 227 // Set the accel/normal text color 228 boolean isSelected = false; 229 if (!isEnabled) { 230 // *** paint the text disabled 231 g.setColor(disabledForeground); 232 } else { 233 // *** paint the text normally 234 if (model.isArmed() || (c instanceof JMenu && model.isSelected())) { 235 g.setColor(selectionForeground); 236 isSelected = true; 237 } else { 238 g.setColor(parentIsMenuBar ? parent.getForeground() : b.getForeground()); // Which is either MenuItem.foreground or the user's choice 239 } 240 } 241 242 // We want to paint the icon after the text color is set since some icon painting depends on the correct 243 // graphics color being set 244 // See <rdar://problem/3792383> Menu icons missing in Java2D's Lines.Joins demo 245 // Paint the Icon 246 if (b.getIcon() != null) { 247 paintIcon(g, b, iconRect, isEnabled); 248 } 249 250 // Paint the Check using the current text color 251 if (checkIcon != null) { 252 paintCheck(g, b, checkIcon, checkIconRect); 253 } 254 255 // Draw the accelerator first in case the HTML renderer changes the color 256 if (keyString != null && !keyString.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 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 374 protected void paintCheck(final Graphics g, final JMenuItem item, Icon checkIcon, Rectangle checkIconRect) { 375 if (isTopLevelMenu(item) || !item.isSelected()) return; 376 377 if (item.isArmed() && checkIcon instanceof InvertableIcon) { 378 ((InvertableIcon)checkIcon).getInvertedIcon().paintIcon(item, g, checkIconRect.x, checkIconRect.y); 379 } else { 380 checkIcon.paintIcon(item, g, checkIconRect.x, checkIconRect.y); 381 } 382 } 383 384 protected void paintIcon(final Graphics g, final JMenuItem c, final Rectangle localIconRect, boolean isEnabled) { 385 final ButtonModel model = c.getModel(); 386 Icon icon; 387 if (!isEnabled) { 388 icon = c.getDisabledIcon(); 389 } else if (model.isPressed() && model.isArmed()) { 390 icon = c.getPressedIcon(); 391 if (icon == null) { 392 // Use default icon 393 icon = c.getIcon(); 394 } 395 } else { 396 icon = c.getIcon(); 397 } 398 399 if (icon != null) icon.paintIcon(c, g, localIconRect.x, localIconRect.y); 400 } 401 402 protected void paintArrow(Graphics g, JMenuItem c, ButtonModel model, Icon arrowIcon, Rectangle arrowIconRect) { 403 if (isTopLevelMenu(c)) return; 404 405 if (c instanceof JMenu && (model.isArmed() || model.isSelected()) && arrowIcon instanceof InvertableIcon) { 406 ((InvertableIcon)arrowIcon).getInvertedIcon().paintIcon(c, g, arrowIconRect.x, arrowIconRect.y); 407 } else { 408 arrowIcon.paintIcon(c, g, arrowIconRect.x, arrowIconRect.y); 409 } 410 } 411 412 /** Draw a string with the graphics g at location (x,y) just like g.drawString() would. 413 * The first occurrence of underlineChar in text will be underlined. The matching is 414 * not case sensitive. 415 */ 416 public void drawString(final Graphics g, final JComponent c, final String text, final int underlinedChar, final int x, final int y, final boolean isEnabled, final boolean isSelected) { 417 char lc, uc; 418 int index = -1, lci, uci; 419 420 if (underlinedChar != '\0') { 421 uc = Character.toUpperCase((char)underlinedChar); 422 lc = Character.toLowerCase((char)underlinedChar); 423 424 uci = text.indexOf(uc); 425 lci = text.indexOf(lc); 426 427 if (uci == -1) index = lci; 428 else if (lci == -1) index = uci; 429 else index = (lci < uci) ? lci : uci; 430 } 431 432 SwingUtilities2.drawStringUnderlineCharAt(c, g, text, index, x, y); 433 } 434 435 /* 436 * Returns false if the component is a JMenu and it is a top 437 * level menu (on the menubar). 438 */ 439 private static boolean isTopLevelMenu(final JMenuItem menuItem) { 440 return (menuItem instanceof JMenu) && (((JMenu)menuItem).isTopLevelMenu()); 441 } 442 443 private String layoutMenuItem(final JMenuItem menuItem, final FontMetrics fm, final String text, final FontMetrics fmAccel, String keyString, final String modifiersString, final Icon icon, final Icon checkIcon, final Icon arrowIcon, final int verticalAlignment, final int horizontalAlignment, final int verticalTextPosition, final int horizontalTextPosition, final Rectangle viewR, final Rectangle iconR, final Rectangle textR, final Rectangle acceleratorR, final Rectangle checkIconR, final Rectangle arrowIconR, final int textIconGap, final int menuItemGap) { 444 // Force it to do "LEFT", then flip the rects if we're right-to-left 445 SwingUtilities.layoutCompoundLabel(menuItem, fm, text, icon, verticalAlignment, SwingConstants.LEFT, verticalTextPosition, horizontalTextPosition, viewR, iconR, textR, textIconGap); 446 447 final boolean acceleratorTextIsEmpty = (keyString == null) || keyString.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 524 public static Border getMenuBarPainter() { 525 final AquaBorder border = new AquaBorder.Default(); 526 border.painter.state.set(Widget.MENU_BAR); 527 return border; 528 } 529 530 public static Border getSelectedMenuBarItemPainter() { 531 final AquaBorder border = new AquaBorder.Default(); 532 border.painter.state.set(Widget.MENU_TITLE); 533 border.painter.state.set(State.PRESSED); 534 return border; 535 } 536 537 public static Border getSelectedMenuItemPainter() { 538 final AquaBorder border = new AquaBorder.Default(); 539 border.painter.state.set(Widget.MENU_ITEM); 540 border.painter.state.set(State.PRESSED); 541 return border; 542 } 543 }