* Palettes/0Menus/GormMenuEditor.m: Display the in certain situations.

* Palettes/0Menus/GormNSMenu.m: Remove call to setMenu: in 
	_createWindow since it's not needed and was causing display issues.
	* Palettes/0Menus/GormNSMenuView.m: Use new method in NSMenuView
	to reduce code duplication.  Corrections for bug #25401.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/apps/gorm/trunk@27681 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Gregory John Casamento 2009-01-25 11:45:09 +00:00
parent 831b07058f
commit 2135f76a59
4 changed files with 247 additions and 525 deletions

View file

@ -1,3 +1,11 @@
2009-01-25 06:50-EST Gregory John Casamento <greg_casamento@yahoo.com>
* Palettes/0Menus/GormMenuEditor.m: Display the in certain situations.
* Palettes/0Menus/GormNSMenu.m: Remove call to setMenu: in
_createWindow since it's not needed and was causing display issues.
* Palettes/0Menus/GormNSMenuView.m: Use new method in NSMenuView
to reduce code duplication. Corrections for bug #25401.
2009-01-06 20:48-EST Gregory John Casamento <greg_casamento@yahoo.com>
* Resources/ClassInformation.plist: Added printDocument: method

View file

@ -125,216 +125,230 @@
{
NSPoint loc = [theEvent locationInWindow];
NSView *hit = [super hitTest: loc];
NSView *view = nil;
[edited display];
[[self window] becomeMainWindow];
[[self window] makeFirstResponder: self];
if (hit == rep)
if([hit isKindOfClass: [NSMenuView class]] &&
![edited _ownedByPopUp])
{
int pos = [rep indexOfItemAtPoint: loc];
view = [[hit subviews] objectAtIndex: 0];
}
if (pos >= 0)
if([view isKindOfClass: [NSMenuView class]] ||
[hit isKindOfClass: [NSMenuView class]])
{
if (view == rep ||
hit == rep)
{
NSMenuItem *item = [edited itemAtIndex: pos];
if ([theEvent clickCount] == 2)
int pos = [rep indexOfItemAtPoint: loc];
if (pos >= 0)
{
id cell;
NSTextField *tf;
NSRect frame;
[self makeSelectionVisible: NO];
[self selectObjects: [NSArray array]];
cell = [rep menuItemCellForItemAtIndex: pos];
tf = [[NSTextField alloc] initWithFrame: [self bounds]];
frame = (NSRect)[cell titleRectForBounds:
[rep rectOfItemAtIndex: pos]];
NSDebugLog(@"cell %@ (%@)", cell, [cell stringValue]);
frame.origin.y += 3;
frame.size.height -= 5;
frame.origin.x += 1;
frame.size.width += 3;
[tf setFrame: frame];
[tf setEditable: YES];
[tf setBezeled: NO];
[tf setBordered: NO];
[self addSubview: tf];
[tf setStringValue: [[cell menuItem] title]];
[self editTextField: tf
withEvent: theEvent];
[[cell menuItem] setTitle: [tf stringValue]];
[tf removeFromSuperview];
RELEASE(tf);
return;
}
[self makeSelectionVisible: NO];
if ([theEvent modifierFlags] & NSShiftKeyMask)
{
NSMutableArray *array;
array = [NSMutableArray arrayWithArray: selection];
if ([array containsObject: item] == YES)
NSMenuItem *item = [edited itemAtIndex: pos];
if ([theEvent clickCount] == 2)
{
[array removeObject: item];
id cell;
NSTextField *tf;
NSRect frame;
[self makeSelectionVisible: NO];
[self selectObjects: [NSArray array]];
cell = [rep menuItemCellForItemAtIndex: pos];
tf = [[NSTextField alloc] initWithFrame: [self bounds]];
frame = (NSRect)[cell titleRectForBounds:
[rep rectOfItemAtIndex: pos]];
NSDebugLog(@"cell %@ (%@)", cell, [cell stringValue]);
frame.origin.y += 3;
frame.size.height -= 5;
frame.origin.x += 1;
frame.size.width += 3;
[tf setFrame: frame];
[tf setEditable: YES];
[tf setBezeled: NO];
[tf setBordered: NO];
[self addSubview: tf];
[tf setStringValue: [[cell menuItem] title]];
[self editTextField: tf
withEvent: theEvent];
[[cell menuItem] setTitle: [tf stringValue]];
[tf removeFromSuperview];
RELEASE(tf);
return;
}
[self makeSelectionVisible: NO];
if ([theEvent modifierFlags] & NSShiftKeyMask)
{
NSMutableArray *array;
array = [NSMutableArray arrayWithArray: selection];
if ([array containsObject: item] == YES)
{
[array removeObject: item];
}
else
{
[array addObject: item];
}
[self selectObjects: array];
[self makeSelectionVisible: YES];
return;
}
[self selectObjects: [NSArray arrayWithObject: item]];
if ([theEvent modifierFlags] & NSControlKeyMask)
{
NSPoint dragPoint = [theEvent locationInWindow];
NSPasteboard *pb;
NSString *name = [document nameForObject: item];
pb = [NSPasteboard pasteboardWithName: NSDragPboard];
[pb declareTypes:
[NSArray arrayWithObject: GormLinkPboardType]
owner: self];
[pb setString: name forType: GormLinkPboardType];
[NSApp displayConnectionBetween: item and: nil];
[NSApp startConnecting];
isLinkSource = YES;
[self dragImage: [NSApp linkImage]
at: dragPoint
offset: NSZeroSize
event: theEvent
pasteboard: pb
source: self
slideBack: YES];
isLinkSource = NO;
}
else
{
[array addObject: item];
}
[self selectObjects: array];
[self makeSelectionVisible: YES];
return;
}
[self selectObjects: [NSArray arrayWithObject: item]];
if ([theEvent modifierFlags] & NSControlKeyMask)
{
NSPoint dragPoint = [theEvent locationInWindow];
NSPasteboard *pb;
NSString *name = [document nameForObject: item];
pb = [NSPasteboard pasteboardWithName: NSDragPboard];
[pb declareTypes:
[NSArray arrayWithObject: GormLinkPboardType]
owner: self];
[pb setString: name forType: GormLinkPboardType];
[NSApp displayConnectionBetween: item and: nil];
[NSApp startConnecting];
isLinkSource = YES;
[self dragImage: [NSApp linkImage]
at: dragPoint
offset: NSZeroSize
event: theEvent
pasteboard: pb
source: self
slideBack: YES];
isLinkSource = NO;
}
else
{
NSDate *future = [NSDate distantFuture];
unsigned eventMask;
NSEvent *e;
NSEventType eType;
BOOL acceptsMouseMoved;
NSRect frame = [rep innerRect];
float maxMouse = NSMaxY(frame);
float minMouse = NSMinY(frame);
NSPoint lastPoint = loc;
NSPoint point = loc;
NSRect lastRect = [rep rectOfItemAtIndex: pos];
id cell = [rep menuItemCellForItemAtIndex: pos];
int newPos;
eventMask = NSLeftMouseUpMask | NSLeftMouseDraggedMask
| NSMouseMovedMask | NSPeriodicMask;
[[self window] setAcceptsMouseMovedEvents: YES];
/*
* Save window state info.
*/
acceptsMouseMoved = [[self window] acceptsMouseMovedEvents];
[rep lockFocus];
/*
* Track mouse movements until left mouse up.
* While we keep track of all mouse movements,
* we only act on a movement when a periodic
* event arives (every 20th of a second)
* in order to avoid excessive amounts of drawing.
*/
[NSEvent startPeriodicEventsAfterDelay: 0.1 withPeriod: 0.05];
e = [NSApp nextEventMatchingMask: eventMask
untilDate: future
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
eType = [e type];
while (eType != NSLeftMouseUp)
{
if (eType != NSPeriodic)
{
point = [e locationInWindow];
}
else if (NSEqualPoints(point, lastPoint) == NO)
{
/*
* Limit mouse movement.
*/
point.x = NSMinX(frame);
if (point.y < minMouse)
point.y = minMouse;
if (point.y > maxMouse)
point.y = maxMouse;
if (NSEqualPoints(point, lastPoint) == NO)
{
[[self window] disableFlushWindow];
/*
* Redraw cells under area being changed.
*/
[rep drawRect: lastRect];
/*
* Update location.
*/
lastRect.origin.y += point.y - lastPoint.y;
lastPoint = point;
/*
* Draw highlighted item being moved.
*/
[cell highlight: YES withFrame: lastRect inView: rep];
[cell setHighlighted: NO];
/*
* Flush any drawing performed for this event.
*/
[[self window] enableFlushWindow];
[[self window] flushWindow];
}
}
NSDate *future = [NSDate distantFuture];
unsigned eventMask;
NSEvent *e;
NSEventType eType;
BOOL acceptsMouseMoved;
NSRect frame = [rep innerRect];
float maxMouse = NSMaxY(frame);
float minMouse = NSMinY(frame);
NSPoint lastPoint = loc;
NSPoint point = loc;
NSRect lastRect = [rep rectOfItemAtIndex: pos];
id cell = [rep menuItemCellForItemAtIndex: pos];
int newPos;
eventMask = NSLeftMouseUpMask | NSLeftMouseDraggedMask
| NSMouseMovedMask | NSPeriodicMask;
[[self window] setAcceptsMouseMovedEvents: YES];
/*
* Save window state info.
*/
acceptsMouseMoved = [[self window] acceptsMouseMovedEvents];
[rep lockFocus];
/*
* Track mouse movements until left mouse up.
* While we keep track of all mouse movements,
* we only act on a movement when a periodic
* event arives (every 20th of a second)
* in order to avoid excessive amounts of drawing.
*/
[NSEvent startPeriodicEventsAfterDelay: 0.1 withPeriod: 0.05];
e = [NSApp nextEventMatchingMask: eventMask
untilDate: future
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
untilDate: future
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
eType = [e type];
while (eType != NSLeftMouseUp)
{
if (eType != NSPeriodic)
{
point = [e locationInWindow];
}
else if (NSEqualPoints(point, lastPoint) == NO)
{
/*
* Limit mouse movement.
*/
point.x = NSMinX(frame);
if (point.y < minMouse)
point.y = minMouse;
if (point.y > maxMouse)
point.y = maxMouse;
if (NSEqualPoints(point, lastPoint) == NO)
{
[[self window] disableFlushWindow];
/*
* Redraw cells under area being changed.
*/
[rep drawRect: lastRect];
/*
* Update location.
*/
lastRect.origin.y += point.y - lastPoint.y;
lastPoint = point;
/*
* Draw highlighted item being moved.
*/
[cell highlight: YES withFrame: lastRect inView: rep];
[cell setHighlighted: NO];
/*
* Flush any drawing performed for this event.
*/
[[self window] enableFlushWindow];
[[self window] flushWindow];
}
}
e = [NSApp nextEventMatchingMask: eventMask
untilDate: future
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
eType = [e type];
}
[NSEvent stopPeriodicEvents];
[rep drawRect: lastRect];
[rep unlockFocus];
newPos = [rep indexOfItemAtPoint: point];
if (newPos < pos)
{
NSMenuItem *item = [edited itemAtIndex: pos];
RETAIN(item);
if (newPos < 0)
newPos = 0;
[edited removeItemAtIndex: pos];
[edited insertItem: item atIndex: newPos];
RELEASE(item);
}
else if (newPos > pos)
{
NSMenuItem *item = [edited itemAtIndex: pos];
RETAIN(item);
[edited removeItemAtIndex: pos];
[edited insertItem: item atIndex: newPos];
RELEASE(item);
}
[edited sizeToFit];
[edited display];
/*
* Restore state to what it was on entry.
*/
[[self window] setAcceptsMouseMovedEvents: acceptsMouseMoved];
}
[NSEvent stopPeriodicEvents];
[rep drawRect: lastRect];
[rep unlockFocus];
newPos = [rep indexOfItemAtPoint: point];
if (newPos < pos)
{
NSMenuItem *item = [edited itemAtIndex: pos];
RETAIN(item);
if (newPos < 0)
newPos = 0;
[edited removeItemAtIndex: pos];
[edited insertItem: item atIndex: newPos];
RELEASE(item);
}
else if (newPos > pos)
{
NSMenuItem *item = [edited itemAtIndex: pos];
RETAIN(item);
[edited removeItemAtIndex: pos];
[edited insertItem: item atIndex: newPos];
RELEASE(item);
}
[edited sizeToFit];
[edited display];
/*
* Restore state to what it was on entry.
*/
[[self window] setAcceptsMouseMovedEvents: acceptsMouseMoved];
[self makeSelectionVisible: YES];
}
[self makeSelectionVisible: YES];
}
}
else
@ -345,7 +359,10 @@
*/
[[document parentEditorForEditor: self] selectObjects:
[NSArray arrayWithObject: edited]];
[hit mouseDown: theEvent];
if(hit != self)
{
[hit mouseDown: theEvent];
}
}
}
@ -658,6 +675,7 @@ void _attachAll(NSMenu *menu, id document)
* Make sure that all our menu items are attached in the document.
*/
_attachAll(edited, document);
[edited display];
}
return self;
@ -815,8 +833,7 @@ void _attachAll(NSMenu *menu, id document)
NSDebugLog(@"not owned by popup");
[edited insertItem: item atIndex: pos++];
}
[edited sizeToFit];
[edited display];
[self selectObjects: items];
[self makeSelectionVisible: YES];
}
@ -840,6 +857,9 @@ void _attachAll(NSMenu *menu, id document)
dragType = nil;
return NO;
}
[edited sizeToFit];
[edited display];
dragType = nil;
return YES;
}

View file

@ -167,7 +167,7 @@
backing: NSBackingStoreBuffered
defer: YES];
[win setMenu: self];
// [win setMenu: self];
[win setLevel: NSSubmenuWindowLevel];
[win setExcludedFromWindowsMenu: YES];
RETAIN(win); // FIXME: Argh.. this may leak.. temporary fix.

View file

@ -27,18 +27,28 @@
#include <AppKit/AppKit.h>
#include "GormNSMenuView.h"
@interface NSMenuView (GormNSMenuViewPrivate)
- (id) itemsLink;
@end
@implementation NSMenuView (GormNSMenuViewPrivate)
- (id) itemsLink
{
return _items_link;
}
@end
@implementation GormNSMenuView
- (BOOL) _executeItemAtIndex: (int)indexOfActionToExecute
removeSubmenu: (BOOL)subMenusNeedRemoving
{
if (indexOfActionToExecute == -1)
{
return YES;
}
if (indexOfActionToExecute >= 0
&& [[self menu] attachedMenu] != nil && [[self menu] attachedMenu] ==
[[[[self menu] itemArray] objectAtIndex: indexOfActionToExecute] submenu])
{
if (subMenusNeedRemoving)
{
[self detachSubmenu];
}
return NO;
}
return YES;
}
- (NSPoint) locationForSubmenu: (NSMenu *)aSubmenu
{
@ -57,321 +67,5 @@
NSMaxY(frame) - NSHeight(submenuFrame));
}
#define MOVE_THRESHOLD_DELTA 2.0
#define DELAY_MULTIPLIER 10
- (BOOL) trackWithEvent: (NSEvent*)event
{
unsigned eventMask = NSPeriodicMask;
NSDate *theDistantFuture = [NSDate distantFuture];
NSPoint lastLocation = {0,0};
BOOL justAttachedNewSubmenu = NO;
BOOL subMenusNeedRemoving = YES;
BOOL shouldFinish = YES;
int delayCount = 0;
int indexOfActionToExecute = -1;
int firstIndex = -1;
NSEvent *original;
NSEventType type;
NSEventType end;
/*
* 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));
type = [event type];
if (type == NSRightMouseDown || type == NSRightMouseDragged)
{
end = NSRightMouseUp;
eventMask |= NSRightMouseUpMask | NSRightMouseDraggedMask;
eventMask |= NSRightMouseDownMask;
}
else if (type == NSOtherMouseDown || type == NSOtherMouseDragged)
{
end = NSOtherMouseUp;
eventMask |= NSOtherMouseUpMask | NSOtherMouseDraggedMask;
eventMask |= NSOtherMouseDownMask;
}
else if (type == NSLeftMouseDown || type == NSLeftMouseDragged)
{
end = NSLeftMouseUp;
eventMask |= NSLeftMouseUpMask | NSLeftMouseDraggedMask;
eventMask |= NSLeftMouseDownMask;
}
else
{
NSLog (@"Unexpected event: %d during event tracking in NSMenuView", type);
end = NSLeftMouseUp;
eventMask |= NSLeftMouseUpMask | NSLeftMouseDraggedMask;
eventMask |= NSLeftMouseDownMask;
}
if ([self isHorizontal] == YES)
{
/*
* Ignore the first mouse up if nothing interesting has happened.
*/
shouldFinish = NO;
}
do
{
if (type == end)
{
shouldFinish = YES;
}
if (type == NSPeriodic || event == original)
{
NSPoint location;
int index;
location = [_window mouseLocationOutsideOfEventStream];
index = [self indexOfItemAtPoint: location];
if (event == original)
{
firstIndex = index;
}
if (index != firstIndex)
{
shouldFinish = YES;
}
/*
* 1 - if menus is only partly visible and the mouse is at the
* edge of the screen we move the menu so it will be visible.
*/
if ([[self attachedMenu] isPartlyOffScreen])
{
NSPoint pointerLoc = [_window convertBaseToScreen: location];
/*
* The +/-1 in the y - direction is because the flipping
* between X-coordinates and GNUstep coordinates let the
* GNUstep screen coordinates start with 1.
*/
if (pointerLoc.x == 0 || pointerLoc.y == 1
|| pointerLoc.x == [[_window screen] frame].size.width - 1
|| pointerLoc.y == [[_window screen] frame].size.height)
[[self attachedMenu] shiftOnScreen];
}
/*
* 2 - Check if we have to reset the justAttachedNewSubmenu
* flag to NO.
*/
if (justAttachedNewSubmenu && index != -1
&& index != _highlightedItemIndex)
{
if (location.x - lastLocation.x > MOVE_THRESHOLD_DELTA)
{
delayCount ++;
if (delayCount >= DELAY_MULTIPLIER)
{
justAttachedNewSubmenu = NO;
}
}
else
{
justAttachedNewSubmenu = NO;
}
}
// 3 - If we have moved outside this menu, take appropriate action
if (index == -1)
{
NSPoint locationInScreenCoordinates;
NSWindow *windowUnderMouse;
NSMenu *candidateMenu;
subMenusNeedRemoving = NO;
locationInScreenCoordinates
= [_window convertBaseToScreen: location];
/*
* 3a - Check if moved into one of the ancester menus.
* This is tricky, there are a few possibilities:
* We are a transient attached menu of a
* non-transient menu
* We are a non-transient attached menu
* We are a root: isTornOff of AppMenu
*/
candidateMenu = [[self attachedMenu] supermenu];
while (candidateMenu
&& !NSMouseInRect (locationInScreenCoordinates,
[[candidateMenu window] frame], NO) // not found yet
&& (! ([candidateMenu isTornOff]
&& ![candidateMenu isTransient])) // no root of display tree
&& [candidateMenu isAttached]) // has displayed parent
{
candidateMenu = [candidateMenu supermenu];
}
if (candidateMenu != nil
&& NSMouseInRect (locationInScreenCoordinates,
[[candidateMenu window] frame], NO))
{
BOOL candidateMenuResult;
// The call to fetch attachedMenu is not needed. But putting
// it here avoids flicker when we go back to an ancestor
// menu and the attached menu is already correct.
[[[candidateMenu attachedMenu] menuRepresentation]
detachSubmenu];
// Reset highlighted index for this menu.
// This way if we return to this submenu later there
// won't be a highlighted item.
[[[candidateMenu attachedMenu] menuRepresentation]
setHighlightedItemIndex: -1];
candidateMenuResult = [[candidateMenu menuRepresentation]
trackWithEvent: original];
return candidateMenuResult;
}
// 3b - Check if we enter the attached submenu
windowUnderMouse = [[[self attachedMenu] attachedMenu] window];
if (windowUnderMouse != nil
&& NSMouseInRect (locationInScreenCoordinates,
[windowUnderMouse frame], NO))
{
BOOL wasTransient = [[self attachedMenu] isTransient];
BOOL subMenuResult;
subMenuResult
= [[self attachedMenuView] trackWithEvent: original];
if (subMenuResult
&& wasTransient == [[self attachedMenu] isTransient])
{
[self detachSubmenu];
}
return subMenuResult;
}
}
// 4 - We changed the selected item and should update.
if (!justAttachedNewSubmenu && index != _highlightedItemIndex)
{
subMenusNeedRemoving = NO;
[self detachSubmenu];
[self setHighlightedItemIndex: index];
// WO: Question? Why the ivar _items_link
if (index >= 0 && [[[self itemsLink] objectAtIndex: index] submenu])
{
[self attachSubmenuForItemAtIndex: index];
justAttachedNewSubmenu = YES;
delayCount = 0;
}
}
// Update last seen location for the justAttachedNewSubmenu logic.
lastLocation = location;
}
event = [NSApp nextEventMatchingMask: eventMask
untilDate: theDistantFuture
inMode: NSEventTrackingRunLoopMode
dequeue: YES];
type = [event type];
}
while (type != end || shouldFinish == NO);
/*
* Ok, we released the mouse
* There are now a few possibilities:
* A - We released the mouse outside the menu.
* Then we want the situation as it was before
* we entered everything.
* B - We released the mouse on a submenu item
* (i) - this was highlighted before we started clicking:
* Remove attached menus
* (ii) - this was not highlighted before pressed the mouse button;
* Keep attached menus.
* C - We released the mouse above an ordinary action:
* Execute the action.
*
* In case A, B and C we want the transient menus to be removed
* In case A and C we want to remove the menus that were created
* during the dragging.
*
* So we should do the following things:
*
* 1 - Stop periodic events,
* 2 - Determine the action.
* 3 - Remove the Transient menus from the screen.
* 4 - Perform the action if there is one.
*/
[NSEvent stopPeriodicEvents];
/*
* We need to store this, because _highlightedItemIndex
* will not be valid after we removed this menu from the screen.
*/
indexOfActionToExecute = _highlightedItemIndex;
// remove transient menus. --------------------------------------------
{
NSMenu *currentMenu = [self attachedMenu];
while (currentMenu && ![currentMenu isTransient])
{
currentMenu = [currentMenu attachedMenu];
}
while ([currentMenu isTransient] && [currentMenu supermenu])
{
currentMenu = [currentMenu supermenu];
}
[[currentMenu menuRepresentation] detachSubmenu];
if ([currentMenu isTransient])
{
[currentMenu closeTransient];
}
}
// ---------------------------------------------------------------------
if (indexOfActionToExecute == -1)
{
return YES;
}
if (indexOfActionToExecute >= 0
&& [[self attachedMenu] attachedMenu] != nil && [[self attachedMenu] attachedMenu] ==
[[[self itemsLink] objectAtIndex: indexOfActionToExecute] submenu])
{
if (subMenusNeedRemoving)
{
[self detachSubmenu];
}
// Clicked on a submenu.
return NO;
}
[[self attachedMenu] performActionForItemAtIndex: indexOfActionToExecute];
/*
* Remove highlighting.
* We first check if it still highlighted because it could be the
* case that we choose an action in a transient window which
* has already dissappeared.
*/
if (_highlightedItemIndex >= 0)
{
[self setHighlightedItemIndex: -1];
}
return YES;
}
@end