1 /* 2 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.apple.laf; 27 28 import java.awt.*; 29 import java.awt.event.MouseEvent; 30 31 import javax.swing.*; 32 import javax.swing.event.*; 33 import javax.swing.plaf.ComponentUI; 34 import javax.swing.plaf.basic.BasicMenuUI; 35 36 public class AquaMenuUI extends BasicMenuUI implements AquaMenuPainter.Client { 37 public static ComponentUI createUI(final JComponent x) { 38 return new AquaMenuUI(); 39 } 40 41 protected ChangeListener createChangeListener(final JComponent c) { 42 return new ChangeHandler((JMenu)c, this); 43 } 44 45 protected void installDefaults() { 46 super.installDefaults(); 47 48 // [3361625] 49 // In Aqua, the menu delay is 8 ticks, according to Eric Schlegel. 50 // That makes the millisecond delay 8 ticks * 1 second / 60 ticks * 1000 milliseconds/second 51 ((JMenu)menuItem).setDelay(8 * 1000 / 60); 52 } 53 54 protected void paintMenuItem(final Graphics g, final JComponent c, final Icon localCheckIcon, final Icon localArrowIcon, final Color background, final Color foreground, final int localDefaultTextIconGap) { 55 AquaMenuPainter.instance().paintMenuItem(this, g, c, localCheckIcon, localArrowIcon, background, foreground, disabledForeground, selectionForeground, localDefaultTextIconGap, acceleratorFont); 56 } 57 58 protected Dimension getPreferredMenuItemSize(final JComponent c, final Icon localCheckIcon, final Icon localArrowIcon, final int localDefaultTextIconGap) { 59 final Dimension d = AquaMenuPainter.instance().getPreferredMenuItemSize(c, localCheckIcon, localArrowIcon, localDefaultTextIconGap, acceleratorFont); 60 if (c.getParent() instanceof JMenuBar) d.height = Math.max(d.height, 21); 61 return d; 62 } 63 64 public void paintBackground(final Graphics g, final JComponent c, final int menuWidth, final int menuHeight) { 65 final Container parent = c.getParent(); 66 final boolean parentIsMenuBar = parent instanceof JMenuBar; 67 68 final ButtonModel model = ((JMenuItem)c).getModel(); 69 if (model.isArmed() || model.isSelected()) { 70 if (parentIsMenuBar) { 71 AquaMenuPainter.instance().paintSelectedMenuTitleBackground(g, menuWidth, menuHeight); 72 } else { 73 AquaMenuPainter.instance().paintSelectedMenuItemBackground(g, menuWidth, menuHeight); 74 } 75 } else { 76 if (parentIsMenuBar) { 77 AquaMenuPainter.instance().paintMenuBarBackground(g, menuWidth, menuHeight, c); 78 } else { 79 g.setColor(c.getBackground()); 80 g.fillRect(0, 0, menuWidth, menuHeight); 81 } 82 } 83 } 84 85 protected MouseInputListener createMouseInputListener(final JComponent c) { 86 return new AquaMouseInputHandler(); 87 } 88 89 protected MenuDragMouseListener createMenuDragMouseListener(final JComponent c) { 90 //return super.createMenuDragMouseListener(c); 91 return new MenuDragMouseHandler(); 92 } 93 94 class MenuDragMouseHandler implements MenuDragMouseListener { 95 public void menuDragMouseDragged(final MenuDragMouseEvent e) { 96 if (menuItem.isEnabled() == false) return; 97 98 final MenuSelectionManager manager = e.getMenuSelectionManager(); 99 final MenuElement path[] = e.getPath(); 100 101 // In Aqua, we always respect the menu's delay, if one is set. 102 // Doesn't matter how the menu is clicked on or otherwise moused over. 103 final Point p = e.getPoint(); 104 if (p.x >= 0 && p.x < menuItem.getWidth() && p.y >= 0 && p.y < menuItem.getHeight()) { 105 final JMenu menu = (JMenu)menuItem; 106 final MenuElement selectedPath[] = manager.getSelectedPath(); 107 if (!(selectedPath.length > 0 && selectedPath[selectedPath.length - 1] == menu.getPopupMenu())) { 108 if (menu.getDelay() == 0) { 109 appendPath(path, menu.getPopupMenu()); 110 } else { 111 manager.setSelectedPath(path); 112 setupPostTimer(menu); 113 } 114 } 115 } else if (e.getID() == MouseEvent.MOUSE_RELEASED) { 116 final Component comp = manager.componentForPoint(e.getComponent(), e.getPoint()); 117 if (comp == null) manager.clearSelectedPath(); 118 } 119 } 120 121 public void menuDragMouseEntered(final MenuDragMouseEvent e) { } 122 public void menuDragMouseExited(final MenuDragMouseEvent e) { } 123 public void menuDragMouseReleased(final MenuDragMouseEvent e) { } 124 } 125 126 static void appendPath(final MenuElement[] path, final MenuElement elem) { 127 final MenuElement newPath[] = new MenuElement[path.length + 1]; 128 System.arraycopy(path, 0, newPath, 0, path.length); 129 newPath[path.length] = elem; 130 MenuSelectionManager.defaultManager().setSelectedPath(newPath); 131 } 132 133 protected class AquaMouseInputHandler extends MouseInputHandler { 134 /** 135 * Invoked when the cursor enters the menu. This method sets the selected 136 * path for the MenuSelectionManager and handles the case 137 * in which a menu item is used to pop up an additional menu, as in a 138 * hierarchical menu system. 139 * 140 * @param e the mouse event; not used 141 */ 142 public void mouseEntered(final MouseEvent e) { 143 final JMenu menu = (JMenu)menuItem; 144 if (!menu.isEnabled()) return; 145 146 final MenuSelectionManager manager = MenuSelectionManager.defaultManager(); 147 final MenuElement selectedPath[] = manager.getSelectedPath(); 148 149 // In Aqua, we always have a menu delay, regardless of where the menu is. 150 if (!(selectedPath.length > 0 && selectedPath[selectedPath.length - 1] == menu.getPopupMenu())) { 151 // the condition below prevents from activating menu in other frame 152 if (!menu.isTopLevelMenu() || (selectedPath.length > 0 && 153 selectedPath[0] == menu.getParent())) { 154 if (menu.getDelay() == 0) { 155 appendPath(getPath(), menu.getPopupMenu()); 156 } else { 157 manager.setSelectedPath(getPath()); 158 setupPostTimer(menu); 159 } 160 } 161 } 162 } 163 } 164 }