1999-07-06 15:50:03 +00:00
|
|
|
/*
|
|
|
|
NSMenuView.m
|
|
|
|
|
|
|
|
Copyright (C) 1999 Free Software Foundation, Inc.
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
Author: David Lazaro Saz <khelekir@encomix.es>
|
|
|
|
Date: Oct 1999
|
|
|
|
|
1999-07-18 03:53:42 +00:00
|
|
|
Author: Michael Hanni <mhanni@sprintmail.com>
|
|
|
|
Date: 1999
|
1999-07-06 15:50:03 +00:00
|
|
|
|
|
|
|
This file is part of the GNUstep GUI Library.
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library 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
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public
|
|
|
|
License along with this library; see the file COPYING.LIB.
|
|
|
|
If not, write to the Free Software Foundation,
|
|
|
|
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
#include <AppKit/NSApplication.h>
|
|
|
|
#include <AppKit/NSEvent.h>
|
1999-11-16 22:25:07 +00:00
|
|
|
#include <AppKit/NSFont.h>
|
1999-06-30 03:10:38 +00:00
|
|
|
#include <AppKit/NSMenuView.h>
|
|
|
|
#include <AppKit/NSWindow.h>
|
|
|
|
#include <AppKit/PSOperators.h>
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
static float GSMenuBarHeight = 25.0; // A wild guess.
|
1999-06-30 03:10:38 +00:00
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
// FIXME Check this strange comment:
|
1999-07-18 03:53:42 +00:00
|
|
|
// These private methods are used in NSPopUpButton. For NSPB we need to be
|
|
|
|
// able to init with a frame, but have a very custom cell size.
|
|
|
|
|
1999-11-22 21:48:03 +00:00
|
|
|
// Michael: This simply means that for popups the menu code cannot
|
|
|
|
// arbitraily decide the cellSize. The size of the popup must be
|
|
|
|
// consistent.
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
@implementation NSMenuView
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
/*
|
|
|
|
* Class methods.
|
|
|
|
*/
|
|
|
|
+ (float) menuBarHeight
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
return GSMenuBarHeight;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
/*
|
|
|
|
* NSView overrides
|
|
|
|
*/
|
|
|
|
- (BOOL) acceptsFirstMouse: (NSEvent*)theEvent
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
/*
|
|
|
|
* Init methods.
|
|
|
|
*/
|
|
|
|
- (id) init
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-07-06 15:45:19 +00:00
|
|
|
return [self initWithFrame: NSZeroRect];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (id) initWithFrame: (NSRect)aFrame
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
cellSize = NSMakeSize(110,20);
|
1999-11-16 22:25:07 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
menuv_highlightedItemIndex = -1;
|
1999-11-16 22:25:07 +00:00
|
|
|
menuv_horizontalEdgePad = 4.;
|
|
|
|
|
|
|
|
// Create an array to store out menu item cells.
|
|
|
|
menuv_itemCells = [NSMutableArray new];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-07-06 15:45:19 +00:00
|
|
|
return [super initWithFrame: aFrame];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) _setCellSize: (NSSize)aSize
|
1999-11-22 21:48:03 +00:00
|
|
|
{
|
|
|
|
cellSize = aSize;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (id) initWithFrame: (NSRect)aFrame
|
|
|
|
cellSize: (NSSize)aSize
|
1999-07-18 03:53:42 +00:00
|
|
|
{
|
2000-01-05 17:42:47 +00:00
|
|
|
[self initWithFrame: aFrame];
|
1999-07-18 03:53:42 +00:00
|
|
|
|
|
|
|
cellSize = aSize;
|
|
|
|
|
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
/*
|
|
|
|
* Getting and Setting Menu View Attributes
|
|
|
|
*/
|
|
|
|
- (void) setMenu: (NSMenu*)menu
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
2000-01-05 17:42:47 +00:00
|
|
|
NSNotificationCenter *theCenter = [NSNotificationCenter defaultCenter];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
if (menuv_menu != nil)
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
|
|
|
// Remove this menu view from the old menu list of observers.
|
|
|
|
[theCenter removeObserver: self name: nil object: menuv_menu];
|
|
|
|
[menuv_menu release];
|
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
ASSIGN(menuv_menu, menu);
|
1999-07-18 03:53:42 +00:00
|
|
|
menuv_items_link = [menuv_menu itemArray];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
// Add this menu view to the menu's list of observers.
|
|
|
|
[theCenter addObserver: self
|
|
|
|
selector: @selector(itemChanged:)
|
|
|
|
name: NSMenuDidChangeItemNotification
|
|
|
|
object: menuv_menu];
|
|
|
|
|
|
|
|
[theCenter addObserver: self
|
|
|
|
selector: @selector(itemAdded:)
|
|
|
|
name: NSMenuDidAddItemNotification
|
|
|
|
object: menuv_menu];
|
|
|
|
|
|
|
|
[theCenter addObserver: self
|
|
|
|
selector: @selector(itemRemoved:)
|
|
|
|
name: NSMenuDidRemoveItemNotification
|
|
|
|
object: menuv_menu];
|
|
|
|
|
|
|
|
// Force menu view's layout to be recalculated.
|
|
|
|
[self setNeedsSizing: YES];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (NSMenu*) menu
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
return menuv_menu;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) setHorizontal: (BOOL)flag
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
menuv_horizontal = flag;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (BOOL) isHorizontal
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
return menuv_horizontal;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) setFont: (NSFont*)font
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
ASSIGN(menuv_font, font);
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (NSFont*) font
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
return menuv_font;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) setHighlightedItemIndex: (int)index
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
id aCell;
|
1999-06-30 03:10:38 +00:00
|
|
|
|
|
|
|
[self lockFocus];
|
|
|
|
|
1999-09-12 03:19:36 +00:00
|
|
|
if (index == -1)
|
|
|
|
{
|
|
|
|
if (menuv_highlightedItemIndex != -1)
|
|
|
|
{
|
|
|
|
NSRect aRect = [self rectOfItemAtIndex: menuv_highlightedItemIndex];
|
1999-07-18 03:53:42 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
aCell = [menuv_itemCells objectAtIndex: menuv_highlightedItemIndex];
|
1999-07-18 03:53:42 +00:00
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
[aCell highlight: NO withFrame: aRect inView: self];
|
1999-09-05 21:29:11 +00:00
|
|
|
|
1999-09-12 03:19:36 +00:00
|
|
|
[window flushWindow];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-09-12 03:19:36 +00:00
|
|
|
menuv_highlightedItemIndex = -1;
|
|
|
|
}
|
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
else if (index >= 0)
|
1999-09-12 03:19:36 +00:00
|
|
|
{
|
2000-01-05 17:42:47 +00:00
|
|
|
if (menuv_highlightedItemIndex != -1)
|
1999-09-12 03:19:36 +00:00
|
|
|
{
|
|
|
|
NSRect aRect = [self rectOfItemAtIndex: menuv_highlightedItemIndex];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
aCell = [menuv_itemCells objectAtIndex: menuv_highlightedItemIndex];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
[aCell highlight: NO withFrame: aRect inView: self];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-09-12 03:19:36 +00:00
|
|
|
[window flushWindow];
|
1999-07-23 00:28:31 +00:00
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-09-12 03:19:36 +00:00
|
|
|
if (index != menuv_highlightedItemIndex)
|
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
id anItem = [menuv_items_link objectAtIndex: index];
|
1999-09-12 03:19:36 +00:00
|
|
|
|
|
|
|
if ([anItem isEnabled])
|
|
|
|
{
|
|
|
|
NSRect aRect = [self rectOfItemAtIndex: index];
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
aCell = [menuv_itemCells objectAtIndex: index];
|
1999-09-12 03:19:36 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
[aCell highlight: YES withFrame: aRect inView: self];
|
1999-09-12 03:19:36 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
[window flushWindow];
|
1999-09-12 03:19:36 +00:00
|
|
|
}
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
// Set ivar to new index.
|
1999-09-12 03:19:36 +00:00
|
|
|
menuv_highlightedItemIndex = index;
|
|
|
|
}
|
|
|
|
else if (menuv_highlightedItemIndex == index)
|
|
|
|
{
|
|
|
|
menuv_highlightedItemIndex = -1;
|
|
|
|
}
|
1999-06-30 21:01:16 +00:00
|
|
|
}
|
1999-09-12 03:19:36 +00:00
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
[self unlockFocus];
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (int) highlightedItemIndex
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
return menuv_highlightedItemIndex;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) setMenuItemCell: (NSMenuItemCell *)cell
|
|
|
|
forItemAtIndex: (int)index
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
[menuv_itemCells replaceObjectAtIndex: index withObject: cell];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
// Mark the new cell and the menu view as needing resizing.
|
1999-07-06 15:45:19 +00:00
|
|
|
[cell setNeedsSizing: YES];
|
|
|
|
[self setNeedsSizing: YES];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (NSMenuItemCell*) menuItemCellForItemAtIndex: (int)index
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
return [menuv_itemCells objectAtIndex: index];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (NSMenuView*) attachedMenuView
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
2000-01-05 17:42:47 +00:00
|
|
|
NSMenu *attachedMenu;
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
if ((attachedMenu = [menuv_menu attachedMenu]))
|
|
|
|
return [attachedMenu menuRepresentation];
|
|
|
|
else
|
|
|
|
return nil;
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (NSMenu*) attachedMenu
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
return [menuv_menu attachedMenu];
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (BOOL) isAttached
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
return [menuv_menu isAttached];
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (BOOL) isTornOff
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
return [menuv_menu isTornOff];
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) setHorizontalEdgePadding: (float)pad
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
menuv_horizontalEdgePad = pad;
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (float) horizontalEdgePadding
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
return menuv_horizontalEdgePad;
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
/*
|
|
|
|
* Notification Methods
|
|
|
|
*/
|
|
|
|
- (void) itemChanged: (NSNotification*)notification
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
int index = [[[notification userInfo] objectForKey: @"NSMenuItemIndex"]
|
|
|
|
intValue];
|
|
|
|
|
|
|
|
// Mark the cell associated with the item as needing resizing.
|
|
|
|
[[menuv_itemCells objectAtIndex: index] setNeedsSizing: YES];
|
|
|
|
|
|
|
|
// Mark the menu view as needing to be resized.
|
|
|
|
[self setNeedsSizing: YES];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) itemAdded: (NSNotification*)notification
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
int index = [[[notification userInfo]
|
|
|
|
objectForKey: @"NSMenuItemIndex"] intValue];
|
|
|
|
NSMenuItem *anItem = [menuv_items_link objectAtIndex: index];
|
|
|
|
id aCell = [NSMenuItemCell new];
|
|
|
|
|
|
|
|
[aCell setMenuItem: anItem];
|
|
|
|
[aCell setMenuView: self];
|
|
|
|
|
|
|
|
if ([self highlightedItemIndex] == index)
|
|
|
|
[aCell setHighlighted: YES];
|
|
|
|
else
|
|
|
|
[aCell setHighlighted: NO];
|
|
|
|
|
|
|
|
[menuv_itemCells insertObject: aCell atIndex: index];
|
|
|
|
|
|
|
|
[aCell setNeedsSizing: YES];
|
|
|
|
|
|
|
|
// Mark the menu view as needing to be resized.
|
|
|
|
[self setNeedsSizing: YES];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) itemRemoved: (NSNotification*)notification
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-12-03 11:52:11 +00:00
|
|
|
int wasHighlighted = [self highlightedItemIndex];
|
1999-11-16 22:25:07 +00:00
|
|
|
int index = [[[notification userInfo] objectForKey: @"NSMenuItemIndex"]
|
|
|
|
intValue];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-12-03 11:52:11 +00:00
|
|
|
if (index <= wasHighlighted)
|
|
|
|
{
|
|
|
|
[self setHighlightedItemIndex: -1];
|
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
[menuv_itemCells removeObjectAtIndex: index];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-12-03 11:52:11 +00:00
|
|
|
if (wasHighlighted > index)
|
|
|
|
{
|
|
|
|
[self setHighlightedItemIndex: --wasHighlighted];
|
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
// Mark the menu view as needing to be resized.
|
|
|
|
[self setNeedsSizing: YES];
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
/*
|
|
|
|
* Working with Submenus.
|
|
|
|
*/
|
|
|
|
- (void) detachSubmenu
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
NSMenu *attachedMenu = [menuv_menu attachedMenu];
|
|
|
|
NSMenuView *attachedMenuView;
|
|
|
|
|
|
|
|
if (!attachedMenu)
|
|
|
|
return;
|
|
|
|
|
|
|
|
attachedMenuView = [attachedMenu menuRepresentation];
|
|
|
|
|
|
|
|
[attachedMenuView detachSubmenu];
|
|
|
|
|
|
|
|
[attachedMenuView setHighlightedItemIndex: -1];
|
|
|
|
|
|
|
|
if ([attachedMenu isFollowTransient])
|
|
|
|
{
|
|
|
|
[attachedMenu closeTransient];
|
|
|
|
[attachedMenuView setHighlightedItemIndex: _oldHighlightedItemIndex];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[attachedMenu close];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) attachSubmenuForItemAtIndex: (int)index
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
2000-01-05 17:42:47 +00:00
|
|
|
/*
|
|
|
|
* Transient menus are used for torn-off menus, which are already on the
|
|
|
|
* screen and for sons of transient menus. As transients disappear as
|
|
|
|
* soon as we release the mouse the user will be able to leave submenus
|
|
|
|
* open on the screen and interact with other menus at the same time.
|
|
|
|
*/
|
1999-11-16 22:25:07 +00:00
|
|
|
NSMenu *attachableMenu = [[menuv_items_link objectAtIndex: index] submenu];
|
|
|
|
|
|
|
|
if ([attachableMenu isTornOff] || [menuv_menu isFollowTransient])
|
|
|
|
{
|
|
|
|
_oldHighlightedItemIndex = [[attachableMenu menuRepresentation]
|
|
|
|
highlightedItemIndex];
|
|
|
|
[attachableMenu displayTransient];
|
|
|
|
[[attachableMenu menuRepresentation] setHighlightedItemIndex: -1];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
[attachableMenu display];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
/*
|
|
|
|
* Calculating Menu Geometry
|
|
|
|
*/
|
|
|
|
- (void) update
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
[menuv_menu update];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
|
|
|
if (menuv_needsSizing)
|
|
|
|
[self sizeToFit];
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) setNeedsSizing: (BOOL)flag
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
menuv_needsSizing = flag;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (BOOL) needsSizing
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
return menuv_needsSizing;
|
|
|
|
}
|
|
|
|
|
1999-11-24 16:54:23 +00:00
|
|
|
- (void) sizeToFit
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-24 16:54:23 +00:00
|
|
|
unsigned i;
|
|
|
|
unsigned howMany = [menuv_itemCells count];
|
|
|
|
float howHigh = (howMany * cellSize.height);
|
|
|
|
float neededImageAndTitleWidth = [[NSFont boldSystemFontOfSize: 12]
|
|
|
|
widthOfString: [menuv_menu title]] + 17;
|
2000-01-05 20:16:59 +00:00
|
|
|
float neededKeyEquivalentWidth = 0.0;
|
|
|
|
float neededStateImageWidth = 0.0;
|
|
|
|
float accumulatedOffset = 0.0;
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
// TODO: Optimize this loop.
|
|
|
|
for (i = 0; i < howMany; i++)
|
1999-11-24 16:54:23 +00:00
|
|
|
{
|
|
|
|
float anImageAndTitleWidth;
|
|
|
|
float anImageWidth;
|
|
|
|
float aKeyEquivalentWidth;
|
|
|
|
float aStateImageWidth;
|
|
|
|
float aTitleWidth;
|
|
|
|
NSMenuItemCell *aCell = [menuv_itemCells objectAtIndex: i];
|
|
|
|
|
|
|
|
// State image area.
|
|
|
|
aStateImageWidth = [aCell stateImageWidth];
|
|
|
|
|
|
|
|
if (aStateImageWidth > neededStateImageWidth)
|
|
|
|
neededStateImageWidth = aStateImageWidth;
|
|
|
|
|
|
|
|
// Image and title area.
|
|
|
|
aTitleWidth = [aCell titleWidth];
|
|
|
|
anImageWidth = [aCell imageWidth];
|
|
|
|
switch ([aCell imagePosition])
|
|
|
|
{
|
2000-01-05 17:42:47 +00:00
|
|
|
case NSNoImage:
|
1999-11-24 16:54:23 +00:00
|
|
|
anImageAndTitleWidth = aTitleWidth;
|
|
|
|
break;
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
case NSImageOnly:
|
1999-11-24 16:54:23 +00:00
|
|
|
anImageAndTitleWidth = anImageWidth;
|
|
|
|
break;
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
case NSImageLeft:
|
|
|
|
case NSImageRight:
|
1999-11-24 16:54:23 +00:00
|
|
|
anImageAndTitleWidth = anImageWidth + aTitleWidth + xDist;
|
|
|
|
break;
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
case NSImageBelow:
|
|
|
|
case NSImageAbove:
|
|
|
|
case NSImageOverlaps:
|
|
|
|
default:
|
1999-11-24 16:54:23 +00:00
|
|
|
if (aTitleWidth > anImageWidth)
|
|
|
|
anImageAndTitleWidth = aTitleWidth;
|
|
|
|
else
|
|
|
|
anImageAndTitleWidth = anImageWidth;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
anImageAndTitleWidth += aStateImageWidth;
|
|
|
|
if (anImageAndTitleWidth > neededImageAndTitleWidth)
|
|
|
|
neededImageAndTitleWidth = anImageAndTitleWidth;
|
|
|
|
|
|
|
|
// Key equivalent area.
|
|
|
|
aKeyEquivalentWidth = [aCell keyEquivalentWidth];
|
|
|
|
|
|
|
|
if (aKeyEquivalentWidth > neededKeyEquivalentWidth)
|
|
|
|
neededKeyEquivalentWidth = aKeyEquivalentWidth;
|
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
// Cache the needed widths.
|
|
|
|
menuv_stateImageWidth = neededStateImageWidth;
|
|
|
|
menuv_imageAndTitleWidth = neededImageAndTitleWidth;
|
|
|
|
menuv_keyEqWidth = neededKeyEquivalentWidth;
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
// Calculate the offsets and cache them.
|
|
|
|
menuv_stateImageOffset = menuv_imageAndTitleOffset = accumulatedOffset =
|
|
|
|
menuv_horizontalEdgePad;
|
|
|
|
accumulatedOffset += 2 * menuv_horizontalEdgePad + neededImageAndTitleWidth;
|
|
|
|
|
|
|
|
menuv_keyEqOffset = accumulatedOffset += menuv_horizontalEdgePad;
|
|
|
|
accumulatedOffset += neededKeyEquivalentWidth + menuv_horizontalEdgePad;
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
// Calculate frame size.
|
1999-12-03 21:38:43 +00:00
|
|
|
if (![menuv_menu _ownedByPopUp])
|
1999-11-24 16:54:23 +00:00
|
|
|
cellSize.width = accumulatedOffset + 3; // Add the border width
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
[self setFrameSize: NSMakeSize(cellSize.width + 1, howHigh)];
|
|
|
|
|
|
|
|
menuv_needsSizing = NO;
|
1999-07-18 03:53:42 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (float) stateImageOffset
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
if (menuv_needsSizing)
|
|
|
|
[self sizeToFit];
|
|
|
|
|
|
|
|
return menuv_stateImageOffset;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (float) stateImageWidth
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
if (menuv_needsSizing)
|
|
|
|
[self sizeToFit];
|
|
|
|
|
|
|
|
return menuv_stateImageWidth;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (float) imageAndTitleOffset
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
if (menuv_needsSizing)
|
|
|
|
[self sizeToFit];
|
|
|
|
|
|
|
|
return menuv_imageAndTitleOffset;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (float) imageAndTitleWidth
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
if (menuv_needsSizing)
|
|
|
|
[self sizeToFit];
|
|
|
|
|
|
|
|
return menuv_imageAndTitleWidth;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (float) keyEquivalentOffset
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
if (menuv_needsSizing)
|
|
|
|
[self sizeToFit];
|
|
|
|
|
|
|
|
return menuv_keyEqOffset;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (float) keyEquivalentWidth
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
if (menuv_needsSizing)
|
|
|
|
[self sizeToFit];
|
|
|
|
|
|
|
|
return menuv_keyEqWidth;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (NSRect) innerRect
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
NSRect aRect = {{bounds.origin.x + 1, bounds.origin.y},
|
|
|
|
{bounds.size.width - 1, bounds.size.height}};
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
return aRect;
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (NSRect) rectOfItemAtIndex: (int)index
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
NSRect theRect;
|
|
|
|
|
|
|
|
if (menuv_needsSizing)
|
|
|
|
[self sizeToFit];
|
|
|
|
|
|
|
|
if (index == 0)
|
1999-11-16 22:25:07 +00:00
|
|
|
theRect.origin.y = bounds.size.height - cellSize.height;
|
1999-06-30 03:10:38 +00:00
|
|
|
else
|
1999-11-16 22:25:07 +00:00
|
|
|
theRect.origin.y = bounds.size.height - (cellSize.height * (index + 1));
|
|
|
|
theRect.origin.x = 1;
|
1999-06-30 03:10:38 +00:00
|
|
|
theRect.size = cellSize;
|
|
|
|
|
|
|
|
return theRect;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (int) indexOfItemAtPoint: (NSPoint)point
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
// The MacOSX API says that this method calls - rectOfItemAtIndex for
|
|
|
|
// *every* cell to figure this out. Well, instead we will just do some
|
1999-07-27 19:15:19 +00:00
|
|
|
// simple math. (NOTE: if we get horizontal methods we will have to do
|
|
|
|
// this. Very much like NSTabView.
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
return ( point.x < frame.origin.x
|
|
|
|
|| point.x > frame.size.width + frame.origin.x
|
|
|
|
|| point.y <= frame.origin.y
|
|
|
|
|| point.y > frame.size.height + frame.origin.y) ?
|
2000-01-05 17:42:47 +00:00
|
|
|
-1 :
|
1999-11-16 22:25:07 +00:00
|
|
|
(frame.size.height - point.y) / cellSize.height;
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
1999-12-03 10:27:39 +00:00
|
|
|
- (void) setNeedsDisplayForItemAtIndex: (int)index
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-12-03 10:27:39 +00:00
|
|
|
NSRect aRect = [self rectOfItemAtIndex: index];
|
|
|
|
|
|
|
|
[self setNeedsDisplayInRect: aRect];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (NSPoint) locationForSubmenu: (NSMenu *)aSubmenu
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
if (menuv_needsSizing)
|
|
|
|
[self sizeToFit];
|
|
|
|
|
|
|
|
// find aSubmenu's parent
|
|
|
|
|
|
|
|
// position aSubmenu's window to be adjacent to its parent.
|
|
|
|
|
|
|
|
// return new origin of window.
|
|
|
|
return NSZeroPoint;
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) resizeWindowWithMaxHeight: (float)maxHeight
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
|
|
|
// set the menuview's window to max height in order to keep on screen?
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (void) setWindowFrameForAttachingToRect: (NSRect)screenRect
|
|
|
|
onScreen: (NSScreen*)screen
|
|
|
|
preferredEdge: (NSRectEdge)edge
|
|
|
|
popUpSelectedItem: (int)selectedItemIndex
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-12-11 03:04:22 +00:00
|
|
|
NSRect r;
|
|
|
|
|
|
|
|
// Move the menu window to screen?
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
// Compute position for popups, if needed
|
|
|
|
if (selectedItemIndex > -1)
|
|
|
|
{
|
|
|
|
screenRect.origin.y += ([self convertSize: cellSize
|
|
|
|
toView: nil].height
|
|
|
|
* selectedItemIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the frameRect
|
|
|
|
r = [NSMenuWindow frameRectForContentRect: screenRect
|
|
|
|
styleMask: [window styleMask]];
|
|
|
|
|
|
|
|
// Update position,if needed, using the preferredEdge;
|
2000-01-05 17:42:47 +00:00
|
|
|
// It seems we should be calling [self resizeWindowWithMaxHeight:];
|
1999-12-11 03:04:22 +00:00
|
|
|
// see the (quite obscure) doc.
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
// Set the window frame
|
|
|
|
[window setFrame: r
|
|
|
|
display: YES];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
/*
|
|
|
|
* Drawing.
|
|
|
|
*/
|
|
|
|
- (void) drawRect: (NSRect)rect
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
int i;
|
|
|
|
NSRect aRect = [self innerRect];
|
|
|
|
int howMany = [menuv_itemCells count];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
NSGraphicsContext *ctxt = GSCurrentContext();
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
// Draw a dark gray line at the left of the menu item cells.
|
|
|
|
DPSgsave(ctxt);
|
|
|
|
DPSsetlinewidth(ctxt, 1);
|
|
|
|
DPSsetgray(ctxt, 0.333);
|
|
|
|
DPSmoveto(ctxt, bounds.origin.x, bounds.origin.y);
|
|
|
|
DPSrlineto(ctxt, 0, bounds.size.height);
|
|
|
|
DPSstroke(ctxt);
|
|
|
|
DPSgrestore(ctxt);
|
|
|
|
|
|
|
|
// Draw the menu cells.
|
1999-07-18 03:53:42 +00:00
|
|
|
aRect.origin.y = cellSize.height * (howMany - 1);
|
1999-06-30 03:10:38 +00:00
|
|
|
aRect.size = cellSize;
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
for (i = 0; i < howMany; i++)
|
2000-01-05 17:42:47 +00:00
|
|
|
{
|
|
|
|
id aCell;
|
1999-11-16 22:25:07 +00:00
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
aCell = [menuv_itemCells objectAtIndex: i];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
[aCell drawWithFrame: aRect inView: self];
|
|
|
|
aRect.origin.y -= cellSize.height;
|
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
/*
|
|
|
|
* Event Handling
|
|
|
|
*/
|
|
|
|
- (void) performActionWithHighlightingForItemAtIndex: (int)index
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
NSMenu *candidateMenu = menuv_menu;
|
|
|
|
NSMenuView *targetMenuView;
|
|
|
|
int indexToHighlight = index;
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
for (;;)
|
|
|
|
{
|
2000-01-05 17:42:47 +00:00
|
|
|
if (![candidateMenu supermenu]
|
|
|
|
|| [candidateMenu isAttached]
|
|
|
|
|| [candidateMenu isTornOff])
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
|
|
|
targetMenuView = [candidateMenu menuRepresentation];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NSMenu *superMenu = [candidateMenu supermenu];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
indexToHighlight = [superMenu indexOfItemWithSubmenu: candidateMenu];
|
|
|
|
candidateMenu = superMenu;
|
|
|
|
}
|
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
if ([targetMenuView attachedMenu])
|
|
|
|
[targetMenuView detachSubmenu];
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
[targetMenuView setHighlightedItemIndex: indexToHighlight];
|
1999-09-05 21:29:11 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
[menuv_menu performActionForItemAtIndex: index];
|
1999-09-05 21:29:11 +00:00
|
|
|
|
1999-11-17 23:01:54 +00:00
|
|
|
[NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]];
|
1999-11-16 22:25:07 +00:00
|
|
|
[targetMenuView setHighlightedItemIndex: -1];
|
|
|
|
}
|
1999-09-05 21:29:11 +00:00
|
|
|
|
2000-01-07 20:46:45 +00:00
|
|
|
#define MOVE_THRESHOLD_DELTA 2.0
|
2000-01-05 20:16:59 +00:00
|
|
|
#define DELAY_MULTIPLIER 6
|
1999-11-17 23:01:54 +00:00
|
|
|
|
2000-01-07 20:46:45 +00:00
|
|
|
- (BOOL) trackWithEvent: (NSEvent*)event
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2000-01-07 20:46:45 +00:00
|
|
|
unsigned eventMask = NSPeriodicMask;
|
1999-11-16 22:25:07 +00:00
|
|
|
NSDate *theDistantFuture = [NSDate distantFuture];
|
2000-01-05 20:16:59 +00:00
|
|
|
int index;
|
|
|
|
NSPoint location;
|
|
|
|
NSPoint lastLocation = {0,0};
|
|
|
|
NSMenu *alreadyAttachedMenu = NO;
|
|
|
|
BOOL mouseMoved = NO;
|
|
|
|
BOOL delayedSelect = NO;
|
|
|
|
int delayCount = 0;
|
|
|
|
float xDelta = MOVE_THRESHOLD_DELTA;
|
|
|
|
float yDelta = 0.0;
|
2000-01-07 20:46:45 +00:00
|
|
|
NSEvent *original;
|
|
|
|
NSEventType type = [event type];
|
|
|
|
NSEventType end;
|
1999-09-12 03:19:36 +00:00
|
|
|
|
2000-01-07 20:46:45 +00:00
|
|
|
/*
|
|
|
|
* The original event is unused except to determine whether the method
|
|
|
|
* was invoked in response to a right or left mouse down.
|
|
|
|
* We pass the same event on when we want tracking to move into a
|
|
|
|
* submenu.
|
|
|
|
*/
|
|
|
|
original = AUTORELEASE(RETAIN(event));
|
|
|
|
if (type == NSRightMouseDown)
|
|
|
|
{
|
|
|
|
end = NSRightMouseUp;
|
|
|
|
eventMask |= NSRightMouseUpMask | NSRightMouseDraggedMask;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
end = NSLeftMouseUp;
|
|
|
|
eventMask |= NSLeftMouseUpMask | NSLeftMouseDraggedMask;
|
|
|
|
}
|
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
do
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
2000-01-05 16:35:47 +00:00
|
|
|
location = [window mouseLocationOutsideOfEventStream];
|
|
|
|
index = [self indexOfItemAtPoint: location];
|
1999-07-06 15:45:19 +00:00
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
if (index != menuv_highlightedItemIndex)
|
|
|
|
{
|
|
|
|
mouseMoved = YES; /* Ok - had an initial movement. */
|
|
|
|
}
|
2000-01-07 20:46:45 +00:00
|
|
|
if (type == NSPeriodic)
|
1999-11-17 23:01:54 +00:00
|
|
|
{
|
|
|
|
if ([menuv_menu isPartlyOffScreen])
|
|
|
|
{
|
2000-01-05 20:16:59 +00:00
|
|
|
NSPoint pointerLoc = [window convertBaseToScreen: location];
|
1999-11-17 23:01:54 +00:00
|
|
|
|
|
|
|
// TODO: Why 1 in the Y axis?
|
2000-01-05 20:16:59 +00:00
|
|
|
if (pointerLoc.x == 0 || pointerLoc.y == 1
|
|
|
|
|| pointerLoc.x == [[window screen] frame].size.width - 1)
|
1999-11-17 23:01:54 +00:00
|
|
|
[menuv_menu shiftOnScreen];
|
|
|
|
}
|
2000-01-05 16:35:47 +00:00
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
if (delayedSelect && mouseMoved && [event type] == NSPeriodic)
|
1999-11-19 18:18:58 +00:00
|
|
|
{
|
2000-01-05 20:16:59 +00:00
|
|
|
float xDiff = location.x - lastLocation.x;
|
|
|
|
float yDiff = location.y - lastLocation.y;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Once the mouse movement has started in one vertical
|
|
|
|
* direction, it must continue in the same direction if
|
|
|
|
* selection is to be delayed.
|
|
|
|
*/
|
|
|
|
if (yDelta == 0.0)
|
|
|
|
{
|
|
|
|
if (yDiff < 0.0)
|
|
|
|
yDelta = -MOVE_THRESHOLD_DELTA;
|
|
|
|
else if (yDiff > 0.0)
|
|
|
|
yDelta = MOVE_THRESHOLD_DELTA;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Check to see if movement is less than the threshold.
|
|
|
|
*/
|
|
|
|
if (xDiff < xDelta
|
|
|
|
|| (yDelta < 0.0 && yDiff > yDelta)
|
|
|
|
|| (yDelta > 0.0 && yDiff < yDelta))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* if we have had too many successive small movements, or
|
|
|
|
* a single movement too far in the wrong direction, we
|
|
|
|
* leave 'delayedSelect' mode.
|
|
|
|
*/
|
|
|
|
delayCount++;
|
|
|
|
if (delayCount >= DELAY_MULTIPLIER
|
2000-01-07 20:46:45 +00:00
|
|
|
|| (xDiff < 0)
|
2000-01-05 20:16:59 +00:00
|
|
|
|| (yDelta < 0.0 && yDiff > -yDelta)
|
|
|
|
|| (yDelta > 0.0 && yDiff < -yDelta))
|
|
|
|
{
|
|
|
|
delayedSelect = NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delayCount = 0;
|
|
|
|
}
|
2000-01-05 16:35:47 +00:00
|
|
|
lastLocation = location;
|
1999-11-19 18:18:58 +00:00
|
|
|
}
|
1999-11-17 23:01:54 +00:00
|
|
|
}
|
1999-07-20 10:34:34 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
if (index == -1)
|
1999-07-06 15:45:19 +00:00
|
|
|
{
|
2000-01-07 20:46:45 +00:00
|
|
|
NSWindow *w;
|
|
|
|
|
|
|
|
location = [window convertBaseToScreen: location];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the mouse is back in the supermenu, we return NO so that
|
|
|
|
* our caller knows the button was not released.
|
|
|
|
*/
|
|
|
|
w = [[menuv_menu supermenu] window];
|
|
|
|
if (w != nil && NSMouseInRect(location, [w frame], NO) == YES)
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* if the mouse is in our attached menu - get that menu to track it.
|
|
|
|
*/
|
|
|
|
w = [[menuv_menu attachedMenu] window];
|
|
|
|
if (w != nil && NSMouseInRect(location, [w frame], NO) == YES)
|
1999-07-20 09:51:55 +00:00
|
|
|
{
|
2000-01-07 20:46:45 +00:00
|
|
|
if ([[self attachedMenuView] trackWithEvent: original])
|
1999-11-16 22:25:07 +00:00
|
|
|
return YES;
|
1999-07-06 15:45:19 +00:00
|
|
|
}
|
2000-01-05 16:35:47 +00:00
|
|
|
else
|
1999-07-20 09:51:55 +00:00
|
|
|
{
|
2000-01-05 16:35:47 +00:00
|
|
|
if (index != menuv_highlightedItemIndex)
|
|
|
|
[self setHighlightedItemIndex: index];
|
1999-07-06 15:45:19 +00:00
|
|
|
}
|
2000-01-07 20:46:45 +00:00
|
|
|
#if 0
|
1999-11-16 22:25:07 +00:00
|
|
|
if (([menuv_menu supermenu] && ![menuv_menu isTornOff])
|
|
|
|
|| [menuv_menu isFollowTransient])
|
|
|
|
return NO;
|
2000-01-07 20:46:45 +00:00
|
|
|
#endif
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
2000-01-05 16:35:47 +00:00
|
|
|
else
|
1999-07-27 19:15:19 +00:00
|
|
|
{
|
2000-01-05 16:35:47 +00:00
|
|
|
if (index != menuv_highlightedItemIndex)
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2000-01-05 16:35:47 +00:00
|
|
|
if (![menuv_menu attachedMenu] || !delayedSelect)
|
|
|
|
{
|
|
|
|
[self setHighlightedItemIndex: index];
|
|
|
|
|
|
|
|
if ([menuv_menu attachedMenu])
|
|
|
|
[self detachSubmenu];
|
|
|
|
|
|
|
|
if ((alreadyAttachedMenu =
|
|
|
|
[[menuv_items_link objectAtIndex: index] submenu]))
|
|
|
|
{
|
|
|
|
[self attachSubmenuForItemAtIndex: index];
|
2000-01-05 20:16:59 +00:00
|
|
|
mouseMoved = NO;
|
2000-01-05 16:35:47 +00:00
|
|
|
delayedSelect = YES;
|
2000-01-05 20:16:59 +00:00
|
|
|
delayCount = 0;
|
|
|
|
yDelta = 0.0;
|
2000-01-05 16:35:47 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delayedSelect = NO;
|
|
|
|
}
|
|
|
|
}
|
1999-07-31 00:54:41 +00:00
|
|
|
}
|
1999-07-27 19:15:19 +00:00
|
|
|
}
|
1999-07-20 10:34:34 +00:00
|
|
|
|
2000-01-07 20:46:45 +00:00
|
|
|
event = [NSApp nextEventMatchingMask: eventMask
|
|
|
|
untilDate: theDistantFuture
|
|
|
|
inMode: NSEventTrackingRunLoopMode
|
|
|
|
dequeue: YES];
|
|
|
|
type = [event type];
|
1999-11-16 22:25:07 +00:00
|
|
|
}
|
2000-01-07 20:46:45 +00:00
|
|
|
while (type != end);
|
1999-07-20 10:34:34 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
// Perform actions as needed.
|
|
|
|
if (index != -1 && !alreadyAttachedMenu)
|
1999-07-20 10:34:34 +00:00
|
|
|
{
|
1999-11-25 02:51:38 +00:00
|
|
|
// Stop the periodic events before performing the action
|
|
|
|
[NSEvent stopPeriodicEvents];
|
1999-11-16 22:25:07 +00:00
|
|
|
[menuv_menu performActionForItemAtIndex: index];
|
1999-07-20 10:34:34 +00:00
|
|
|
|
1999-12-11 03:04:22 +00:00
|
|
|
if (![menuv_menu isFollowTransient] && ![menuv_menu _ownedByPopUp])
|
1999-11-16 22:25:07 +00:00
|
|
|
[self setHighlightedItemIndex: -1];
|
|
|
|
}
|
1999-07-20 10:34:34 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
// Close menus if needed.
|
2000-01-05 17:42:47 +00:00
|
|
|
if (!menuv_keepAttachedMenus || index == -1
|
|
|
|
|| (alreadyAttachedMenu && [alreadyAttachedMenu isFollowTransient]))
|
1999-07-06 15:45:19 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
NSMenu *parentMenu;
|
|
|
|
NSMenu *masterMenu;
|
1999-07-06 15:45:19 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
for (parentMenu = masterMenu = menuv_menu;
|
|
|
|
(parentMenu = [masterMenu supermenu])
|
|
|
|
&& (![masterMenu isTornOff] || [masterMenu isFollowTransient]);
|
|
|
|
masterMenu = parentMenu);
|
1999-07-06 15:45:19 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
if ([masterMenu attachedMenu])
|
1999-07-06 15:45:19 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
NSMenuView *masterMenuView = [masterMenu menuRepresentation];
|
|
|
|
|
|
|
|
[masterMenuView detachSubmenu];
|
|
|
|
[masterMenuView setHighlightedItemIndex: -1];
|
1999-07-06 15:45:19 +00:00
|
|
|
}
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
1999-07-20 10:34:34 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
return YES;
|
|
|
|
}
|
1999-07-20 10:34:34 +00:00
|
|
|
|
2000-01-07 20:46:45 +00:00
|
|
|
- (void) mouseDown: (NSEvent*)theEvent
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
2000-01-07 20:46:45 +00:00
|
|
|
NSMenu *candidateMenu;
|
|
|
|
NSMenu *masterMenu;
|
|
|
|
NSMenuView *masterMenuView;
|
|
|
|
NSPoint originalLocation;
|
1999-07-06 15:45:19 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
menuv_keepAttachedMenus = YES;
|
|
|
|
|
2000-01-07 20:46:45 +00:00
|
|
|
masterMenu = menuv_menu;
|
|
|
|
while ((candidateMenu = [masterMenu supermenu]) != nil
|
|
|
|
&& ([masterMenu isTornOff] == NO || [masterMenu isFollowTransient] == YES))
|
|
|
|
{
|
|
|
|
masterMenu = candidateMenu;
|
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
originalLocation = [[masterMenu window] frame].origin;
|
|
|
|
|
|
|
|
masterMenuView = [masterMenu menuRepresentation];
|
|
|
|
|
|
|
|
masterMenuView->menuv_keepAttachedMenus = YES;
|
|
|
|
|
2000-01-05 20:16:59 +00:00
|
|
|
[NSEvent startPeriodicEventsAfterDelay: 0.1 withPeriod: 0.05];
|
1999-11-16 22:25:07 +00:00
|
|
|
|
|
|
|
[masterMenuView trackWithEvent: theEvent];
|
|
|
|
|
|
|
|
[NSEvent stopPeriodicEvents];
|
|
|
|
|
|
|
|
if (!NSEqualPoints(originalLocation, [[masterMenu window] frame].origin))
|
|
|
|
{
|
|
|
|
[masterMenu nestedSetFrameOrigin: originalLocation];
|
|
|
|
[masterMenu nestedCheckOffScreen];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
1999-11-16 22:25:07 +00:00
|
|
|
masterMenuView->menuv_keepAttachedMenus = NO;
|
1999-06-30 03:10:38 +00:00
|
|
|
|
1999-11-16 22:25:07 +00:00
|
|
|
menuv_keepAttachedMenus = NO;
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (BOOL) performKeyEquivalent: (NSEvent *)theEvent
|
1999-06-30 03:10:38 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
return [menuv_menu performKeyEquivalent: theEvent];
|
1999-06-30 03:10:38 +00:00
|
|
|
}
|
1999-10-18 22:56:19 +00:00
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
/*
|
|
|
|
* NSCoding Protocol
|
|
|
|
*/
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)encoder
|
1999-10-18 22:56:19 +00:00
|
|
|
{
|
1999-11-16 22:25:07 +00:00
|
|
|
[super encodeWithCoder: encoder];
|
|
|
|
|
|
|
|
[encoder encodeObject: menuv_itemCells];
|
|
|
|
[encoder encodeObject: menuv_font];
|
|
|
|
[encoder encodeConditionalObject: menuv_menu];
|
|
|
|
[encoder encodeConditionalObject: menuv_items_link];
|
|
|
|
[encoder encodeValueOfObjCType: @encode(BOOL) at: &menuv_horizontal];
|
|
|
|
[encoder encodeValueOfObjCType: @encode(float) at: &menuv_horizontalEdgePad];
|
|
|
|
[encoder encodeValueOfObjCType: @encode(NSSize) at: &cellSize];
|
|
|
|
}
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
- (id) initWithCoder: (NSCoder*)decoder
|
1999-11-16 22:25:07 +00:00
|
|
|
{
|
|
|
|
self = [super initWithCoder: decoder];
|
|
|
|
|
2000-01-05 17:42:47 +00:00
|
|
|
[decoder decodeValueOfObjCType: @encode(id) at: &menuv_itemCells];
|
|
|
|
[decoder decodeValueOfObjCType: @encode(id) at: &menuv_font];
|
1999-11-16 22:25:07 +00:00
|
|
|
menuv_menu = [decoder decodeObject];
|
|
|
|
menuv_items_link = [decoder decodeObject];
|
|
|
|
[decoder decodeValueOfObjCType: @encode(BOOL) at: &menuv_horizontal];
|
|
|
|
[decoder decodeValueOfObjCType: @encode(float) at: &menuv_horizontalEdgePad];
|
|
|
|
[decoder decodeValueOfObjCType: @encode(NSSize) at: &cellSize];
|
|
|
|
|
|
|
|
menuv_highlightedItemIndex = -1;
|
|
|
|
menuv_needsSizing = YES;
|
|
|
|
|
|
|
|
return self;
|
1999-10-18 22:56:19 +00:00
|
|
|
}
|
|
|
|
|
1999-06-30 03:10:38 +00:00
|
|
|
@end
|