| /* |
| * Copyright (c) 2002, 2008, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package javax.swing.plaf.synth; |
| |
| import sun.swing.StringUIClientPropertyKey; |
| import sun.swing.MenuItemLayoutHelper; |
| import sun.swing.plaf.synth.SynthIcon; |
| |
| import javax.swing.*; |
| import javax.swing.text.View; |
| import java.awt.*; |
| |
| /** |
| * Calculates preferred size and layouts synth menu items. |
| * |
| * All JMenuItems (and JMenus) include enough space for the insets |
| * plus one or more elements. When we say "label" below, we mean |
| * "icon and/or text." |
| * |
| * Cases to consider for SynthMenuItemUI (visualized here in a |
| * LTR orientation; the RTL case would be reversed): |
| * label |
| * check icon + label |
| * check icon + label + accelerator |
| * label + accelerator |
| * |
| * Cases to consider for SynthMenuUI (again visualized here in a |
| * LTR orientation): |
| * label + arrow |
| * |
| * Note that in the above scenarios, accelerator and arrow icon are |
| * mutually exclusive. This means that if a popup menu contains a mix |
| * of JMenus and JMenuItems, we only need to allow enough space for |
| * max(maxAccelerator, maxArrow), and both accelerators and arrow icons |
| * can occupy the same "column" of space in the menu. |
| */ |
| class SynthMenuItemLayoutHelper extends MenuItemLayoutHelper { |
| |
| public static final StringUIClientPropertyKey MAX_ACC_OR_ARROW_WIDTH = |
| new StringUIClientPropertyKey("maxAccOrArrowWidth"); |
| |
| public static final ColumnAlignment LTR_ALIGNMENT_1 = |
| new ColumnAlignment( |
| SwingConstants.LEFT, |
| SwingConstants.LEFT, |
| SwingConstants.LEFT, |
| SwingConstants.RIGHT, |
| SwingConstants.RIGHT |
| ); |
| public static final ColumnAlignment LTR_ALIGNMENT_2 = |
| new ColumnAlignment( |
| SwingConstants.LEFT, |
| SwingConstants.LEFT, |
| SwingConstants.LEFT, |
| SwingConstants.LEFT, |
| SwingConstants.RIGHT |
| ); |
| public static final ColumnAlignment RTL_ALIGNMENT_1 = |
| new ColumnAlignment( |
| SwingConstants.RIGHT, |
| SwingConstants.RIGHT, |
| SwingConstants.RIGHT, |
| SwingConstants.LEFT, |
| SwingConstants.LEFT |
| ); |
| public static final ColumnAlignment RTL_ALIGNMENT_2 = |
| new ColumnAlignment( |
| SwingConstants.RIGHT, |
| SwingConstants.RIGHT, |
| SwingConstants.RIGHT, |
| SwingConstants.RIGHT, |
| SwingConstants.LEFT |
| ); |
| |
| private SynthContext context; |
| private SynthContext accContext; |
| private SynthStyle style; |
| private SynthStyle accStyle; |
| private SynthGraphicsUtils gu; |
| private SynthGraphicsUtils accGu; |
| private boolean alignAcceleratorText; |
| private int maxAccOrArrowWidth; |
| |
| public SynthMenuItemLayoutHelper(SynthContext context, SynthContext accContext, |
| JMenuItem mi, Icon checkIcon, Icon arrowIcon, |
| Rectangle viewRect, int gap, String accDelimiter, |
| boolean isLeftToRight, boolean useCheckAndArrow, |
| String propertyPrefix) { |
| this.context = context; |
| this.accContext = accContext; |
| this.style = context.getStyle(); |
| this.accStyle = accContext.getStyle(); |
| this.gu = style.getGraphicsUtils(context); |
| this.accGu = accStyle.getGraphicsUtils(accContext); |
| this.alignAcceleratorText = getAlignAcceleratorText(propertyPrefix); |
| reset(mi, checkIcon, arrowIcon, viewRect, gap, accDelimiter, |
| isLeftToRight, style.getFont(context), accStyle.getFont(accContext), |
| useCheckAndArrow, propertyPrefix); |
| setLeadingGap(0); |
| } |
| |
| private boolean getAlignAcceleratorText(String propertyPrefix) { |
| return style.getBoolean(context, |
| propertyPrefix + ".alignAcceleratorText", true); |
| } |
| |
| protected void calcWidthsAndHeights() { |
| // iconRect |
| if (getIcon() != null) { |
| getIconSize().setWidth(SynthIcon.getIconWidth(getIcon(), context)); |
| getIconSize().setHeight(SynthIcon.getIconHeight(getIcon(), context)); |
| } |
| |
| // accRect |
| if (!getAccText().equals("")) { |
| getAccSize().setWidth(accGu.computeStringWidth(getAccContext(), |
| getAccFontMetrics().getFont(), getAccFontMetrics(), |
| getAccText())); |
| getAccSize().setHeight(getAccFontMetrics().getHeight()); |
| } |
| |
| // textRect |
| if (getText() == null) { |
| setText(""); |
| } else if (!getText().equals("")) { |
| if (getHtmlView() != null) { |
| // Text is HTML |
| getTextSize().setWidth( |
| (int) getHtmlView().getPreferredSpan(View.X_AXIS)); |
| getTextSize().setHeight( |
| (int) getHtmlView().getPreferredSpan(View.Y_AXIS)); |
| } else { |
| // Text isn't HTML |
| getTextSize().setWidth(gu.computeStringWidth(context, |
| getFontMetrics().getFont(), getFontMetrics(), |
| getText())); |
| getTextSize().setHeight(getFontMetrics().getHeight()); |
| } |
| } |
| |
| if (useCheckAndArrow()) { |
| // checkIcon |
| if (getCheckIcon() != null) { |
| getCheckSize().setWidth( |
| SynthIcon.getIconWidth(getCheckIcon(), context)); |
| getCheckSize().setHeight( |
| SynthIcon.getIconHeight(getCheckIcon(), context)); |
| } |
| // arrowRect |
| if (getArrowIcon() != null) { |
| getArrowSize().setWidth( |
| SynthIcon.getIconWidth(getArrowIcon(), context)); |
| getArrowSize().setHeight( |
| SynthIcon.getIconHeight(getArrowIcon(), context)); |
| } |
| } |
| |
| // labelRect |
| if (isColumnLayout()) { |
| getLabelSize().setWidth(getIconSize().getWidth() |
| + getTextSize().getWidth() + getGap()); |
| getLabelSize().setHeight(MenuItemLayoutHelper.max( |
| getCheckSize().getHeight(), |
| getIconSize().getHeight(), |
| getTextSize().getHeight(), |
| getAccSize().getHeight(), |
| getArrowSize().getHeight())); |
| } else { |
| Rectangle textRect = new Rectangle(); |
| Rectangle iconRect = new Rectangle(); |
| gu.layoutText(context, getFontMetrics(), getText(), getIcon(), |
| getHorizontalAlignment(), getVerticalAlignment(), |
| getHorizontalTextPosition(), getVerticalTextPosition(), |
| getViewRect(), iconRect, textRect, getGap()); |
| textRect.width += getLeftTextExtraWidth(); |
| Rectangle labelRect = iconRect.union(textRect); |
| getLabelSize().setHeight(labelRect.height); |
| getLabelSize().setWidth(labelRect.width); |
| } |
| } |
| |
| protected void calcMaxWidths() { |
| calcMaxWidth(getCheckSize(), MAX_CHECK_WIDTH); |
| maxAccOrArrowWidth = |
| calcMaxValue(MAX_ACC_OR_ARROW_WIDTH, getArrowSize().getWidth()); |
| maxAccOrArrowWidth = |
| calcMaxValue(MAX_ACC_OR_ARROW_WIDTH, getAccSize().getWidth()); |
| |
| if (isColumnLayout()) { |
| calcMaxWidth(getIconSize(), MAX_ICON_WIDTH); |
| calcMaxWidth(getTextSize(), MAX_TEXT_WIDTH); |
| int curGap = getGap(); |
| if ((getIconSize().getMaxWidth() == 0) |
| || (getTextSize().getMaxWidth() == 0)) { |
| curGap = 0; |
| } |
| getLabelSize().setMaxWidth( |
| calcMaxValue(MAX_LABEL_WIDTH, getIconSize().getMaxWidth() |
| + getTextSize().getMaxWidth() + curGap)); |
| } else { |
| // We shouldn't use current icon and text widths |
| // in maximal widths calculation for complex layout. |
| getIconSize().setMaxWidth(getParentIntProperty( |
| MAX_ICON_WIDTH)); |
| calcMaxWidth(getLabelSize(), MAX_LABEL_WIDTH); |
| // If maxLabelWidth is wider |
| // than the widest icon + the widest text + gap, |
| // we should update the maximal text witdh |
| int candidateTextWidth = getLabelSize().getMaxWidth() - |
| getIconSize().getMaxWidth(); |
| if (getIconSize().getMaxWidth() > 0) { |
| candidateTextWidth -= getGap(); |
| } |
| getTextSize().setMaxWidth(calcMaxValue( |
| MAX_TEXT_WIDTH, candidateTextWidth)); |
| } |
| } |
| |
| public SynthContext getContext() { |
| return context; |
| } |
| |
| public SynthContext getAccContext() { |
| return accContext; |
| } |
| |
| public SynthStyle getStyle() { |
| return style; |
| } |
| |
| public SynthStyle getAccStyle() { |
| return accStyle; |
| } |
| |
| public SynthGraphicsUtils getGraphicsUtils() { |
| return gu; |
| } |
| |
| public SynthGraphicsUtils getAccGraphicsUtils() { |
| return accGu; |
| } |
| |
| public boolean alignAcceleratorText() { |
| return alignAcceleratorText; |
| } |
| |
| public int getMaxAccOrArrowWidth() { |
| return maxAccOrArrowWidth; |
| } |
| |
| protected void prepareForLayout(LayoutResult lr) { |
| lr.getCheckRect().width = getCheckSize().getMaxWidth(); |
| // An item can have an arrow or a check icon at once |
| if (useCheckAndArrow() && (!"".equals(getAccText()))) { |
| lr.getAccRect().width = maxAccOrArrowWidth; |
| } else { |
| lr.getArrowRect().width = maxAccOrArrowWidth; |
| } |
| } |
| |
| public ColumnAlignment getLTRColumnAlignment() { |
| if (alignAcceleratorText()) { |
| return LTR_ALIGNMENT_2; |
| } else { |
| return LTR_ALIGNMENT_1; |
| } |
| } |
| |
| public ColumnAlignment getRTLColumnAlignment() { |
| if (alignAcceleratorText()) { |
| return RTL_ALIGNMENT_2; |
| } else { |
| return RTL_ALIGNMENT_1; |
| } |
| } |
| |
| protected void layoutIconAndTextInLabelRect(LayoutResult lr) { |
| lr.setTextRect(new Rectangle()); |
| lr.setIconRect(new Rectangle()); |
| gu.layoutText(context, getFontMetrics(), getText(), getIcon(), |
| getHorizontalAlignment(), getVerticalAlignment(), |
| getHorizontalTextPosition(), getVerticalTextPosition(), |
| lr.getLabelRect(), lr.getIconRect(), lr.getTextRect(), getGap()); |
| } |
| } |