< prev index next >

src/java.desktop/macosx/classes/com/apple/laf/AquaMenuPainter.java

Print this page


   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


 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


 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         }


 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();


   1 /*
   2  * Copyright (c) 2011, 2019, 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


 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.isEmpty()) {
 257             final int yAccel = acceleratorRect.y + fm.getAscent();
 258             if (modifiersString.isEmpty()) {
 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.isEmpty()) {
 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


 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.isEmpty();
 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         }


 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.isEmpty();
 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();


< prev index next >