📄 officexpmenuitemui.java
字号:
/* ====================================================================
*
* Office Look and Feels License
* http://sourceforge.net/projects/officelnfs
*
* Copyright (c) 2003-2005 Robert Futrell. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "Office Look And Feels" and "OfficeLnFs" must not
* be used to endorse or promote products derived from this software
* without prior written permission. For written permission, please
* contact robert_futrell@users.sourceforge.net.
*
* 4. Products derived from this software may not be called "OfficeLnFs"
* nor may "OfficeLnFs" appear in their names without prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ====================================================================
*/
package org.fife.plaf.OfficeXP;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import javax.swing.ButtonModel;
import javax.swing.*;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentUI;
import com.sun.java.swing.plaf.windows.WindowsMenuItemUI;
/**
* UI for menu items using the OfficeXP Look and Feel.
*
* @author Robert Futrell
* @version 1.0
*/
public class OfficeXPMenuItemUI extends WindowsMenuItemUI {
static final int MENU_ITEM_HEIGHT = 23;
static final String MAX_TEXT_WIDTH = "maxTextWidth";
static final String MAX_ACC_WIDTH = "maxAccWidth";
// These rects are used for painting and preferredsize calculations.
// They used to be regenerated constantly. Now they are reused.
protected static final Rectangle zeroRect = new Rectangle(0,0,0,0);
protected static Rectangle iconRect = new Rectangle();
protected static Rectangle textRect = new Rectangle();
protected static Rectangle acceleratorRect = new Rectangle();
protected static Rectangle viewRect = new Rectangle(Short.MAX_VALUE, Short.MAX_VALUE);
protected static Rectangle r = new Rectangle();
protected MouseInputListener createMouseInputListener(JComponent c) {
return new RMouseInputHandler();
}
public static ComponentUI createUI(JComponent c) {
return new OfficeXPMenuItemUI();
}
protected Dimension getPreferredMenuItemSize(JComponent c,
Icon checkIcon,
Icon arrowIcon,
int defaultTextIconGap) {
JMenuItem b = (JMenuItem) c;
Icon 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 += "+";
}
int keyCode = accelerator.getKeyCode();
if (keyCode != 0) {
acceleratorText += KeyEvent.getKeyText(keyCode);
}
else {
acceleratorText += accelerator.getKeyChar();
}
}
Font font = b.getFont();
FontMetrics fm = c.getFontMetrics(font);
resetRects();
layoutMenuItem(
fm, text, acceleratorText, icon, checkIcon, arrowIcon,
viewRect, iconRect, textRect, acceleratorRect,
text == null ? 0 : defaultTextIconGap,
defaultTextIconGap
);
// Find the union of the icon and text rects.
r.setBounds(textRect);
r = SwingUtilities.computeUnion(iconRect.x, iconRect.y,
iconRect.width, iconRect.height, r);
// To make the text and accelerators of each menu item in a menu
// align, we'll check the width of each for this menu item, and if
// either value is greater than the parent menu's cached current
// greatest value, it is updated. Since all menu items do this
// (even child JMenus, but they do it in OfficeXPMenuUI), the
// parent menu will have the proper values.
// We need a JComponent-derived parent in order to store the
// width properties.
Container parent = menuItem.getParent();
if (parent != null && parent instanceof JComponent) {
JComponent p = (JComponent) parent;
// Get widest values so far from parent, or null if none yet.
Integer maxTextWidth = (Integer) p.getClientProperty(MAX_TEXT_WIDTH);
Integer maxAccWidth = (Integer) p.getClientProperty(MAX_ACC_WIDTH);
int maxTextValue = maxTextWidth!=null ? maxTextWidth.intValue() : 0;
int maxAccValue = maxAccWidth!=null ? maxAccWidth.intValue() : 0;
//Compare the text widths, and adjust the r.width to the widest.
if (r.width < maxTextValue) {
r.width = maxTextValue;
}
else {
p.putClientProperty(MAX_TEXT_WIDTH, new Integer(r.width) );
}
// Compare the accelarator widths.
if (acceleratorRect.width > maxAccValue) {
maxAccValue = acceleratorRect.width;
p.putClientProperty(MAX_ACC_WIDTH, new Integer(acceleratorRect.width) );
}
// Add on the widest accelerator.
r.width += maxAccValue;
r.width += defaultTextIconGap;
}
// Add in the checkIcon
r.width += 20;//checkIconRect.width;
r.width += defaultTextIconGap;
// Add in the arrowIcon
r.width += defaultTextIconGap;
r.width += 12;//arrowIconRect.width;
// Add in the "padding" on either side of the menu item.
r.width += 2*defaultTextIconGap;
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 new Dimension((int)r.getWidth(), MENU_ITEM_HEIGHT);
}
/**
* 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 viewR rectangle.
*/
public static String layoutCompoundLabel(JComponent c, FontMetrics fm,
String text, Rectangle viewR,
Rectangle iconR, Rectangle textR) {
boolean ltr = true;
if (c!=null) ltr = c.getComponentOrientation().isLeftToRight();
//int hAlign = ltr ? SwingConstants.RIGHT : SwingConstants.LEFT;
int hTextPos = ltr ? SwingConstants.LEFT : SwingConstants.RIGHT;
// Note that iconR won't matter if an icon doesn't exist, so it
// doesn't matter that it's in the same (x,y) location as the text.
iconR.width = 20;
iconR.height = 20;
if (hTextPos==SwingConstants.LEFT) {
iconR.x = 4;
}
else {
iconR.x = viewR.x+viewR.width-20-1;
}
iconR.y = viewR.y + (viewR.height/2) - 7; //(iconR.height/2);
// Initialize the text bounds rectangle textR. If a null
// or and empty String was specified we substitute "" here
// and use 0,0,0,0 for textR.
boolean textIsEmpty = (text == null) || text.equals("");
if (textIsEmpty) {
textR.width = textR.height = 0;
text = "";
}
else {
textR.width = SwingUtilities.computeStringWidth(fm,text);
textR.height = fm.getHeight();
/* If the label text string is too wide to fit within the available
* space, "..." and as many characters as will fit will be
* displayed instead.
*/
int availTextWidth = viewR.width - 32;
if (textR.width > availTextWidth) {
String clipString = "...";
int totalWidth = SwingUtilities.computeStringWidth(fm,clipString);
int nChars;
for(nChars = 0; nChars < text.length(); nChars++) {
totalWidth += fm.charWidth(text.charAt(nChars));
if (totalWidth > availTextWidth)
break;
}
text = text.substring(0, nChars) + clipString;
textR.width = SwingUtilities.computeStringWidth(fm,text);
}
}
// If this is a top-level menu, there will be no icon.
if ((c instanceof JMenu) && ((JMenu)c).isTopLevelMenu()) {
int nonShadowWidth = viewR.width - 4;
textR.x = viewR.x + nonShadowWidth/2 - textR.width/2; // Text will be centered.
}
else
// Text will be placed after the icon/check/whatever if it's not
// a top-level menu item.
if (hTextPos==SwingConstants.LEFT) {
textR.x = 32;
}
else { // SwingConstants.RIGHT
Integer i = (Integer)c.getClientProperty(MAX_ACC_WIDTH);
//int maxAccWidth = i==null ? 0 : i.intValue();
textR.x = viewR.x+viewR.width -(32 + /*defaultTextIconGap*/5 + textR.width);
}
// Must compute text's y-coordinate after textR.height has been computed.
textR.y = viewR.y + (viewR.height/2) - (textR.height/2);
return text;
}
/**
* 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.
*/
protected String layoutMenuItem(FontMetrics fm, String text,
String acceleratorText, Icon icon, Icon checkIcon,
Icon arrowIcon, Rectangle viewRect, Rectangle iconRect,
Rectangle textRect, Rectangle acceleratorRect,
int textIconGap, int menuItemGap) {
// Lay out the text and icon rectangles.
layoutCompoundLabel(menuItem, fm, text, viewRect, iconRect, textRect);
// Give dimensions to the accelerator text rectangle if the text is
// actually something.
if (!acceleratorText.equals("")) {
acceleratorRect.width = SwingUtilities.computeStringWidth( fm, acceleratorText );
acceleratorRect.height = fm.getHeight();
if (menuItem.getComponentOrientation().isLeftToRight()) {
acceleratorRect.x = viewRect.x + viewRect.width - 12/*arrowIconRect.width*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -