Package org.fife.plaf.OfficeXP

Source Code of org.fife.plaf.OfficeXP.OfficeXPMenuItemUI$RMouseInputHandler

/* ====================================================================
*
* 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*/
                  - menuItemGap - acceleratorRect.width;
      }
      else {
        acceleratorRect.x = viewRect.x + 20;
      }
      acceleratorRect.y = textRect.y;
    }

    //Rectangle labelRect = iconRect.union(textRect);

        return text;

    }


    public void paint(final Graphics g, final JComponent c) {
        paintMenuItem(g, c, checkIcon, arrowIcon,
                      selectionBackground, selectionForeground,
                      defaultTextIconGap);
    }



    /**
     * Draws the background of the menu item.
     *
     * @param g the paint graphics
     * @param menuItem menu item to be painted
     * @param bgColor selection background color
     */
  protected void paintBackground(Graphics g, JMenuItem menuItem, Color bgColor) {

    ButtonModel model = menuItem.getModel();
    Color oldColor = g.getColor();
    int menuItemWidth = menuItem.getWidth();
    int menuItemHeight = menuItem.getHeight();

    paintUnarmedBackground(g, menuItem);

    // 20061120 fabio: Highlight shouldn't be painted when item is disabled
    if (model.isArmed() && menuItem.isEnabled()) {

      int width = menuItemWidth - 3;
      int height = menuItemHeight - 2;

      g.setColor(UIManager.getColor("OfficeLnF.HighlightBorderColor"));
      g.drawRect(1,0, width,height);
      g.setColor(UIManager.getColor("OfficeLnF.HighlightColor"));
      g.fillRect(2,1, width-1,height-1);

    } else {
      // Do nothing; the background has already been painted above.
    }

    // Add the white line to the bottom item.  Note that this CANNOT be added as
    // a part of the popup menu's border because of Office XP's menu item design;
    // there's an empty line between each menu item, but the top and bottom empty
    // lines are pure background color (no "khaki" on the left).  If you can think
    // of a simpler way to do it, then by all means, go ahead.
    JPopupMenu popupMenu = (JPopupMenu)menuItem.getParent();
    if (popupMenu.getComponentIndex(menuItem) == popupMenu.getComponentCount()-1) {
      g.setColor(menuItem.getBackground());
      int y = menuItemHeight - 1;
      // Do whole line to cover both LTR and RTL.
      g.drawLine(0,y, menuItemWidth-1,y);
    }

    g.setColor(oldColor);

    }


  protected void paintCheck(Graphics g, JMenuItem menuItem) {
    ButtonModel model = menuItem.getModel();
    if(menuItem.isSelected()) {
      int x = iconRect.x-2;
      if (!menuItem.getComponentOrientation().isLeftToRight()) {
        x++; // ???
      }
      int y = 1;
      int width = 19;//20;//checkIconRect.width;
      int height = 19;//20;//checkIconRect.height;
      Color oldColor = g.getColor();
      g.setColor(UIManager.getColor("OfficeLnF.HighlightBorderColor"));
      g.drawRect(x,y, width,height);
      if (model.isArmed())
        g.setColor(UIManager.getColor("OfficeXPLnF.PressedHighlightColor"));
      else
        g.setColor(UIManager.getColor("OfficeXPLnF.CheckBoxHighlightColor"));
      g.fillRect(x+1,y+1, width-1,height-1);
      g.setColor(oldColor);
      checkIcon.paintIcon(menuItem, g, x+6,y+6);//8,7);//checkIconRect.x, checkIconRect.y);
    }
  }


  protected void paintIcon(Graphics g, JMenuItem menuItem) {
    OfficeXPUtilities.paintMenuItemIcon(g, menuItem, iconRect);
  }


  protected void paintMenuItem(Graphics g, JComponent c,
                                     Icon checkIcon, Icon arrowIcon,
                                     Color background, Color foreground,
                                     int defaultTextIconGap) {

    JMenuItem b = (JMenuItem) c;
    ButtonModel model = b.getModel();

    int menuWidth = b.getWidth();
    int menuHeight = b.getHeight();

    resetRects();

    viewRect.setBounds( 0, 0, menuWidth, menuHeight );

    Font holdf = g.getFont();
    Font f = c.getFont();
    g.setFont(f);
    FontMetrics fm = c.getFontMetrics(f);

    // get Accelerator text
    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();
    }

    // layout the text and icon
    String text = layoutMenuItem(
      fm, b.getText(), acceleratorText, b.getIcon(),
      checkIcon, arrowIcon,
      viewRect, iconRect, textRect, acceleratorRect,
      b.getText() == null ? 0 : defaultTextIconGap,
      defaultTextIconGap
    );

    // Paint background
    paintBackground(g, b, background);

    Color holdc = g.getColor();

    // Paint the Check
    boolean isCheckOrRadio = (c instanceof JCheckBoxMenuItem) ||
              (c instanceof JRadioButtonMenuItem);
    if (checkIcon != null && isCheckOrRadio)
      paintCheck(g, menuItem);

    // Paint the Icon
    if(b.getIcon()!=null && !isCheckOrRadio)
      paintIcon(g, menuItem);

    // Draw the Text
    paintText(g, b, textRect, text);

    // Draw the Accelerator Text
    if(!acceleratorText.equals("")) {

      //Get the maxAccWidth from the parent to calculate the offset.
      int accOffset = 0;
      Container parent = menuItem.getParent();
      if (parent != null && parent instanceof JComponent) {

        JComponent p = (JComponent) parent;
        Integer maxValueInt = (Integer) p.getClientProperty(OfficeXPMenuItemUI.MAX_ACC_WIDTH);
        int maxValue = maxValueInt != null ?
                maxValueInt.intValue() : acceleratorRect.width;

        //Calculate the offset, with which the accelerator texts will be drawn.
        accOffset = maxValue - acceleratorRect.width;

      }

      // Ensure all accelerators are right-aligned for RTL.
      if (!c.getComponentOrientation().isLeftToRight()) {
        Integer maxValueInt = null;
        if (parent!=null && parent instanceof JComponent) {
          maxValueInt = (Integer)((JComponent)b.getParent()).
            getClientProperty(OfficeXPMenuItemUI.MAX_ACC_WIDTH);
        }
        int maxValue = maxValueInt!=null ? maxValueInt.intValue() :
                      acceleratorRect.width;
        accOffset = 0;
        acceleratorRect.x = 20 + maxValue - acceleratorRect.width;
      }

      if(!model.isEnabled()) {
        // *** paint the acceleratorText disabled

        if ( disabledForeground != null ) {
          g.setColor( disabledForeground );
          OfficeXPGraphicsUtils.drawString(g,fm,acceleratorText,0,
                  acceleratorRect.x - accOffset,
                  acceleratorRect.y + fm.getAscent());
        }
        else {
          g.setColor(b.getBackground().brighter());
          OfficeXPGraphicsUtils.drawString(g,fm,acceleratorText,0,
                  acceleratorRect.x - accOffset,
                  acceleratorRect.y + fm.getAscent());
          g.setColor(b.getBackground().darker());
          OfficeXPGraphicsUtils.drawString(g,fm,acceleratorText,0,
                  acceleratorRect.x - accOffset - 1,
                  acceleratorRect.y + fm.getAscent() - 1);
        }

      }
      else {
        // *** paint the acceleratorText normally
        g.setColor( acceleratorForeground );
        OfficeXPGraphicsUtils.drawString(g,fm,acceleratorText, 0,
                  acceleratorRect.x - accOffset,
                  acceleratorRect.y + fm.getAscent());
      }

    }

    g.setColor(holdc);
    g.setFont(holdf);

  }


    /**
     * Method which renders the text of the current menu item.
     *
     * @param g Graphics context
     * @param menuItem Current menu item to render
     * @param textRect Bounding rectangle to render the text.
     * @param text String to render
     */
  protected void paintText(Graphics g, JMenuItem menuItem,
            Rectangle textRect, String text) {

    ButtonModel model = menuItem.getModel();

    if(!model.isEnabled()) {
      OfficeXPGraphicsUtils.paintText(g, menuItem, textRect, text, 0);
    }
    else {
      FontMetrics fm = menuItem.getFontMetrics(g.getFont());
      int mnemonicIndex = menuItem.getDisplayedMnemonicIndex();
      Color oldColor = g.getColor();
      OfficeXPGraphicsUtils.drawStringUnderlineCharAt(g,fm,text,mnemonicIndex,
              textRect.x, textRect.y + fm.getAscent());
      g.setColor(oldColor);
    }

    }


  protected void paintUnarmedBackground(Graphics g, JMenuItem menuItem) {
    OfficeXPUtilities.paintMenuItemBackground(g, menuItem);
  }


    protected void resetRects() {
        iconRect.setBounds(zeroRect);
        textRect.setBounds(zeroRect);
        acceleratorRect.setBounds(zeroRect);
        viewRect.setBounds(0,0,Short.MAX_VALUE, Short.MAX_VALUE);
        r.setBounds(zeroRect);
    }


  /*
   * Returns false if the component is a JMenu and it is a top
   * level menu (on the menubar).
   */
  private boolean useCheckAndArrow(){
    boolean b = true;
    if((menuItem instanceof JMenu) && (((JMenu)menuItem).isTopLevelMenu()))
      b = false;
    return b;
  }


  private class RMouseInputHandler extends MouseInputHandler {

    public void mouseExited(MouseEvent mouseEvent) {
      MenuSelectionManager menuSelectionManager = MenuSelectionManager.defaultManager();
      int mask = InputEvent.BUTTON1_MASK | InputEvent.BUTTON2_MASK |
          InputEvent.BUTTON3_MASK;
      if ((mouseEvent.getModifiers() & mask) != 0) {
        MenuSelectionManager.defaultManager().processMouseEvent(mouseEvent);
      }
      else {
        MenuElement path[] = menuSelectionManager.getSelectedPath();
        if (path.length > 1 && !(path[path.length-1] instanceof JPopupMenu)) {
          MenuElement newPath[] = new MenuElement[path.length-1];
          for (int i = 0; i < path.length - 1; i++)
            newPath[i] = path[i];
          menuSelectionManager.setSelectedPath(newPath);
        }
      }
    }

  }


}
TOP

Related Classes of org.fife.plaf.OfficeXP.OfficeXPMenuItemUI$RMouseInputHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.