mirror of
https://github.com/openjdk/jdk.git
synced 2026-05-11 14:11:36 +00:00
6584657: GTK Look and Feel: Bugs in menu item layout
Reviewed-by: peterz, alexp
This commit is contained in:
parent
1dce4ceddd
commit
f092fd7939
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1997-2008 Sun Microsystems, Inc. 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
|
||||
@ -974,6 +974,7 @@ public class SwingUtilities implements SwingConstants
|
||||
|
||||
boolean textIsEmpty = (text == null) || text.equals("");
|
||||
int lsb = 0;
|
||||
int rsb = 0;
|
||||
/* Unless both text and icon are non-null, we effectively ignore
|
||||
* the value of textIconGap.
|
||||
*/
|
||||
@ -1015,7 +1016,7 @@ public class SwingUtilities implements SwingConstants
|
||||
if (lsb < 0) {
|
||||
textR.width -= lsb;
|
||||
}
|
||||
int rsb = SwingUtilities2.getRightSideBearing(c, fm, text);
|
||||
rsb = SwingUtilities2.getRightSideBearing(c, fm, text);
|
||||
if (rsb > 0) {
|
||||
textR.width += rsb;
|
||||
}
|
||||
@ -1118,6 +1119,11 @@ public class SwingUtilities implements SwingConstants
|
||||
// lsb is negative. Shift the x location so that the text is
|
||||
// visually drawn at the right location.
|
||||
textR.x -= lsb;
|
||||
|
||||
textR.width += lsb;
|
||||
}
|
||||
if (rsb > 0) {
|
||||
textR.width -= rsb;
|
||||
}
|
||||
|
||||
return text;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1998-2008 Sun Microsystems, Inc. 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
|
||||
@ -30,7 +30,6 @@ import javax.swing.plaf.UIResource;
|
||||
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import static sun.swing.SwingUtilities2.BASICMENUITEMUI_MAX_TEXT_OFFSET;
|
||||
|
||||
/**
|
||||
* The default layout manager for Popup menus and menubars. This
|
||||
@ -49,18 +48,7 @@ public class DefaultMenuLayout extends BoxLayout implements UIResource {
|
||||
public Dimension preferredLayoutSize(Container target) {
|
||||
if (target instanceof JPopupMenu) {
|
||||
JPopupMenu popupMenu = (JPopupMenu) target;
|
||||
|
||||
// Before the calculation of menu preferred size
|
||||
// clear the previously calculated maximal widths and offsets
|
||||
// in menu's Client Properties
|
||||
popupMenu.putClientProperty(BasicMenuItemUI.MAX_ACC_WIDTH, null);
|
||||
popupMenu.putClientProperty(BasicMenuItemUI.MAX_ARROW_WIDTH, null);
|
||||
popupMenu.putClientProperty(BasicMenuItemUI.MAX_CHECK_WIDTH, null);
|
||||
popupMenu.putClientProperty(BasicMenuItemUI.MAX_ICON_WIDTH, null);
|
||||
popupMenu.putClientProperty(BasicMenuItemUI.MAX_LABEL_WIDTH, null);
|
||||
popupMenu.putClientProperty(BasicMenuItemUI.MAX_TEXT_WIDTH, null);
|
||||
popupMenu.putClientProperty(BASICMENUITEMUI_MAX_TEXT_OFFSET, null);
|
||||
|
||||
sun.swing.MenuItemLayoutHelper.clearUsedClientProperties(popupMenu);
|
||||
if (popupMenu.getComponentCount() == 0) {
|
||||
return new Dimension(0, 0);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2002-2008 Sun Microsystems, Inc. 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
|
||||
@ -47,19 +47,22 @@ class DefaultMenuLayout extends BoxLayout implements UIResource {
|
||||
super(target, axis);
|
||||
}
|
||||
|
||||
public void invalidateLayout(Container target) {
|
||||
if (target instanceof JPopupMenu) {
|
||||
SynthPopupMenuUI popupUI = (SynthPopupMenuUI)((JPopupMenu)target).
|
||||
getUI();
|
||||
popupUI.resetAlignmentHints();
|
||||
}
|
||||
super.invalidateLayout(target);
|
||||
}
|
||||
|
||||
public Dimension preferredLayoutSize(Container target) {
|
||||
if (target instanceof JPopupMenu && target.getComponentCount() == 0) {
|
||||
return new Dimension(0, 0);
|
||||
if (target instanceof JPopupMenu) {
|
||||
JPopupMenu popupMenu = (JPopupMenu) target;
|
||||
|
||||
popupMenu.putClientProperty(
|
||||
SynthMenuItemLayoutHelper.MAX_ACC_OR_ARROW_WIDTH, null);
|
||||
sun.swing.MenuItemLayoutHelper.clearUsedClientProperties(popupMenu);
|
||||
|
||||
if (popupMenu.getComponentCount() == 0) {
|
||||
return new Dimension(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Make BoxLayout recalculate cached preferred sizes
|
||||
super.invalidateLayout(target);
|
||||
|
||||
return super.preferredLayoutSize(target);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2002-2008 Sun Microsystems, Inc. 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
|
||||
@ -25,6 +25,8 @@
|
||||
package javax.swing.plaf.synth;
|
||||
|
||||
import sun.swing.SwingUtilities2;
|
||||
import sun.swing.MenuItemLayoutHelper;
|
||||
|
||||
import java.awt.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
@ -411,6 +413,198 @@ public class SynthGraphicsUtils {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A quick note about how preferred sizes are calculated... Generally
|
||||
* speaking, SynthPopupMenuUI will run through the list of its children
|
||||
* (from top to bottom) and ask each for its preferred size. Each menu
|
||||
* item will add up the max width of each element (icons, text,
|
||||
* accelerator spacing, accelerator text or arrow icon) encountered thus
|
||||
* far, so by the time all menu items have been calculated, we will
|
||||
* know the maximum (preferred) menu item size for that popup menu.
|
||||
* Later when it comes time to paint each menu item, we can use those
|
||||
* same accumulated max element sizes in order to layout the item.
|
||||
*/
|
||||
static Dimension getPreferredMenuItemSize(SynthContext context,
|
||||
SynthContext accContext, JComponent c,
|
||||
Icon checkIcon, Icon arrowIcon, int defaultTextIconGap,
|
||||
String acceleratorDelimiter, boolean useCheckAndArrow,
|
||||
String propertyPrefix) {
|
||||
|
||||
JMenuItem mi = (JMenuItem) c;
|
||||
SynthMenuItemLayoutHelper lh = new SynthMenuItemLayoutHelper(
|
||||
context, accContext, mi, checkIcon, arrowIcon,
|
||||
MenuItemLayoutHelper.createMaxRect(), defaultTextIconGap,
|
||||
acceleratorDelimiter, SynthLookAndFeel.isLeftToRight(mi),
|
||||
useCheckAndArrow, propertyPrefix);
|
||||
|
||||
Dimension result = new Dimension();
|
||||
|
||||
// Calculate the result width
|
||||
int gap = lh.getGap();
|
||||
result.width = 0;
|
||||
MenuItemLayoutHelper.addMaxWidth(lh.getCheckSize(), gap, result);
|
||||
MenuItemLayoutHelper.addMaxWidth(lh.getLabelSize(), gap, result);
|
||||
MenuItemLayoutHelper.addWidth(lh.getMaxAccOrArrowWidth(), 5 * gap, result);
|
||||
// The last gap is unnecessary
|
||||
result.width -= gap;
|
||||
|
||||
// Calculate the result height
|
||||
result.height = MenuItemLayoutHelper.max(lh.getCheckSize().getHeight(),
|
||||
lh.getLabelSize().getHeight(), lh.getAccSize().getHeight(),
|
||||
lh.getArrowSize().getHeight());
|
||||
|
||||
// Take into account menu item insets
|
||||
Insets insets = lh.getMenuItem().getInsets();
|
||||
if (insets != null) {
|
||||
result.width += insets.left + insets.right;
|
||||
result.height += insets.top + insets.bottom;
|
||||
}
|
||||
|
||||
// if the width is even, bump it up one. This is critical
|
||||
// for the focus dash lhne to draw properly
|
||||
if (result.width % 2 == 0) {
|
||||
result.width++;
|
||||
}
|
||||
|
||||
// if the height is even, bump it up one. This is critical
|
||||
// for the text to center properly
|
||||
if (result.height % 2 == 0) {
|
||||
result.height++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void applyInsets(Rectangle rect, Insets insets) {
|
||||
if (insets != null) {
|
||||
rect.x += insets.left;
|
||||
rect.y += insets.top;
|
||||
rect.width -= (insets.right + rect.x);
|
||||
rect.height -= (insets.bottom + rect.y);
|
||||
}
|
||||
}
|
||||
|
||||
static void paint(SynthContext context, SynthContext accContext, Graphics g,
|
||||
Icon checkIcon, Icon arrowIcon, String acceleratorDelimiter,
|
||||
int defaultTextIconGap, String propertyPrefix) {
|
||||
JMenuItem mi = (JMenuItem) context.getComponent();
|
||||
SynthStyle style = context.getStyle();
|
||||
g.setFont(style.getFont(context));
|
||||
|
||||
Rectangle viewRect = new Rectangle(0, 0, mi.getWidth(), mi.getHeight());
|
||||
applyInsets(viewRect, mi.getInsets());
|
||||
|
||||
SynthMenuItemLayoutHelper lh = new SynthMenuItemLayoutHelper(
|
||||
context, accContext, mi, checkIcon,
|
||||
arrowIcon, viewRect, defaultTextIconGap, acceleratorDelimiter,
|
||||
SynthLookAndFeel.isLeftToRight(mi),
|
||||
MenuItemLayoutHelper.useCheckAndArrow(mi), propertyPrefix);
|
||||
MenuItemLayoutHelper.LayoutResult lr = lh.layoutMenuItem();
|
||||
|
||||
paintMenuItem(g, lh, lr);
|
||||
}
|
||||
|
||||
static void paintMenuItem(Graphics g, SynthMenuItemLayoutHelper lh,
|
||||
MenuItemLayoutHelper.LayoutResult lr) {
|
||||
// Save original graphics font and color
|
||||
Font holdf = g.getFont();
|
||||
Color holdc = g.getColor();
|
||||
|
||||
paintBackground(g, lh);
|
||||
paintCheckIcon(g, lh, lr);
|
||||
paintIcon(g, lh, lr);
|
||||
paintText(g, lh, lr);
|
||||
paintAccText(g, lh, lr);
|
||||
paintArrowIcon(g, lh, lr);
|
||||
|
||||
// Restore original graphics font and color
|
||||
g.setColor(holdc);
|
||||
g.setFont(holdf);
|
||||
}
|
||||
|
||||
static void paintBackground(Graphics g, SynthMenuItemLayoutHelper lh) {
|
||||
paintBackground(lh.getContext(), g, lh.getMenuItem());
|
||||
}
|
||||
|
||||
static void paintBackground(SynthContext context, Graphics g, JComponent c) {
|
||||
context.getPainter().paintMenuItemBackground(context, g, 0, 0,
|
||||
c.getWidth(), c.getHeight());
|
||||
}
|
||||
|
||||
static void paintIcon(Graphics g, SynthMenuItemLayoutHelper lh,
|
||||
MenuItemLayoutHelper.LayoutResult lr) {
|
||||
if (lh.getIcon() != null) {
|
||||
Icon icon;
|
||||
JMenuItem mi = lh.getMenuItem();
|
||||
ButtonModel model = mi.getModel();
|
||||
if (!model.isEnabled()) {
|
||||
icon = mi.getDisabledIcon();
|
||||
} else if (model.isPressed() && model.isArmed()) {
|
||||
icon = mi.getPressedIcon();
|
||||
if (icon == null) {
|
||||
// Use default icon
|
||||
icon = mi.getIcon();
|
||||
}
|
||||
} else {
|
||||
icon = mi.getIcon();
|
||||
}
|
||||
|
||||
if (icon != null) {
|
||||
Rectangle iconRect = lr.getIconRect();
|
||||
SynthIcon.paintIcon(icon, lh.getContext(), g, iconRect.x,
|
||||
iconRect.y, iconRect.width, iconRect.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void paintCheckIcon(Graphics g, SynthMenuItemLayoutHelper lh,
|
||||
MenuItemLayoutHelper.LayoutResult lr) {
|
||||
if (lh.getCheckIcon() != null) {
|
||||
Rectangle checkRect = lr.getCheckRect();
|
||||
SynthIcon.paintIcon(lh.getCheckIcon(), lh.getContext(), g,
|
||||
checkRect.x, checkRect.y, checkRect.width, checkRect.height);
|
||||
}
|
||||
}
|
||||
|
||||
static void paintAccText(Graphics g, SynthMenuItemLayoutHelper lh,
|
||||
MenuItemLayoutHelper.LayoutResult lr) {
|
||||
String accText = lh.getAccText();
|
||||
if (accText != null && !accText.equals("")) {
|
||||
g.setColor(lh.getAccStyle().getColor(lh.getAccContext(),
|
||||
ColorType.TEXT_FOREGROUND));
|
||||
g.setFont(lh.getAccStyle().getFont(lh.getAccContext()));
|
||||
lh.getAccGraphicsUtils().paintText(lh.getAccContext(), g, accText,
|
||||
lr.getAccRect().x, lr.getAccRect().y, -1);
|
||||
}
|
||||
}
|
||||
|
||||
static void paintText(Graphics g, SynthMenuItemLayoutHelper lh,
|
||||
MenuItemLayoutHelper.LayoutResult lr) {
|
||||
if (!lh.getText().equals("")) {
|
||||
if (lh.getHtmlView() != null) {
|
||||
// Text is HTML
|
||||
lh.getHtmlView().paint(g, lr.getTextRect());
|
||||
} else {
|
||||
// Text isn't HTML
|
||||
g.setColor(lh.getStyle().getColor(
|
||||
lh.getContext(), ColorType.TEXT_FOREGROUND));
|
||||
g.setFont(lh.getStyle().getFont(lh.getContext()));
|
||||
lh.getGraphicsUtils().paintText(lh.getContext(), g, lh.getText(),
|
||||
lr.getTextRect().x, lr.getTextRect().y,
|
||||
lh.getMenuItem().getDisplayedMnemonicIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void paintArrowIcon(Graphics g, SynthMenuItemLayoutHelper lh,
|
||||
MenuItemLayoutHelper.LayoutResult lr) {
|
||||
if (lh.getArrowIcon() != null) {
|
||||
Rectangle arrowRect = lr.getArrowRect();
|
||||
SynthIcon.paintIcon(lh.getArrowIcon(), lh.getContext(), g,
|
||||
arrowRect.x, arrowRect.y, arrowRect.width, arrowRect.height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps a SynthIcon around the Icon interface, forwarding calls to
|
||||
* the SynthIcon with a given SynthContext.
|
||||
|
||||
@ -0,0 +1,307 @@
|
||||
/*
|
||||
* Copyright 2002-2008 Sun Microsystems, Inc. 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. Sun designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.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());
|
||||
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());
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2002-2008 Sun Microsystems, Inc. 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
|
||||
@ -37,7 +37,7 @@ import javax.swing.plaf.*;
|
||||
import javax.swing.plaf.basic.*;
|
||||
import javax.swing.text.View;
|
||||
import sun.swing.plaf.synth.*;
|
||||
import sun.swing.SwingUtilities2;
|
||||
import sun.swing.MenuItemLayoutHelper;
|
||||
|
||||
|
||||
/**
|
||||
@ -59,542 +59,16 @@ class SynthMenuItemUI extends BasicMenuItemUI implements
|
||||
return new SynthMenuItemUI();
|
||||
}
|
||||
|
||||
//
|
||||
// The next handful of static methods are used by both SynthMenuUI
|
||||
// and SynthMenuItemUI. This is necessitated by SynthMenuUI not
|
||||
// extending SynthMenuItemUI.
|
||||
//
|
||||
|
||||
/*
|
||||
* All JMenuItems (and JMenus) include enough space for the insets
|
||||
* plus one or more elements. When we say "icon(s)" below, we mean
|
||||
* "check/radio indicator and/or user icon." If both are defined for
|
||||
* a given menu item, then in a LTR orientation the check/radio indicator
|
||||
* is on the left side followed by the user icon to the right; it is
|
||||
* just the opposite in a RTL orientation.
|
||||
*
|
||||
* Cases to consider for SynthMenuItemUI (visualized here in a
|
||||
* LTR orientation; the RTL case would be reversed):
|
||||
* text
|
||||
* icon(s) + text
|
||||
* icon(s) + text + accelerator
|
||||
* text + accelerator
|
||||
*
|
||||
* Cases to consider for SynthMenuUI (again visualized here in a
|
||||
* LTR orientation):
|
||||
* text + arrow
|
||||
* (user)icon + text + 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.
|
||||
*
|
||||
* A quick note about how preferred sizes are calculated... Generally
|
||||
* speaking, SynthPopupMenuUI will run through the list of its children
|
||||
* (from top to bottom) and ask each for its preferred size. Each menu
|
||||
* item will add up the max width of each element (icons, text,
|
||||
* accelerator spacing, accelerator text or arrow icon) encountered thus
|
||||
* far, so by the time all menu items have been calculated, we will
|
||||
* know the maximum (preferred) menu item size for that popup menu.
|
||||
* Later when it comes time to paint each menu item, we can use those
|
||||
* same accumulated max element sizes in order to layout the item.
|
||||
*/
|
||||
static Dimension getPreferredMenuItemSize(SynthContext context,
|
||||
SynthContext accContext, JComponent c,
|
||||
Icon checkIcon, Icon arrowIcon, int defaultTextIconGap,
|
||||
String acceleratorDelimiter) {
|
||||
JMenuItem b = (JMenuItem) c;
|
||||
Icon icon = b.getIcon();
|
||||
String text = b.getText();
|
||||
KeyStroke accelerator = b.getAccelerator();
|
||||
String acceleratorText = "";
|
||||
|
||||
if (accelerator != null) {
|
||||
int modifiers = accelerator.getModifiers();
|
||||
if (modifiers > 0) {
|
||||
acceleratorText = KeyEvent.getKeyModifiersText(modifiers);
|
||||
acceleratorText += acceleratorDelimiter;
|
||||
}
|
||||
int keyCode = accelerator.getKeyCode();
|
||||
if (keyCode != 0) {
|
||||
acceleratorText += KeyEvent.getKeyText(keyCode);
|
||||
} else {
|
||||
acceleratorText += accelerator.getKeyChar();
|
||||
}
|
||||
}
|
||||
|
||||
Font font = context.getStyle().getFont(context);
|
||||
FontMetrics fm = b.getFontMetrics(font);
|
||||
FontMetrics fmAccel = b.getFontMetrics(accContext.getStyle().
|
||||
getFont(accContext));
|
||||
|
||||
resetRects();
|
||||
|
||||
layoutMenuItem(
|
||||
context, fm, accContext, text, fmAccel, acceleratorText,
|
||||
icon, checkIcon, arrowIcon, b.getVerticalAlignment(),
|
||||
b.getHorizontalAlignment(), b.getVerticalTextPosition(),
|
||||
b.getHorizontalTextPosition(), viewRect, iconRect, textRect,
|
||||
acceleratorRect, checkIconRect, arrowIconRect,
|
||||
text == null ? 0 : defaultTextIconGap, defaultTextIconGap);
|
||||
|
||||
r.setBounds(textRect);
|
||||
|
||||
int totalIconWidth = 0;
|
||||
int maxIconHeight = 0;
|
||||
if (icon != null) {
|
||||
// Add in the user icon
|
||||
totalIconWidth += iconRect.width;
|
||||
if (textRect.width > 0) {
|
||||
// Allow for some room between the user icon and the text
|
||||
totalIconWidth += defaultTextIconGap;
|
||||
}
|
||||
maxIconHeight = Math.max(iconRect.height, maxIconHeight);
|
||||
}
|
||||
if (checkIcon != null) {
|
||||
// Add in the checkIcon
|
||||
totalIconWidth += checkIconRect.width;
|
||||
if (textRect.width > 0 || icon != null) {
|
||||
// Allow for some room between the check/radio indicator
|
||||
// and the text (or user icon, if both are specified)
|
||||
totalIconWidth += defaultTextIconGap;
|
||||
}
|
||||
maxIconHeight = Math.max(checkIconRect.height, maxIconHeight);
|
||||
}
|
||||
|
||||
int arrowWidth = 0;
|
||||
if (arrowIcon != null) {
|
||||
// Add in the arrowIcon
|
||||
arrowWidth += defaultTextIconGap;
|
||||
arrowWidth += arrowIconRect.width;
|
||||
maxIconHeight = Math.max(arrowIconRect.height, maxIconHeight);
|
||||
}
|
||||
|
||||
int accelSpacing = 0;
|
||||
if (acceleratorRect.width > 0) {
|
||||
// Allow for some room between the text and the accelerator
|
||||
accelSpacing += 4*defaultTextIconGap;
|
||||
}
|
||||
|
||||
// Take text and all icons into account when determining height
|
||||
r.height = Math.max(r.height, maxIconHeight);
|
||||
|
||||
// To make the accelerator texts appear in a column,
|
||||
// find the widest MenuItem text and the widest accelerator text.
|
||||
|
||||
// Get the parent, which stores the information.
|
||||
Container parent = b.getParent();
|
||||
|
||||
if (parent instanceof JPopupMenu) {
|
||||
SynthPopupMenuUI popupUI = (SynthPopupMenuUI)SynthLookAndFeel.
|
||||
getUIOfType(((JPopupMenu)parent).getUI(),
|
||||
SynthPopupMenuUI.class);
|
||||
|
||||
if (popupUI != null) {
|
||||
// This gives us the widest MenuItem text encountered thus
|
||||
// far in the parent JPopupMenu
|
||||
r.width = popupUI.adjustTextWidth(r.width);
|
||||
|
||||
// Add in the widest icon (includes both user and
|
||||
// check/radio icons) encountered thus far
|
||||
r.width += popupUI.adjustIconWidth(totalIconWidth);
|
||||
|
||||
// Add in the widest text/accelerator spacing
|
||||
// encountered thus far
|
||||
r.width += popupUI.adjustAccelSpacingWidth(accelSpacing);
|
||||
|
||||
// Add in the widest accelerator text (or arrow)
|
||||
// encountered thus far (at least one of these values
|
||||
// will always be zero, so we combine them here to
|
||||
// avoid double counting)
|
||||
int totalAccelOrArrow = acceleratorRect.width + arrowWidth;
|
||||
r.width += popupUI.adjustAcceleratorWidth(totalAccelOrArrow);
|
||||
}
|
||||
}
|
||||
else if (parent != null && !(b instanceof JMenu &&
|
||||
((JMenu)b).isTopLevelMenu())) {
|
||||
r.width +=
|
||||
totalIconWidth + accelSpacing +
|
||||
acceleratorRect.width + arrowWidth;
|
||||
}
|
||||
|
||||
Insets insets = b.getInsets();
|
||||
if(insets != null) {
|
||||
r.width += insets.left + insets.right;
|
||||
r.height += insets.top + insets.bottom;
|
||||
}
|
||||
|
||||
// if the width is even, bump it up one. This is critical
|
||||
// for the focus dash line to draw properly
|
||||
if(r.width%2 == 0) {
|
||||
r.width++;
|
||||
}
|
||||
|
||||
// if the height is even, bump it up one. This is critical
|
||||
// for the text to center properly
|
||||
if(r.height%2 == 0) {
|
||||
r.height++;
|
||||
}
|
||||
return r.getSize();
|
||||
}
|
||||
|
||||
static void paint(SynthContext context, SynthContext accContext,
|
||||
Graphics g, Icon checkIcon, Icon arrowIcon,
|
||||
String acceleratorDelimiter,
|
||||
int defaultTextIconGap) {
|
||||
JComponent c = context.getComponent();
|
||||
JMenuItem b = (JMenuItem)c;
|
||||
ButtonModel model = b.getModel();
|
||||
Insets i = b.getInsets();
|
||||
|
||||
resetRects();
|
||||
|
||||
viewRect.setBounds(0, 0, b.getWidth(), b.getHeight());
|
||||
|
||||
viewRect.x += i.left;
|
||||
viewRect.y += i.top;
|
||||
viewRect.width -= (i.right + viewRect.x);
|
||||
viewRect.height -= (i.bottom + viewRect.y);
|
||||
|
||||
SynthStyle style = context.getStyle();
|
||||
Font f = style.getFont(context);
|
||||
g.setFont(f);
|
||||
FontMetrics fm = SwingUtilities2.getFontMetrics(c, g, f);
|
||||
FontMetrics accFM = SwingUtilities2.getFontMetrics(c, g,
|
||||
accContext.getStyle().
|
||||
getFont(accContext));
|
||||
|
||||
// get Accelerator text
|
||||
KeyStroke accelerator = b.getAccelerator();
|
||||
String acceleratorText = "";
|
||||
if (accelerator != null) {
|
||||
int modifiers = accelerator.getModifiers();
|
||||
if (modifiers > 0) {
|
||||
acceleratorText = KeyEvent.getKeyModifiersText(modifiers);
|
||||
acceleratorText += acceleratorDelimiter;
|
||||
}
|
||||
|
||||
int keyCode = accelerator.getKeyCode();
|
||||
if (keyCode != 0) {
|
||||
acceleratorText += KeyEvent.getKeyText(keyCode);
|
||||
} else {
|
||||
acceleratorText += accelerator.getKeyChar();
|
||||
}
|
||||
}
|
||||
|
||||
// Layout the text and icon
|
||||
String text = layoutMenuItem(context, fm, accContext,
|
||||
b.getText(), accFM, acceleratorText, b.getIcon(),
|
||||
checkIcon, arrowIcon,
|
||||
b.getVerticalAlignment(), b.getHorizontalAlignment(),
|
||||
b.getVerticalTextPosition(), b.getHorizontalTextPosition(),
|
||||
viewRect, iconRect, textRect, acceleratorRect,
|
||||
checkIconRect, arrowIconRect,
|
||||
b.getText() == null ? 0 : defaultTextIconGap,
|
||||
defaultTextIconGap
|
||||
);
|
||||
|
||||
// Paint the Check
|
||||
if (checkIcon != null) {
|
||||
SynthIcon.paintIcon(checkIcon, context, g, checkIconRect.x,
|
||||
checkIconRect.y, checkIconRect.width, checkIconRect.height);
|
||||
}
|
||||
|
||||
// Paint the Icon
|
||||
if(b.getIcon() != null) {
|
||||
Icon icon;
|
||||
if(!model.isEnabled()) {
|
||||
icon = b.getDisabledIcon();
|
||||
} else if(model.isPressed() && model.isArmed()) {
|
||||
icon = b.getPressedIcon();
|
||||
if(icon == null) {
|
||||
// Use default icon
|
||||
icon = b.getIcon();
|
||||
}
|
||||
} else {
|
||||
icon = b.getIcon();
|
||||
}
|
||||
|
||||
if (icon!=null) {
|
||||
SynthIcon.paintIcon(icon, context, g, iconRect.x,
|
||||
iconRect.y, iconRect.width, iconRect.height);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the Text
|
||||
if(text != null) {
|
||||
View v = (View) c.getClientProperty(BasicHTML.propertyKey);
|
||||
if (v != null) {
|
||||
v.paint(g, textRect);
|
||||
} else {
|
||||
g.setColor(style.getColor(context, ColorType.TEXT_FOREGROUND));
|
||||
g.setFont(style.getFont(context));
|
||||
style.getGraphicsUtils(context).paintText(context, g, text,
|
||||
textRect.x, textRect.y, b.getDisplayedMnemonicIndex());
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the Accelerator Text
|
||||
if(acceleratorText != null && !acceleratorText.equals("")) {
|
||||
// Get the maxAccWidth from the parent to calculate the offset.
|
||||
int accOffset = 0;
|
||||
Container parent = b.getParent();
|
||||
if (parent != null && parent instanceof JPopupMenu) {
|
||||
SynthPopupMenuUI popupUI = (SynthPopupMenuUI)
|
||||
((JPopupMenu)parent).getUI();
|
||||
|
||||
// Note that we can only get here for SynthMenuItemUI
|
||||
// (not SynthMenuUI) since acceleratorText is defined,
|
||||
// so this cast should be safe
|
||||
SynthMenuItemUI miUI = (SynthMenuItemUI)
|
||||
SynthLookAndFeel.getUIOfType(b.getUI(),
|
||||
SynthMenuItemUI.class);
|
||||
|
||||
if (popupUI != null && miUI != null) {
|
||||
String prop =
|
||||
miUI.getPropertyPrefix() + ".alignAcceleratorText";
|
||||
boolean align = style.getBoolean(context, prop, true);
|
||||
|
||||
// Calculate the offset, with which the accelerator texts
|
||||
// will be drawn.
|
||||
if (align) {
|
||||
// When align==true and we're in the LTR case,
|
||||
// we add an offset here so that all accelerators
|
||||
// will be left-justified in their own column.
|
||||
int max = popupUI.getMaxAcceleratorWidth();
|
||||
if (max > 0) {
|
||||
accOffset = max - acceleratorRect.width;
|
||||
if (!SynthLookAndFeel.isLeftToRight(c)) {
|
||||
// In the RTL, flip the sign so that all
|
||||
// accelerators will be right-justified.
|
||||
accOffset = -accOffset;
|
||||
}
|
||||
}
|
||||
} //else {
|
||||
// Don't need to do anything special here; in the
|
||||
// LTR case, the accelerator is already justified
|
||||
// against the right edge of the menu (and against
|
||||
// the left edge in the RTL case).
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
SynthStyle accStyle = accContext.getStyle();
|
||||
|
||||
g.setColor(accStyle.getColor(accContext,
|
||||
ColorType.TEXT_FOREGROUND));
|
||||
g.setFont(accStyle.getFont(accContext));
|
||||
accStyle.getGraphicsUtils(accContext).paintText(
|
||||
accContext, g, acceleratorText, acceleratorRect.x -
|
||||
accOffset, acceleratorRect.y, -1);
|
||||
}
|
||||
|
||||
// Paint the Arrow
|
||||
if (arrowIcon != null) {
|
||||
SynthIcon.paintIcon(arrowIcon, context, g, arrowIconRect.x,
|
||||
arrowIconRect.y, arrowIconRect.width, arrowIconRect.height);
|
||||
public void uninstallUI(JComponent c) {
|
||||
super.uninstallUI(c);
|
||||
// Remove values from the parent's Client Properties.
|
||||
JComponent p = MenuItemLayoutHelper.getMenuItemParent((JMenuItem) c);
|
||||
if (p != null) {
|
||||
p.putClientProperty(
|
||||
SynthMenuItemLayoutHelper.MAX_ACC_OR_ARROW_WIDTH, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute and return the location of the icons origin, the
|
||||
* location of origin of the text baseline, and a possibly clipped
|
||||
* version of the compound labels string. Locations are computed
|
||||
* relative to the viewRect rectangle.
|
||||
*/
|
||||
|
||||
private static String layoutMenuItem(
|
||||
SynthContext context,
|
||||
FontMetrics fm,
|
||||
SynthContext accContext,
|
||||
String text,
|
||||
FontMetrics fmAccel,
|
||||
String acceleratorText,
|
||||
Icon icon,
|
||||
Icon checkIcon,
|
||||
Icon arrowIcon,
|
||||
int verticalAlignment,
|
||||
int horizontalAlignment,
|
||||
int verticalTextPosition,
|
||||
int horizontalTextPosition,
|
||||
Rectangle viewRect,
|
||||
Rectangle iconRect,
|
||||
Rectangle textRect,
|
||||
Rectangle acceleratorRect,
|
||||
Rectangle checkIconRect,
|
||||
Rectangle arrowIconRect,
|
||||
int textIconGap,
|
||||
int menuItemGap
|
||||
)
|
||||
{
|
||||
// If parent is JPopupMenu, get and store it's UI
|
||||
SynthPopupMenuUI popupUI = null;
|
||||
JComponent b = context.getComponent();
|
||||
Container parent = b.getParent();
|
||||
if(parent instanceof JPopupMenu) {
|
||||
popupUI = (SynthPopupMenuUI)SynthLookAndFeel.
|
||||
getUIOfType(((JPopupMenu)parent).getUI(),
|
||||
SynthPopupMenuUI.class);
|
||||
}
|
||||
|
||||
context.getStyle().getGraphicsUtils(context).layoutText(
|
||||
context, fm, text, icon,horizontalAlignment, verticalAlignment,
|
||||
horizontalTextPosition, verticalTextPosition, viewRect,
|
||||
iconRect, textRect, textIconGap);
|
||||
|
||||
/* Initialize the acceleratorText bounds rectangle textRect. If a null
|
||||
* or and empty String was specified we substitute "" here
|
||||
* and use 0,0,0,0 for acceleratorTextRect.
|
||||
*/
|
||||
if( (acceleratorText == null) || acceleratorText.equals("") ) {
|
||||
acceleratorRect.width = acceleratorRect.height = 0;
|
||||
acceleratorText = "";
|
||||
}
|
||||
else {
|
||||
SynthStyle style = accContext.getStyle();
|
||||
acceleratorRect.width = style.getGraphicsUtils(accContext).
|
||||
computeStringWidth(accContext, fmAccel.getFont(), fmAccel,
|
||||
acceleratorText);
|
||||
acceleratorRect.height = fmAccel.getHeight();
|
||||
}
|
||||
|
||||
// Initialize the checkIcon bounds rectangle width & height.
|
||||
if (checkIcon != null) {
|
||||
checkIconRect.width = SynthIcon.getIconWidth(checkIcon,
|
||||
context);
|
||||
checkIconRect.height = SynthIcon.getIconHeight(checkIcon,
|
||||
context);
|
||||
}
|
||||
else {
|
||||
checkIconRect.width = checkIconRect.height = 0;
|
||||
}
|
||||
|
||||
// Initialize the arrowIcon bounds rectangle width & height.
|
||||
if (arrowIcon != null) {
|
||||
arrowIconRect.width = SynthIcon.getIconWidth(arrowIcon,
|
||||
context);
|
||||
arrowIconRect.height = SynthIcon.getIconHeight(arrowIcon,
|
||||
context);
|
||||
} else {
|
||||
arrowIconRect.width = arrowIconRect.height = 0;
|
||||
}
|
||||
|
||||
// Note: layoutText() has already left room for
|
||||
// the user icon, so no need to adjust textRect below
|
||||
// to account for the user icon. However, we do have to
|
||||
// reposition textRect when the check icon is visible.
|
||||
|
||||
Rectangle labelRect = iconRect.union(textRect);
|
||||
if( SynthLookAndFeel.isLeftToRight(context.getComponent()) ) {
|
||||
// Position the check and user icons
|
||||
iconRect.x = viewRect.x;
|
||||
if (checkIcon != null) {
|
||||
checkIconRect.x = viewRect.x;
|
||||
iconRect.x += menuItemGap + checkIconRect.width;
|
||||
textRect.x += menuItemGap + checkIconRect.width;
|
||||
}
|
||||
|
||||
// Position the arrow icon
|
||||
arrowIconRect.x =
|
||||
viewRect.x + viewRect.width - arrowIconRect.width;
|
||||
|
||||
// Position the accelerator text rect
|
||||
acceleratorRect.x =
|
||||
viewRect.x + viewRect.width - acceleratorRect.width;
|
||||
|
||||
/* Align icons and text horizontally */
|
||||
if(popupUI != null) {
|
||||
int thisTextOffset = popupUI.adjustTextOffset(textRect.x
|
||||
- viewRect.x);
|
||||
textRect.x = thisTextOffset + viewRect.x;
|
||||
|
||||
if(icon != null) {
|
||||
// REMIND: The following code currently assumes the
|
||||
// default (TRAILING) horizontalTextPosition, which means
|
||||
// it will always place the icon to the left of the text.
|
||||
// Other values of horizontalTextPosition aren't very
|
||||
// useful for menu items, so we ignore them for now, but
|
||||
// someday we might want to fix this situation.
|
||||
int thisIconOffset =
|
||||
popupUI.adjustIconOffset(iconRect.x - viewRect.x);
|
||||
iconRect.x = thisIconOffset + viewRect.x;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Position the accelerator text rect
|
||||
acceleratorRect.x = viewRect.x;
|
||||
|
||||
// Position the arrow icon
|
||||
arrowIconRect.x = viewRect.x;
|
||||
|
||||
// Position the check and user icons
|
||||
iconRect.x =
|
||||
viewRect.x + viewRect.width - iconRect.width;
|
||||
if (checkIcon != null) {
|
||||
checkIconRect.x =
|
||||
viewRect.x + viewRect.width - checkIconRect.width;
|
||||
textRect.x -= menuItemGap + checkIconRect.width;
|
||||
iconRect.x -= menuItemGap + checkIconRect.width;
|
||||
}
|
||||
|
||||
/* Align icons and text horizontally */
|
||||
if(popupUI != null) {
|
||||
int thisTextOffset = viewRect.x + viewRect.width
|
||||
- textRect.x - textRect.width;
|
||||
thisTextOffset = popupUI.adjustTextOffset(thisTextOffset);
|
||||
textRect.x = viewRect.x + viewRect.width
|
||||
- thisTextOffset - textRect.width;
|
||||
if(icon != null) {
|
||||
// REMIND: The following code currently assumes the
|
||||
// default (TRAILING) horizontalTextPosition, which means
|
||||
// it will always place the icon to the right of the text.
|
||||
// Other values of horizontalTextPosition aren't very
|
||||
// useful for menu items, so we ignore them for now, but
|
||||
// someday we might want to fix this situation.
|
||||
int thisIconOffset = viewRect.x + viewRect.width
|
||||
- iconRect.x - iconRect.width;
|
||||
thisIconOffset =
|
||||
popupUI.adjustIconOffset(thisIconOffset);
|
||||
iconRect.x = viewRect.x + viewRect.width
|
||||
- thisIconOffset - iconRect.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Align the accelerator text and all icons vertically
|
||||
// with the center of the label rect.
|
||||
int midY = labelRect.y + (labelRect.height/2);
|
||||
iconRect.y = midY - (iconRect.height/2);
|
||||
acceleratorRect.y = midY - (acceleratorRect.height/2);
|
||||
arrowIconRect.y = midY - (arrowIconRect.height/2);
|
||||
checkIconRect.y = midY - (checkIconRect.height/2);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
// these rects are used for painting and preferredsize calculations.
|
||||
// they used to be regenerated constantly. Now they are reused.
|
||||
static Rectangle iconRect = new Rectangle();
|
||||
static Rectangle textRect = new Rectangle();
|
||||
static Rectangle acceleratorRect = new Rectangle();
|
||||
static Rectangle checkIconRect = new Rectangle();
|
||||
static Rectangle arrowIconRect = new Rectangle();
|
||||
static Rectangle viewRect = new Rectangle(Short.MAX_VALUE,Short.MAX_VALUE);
|
||||
static Rectangle r = new Rectangle();
|
||||
|
||||
private static void resetRects() {
|
||||
iconRect.setBounds(0, 0, 0, 0);
|
||||
textRect.setBounds(0, 0, 0, 0);
|
||||
acceleratorRect.setBounds(0, 0, 0, 0);
|
||||
checkIconRect.setBounds(0, 0, 0, 0);
|
||||
arrowIconRect.setBounds(0, 0, 0, 0);
|
||||
viewRect.setBounds(0,0,Short.MAX_VALUE, Short.MAX_VALUE);
|
||||
r.setBounds(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
protected void installDefaults() {
|
||||
updateStyle(menuItem);
|
||||
}
|
||||
@ -718,9 +192,11 @@ class SynthMenuItemUI extends BasicMenuItemUI implements
|
||||
int defaultTextIconGap) {
|
||||
SynthContext context = getContext(c);
|
||||
SynthContext accContext = getContext(c, Region.MENU_ITEM_ACCELERATOR);
|
||||
Dimension value = getPreferredMenuItemSize(context, accContext,
|
||||
c, checkIcon, arrowIcon, defaultTextIconGap,
|
||||
acceleratorDelimiter);
|
||||
Dimension value = SynthGraphicsUtils.getPreferredMenuItemSize(
|
||||
context, accContext, c, checkIcon, arrowIcon,
|
||||
defaultTextIconGap, acceleratorDelimiter,
|
||||
MenuItemLayoutHelper.useCheckAndArrow(menuItem),
|
||||
getPropertyPrefix());
|
||||
context.dispose();
|
||||
accContext.dispose();
|
||||
return value;
|
||||
@ -751,14 +227,13 @@ class SynthMenuItemUI extends BasicMenuItemUI implements
|
||||
String prefix = getPropertyPrefix();
|
||||
Icon checkIcon = style.getIcon(context, prefix + ".checkIcon");
|
||||
Icon arrowIcon = style.getIcon(context, prefix + ".arrowIcon");
|
||||
paint(context, accContext, g, checkIcon, arrowIcon,
|
||||
acceleratorDelimiter, defaultTextIconGap);
|
||||
SynthGraphicsUtils.paint(context, accContext, g, checkIcon, arrowIcon,
|
||||
acceleratorDelimiter, defaultTextIconGap, getPropertyPrefix());
|
||||
accContext.dispose();
|
||||
}
|
||||
|
||||
void paintBackground(SynthContext context, Graphics g, JComponent c) {
|
||||
context.getPainter().paintMenuItemBackground(context, g, 0, 0,
|
||||
c.getWidth(), c.getHeight());
|
||||
SynthGraphicsUtils.paintBackground(context, g, c);
|
||||
}
|
||||
|
||||
public void paintBorder(SynthContext context, Graphics g, int x,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2002-2008 Sun Microsystems, Inc. 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
|
||||
@ -35,7 +35,7 @@ import javax.swing.border.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import sun.swing.plaf.synth.SynthUI;
|
||||
|
||||
import sun.swing.MenuItemLayoutHelper;
|
||||
|
||||
/**
|
||||
* Synth's MenuUI.
|
||||
@ -86,7 +86,7 @@ class SynthMenuUI extends BasicMenuUI implements PropertyChangeListener,
|
||||
acceleratorDelimiter = style.getString(context, prefix +
|
||||
".acceleratorDelimiter", "+");
|
||||
|
||||
if (useCheckAndArrow()) {
|
||||
if (MenuItemLayoutHelper.useCheckAndArrow(menuItem)) {
|
||||
checkIcon = style.getIcon(context, prefix + ".checkIcon");
|
||||
arrowIcon = style.getIcon(context, prefix + ".arrowIcon");
|
||||
} else {
|
||||
@ -111,6 +111,16 @@ class SynthMenuUI extends BasicMenuUI implements PropertyChangeListener,
|
||||
accContext.dispose();
|
||||
}
|
||||
|
||||
public void uninstallUI(JComponent c) {
|
||||
super.uninstallUI(c);
|
||||
// Remove values from the parent's Client Properties.
|
||||
JComponent p = MenuItemLayoutHelper.getMenuItemParent((JMenuItem) c);
|
||||
if (p != null) {
|
||||
p.putClientProperty(
|
||||
SynthMenuItemLayoutHelper.MAX_ACC_OR_ARROW_WIDTH, null);
|
||||
}
|
||||
}
|
||||
|
||||
protected void uninstallDefaults() {
|
||||
SynthContext context = getContext(menuItem, ENABLED);
|
||||
style.uninstallDefaults(context);
|
||||
@ -182,9 +192,11 @@ class SynthMenuUI extends BasicMenuUI implements PropertyChangeListener,
|
||||
int defaultTextIconGap) {
|
||||
SynthContext context = getContext(c);
|
||||
SynthContext accContext = getContext(c, Region.MENU_ITEM_ACCELERATOR);
|
||||
Dimension value = SynthMenuItemUI.getPreferredMenuItemSize(
|
||||
context, accContext, c, checkIcon, arrowIcon,
|
||||
defaultTextIconGap, acceleratorDelimiter);
|
||||
Dimension value = SynthGraphicsUtils.getPreferredMenuItemSize(
|
||||
context, accContext, c, checkIcon, arrowIcon,
|
||||
defaultTextIconGap, acceleratorDelimiter,
|
||||
MenuItemLayoutHelper.useCheckAndArrow(menuItem),
|
||||
getPropertyPrefix());
|
||||
context.dispose();
|
||||
accContext.dispose();
|
||||
return value;
|
||||
@ -211,21 +223,12 @@ class SynthMenuUI extends BasicMenuUI implements PropertyChangeListener,
|
||||
protected void paint(SynthContext context, Graphics g) {
|
||||
SynthContext accContext = getContext(menuItem,
|
||||
Region.MENU_ITEM_ACCELERATOR);
|
||||
SynthStyle style = context.getStyle();
|
||||
Icon checkIcon;
|
||||
Icon arrowIcon;
|
||||
if (useCheckAndArrow()) {
|
||||
// Refetch the appropriate icons for the current state
|
||||
String prefix = getPropertyPrefix();
|
||||
checkIcon = style.getIcon(context, prefix + ".checkIcon");
|
||||
arrowIcon = style.getIcon(context, prefix + ".arrowIcon");
|
||||
} else {
|
||||
// Not needed in this case
|
||||
checkIcon = null;
|
||||
arrowIcon = null;
|
||||
}
|
||||
SynthMenuItemUI.paint(context, accContext, g, checkIcon, arrowIcon,
|
||||
acceleratorDelimiter, defaultTextIconGap);
|
||||
// Refetch the appropriate check indicator for the current state
|
||||
String prefix = getPropertyPrefix();
|
||||
Icon checkIcon = style.getIcon(context, prefix + ".checkIcon");
|
||||
Icon arrowIcon = style.getIcon(context, prefix + ".arrowIcon");
|
||||
SynthGraphicsUtils.paint(context, accContext, g, checkIcon, arrowIcon,
|
||||
acceleratorDelimiter, defaultTextIconGap, getPropertyPrefix());
|
||||
accContext.dispose();
|
||||
}
|
||||
|
||||
@ -239,8 +242,4 @@ class SynthMenuUI extends BasicMenuUI implements PropertyChangeListener,
|
||||
updateStyle((JMenu)e.getSource());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean useCheckAndArrow() {
|
||||
return !((JMenu)menuItem).isTopLevelMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2006 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 2002-2008 Sun Microsystems, Inc. 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
|
||||
@ -58,34 +58,6 @@ import sun.swing.plaf.synth.SynthUI;
|
||||
*/
|
||||
class SynthPopupMenuUI extends BasicPopupMenuUI implements
|
||||
PropertyChangeListener, SynthUI {
|
||||
/**
|
||||
* Maximum size of the text portion of the children menu items.
|
||||
*/
|
||||
private int maxTextWidth;
|
||||
|
||||
/**
|
||||
* Maximum size of the icon portion of the children menu items.
|
||||
*/
|
||||
private int maxIconWidth;
|
||||
|
||||
/**
|
||||
* Maximum size of the spacing between the text and accelerator
|
||||
* portions of the children menu items.
|
||||
*/
|
||||
private int maxAccelSpacingWidth;
|
||||
|
||||
/**
|
||||
* Maximum size of the text for the accelerator portion of the children
|
||||
* menu items.
|
||||
*/
|
||||
private int maxAcceleratorWidth;
|
||||
|
||||
/*
|
||||
* Maximum icon and text offsets of the children menu items.
|
||||
*/
|
||||
private int maxTextOffset;
|
||||
private int maxIconOffset;
|
||||
|
||||
private SynthStyle style;
|
||||
|
||||
public static ComponentUI createUI(JComponent x) {
|
||||
@ -153,90 +125,6 @@ class SynthPopupMenuUI extends BasicPopupMenuUI implements
|
||||
return SynthLookAndFeel.getComponentState(c);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the max text and accerator widths,
|
||||
* text and icon offsets.
|
||||
*/
|
||||
void resetAlignmentHints() {
|
||||
maxTextWidth = maxIconWidth
|
||||
= maxAccelSpacingWidth = maxAcceleratorWidth
|
||||
= maxTextOffset = maxIconOffset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the width needed to display the maximum menu item string.
|
||||
*
|
||||
* @param width Text width.
|
||||
* @return max width
|
||||
*/
|
||||
int adjustTextWidth(int width) {
|
||||
maxTextWidth = Math.max(maxTextWidth, width);
|
||||
return maxTextWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the width needed to display the maximum menu item icon.
|
||||
*
|
||||
* @param width Icon width.
|
||||
* @return max width
|
||||
*/
|
||||
int adjustIconWidth(int width) {
|
||||
maxIconWidth = Math.max(maxIconWidth, width);
|
||||
return maxIconWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the width needed to pad between the maximum menu item
|
||||
* text and accelerator.
|
||||
*
|
||||
* @param width Spacing width.
|
||||
* @return max width
|
||||
*/
|
||||
int adjustAccelSpacingWidth(int width) {
|
||||
maxAccelSpacingWidth = Math.max(maxAccelSpacingWidth, width);
|
||||
return maxAccelSpacingWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the width needed to display the maximum accelerator.
|
||||
*
|
||||
* @param width Text width.
|
||||
* @return max width
|
||||
*/
|
||||
int adjustAcceleratorWidth(int width) {
|
||||
maxAcceleratorWidth = Math.max(maxAcceleratorWidth, width);
|
||||
return maxAcceleratorWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum size needed to display accelerators of children menu items.
|
||||
*/
|
||||
int getMaxAcceleratorWidth() {
|
||||
return maxAcceleratorWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the text offset needed to align text horizontally.
|
||||
*
|
||||
* @param offset Text offset
|
||||
* @return max offset
|
||||
*/
|
||||
int adjustTextOffset(int offset) {
|
||||
maxTextOffset = Math.max(maxTextOffset, offset);
|
||||
return maxTextOffset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts the icon offset needed to align icons horizontally
|
||||
*
|
||||
* @param offset Icon offset
|
||||
* @return max offset
|
||||
*/
|
||||
int adjustIconOffset(int offset) {
|
||||
maxIconOffset = Math.max(maxIconOffset, offset);
|
||||
return maxIconOffset;
|
||||
}
|
||||
|
||||
public void update(Graphics g, JComponent c) {
|
||||
SynthContext context = getContext(c);
|
||||
|
||||
|
||||
1339
jdk/src/share/classes/sun/swing/MenuItemLayoutHelper.java
Normal file
1339
jdk/src/share/classes/sun/swing/MenuItemLayoutHelper.java
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user