0001: /*
0002: * Copyright (c) 2005-2008 Substance Kirill Grouchnikov. All Rights Reserved.
0003: *
0004: * Redistribution and use in source and binary forms, with or without
0005: * modification, are permitted provided that the following conditions are met:
0006: *
0007: * o Redistributions of source code must retain the above copyright notice,
0008: * this list of conditions and the following disclaimer.
0009: *
0010: * o Redistributions in binary form must reproduce the above copyright notice,
0011: * this list of conditions and the following disclaimer in the documentation
0012: * and/or other materials provided with the distribution.
0013: *
0014: * o Neither the name of Substance Kirill Grouchnikov nor the names of
0015: * its contributors may be used to endorse or promote products derived
0016: * from this software without specific prior written permission.
0017: *
0018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
0020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
0021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
0022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
0023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
0024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
0025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
0026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
0027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0029: */
0030: package org.jvnet.substance.utils.menu;
0031:
0032: import java.awt.*;
0033: import java.awt.event.KeyEvent;
0034: import java.awt.geom.Area;
0035: import java.beans.PropertyChangeEvent;
0036: import java.beans.PropertyChangeListener;
0037:
0038: import javax.swing.*;
0039: import javax.swing.plaf.ButtonUI;
0040: import javax.swing.plaf.basic.BasicHTML;
0041: import javax.swing.text.View;
0042:
0043: import org.jvnet.lafwidget.layout.TransitionLayout;
0044: import org.jvnet.substance.*;
0045: import org.jvnet.substance.painter.text.SubstanceTextPainter;
0046: import org.jvnet.substance.utils.SubstanceCoreUtilities;
0047: import org.jvnet.substance.utils.SubstanceConstants.MenuGutterFillKind;
0048:
0049: /**
0050: * A collection of ugly finctions from
0051: * {@link javax.swing.plaf.basic.BasicMenuItemUI} since they are private. This
0052: * class is <b>for internal use only</b>.
0053: *
0054: * @author Kirill Grouchnikov
0055: */
0056: public class MenuUtilities {
0057: /**
0058: * Delegate for painting the background.
0059: */
0060: private static SubstanceMenuBackgroundDelegate backgroundDelegate = new SubstanceMenuBackgroundDelegate(
0061: 0.4f);
0062:
0063: public static final String LAYOUT_METRICS = "substancelaf.internal.menus.layoutMetrics";
0064:
0065: public static final String GUTTER_X = "substancelaf.internal.menus.gutterX";
0066:
0067: public static class MenuPropertyListener implements
0068: PropertyChangeListener {
0069: protected JMenuItem menuItem;
0070:
0071: public MenuPropertyListener(JMenuItem menuItem) {
0072: this .menuItem = menuItem;
0073: }
0074:
0075: public void install() {
0076: this .menuItem.addPropertyChangeListener(this );
0077: }
0078:
0079: public void uninstall() {
0080: this .menuItem.removePropertyChangeListener(this );
0081: }
0082:
0083: public void propertyChange(PropertyChangeEvent evt) {
0084: // if (!evt.getPropertyName().equals(
0085: // SubstanceMenu.SINGLE_MENU_TEXT_OFFSET))
0086: // SwingUtilities.invokeLater(new Runnable() {
0087: // public void run() {
0088: // menuItem.putClientProperty(
0089: // SubstanceMenu.SINGLE_MENU_TEXT_OFFSET, null);
0090: // if (menuItem.getParent() instanceof JPopupMenu) {
0091: // JPopupMenu parent = (JPopupMenu) menuItem
0092: // .getParent();
0093: // parent
0094: // .putClientProperty(
0095: // SubstanceMenu.SINGLE_MENU_TEXT_OFFSET,
0096: // null);
0097: // }
0098: // }
0099: // });
0100: if (!evt.getPropertyName().equals(
0101: MenuUtilities.LAYOUT_METRICS)) {
0102: SwingUtilities.invokeLater(new Runnable() {
0103: public void run() {
0104: MenuUtilities.cleanPopupLayoutMetrics(menuItem);
0105: }
0106: });
0107: }
0108: }
0109:
0110: }
0111:
0112: public static class MenuLayoutInfo {
0113: public Rectangle viewRect;
0114: public Rectangle iconRect;
0115: public Rectangle checkIconRect;
0116: public Rectangle textRect;
0117: public Rectangle acceleratorRect;
0118: public Rectangle arrowIconRect;
0119: public String text;
0120: }
0121:
0122: public static class MenuLayoutMetrics {
0123: public int maxIconWidth;
0124: public int maxCheckIconWidth;
0125: public int maxTextWidth;
0126: public int maxAcceleratorWidth;
0127: public int maxArrowIconWidth;
0128: public int maxGap;
0129: }
0130:
0131: /* Client Property keys for the icon and text maximal offsets */
0132: // static final StringBuffer MAX_ICON_OFFSET = new StringBuffer(
0133: // "maxIconOffset");
0134: //
0135: // static final StringBuffer MAX_TEXT_OFFSET = new StringBuffer(
0136: // "maxTextOffset");
0137: //
0138: // public static int getTextOffset(Component menuItemParent) {
0139: // if (!(menuItemParent instanceof JPopupMenu)) {
0140: // return 0;
0141: // }
0142: //
0143: // return getTextOffset(null, menuItemParent);
0144: // }
0145: // private static int getSingleItemTextOffset(JMenuItem menuItem) {
0146: // // Check if we have this property on the menu item.
0147: // Object prop = menuItem
0148: // .getClientProperty(SubstanceMenu.SINGLE_MENU_TEXT_OFFSET);
0149: // if (prop instanceof Integer) {
0150: // // This property is reset on every property change
0151: // // to the menu item. If the property exists, nothing
0152: // // has changed since the last time it was computed.
0153: // return (Integer) prop;
0154: // }
0155: //
0156: // SubstanceMenu ui = (SubstanceMenu) menuItem.getUI();
0157: // int result = MenuUtilities.getTextOffset(menuItem, ui
0158: // .getAcceleratorFont(), ui.getCheckIcon(), ui.getArrowIcon(), ui
0159: // .getDefaultTextIconGap());
0160: // // Now that the offset has been computed, set it on the menu item.
0161: // menuItem.putClientProperty(SubstanceMenu.SINGLE_MENU_TEXT_OFFSET,
0162: // result);
0163: // return result;
0164: // }
0165: // public static int getTextOffset(JMenuItem menuItem) {
0166: // return getTextOffset(menuItem, menuItem.getParent());
0167: // }
0168: //
0169: // public static int getTextOffset(JMenuItem menuItem, Component parent) {
0170: // if (!(parent instanceof JPopupMenu)) {
0171: // return getSingleItemTextOffset(menuItem);
0172: // }
0173: //
0174: // // test if there's a computed property on the parent
0175: // JPopupMenu popupMenu = (JPopupMenu) parent;
0176: // Object prop = popupMenu
0177: // .getClientProperty(SubstanceMenu.SINGLE_MENU_TEXT_OFFSET);
0178: // if (prop instanceof Integer) {
0179: // // This property is reset on every change to both the
0180: // // popup (adding / removing child menu component) and
0181: // // and each child component (on any property change).
0182: // // So, if this property exists on the popup menu, nothing
0183: // // has changed since the last time the offset was computed.
0184: // return (Integer) prop;
0185: // }
0186: // int maxTextOffset = -1;
0187: // int maxIconWidth = 0;
0188: // int maxIconX = 0;
0189: // int maxCheckIconX = 0;
0190: // int maxCheckIconWidth = 0;
0191: // // int maxViewRect = 0;
0192: // for (int i = 0; i < popupMenu.getComponentCount(); i++) {
0193: // Component comp = popupMenu.getComponent(i);
0194: // if (comp instanceof JMenuItem) {
0195: // JMenuItem childMenuItem = (JMenuItem) comp;
0196: // ButtonUI bui = childMenuItem.getUI();
0197: // if (!(bui instanceof SubstanceMenu))
0198: // continue;
0199: // SubstanceMenu ui = (SubstanceMenu) bui;
0200: // MenuLayoutInfo mli = MenuUtilities.getMenuLayoutInfo(
0201: // childMenuItem, ui.getAcceleratorFont(), ui
0202: // .getCheckIcon(), ui.getArrowIcon(), ui
0203: // .getDefaultTextIconGap());
0204: //
0205: // if (popupMenu.getComponentOrientation().isLeftToRight()) {
0206: // if (mli.textRect != null) {
0207: // maxTextOffset = Math.max(maxTextOffset, mli.textRect.x);
0208: // }
0209: // if (mli.iconRect != null) {
0210: // maxIconWidth = Math
0211: // .max(maxIconWidth, mli.iconRect.width
0212: // + ui.getDefaultTextIconGap());
0213: // maxIconX = Math.max(maxIconX, mli.iconRect.x);
0214: // }
0215: // if (mli.checkIconRect != null) {
0216: // maxCheckIconWidth = Math.max(maxCheckIconWidth,
0217: // mli.checkIconRect.width + 2
0218: // * ui.getDefaultTextIconGap());
0219: // maxCheckIconX = Math.max(maxCheckIconX,
0220: // mli.checkIconRect.x);
0221: // }
0222: // } else {
0223: // if (mli.textRect != null) {
0224: // maxTextOffset = Math.max(maxTextOffset, mli.viewRect.x
0225: // + mli.viewRect.width
0226: // - (mli.textRect.x + mli.textRect.width));
0227: // }
0228: // if (mli.iconRect != null) {
0229: // maxIconWidth = Math.max(maxIconWidth,
0230: // mli.iconRect.width + 2
0231: // * ui.getDefaultTextIconGap());
0232: // maxIconX = Math.max(maxIconX, mli.iconRect.x
0233: // + mli.iconRect.width);
0234: // }
0235: // if (mli.checkIconRect != null) {
0236: // maxCheckIconWidth = Math.max(maxCheckIconWidth,
0237: // mli.checkIconRect.width
0238: // + ui.getDefaultTextIconGap());
0239: // maxCheckIconX = Math.max(maxCheckIconX,
0240: // mli.checkIconRect.x + mli.checkIconRect.width);
0241: // }
0242: // // maxViewRect = Math.max(maxViewRect, mli.viewRect.x
0243: // // + mli.viewRect.width);
0244: // }
0245: //
0246: // //
0247: // // int childResult = MenuUtilities.getTextOffset(g,
0248: // // childMenuItem,
0249: // // ui.getAcceleratorFont(), ui.getCheckIcon(), ui
0250: // // .getArrowIcon(), ui.getDefaultTextIconGap());
0251: // // if (maxOffset < childResult)
0252: // // maxOffset = childResult;
0253: // }
0254: // }
0255: // // Now that the offset is computed, store it on the
0256: // // popup menu.
0257: // int maxOffset = Math.max(maxTextOffset, maxIconWidth
0258: // + maxCheckIconWidth);
0259: // if (popupMenu.getComponentOrientation().isLeftToRight()) {
0260: // maxOffset = Math.max(maxOffset, maxIconX + maxIconWidth);
0261: // maxOffset = Math.max(maxOffset, maxCheckIconX + maxCheckIconWidth);
0262: // } else {
0263: // // maxOffset = Math.max(maxOffset, maxViewRect
0264: // // - (maxIconX - maxIconWidth));
0265: // }
0266: // popupMenu.putClientProperty(SubstanceMenu.SINGLE_MENU_TEXT_OFFSET,
0267: // maxOffset);
0268: // return maxOffset;
0269: // }
0270: //
0271: // public static int getTextOffset(JMenuItem menuItem, Font acceleratorFont,
0272: // Icon checkIcon, Icon arrowIcon, int defaultTextIconGap) {
0273: //
0274: // // Dimension size = b.getSize();
0275: // // int menuWidth = menuItem.getWidth();
0276: // // int menuHeight = menuItem.getHeight();
0277: // Insets i = menuItem.getInsets();
0278: //
0279: // Rectangle iconRect = new Rectangle();
0280: // Rectangle textRect = new Rectangle();
0281: // Rectangle acceleratorRect = new Rectangle();
0282: // Rectangle checkIconRect = new Rectangle();
0283: // Rectangle arrowIconRect = new Rectangle();
0284: // Rectangle viewRect = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE);
0285: //
0286: // int menuWidth = menuItem.getWidth();
0287: // int menuHeight = menuItem.getHeight();
0288: // if ((menuWidth > 0) && (menuHeight > 0))
0289: // viewRect.setBounds(0, 0, menuWidth, menuHeight);
0290: //
0291: // // fix for defect 108 - failed on b62 of Mustang and later on Hebrew
0292: // // localized menu strings.
0293: // // viewRect.setBounds(0, 0, menuWidth, menuHeight);
0294: //
0295: // viewRect.x += i.left;
0296: // viewRect.y += i.top;
0297: // viewRect.width -= (i.right + viewRect.x);
0298: // viewRect.height -= (i.bottom + viewRect.y);
0299: //
0300: // FontMetrics fm = menuItem.getFontMetrics(menuItem.getFont());
0301: // FontMetrics fmAccel = menuItem.getFontMetrics(acceleratorFont);
0302: //
0303: // // get Accelerator text
0304: // KeyStroke accelerator = menuItem.getAccelerator();
0305: // String acceleratorText = "";
0306: // if (accelerator != null) {
0307: // int modifiers = accelerator.getModifiers();
0308: // if (modifiers > 0) {
0309: // acceleratorText = KeyEvent.getKeyModifiersText(modifiers);
0310: // // acceleratorText += "-";
0311: // acceleratorText += UIManager
0312: // .getString("MenuItem.acceleratorDelimiter");
0313: // }
0314: //
0315: // int keyCode = accelerator.getKeyCode();
0316: // if (keyCode != 0) {
0317: // acceleratorText += KeyEvent.getKeyText(keyCode);
0318: // } else {
0319: // acceleratorText += accelerator.getKeyChar();
0320: // }
0321: // }
0322: //
0323: // // layout the text and icon
0324: // layoutMenuItem(menuItem, fm, menuItem.getText(), fmAccel,
0325: // acceleratorText, menuItem.getIcon(), checkIcon, arrowIcon,
0326: // menuItem.getVerticalAlignment(), menuItem
0327: // .getHorizontalAlignment(), menuItem
0328: // .getVerticalTextPosition(), menuItem
0329: // .getHorizontalTextPosition(), viewRect, iconRect,
0330: // textRect, acceleratorRect, checkIconRect, arrowIconRect,
0331: // menuItem.getText() == null ? 0 : defaultTextIconGap,
0332: // defaultTextIconGap);
0333: //
0334: // if (menuItem.getComponentOrientation().isLeftToRight()) {
0335: // return textRect.x;
0336: // } else {
0337: // // int result = viewRect.x + viewRect.width;
0338: // // if (iconRect.width != 0) {
0339: // // result -= (iconRect.x + defaultTextIconGap);
0340: // // }
0341: // // else {
0342: // // if (checkIconRect.width != 0) {
0343: // // result -= (checkIconRect.x + defaultTextIconGap);
0344: // // }
0345: // // }
0346: // return viewRect.x + viewRect.width - iconRect.x
0347: // - ((iconRect.width != 0) ? 0 : defaultTextIconGap);
0348: // }
0349: // }
0350: public static MenuLayoutInfo getMenuLayoutInfo(
0351: // Graphics g,
0352: JMenuItem menuItem, Font acceleratorFont, Icon checkIcon,
0353: Icon arrowIcon, int defaultTextIconGap) {
0354:
0355: // Dimension size = b.getSize();
0356: // int menuWidth = menuItem.getWidth();
0357: // int menuHeight = menuItem.getHeight();
0358: Insets i = menuItem.getInsets();
0359:
0360: Rectangle iconRect = new Rectangle(0, 0, 0, 0);
0361: Rectangle textRect = new Rectangle(0, 0, 0, 0);
0362: Rectangle acceleratorRect = new Rectangle(0, 0, 0, 0);
0363: Rectangle checkIconRect = new Rectangle(0, 0, 0, 0);
0364: Rectangle arrowIconRect = new Rectangle(0, 0, 0, 0);
0365: Rectangle viewRect = new Rectangle(Short.MAX_VALUE,
0366: Short.MAX_VALUE);
0367:
0368: int menuWidth = menuItem.getWidth();
0369: int menuHeight = menuItem.getHeight();
0370: if ((menuWidth > 0) && (menuHeight > 0))
0371: viewRect.setBounds(0, 0, menuWidth, menuHeight);
0372:
0373: // fix for defect 108 - failed on b62 of Mustang and later on Hebrew
0374: // localized menu strings.
0375: // viewRect.setBounds(0, 0, menuWidth, menuHeight);
0376:
0377: viewRect.x += i.left;
0378: viewRect.y += i.top;
0379: viewRect.width -= (i.right + viewRect.x);
0380: viewRect.height -= (i.bottom + viewRect.y);
0381:
0382: // Font f = menuItem.getFont();
0383: // g.setFont(f);
0384: FontMetrics fm = menuItem.getFontMetrics(menuItem.getFont());
0385: FontMetrics fmAccel = menuItem.getFontMetrics(acceleratorFont);
0386:
0387: // get Accelerator text
0388: KeyStroke accelerator = menuItem.getAccelerator();
0389: String acceleratorText = "";
0390: if (accelerator != null) {
0391: int modifiers = accelerator.getModifiers();
0392: if (modifiers > 0) {
0393: acceleratorText = KeyEvent
0394: .getKeyModifiersText(modifiers);
0395: // acceleratorText += "-";
0396: acceleratorText += UIManager
0397: .getString("MenuItem.acceleratorDelimiter");
0398: }
0399:
0400: int keyCode = accelerator.getKeyCode();
0401: if (keyCode != 0) {
0402: acceleratorText += KeyEvent.getKeyText(keyCode);
0403: } else {
0404: acceleratorText += accelerator.getKeyChar();
0405: }
0406: }
0407:
0408: // layout the text and icon
0409: String text = layoutMenuItem(menuItem, fm, menuItem.getText(),
0410: fmAccel, acceleratorText, menuItem.getIcon(),
0411: checkIcon, arrowIcon, menuItem.getVerticalAlignment(),
0412: menuItem.getHorizontalAlignment(), menuItem
0413: .getVerticalTextPosition(), menuItem
0414: .getHorizontalTextPosition(), viewRect,
0415: iconRect, textRect, acceleratorRect, checkIconRect,
0416: arrowIconRect, menuItem.getText() == null ? 0
0417: : defaultTextIconGap, defaultTextIconGap);
0418:
0419: MenuLayoutInfo mlInfo = new MenuLayoutInfo();
0420: // mlInfo.checkIconRect = (checkIconRect.width > 0) ? checkIconRect :
0421: // null;
0422: // mlInfo.iconRect = (iconRect.width > 0) ? iconRect : null;
0423: // mlInfo.textRect = (textRect.width > 0) ? textRect : null;
0424: // mlInfo.viewRect = (viewRect.width > 0) ? viewRect : null;
0425: mlInfo.checkIconRect = checkIconRect;
0426: mlInfo.iconRect = iconRect;
0427: mlInfo.textRect = textRect;
0428: mlInfo.viewRect = viewRect;
0429: mlInfo.acceleratorRect = acceleratorRect;
0430: mlInfo.arrowIconRect = arrowIconRect;
0431: mlInfo.text = text;
0432:
0433: return mlInfo;
0434: //
0435: // if (menuItem.getComponentOrientation().isLeftToRight()) {
0436: // return textRect.x;
0437: // } else {
0438: // // int result = viewRect.x + viewRect.width;
0439: // // if (iconRect.width != 0) {
0440: // // result -= (iconRect.x + defaultTextIconGap);
0441: // // }
0442: // // else {
0443: // // if (checkIconRect.width != 0) {
0444: // // result -= (checkIconRect.x + defaultTextIconGap);
0445: // // }
0446: // // }
0447: // return viewRect.x + viewRect.width - iconRect.x
0448: // - ((iconRect.width != 0) ? 0 : defaultTextIconGap);
0449: // }
0450: }
0451:
0452: /**
0453: * Compute and return the location of the icons origin, the location of
0454: * origin of the text baseline, and a possibly clipped version of the
0455: * compound labels string. Locations are computed relative to the viewRect
0456: * rectangle.
0457: */
0458: private static String layoutMenuItem(JMenuItem menuItem,
0459: FontMetrics fm, String text, FontMetrics fmAccel,
0460: String acceleratorText, Icon icon, Icon checkIcon,
0461: Icon arrowIcon, int verticalAlignment,
0462: int horizontalAlignment, int verticalTextPosition,
0463: int horizontalTextPosition, Rectangle viewRect,
0464: Rectangle iconRect, Rectangle textRect,
0465: Rectangle acceleratorRect, Rectangle checkIconRect,
0466: Rectangle arrowIconRect, int textIconGap, int menuItemGap) {
0467:
0468: SwingUtilities.layoutCompoundLabel(menuItem, fm, text, icon,
0469: verticalAlignment, horizontalAlignment,
0470: verticalTextPosition, horizontalTextPosition, viewRect,
0471: iconRect, textRect, textIconGap);
0472:
0473: /*
0474: * Initialize the acceelratorText bounds rectangle textRect. If a null
0475: * or and empty String was specified we substitute "" here and use
0476: * 0,0,0,0 for acceleratorTextRect.
0477: */
0478: if ((acceleratorText == null) || acceleratorText.equals("")) {
0479: acceleratorRect.width = acceleratorRect.height = 0;
0480: acceleratorText = "";
0481: } else {
0482: acceleratorRect.width = fmAccel
0483: .stringWidth(acceleratorText);
0484: acceleratorRect.height = fmAccel.getHeight();
0485: }
0486:
0487: /*
0488: * Initialize the checkIcon bounds rectangle's width & height.
0489: */
0490:
0491: if (useCheckAndArrow(menuItem)) {
0492: if (checkIcon != null) {
0493: checkIconRect.width = checkIcon.getIconWidth();
0494: checkIconRect.height = checkIcon.getIconHeight();
0495: } else {
0496: checkIconRect.width = checkIconRect.height = 0;
0497: }
0498:
0499: /*
0500: * Initialize the arrowIcon bounds rectangle width & height.
0501: */
0502:
0503: if (arrowIcon != null) {
0504: arrowIconRect.width = arrowIcon.getIconWidth();
0505: arrowIconRect.height = arrowIcon.getIconHeight();
0506: } else {
0507: arrowIconRect.width = arrowIconRect.height = 0;
0508: }
0509: }
0510:
0511: Rectangle labelRect = iconRect.union(textRect);
0512: if (menuItem.getComponentOrientation().isLeftToRight()) {
0513: textRect.x += menuItemGap;
0514: iconRect.x += menuItemGap;
0515:
0516: // Position the Accelerator text rect
0517: acceleratorRect.x = viewRect.x + viewRect.width
0518: - arrowIconRect.width - menuItemGap
0519: - acceleratorRect.width;
0520:
0521: // Position the Check and Arrow Icons
0522: if (useCheckAndArrow(menuItem)) {
0523: checkIconRect.x = viewRect.x + menuItemGap;
0524: textRect.x += menuItemGap + checkIconRect.width;
0525: iconRect.x += menuItemGap + checkIconRect.width;
0526: arrowIconRect.x = viewRect.x + viewRect.width
0527: - menuItemGap - arrowIconRect.width;
0528: }
0529: } else {
0530: textRect.x -= menuItemGap;
0531: iconRect.x -= menuItemGap;
0532:
0533: // Position the Accelerator text rect
0534: acceleratorRect.x = viewRect.x + arrowIconRect.width
0535: + menuItemGap;
0536:
0537: // Position the Check and Arrow Icons
0538: if (useCheckAndArrow(menuItem)) {
0539: checkIconRect.x = viewRect.x + viewRect.width
0540: - menuItemGap - checkIconRect.width;
0541: textRect.x -= menuItemGap + checkIconRect.width;
0542: iconRect.x -= menuItemGap + checkIconRect.width;
0543: arrowIconRect.x = viewRect.x + menuItemGap;
0544: }
0545: }
0546:
0547: // Align the accelertor text and the check and arrow icons vertically
0548: // with the center of the label rect.
0549: acceleratorRect.y = labelRect.y + (labelRect.height / 2)
0550: - (acceleratorRect.height / 2);
0551: if (useCheckAndArrow(menuItem)) {
0552: arrowIconRect.y = labelRect.y + (labelRect.height / 2)
0553: - (arrowIconRect.height / 2);
0554: checkIconRect.y = labelRect.y + (labelRect.height / 2)
0555: - (checkIconRect.height / 2);
0556: }
0557:
0558: /*
0559: * System.out.println("Layout: text="+menuItem.getText()+"\n\tv="
0560: * +viewRect+"\n\tc="+checkIconRect+"\n\ti="
0561: * +iconRect+"\n\tt="+textRect+"\n\tacc="
0562: * +acceleratorRect+"\n\ta="+arrowIconRect+"\n");
0563: */
0564:
0565: return text;
0566: }
0567:
0568: /*
0569: * Returns false if the component is a JMenu and it is a top level menu (on
0570: * the menubar).
0571: */
0572: private static boolean useCheckAndArrow(JMenuItem menuItem) {
0573: boolean b = true;
0574: if ((menuItem instanceof JMenu)
0575: && (((JMenu) menuItem).isTopLevelMenu())) {
0576: b = false;
0577: }
0578: return b;
0579: }
0580:
0581: private static JComponent getMenuItemParent(JMenuItem mi) {
0582: Container parent = mi.getParent();
0583: if ((parent instanceof JComponent)
0584: && (!(mi instanceof JMenu) || !((JMenu) mi)
0585: .isTopLevelMenu())) {
0586: return (JComponent) parent;
0587: } else {
0588: return null;
0589: }
0590: }
0591:
0592: // public static void lineupTextRectangle(JMenuItem menuItem,
0593: // Rectangle textRect, Font acceleratorFont, Icon checkIcon,
0594: // Icon arrowIcon, int defaultTextIconGap) {
0595: // if (textRect == null)
0596: // return;
0597: // int textOffset = MenuUtilities.getTextOffset(menuItem);
0598: // // System.out.println()
0599: // if (menuItem.getComponentOrientation().isLeftToRight()) {
0600: // textRect.setLocation(textOffset, textRect.y);
0601: // } else {
0602: // int loc = menuItem.getWidth() - textOffset - textRect.width
0603: // - defaultTextIconGap;
0604: // textRect.setLocation(loc, textRect.y);
0605: // }
0606: //
0607: // }
0608:
0609: public static void paintMenuItem(Graphics g, JMenuItem menuItem,
0610: Icon checkIcon, Icon arrowIcon, int defaultTextIconGap) {
0611: Graphics2D g2d = (Graphics2D) g.create();
0612:
0613: // special handling of menu items covered by lightweight popups
0614: // for the defect 297
0615: if (Boolean.TRUE
0616: .equals(menuItem
0617: .getClientProperty(SubstanceCoreUtilities.IS_COVERED_BY_LIGHTWEIGHT_POPUPS))) {
0618: JRootPane rootPane = SwingUtilities.getRootPane(menuItem);
0619: if (rootPane != null) {
0620: Component[] popups = rootPane.getLayeredPane()
0621: .getComponentsInLayer(JLayeredPane.POPUP_LAYER);
0622: if (popups != null) {
0623: int popupIndexToStartWith = SubstanceCoreUtilities
0624: .getPopupParentIndexOf(menuItem, popups) - 1;
0625: Area clip = new Area(g2d.getClip());
0626: for (int i = popupIndexToStartWith; i >= 0; i--) {
0627: Component popup = popups[i];
0628: // convert the popup bounds to the menu item coordinate
0629: // system
0630: Rectangle popupArea = SwingUtilities
0631: .convertRectangle(rootPane
0632: .getLayeredPane(), popup
0633: .getBounds(), menuItem);
0634: // and subtract this area from the clip
0635: clip.subtract(new Area(popupArea));
0636: }
0637: // at this point we have the original clip minus
0638: // all the overlapping lightweight popups that are painted
0639: // after this menu item
0640: g2d.setClip(clip);
0641: }
0642: }
0643: }
0644:
0645: ButtonModel model = menuItem.getModel();
0646: SubstanceMenu menuUi = (SubstanceMenu) menuItem.getUI();
0647:
0648: Font f = menuItem.getFont();
0649: g2d.setFont(f);
0650:
0651: // get Accelerator text
0652: KeyStroke accelerator = menuItem.getAccelerator();
0653: String acceleratorText = "";
0654: if (accelerator != null) {
0655: int modifiers = accelerator.getModifiers();
0656: if (modifiers > 0) {
0657: acceleratorText = KeyEvent
0658: .getKeyModifiersText(modifiers);
0659: acceleratorText += UIManager
0660: .getString("MenuItem.acceleratorDelimiter");
0661: }
0662:
0663: int keyCode = accelerator.getKeyCode();
0664: if (keyCode != 0) {
0665: acceleratorText += KeyEvent.getKeyText(keyCode);
0666: } else {
0667: acceleratorText += accelerator.getKeyChar();
0668: }
0669: }
0670: Icon icon = menuItem.getIcon();
0671: // MenuLayoutInfo mli = MenuUtilities.getMenuLayoutInfo(menuItem, menuUi
0672: // .getAcceleratorFont(), menuUi.getCheckIcon(), menuUi
0673: // .getArrowIcon(), menuUi.getDefaultTextIconGap());
0674:
0675: MenuLayoutInfo mli = MenuUtilities.getMenuLayoutInfo(menuItem,
0676: menuUi.getAcceleratorFont(), menuUi.getCheckIcon(),
0677: menuUi.getArrowIcon(), menuUi.getDefaultTextIconGap());
0678: MenuLayoutMetrics popupMetrics = MenuUtilities
0679: .getPopupLayoutMetrics(menuItem);
0680: Insets i = menuItem.getInsets();
0681: // FontMetrics fm = menuItem.getFontMetrics(menuItem.getFont());
0682: // int fontHeight = fm.getHeight();
0683: if (popupMetrics != null) {
0684: MenuGutterFillKind gutterFillKind = SubstanceCoreUtilities
0685: .getMenuGutterFillKind();
0686: boolean needExtraIconTextGap = (gutterFillKind != null)
0687: && (gutterFillKind != MenuGutterFillKind.NONE);
0688: int gap = popupMetrics.maxGap;
0689: if (menuItem.getComponentOrientation().isLeftToRight()) {
0690: int currX = i.left + gap / 2;
0691: if (checkIcon != null) {
0692: mli.checkIconRect = new Rectangle(currX, i.top,
0693: checkIcon.getIconWidth(), checkIcon
0694: .getIconHeight());
0695: int bump = (popupMetrics.maxCheckIconWidth - checkIcon
0696: .getIconWidth()) / 2;
0697: mli.checkIconRect.x += bump;
0698: }
0699: if (popupMetrics.maxCheckIconWidth > 0) {
0700: currX += (popupMetrics.maxCheckIconWidth + gap);
0701: }
0702: if (icon != null) {
0703: mli.iconRect = new Rectangle(currX, i.top, icon
0704: .getIconWidth(), icon.getIconHeight());
0705: int bump = (popupMetrics.maxIconWidth - icon
0706: .getIconWidth()) / 2;
0707: mli.iconRect.x += bump;
0708: }
0709: if (popupMetrics.maxIconWidth > 0) {
0710: currX += (popupMetrics.maxIconWidth + gap);
0711: }
0712: menuItem.putClientProperty(GUTTER_X, currX + gap / 2);
0713: if (needExtraIconTextGap)
0714: currX += gap;
0715: if (menuItem.getText() != null) {
0716: mli.textRect = new Rectangle(currX, mli.textRect.y,
0717: popupMetrics.maxTextWidth,
0718: mli.textRect.height);
0719: mli.text = menuItem.getText();
0720: }
0721: currX += (popupMetrics.maxTextWidth + gap);
0722: if (popupMetrics.maxAcceleratorWidth > 0) {
0723: currX += 5 * gap;
0724: // accelerator text is right-aligned
0725: mli.acceleratorRect = new Rectangle(currX
0726: + popupMetrics.maxAcceleratorWidth
0727: - mli.acceleratorRect.width,
0728: mli.textRect.y, mli.acceleratorRect.width,
0729: mli.textRect.height);
0730: }
0731: if (popupMetrics.maxAcceleratorWidth > 0) {
0732: currX += (popupMetrics.maxAcceleratorWidth + gap);
0733: }
0734:
0735: if (arrowIcon != null) {
0736: mli.arrowIconRect = new Rectangle(currX, i.top,
0737: popupMetrics.maxArrowIconWidth, arrowIcon
0738: .getIconHeight());
0739: }
0740:
0741: Rectangle labelRect = new Rectangle(0, 0, menuItem
0742: .getWidth(), menuItem.getHeight());
0743: // if (mli.iconRect != null)
0744: // labelRect = labelRect.union(mli.iconRect);
0745: if (mli.textRect != null)
0746: labelRect = mli.textRect;
0747: // // Align the accelerator text and the check and arrow icons
0748: // // vertically with the center of the label rect.
0749: // if (mli.acceleratorRect != null) {
0750: // mli.acceleratorRect.y = labelRect.y;
0751: // //+ (labelRect.height / 2)
0752: // //- (mli.acceleratorRect.height / 2);
0753: // }
0754: if (mli.iconRect != null) {
0755: mli.iconRect.y = labelRect.y
0756: + (labelRect.height / 2)
0757: - (mli.iconRect.height / 2);
0758: }
0759: if (mli.arrowIconRect != null) {
0760: mli.arrowIconRect.y = labelRect.y
0761: + (labelRect.height / 2)
0762: - (mli.arrowIconRect.height / 2);
0763: }
0764: if (mli.checkIconRect != null) {
0765: mli.checkIconRect.y = labelRect.y
0766: + (labelRect.height / 2)
0767: - (mli.checkIconRect.height / 2);
0768: }
0769: } else {
0770: int currX = menuItem.getWidth() - i.right - gap / 2;
0771: if (checkIcon != null) {
0772: mli.checkIconRect = new Rectangle(currX
0773: - popupMetrics.maxCheckIconWidth, i.top,
0774: checkIcon.getIconWidth(), checkIcon
0775: .getIconHeight());
0776: int bump = (popupMetrics.maxCheckIconWidth - checkIcon
0777: .getIconWidth()) / 2;
0778: mli.checkIconRect.x += bump;
0779: }
0780: if (popupMetrics.maxCheckIconWidth > 0) {
0781: currX -= (popupMetrics.maxCheckIconWidth + gap);
0782: }
0783: if (icon != null) {
0784: // icons are center-aligned
0785: mli.iconRect = new Rectangle(currX
0786: - popupMetrics.maxIconWidth, i.top, icon
0787: .getIconWidth(), icon.getIconHeight());
0788: int bump = (popupMetrics.maxIconWidth - icon
0789: .getIconWidth()) / 2;
0790: mli.iconRect.x += bump;
0791: }
0792: if (popupMetrics.maxIconWidth > 0) {
0793: currX -= (popupMetrics.maxIconWidth + gap);
0794: }
0795: menuItem.putClientProperty(GUTTER_X, currX + gap / 2);
0796: if (needExtraIconTextGap)
0797: currX -= gap;
0798: if (menuItem.getText() != null) {
0799: // text is right-aligned
0800: mli.textRect = new Rectangle(currX
0801: - mli.textRect.width, mli.textRect.y,
0802: popupMetrics.maxTextWidth,
0803: mli.textRect.height);
0804: mli.text = menuItem.getText();
0805: }
0806: currX -= (popupMetrics.maxTextWidth + gap);
0807: if (popupMetrics.maxAcceleratorWidth > 0) {
0808: currX -= 5 * gap;
0809: // accelerator text is left-aligned
0810: mli.acceleratorRect = new Rectangle(currX
0811: - popupMetrics.maxAcceleratorWidth,
0812: mli.textRect.y, mli.acceleratorRect.width,
0813: mli.textRect.height);
0814: }
0815: if (popupMetrics.maxAcceleratorWidth > 0) {
0816: currX -= (popupMetrics.maxAcceleratorWidth + gap);
0817: }
0818:
0819: if (arrowIcon != null) {
0820: mli.arrowIconRect = new Rectangle(currX
0821: - popupMetrics.maxArrowIconWidth, i.top,
0822: popupMetrics.maxArrowIconWidth, arrowIcon
0823: .getIconHeight());
0824: }
0825:
0826: Rectangle labelRect = new Rectangle(0, 0, menuItem
0827: .getWidth(), menuItem.getHeight());
0828: // if (mli.iconRect != null)
0829: // labelRect = labelRect.union(mli.iconRect);
0830: if (mli.textRect != null)
0831: labelRect = mli.textRect;
0832: // // Align the accelerator text and the check and arrow icons
0833: // // vertically with the center of the label rect.
0834: // if (mli.acceleratorRect != null) {
0835: // mli.acceleratorRect.y = labelRect.y;
0836: // //+ (labelRect.height / 2)
0837: // //- (mli.acceleratorRect.height / 2);
0838: // }
0839: if (mli.iconRect != null) {
0840: mli.iconRect.y = labelRect.y
0841: + (labelRect.height / 2)
0842: - (mli.iconRect.height / 2);
0843: }
0844: if (mli.arrowIconRect != null) {
0845: mli.arrowIconRect.y = labelRect.y
0846: + (labelRect.height / 2)
0847: - (mli.arrowIconRect.height / 2);
0848: }
0849: if (mli.checkIconRect != null) {
0850: mli.checkIconRect.y = labelRect.y
0851: + (labelRect.height / 2)
0852: - (mli.checkIconRect.height / 2);
0853: }
0854: }
0855: }
0856: Component parent = menuItem.getParent();
0857: if (parent instanceof JPopupMenu) {
0858: ((JPopupMenu) parent).putClientProperty(GUTTER_X, menuItem
0859: .getClientProperty(GUTTER_X));
0860: }
0861:
0862: // MenuUtilities.lineupTextRectangle(menuItem, mli.textRect, menuUi
0863: // .getAcceleratorFont(), menuUi.getCheckIcon(), menuUi
0864: // .getArrowIcon(), menuUi.getDefaultTextIconGap());
0865:
0866: SubstanceTextPainter textPainter = SubstanceLookAndFeel
0867: .getCurrentTextPainter();
0868: textPainter.init(menuItem, null, true);
0869: if (textPainter.needsBackgroundImage()) {
0870: // This is a workaround for disabled menu items. Since
0871: // SWT (native) pipeline doesn't support painting translucent
0872: // texts, we need a way to have the background painted in
0873: // full opacity, but the texts (and highlights) painted with
0874: // custom translucency. Here, we cheat and first paint the
0875: // background fill (with watermark) with full opacity. Since
0876: // there can be no highlights on disabled menu items, we don't
0877: // need to worry about hightlights. Then, the painting will be done
0878: // once again, overlaying the background, highlights and
0879: // text with custom alpha factor.
0880: paintBackground(g2d, menuItem);
0881: }
0882: textPainter.renderSurface(g2d);
0883:
0884: // Paint background
0885: textPainter.init(menuItem, null, true);
0886: paintBackground(g2d, menuItem);
0887: paintHighlights(g2d, menuItem);
0888:
0889: float textAlpha = 1.0f;
0890: if (mli.text != null) {
0891: View v = (View) menuItem
0892: .getClientProperty(BasicHTML.propertyKey);
0893: if (v != null) {
0894: v.paint(g2d, mli.textRect);
0895: } else {
0896: textAlpha = SubstanceCoreUtilities.paintText(menuItem,
0897: mli.textRect, mli.text, menuItem
0898: .getDisplayedMnemonicIndex());
0899: }
0900: }
0901:
0902: // Draw the Accelerator Text
0903: if (acceleratorText != null && !acceleratorText.equals("")) {
0904: SubstanceCoreUtilities.paintText(menuItem,
0905: mli.acceleratorRect, acceleratorText, -1);
0906: }
0907:
0908: Graphics2D graphics = (Graphics2D) g2d.create();
0909: graphics.setComposite(TransitionLayout.getAlphaComposite(
0910: menuItem, textAlpha, g2d));
0911:
0912: textPainter.renderSurface(graphics);
0913: graphics.dispose();
0914:
0915: // Paint the Check
0916: if (checkIcon != null) {
0917: if (useCheckAndArrow(menuItem))
0918: checkIcon.paintIcon(menuItem, g2d, mli.checkIconRect.x,
0919: mli.checkIconRect.y);
0920: }
0921:
0922: // Paint the Icon
0923: if (icon != null) {
0924: if (!model.isEnabled()) {
0925: icon = menuItem.getDisabledIcon();
0926: } else if (model.isPressed() && model.isArmed()) {
0927: icon = menuItem.getPressedIcon();
0928: if (icon == null) {
0929: // Use default icon
0930: icon = menuItem.getIcon();
0931: }
0932: } else {
0933: icon = menuItem.getIcon();
0934: }
0935:
0936: if (icon != null) {
0937: icon.paintIcon(menuItem, g2d, mli.iconRect.x,
0938: mli.iconRect.y);
0939: }
0940: }
0941:
0942: // Paint the Arrow
0943: if (arrowIcon != null) {
0944: if (useCheckAndArrow(menuItem))
0945: arrowIcon.paintIcon(menuItem, g2d, mli.arrowIconRect.x,
0946: mli.arrowIconRect.y);
0947: }
0948:
0949: // g2d.setColor(Color.red);
0950: // if (mli.iconRect != null)
0951: // g2d.draw(mli.iconRect);
0952: // if (mli.checkIconRect != null)
0953: // g2d.draw(mli.checkIconRect);
0954: // if (mli.textRect != null)
0955: // g2d.draw(mli.textRect);
0956:
0957: // g2d.setColor(Color.red);
0958: // g2d.drawRect(mli.checkIconRect.x, mli.checkIconRect.y,
0959: // mli.checkIconRect.width, mli.checkIconRect.height);
0960: // g2d.drawRect(mli.iconRect.x, mli.iconRect.y, mli.iconRect.width,
0961: // mli.iconRect.height);
0962: // g2d.drawRect(mli.textRect.x, mli.textRect.y, mli.textRect.width,
0963: // mli.textRect.height);
0964: // g2d.drawRect(mli.arrowIconRect.x, mli.arrowIconRect.y,
0965: // mli.arrowIconRect.width, mli.arrowIconRect.height);
0966: // g2d.drawRect(mli.acceleratorRect.x, mli.acceleratorRect.y,
0967: // mli.acceleratorRect.width, mli.acceleratorRect.height);
0968:
0969: g2d.dispose();
0970: }
0971:
0972: protected static void paintBackground(Graphics g,
0973: final JMenuItem menuItem) {
0974: int textOffset = MenuUtilities.getTextOffset(menuItem, menuItem
0975: .getParent());
0976: // System.out.println(menuItem.getText() + ":" + textOffset);
0977: SubstanceTextPainter textPainter = SubstanceLookAndFeel
0978: .getCurrentTextPainter();
0979: final Color bgColor = SubstanceCoreUtilities
0980: .getBackgroundFillColor(menuItem);
0981: final int finalTextOffset = textOffset;
0982: SubstanceTextPainter.BackgroundPaintingCallback callback = new SubstanceTextPainter.BackgroundPaintingCallback() {
0983: public void paintBackground(Graphics g) {
0984: Graphics2D g2d = (Graphics2D) g.create();
0985: backgroundDelegate.paintBackground(g, menuItem,
0986: bgColor, 0.5f, finalTextOffset);
0987: g2d.dispose();
0988: }
0989: };
0990: if (textPainter.needsBackgroundImage()) {
0991: textPainter
0992: .setBackgroundFill(menuItem, bgColor, true, 0, 0);
0993: textPainter.attachCallback(callback);
0994: } else {
0995: callback.paintBackground(g);
0996: }
0997: }
0998:
0999: protected static void paintHighlights(Graphics g,
1000: final JMenuItem menuItem) {
1001: SubstanceTextPainter textPainter = SubstanceLookAndFeel
1002: .getCurrentTextPainter();
1003: SubstanceTextPainter.BackgroundPaintingCallback callback = new SubstanceTextPainter.BackgroundPaintingCallback() {
1004: public void paintBackground(Graphics g) {
1005: Graphics2D g2d = (Graphics2D) g.create();
1006: SubstanceMenuBackgroundDelegate.paintHighlights(g,
1007: menuItem, 0.5f);
1008: g2d.dispose();
1009: }
1010: };
1011: if (textPainter.needsBackgroundImage()) {
1012: textPainter.attachCallback(callback);
1013: } else {
1014: callback.paintBackground(g);
1015: }
1016: }
1017:
1018: protected static MenuLayoutMetrics getMetrics(JPopupMenu popupMenu) {
1019: MenuLayoutMetrics metrics = new MenuLayoutMetrics();
1020: for (int i = 0; i < popupMenu.getComponentCount(); i++) {
1021: Component comp = popupMenu.getComponent(i);
1022: if (comp instanceof JMenuItem) {
1023: JMenuItem childMenuItem = (JMenuItem) comp;
1024: ButtonUI bui = childMenuItem.getUI();
1025: if (!(bui instanceof SubstanceMenu))
1026: continue;
1027: SubstanceMenu ui = (SubstanceMenu) bui;
1028: MenuLayoutInfo mli = MenuUtilities.getMenuLayoutInfo(
1029: childMenuItem, ui.getAcceleratorFont(), ui
1030: .getCheckIcon(), ui.getArrowIcon(), ui
1031: .getDefaultTextIconGap());
1032: metrics.maxIconWidth = Math.max(metrics.maxIconWidth,
1033: mli.iconRect.width);
1034: metrics.maxCheckIconWidth = Math.max(
1035: metrics.maxCheckIconWidth,
1036: mli.checkIconRect.width);
1037: metrics.maxTextWidth = Math.max(metrics.maxTextWidth,
1038: mli.textRect.width);
1039: metrics.maxAcceleratorWidth = Math.max(
1040: metrics.maxAcceleratorWidth,
1041: mli.acceleratorRect.width);
1042: metrics.maxArrowIconWidth = Math.max(
1043: metrics.maxArrowIconWidth,
1044: mli.arrowIconRect.width);
1045: metrics.maxGap = Math.max(metrics.maxGap, ui
1046: .getDefaultTextIconGap());
1047: }
1048: }
1049: return metrics;
1050: }
1051:
1052: public static MenuLayoutMetrics getPopupLayoutMetrics(
1053: JMenuItem menuItem) {
1054: Component comp = menuItem.getParent();
1055: if (comp instanceof JPopupMenu) {
1056: JPopupMenu popupMenu = (JPopupMenu) comp;
1057: Object prop = popupMenu.getClientProperty(LAYOUT_METRICS);
1058: if (prop instanceof MenuLayoutMetrics) {
1059: return (MenuLayoutMetrics) prop;
1060: }
1061: MenuLayoutMetrics metrics = getMetrics(popupMenu);
1062: popupMenu.putClientProperty(LAYOUT_METRICS, metrics);
1063: return metrics;
1064: }
1065: // If here, the parent is not popup menu - this is a top-level menu
1066: // in a menu bar. No need to align the different rectangles
1067: return null;
1068: }
1069:
1070: public static void cleanPopupLayoutMetrics(JMenuItem menuItem) {
1071: Component comp = menuItem.getParent();
1072: if (comp instanceof JPopupMenu) {
1073: JPopupMenu popupMenu = (JPopupMenu) comp;
1074: cleanPopupLayoutMetrics(popupMenu);
1075: }
1076: }
1077:
1078: public static void cleanPopupLayoutMetrics(JPopupMenu popupMenu) {
1079: if (popupMenu != null) {
1080: popupMenu.putClientProperty(LAYOUT_METRICS, null);
1081: }
1082: }
1083:
1084: public static int getPreferredWidth(JMenuItem menuItem) {
1085: Insets ins = menuItem.getInsets();
1086: MenuLayoutMetrics popupMetrics = MenuUtilities
1087: .getPopupLayoutMetrics(menuItem);
1088:
1089: int width = popupMetrics.maxCheckIconWidth
1090: + popupMetrics.maxIconWidth + popupMetrics.maxTextWidth
1091: + popupMetrics.maxAcceleratorWidth
1092: + popupMetrics.maxArrowIconWidth + ins.left + ins.right;
1093:
1094: int gapsToAdd = 0;
1095: if (popupMetrics.maxCheckIconWidth > 0)
1096: gapsToAdd++;
1097: if (popupMetrics.maxIconWidth > 0)
1098: gapsToAdd++;
1099: if (popupMetrics.maxAcceleratorWidth > 0)
1100: gapsToAdd++;
1101: if (popupMetrics.maxArrowIconWidth > 0)
1102: gapsToAdd++;
1103:
1104: int gap = popupMetrics.maxGap;
1105: width += ((1 + gapsToAdd) * gap);
1106:
1107: if (popupMetrics.maxAcceleratorWidth > 0) {
1108: // at least one menu item has accelerator text
1109: width += 5 * gap;
1110: }
1111:
1112: MenuGutterFillKind gutterFillKind = SubstanceCoreUtilities
1113: .getMenuGutterFillKind();
1114: boolean needExtraIconTextGap = (gutterFillKind != null)
1115: && (gutterFillKind != MenuGutterFillKind.NONE);
1116: if (needExtraIconTextGap)
1117: width += gap;
1118:
1119: return width;
1120: }
1121:
1122: public static int getTextOffset(JComponent menuItem,
1123: Component menuItemParent) {
1124: if (!(menuItemParent instanceof JPopupMenu)) {
1125: return 0;
1126: }
1127:
1128: Object itemProp = menuItem.getClientProperty(GUTTER_X);
1129: if (itemProp instanceof Integer) {
1130: return (Integer) itemProp;
1131: }
1132:
1133: JPopupMenu popupMenu = (JPopupMenu) menuItemParent;
1134: Object parentProp = popupMenu.getClientProperty(GUTTER_X);
1135: if (parentProp instanceof Integer) {
1136: return (Integer) parentProp;
1137: }
1138: return 0;
1139: // MenuLayoutMetrics metrics = getMetrics(popupMenu);
1140: // if (popupMenu.getComponentOrientation().isLeftToRight()) {
1141: // return SubstanceSizeUtils.getMenuItemMargin(SubstanceSizeUtils
1142: // .getComponentFontSize(menuItem))
1143: // + popupMenu.getInsets().left
1144: // + metrics.maxCheckIconWidth
1145: // + metrics.maxIconWidth
1146: // + (int) (2.5 * SubstanceSizeUtils
1147: // .getMenuTextIconGap(SubstanceSizeUtils
1148: // .getComponentFontSize(popupMenu)));
1149: // } else {
1150: // return 0;
1151: // }
1152: }
1153: }
|