diff --git a/ChangeLog b/ChangeLog index e19edc4e4..1a301e772 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +1999-06-29 Michael Hanni + + * Source/NSMenu.m: complete rewrite. Some work still required to + finish implementing obscure MacOSX methods, but otherwise functional. + * Source/NSMenuView.m: new file. Implementation of MacOSX menu + view class. Most classes implemented to provide basic + functionality. Some work required in event code to "forward"curse + to close/deselect menus in one case. I'll fix this ASAP. + * Source/NSMenuItemCell.m: new file. Implementation complete, plus + modifications to allow its use as an . + * Source/*.m: compilation fixes. + Sun Jun 27 7:50:00 1999 Richard Frith-Macdonald * Source/GNUmakefile: Install GSWraps.h diff --git a/Headers/gnustep/gui/NSMenu.h b/Headers/gnustep/gui/NSMenu.h index 872b8b3a4..4621c61e5 100644 --- a/Headers/gnustep/gui/NSMenu.h +++ b/Headers/gnustep/gui/NSMenu.h @@ -35,17 +35,22 @@ @class NSEvent; @class NSMatrix; +@class NSMenuView; @class NSMenuMatrix; +@class NSMenuWindow; @interface NSMenu : NSObject { - NSString* title; - NSMenuMatrix* menuCells; - NSMenu* supermenu; - NSMenu* attachedMenu; - BOOL autoenablesItems; - BOOL menuChangedMessagesEnabled; - BOOL menuHasChanged; + NSString *menu_title; + NSMutableArray *menu_items; + NSMenuView *menu_view; + NSMenu *menu_supermenu; + NSMenu *menu_attached_menu; + id menu_rep; + BOOL menu_ChangedMessagesEnabled; + BOOL menu_autoenable; + BOOL menu_changed; + BOOL menu_is_tornoff; // Reserved for back-end use void *be_menu_reserved; @@ -107,7 +112,7 @@ - (NSString*)title; /* Getting the menu cells matrix */ -- (NSMenuMatrix*)menuCells; +- (NSMenuView *)menuView; // non OS spec methods - (void)_rightMouseDisplay; @@ -128,35 +133,6 @@ - (void)close; @end - -/* Private class used to display the menu cells and respond to user actions */ -@interface NSMenuMatrix : NSControl -{ - NSMutableArray* cells; - NSSize cellSize; - NSMenu* menu; - id selectedCell; - NSRect selectedCellRect; -} - -- initWithFrame:(NSRect)rect; -- (id )insertItemWithTitle:(NSString*)aString - action:(SEL)aSelector - keyEquivalent:(NSString*)charCode - atIndex:(unsigned int)index; -- (void)removeItem:(id )anItem; -- (NSArray*)itemArray; -- (id )itemWithTitle:(NSString*)aString; -- (id )itemWithTag:(int)aTag; -- (NSRect)cellFrameAtRow:(int)index; -- (NSSize)cellSize; -- (void)setMenu:(NSMenu*)menu; -- (void)setSelectedCell:(id)aCell; -- (id)selectedCell; -- (NSRect)selectedCellRect; - -@end - extern NSString* const NSMenuDidSendActionNotification; extern NSString* const NSMenuWillSendActionNotification; diff --git a/Headers/gnustep/gui/NSMenuItemCell.h b/Headers/gnustep/gui/NSMenuItemCell.h new file mode 100644 index 000000000..fc5401cd4 --- /dev/null +++ b/Headers/gnustep/gui/NSMenuItemCell.h @@ -0,0 +1,102 @@ +/* + NSMenuItemCell.h + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Michael Hanni + Date: June 1999 + + 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. +*/ + +#ifndef _GNUstep_H_NSMenuItemCell +#define _GNUstep_H_NSMenuItemCell + +#include +#include +#include + +@interface NSMenuItemCell : NSButtonCell +{ + id representedObject; + BOOL mcell_highlighted; + BOOL mcell_has_submenu; + + // Not used is GS. + NSMenuItem *mcell_item; + + BOOL mcell_needs_sizing; + float mcell_imageWidth; + float mcell_titleWidth; + float mcell_keyEqWidth; + float mcell_stateImgWidth; +} + +// NSMenuItem Protocol demands these: +- (void)setTarget:(id)anObject; + +- (void)setTitle:(NSString*)aString; +- (NSString*)title; + +- (NSString*)keyEquivalent; + +- (NSString*)userKeyEquivalent; + +- (void)setRepresentedObject:(id)anObject; +- (id)representedObject; + +// NSMenuItemCell from MacOSX API. + +- (void)setHighlighted:(BOOL)flag; +- (BOOL)isHighlighted; + +// These NSMenuItem calls are deprecated in GS. You should not use them +// under any circumstance (i.e. they don't do anything.) + +- (void)setMenuItem:(NSMenuItem *)item; +- (NSMenuItem *)menuItem; + +- (void)calcSize; +- (void)setNeedsSizing:(BOOL)flag; +- (BOOL)needsSizing; + +- (float)imageWidth; +- (float)titleWidth; +- (float)keyEquivalentWidth; +- (float)stateImageWidth; + +- (NSRect)imageRectForBounds:(NSRect)cellFrame; +- (NSRect)keyEquivalentRectForBounds:(NSRect)cellFrame; +- (NSRect)stateImageRectForBounds:(NSRect)cellFrame; +- (NSRect)titleRectForBounds:(NSRect)cellFrame; + +- (void)drawBorderAndBackgroundWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView; +- (void)drawImageWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView; +- (void)drawKeyEquivalentWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView; +- (void)drawSeparatorItemWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView; +- (void)drawStateImageWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView; +- (void)drawTitleWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView; +@end + +#endif diff --git a/Headers/gnustep/gui/NSMenuView.h b/Headers/gnustep/gui/NSMenuView.h new file mode 100644 index 000000000..4fffa5500 --- /dev/null +++ b/Headers/gnustep/gui/NSMenuView.h @@ -0,0 +1,111 @@ +/* + NSMenuView.h + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Michael Hanni + Date: June 1999 + + 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. +*/ + +#ifndef _GNUstep_H_NSMenuView +#define _GNUstep_H_NSMenuView + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +@class NSFont; + +@interface NSMenuView : NSView +{ + NSMenu *menuv_menu; + BOOL menuv_horizontal; + NSFont *menuv_font; + int menuv_highlightedItemIndex; + BOOL menuv_isAttached; + BOOL menuv_isTornOff; + float menuv_hEdgePad; + float menuv_stateImageOffset; + float menuv_stateImageWidth; + float menuv_imageAndTitleOffset; + float menuv_imageAndTitleWidth; + float menuv_keyEqOffset; + float menuv_keyEqWidth; + BOOL menuv_needsSizing; + NSSize cellSize; +} ++ (float)menuBarHeight; + +- (void)setMenu:(NSMenu *)menu; +- (NSMenu *)menu; +- (void)setHorizontal:(BOOL)flag; +- (BOOL)isHorizontal; +- (void)setFont:(NSFont *)font; +- (NSFont *)font; +- (void)setHighlightedItemIndex:(int)index; +- (int)highlightedItemIndex; +- (void)setMenuItemCell:(NSMenuItemCell *)cell + forItemAtIndex:(int)index; +- (NSMenuItemCell *)menuItemCellForItemAtIndex:(int)index; +- (NSMenuView *)attachedMenuView; +- (NSMenu *)attachedMenu; +- (BOOL)isAttached; +- (BOOL)isTornOff; +- (void)setHorizontalEdgePadding:(float)pad; +- (float)horizontalEdgePadding; +- (void)itemChanged:(NSNotification *)notification; +- (void)itemAdded:(NSNotification *)notification; +- (void)itemRemoved:(NSNotification *)notification; +- (void)detachSubmenu; +- (void)attachSubmenuForItemAtIndex:(int)index; +- (void)update; +- (void)setNeedsSizing:(BOOL)flag; +- (BOOL)needsSizing; +- (void)sizeToFit; +- (float)stateImageOffset; +- (float)stateImageWidth; +- (float)imageAndTitleOffset; +- (float)imageAndTitleWidth; +- (float)keyEquivalentOffset; +- (float)keyEquivalentWidth; +- (NSRect)innerRect; +- (NSRect)rectOfItemAtIndex:(int)index; +- (int)indexOfItemAtPoint:(NSPoint)point; +- (void)setNeedsDisplayForItemAtIndex:(int)index; +- (NSPoint)locationForSubmenu:(NSMenu *)aSubmenu; +- (void)resizeWindowWithMaxHeight:(float)maxHeight; +- (void)setWindowFrameForAttachingToRect:(NSRect)screenRect + onScreen:(NSScreen *)screen + preferredEdge:(NSRectEdge)edge + popUpSelectedItem:(int)selectedItemIndex; +- (void)performActionWithHighlightingForItemAtIndex:(int)index; +- (BOOL)trackWithEvent:(NSEvent *)event; +@end + +#endif diff --git a/Headers/gnustep/gui/NSPopUpButton.h b/Headers/gnustep/gui/NSPopUpButton.h index 64617e638..386ee64de 100644 --- a/Headers/gnustep/gui/NSPopUpButton.h +++ b/Headers/gnustep/gui/NSPopUpButton.h @@ -41,13 +41,32 @@ @class NSMatrix; @class NSPopUpButton; -@interface NSPopUpButtonMatrix : NSMenuMatrix +@interface NSPopUpButtonMatrix : NSControl { + NSMutableArray* cells; + NSSize cellSize; + NSMenu* menu; + id selectedCell; + NSRect selectedCellRect; BOOL pull_down; int selected_cell; NSPopUpButton *popup_button; } -- (id) initWithFrame: (NSRect)rect; +- initWithFrame:(NSRect)rect; +- (id )insertItemWithTitle:(NSString*)aString + action:(SEL)aSelector + keyEquivalent:(NSString*)charCode + atIndex:(unsigned int)index; +- (void)removeItem:(id )anItem; +- (NSArray*)itemArray; +- (id )itemWithTitle:(NSString*)aString; +- (id )itemWithTag:(int)aTag; +- (NSRect)cellFrameAtRow:(int)index; +- (NSSize)cellSize; +- (void)setMenu:(NSMenu*)menu; +- (void)setSelectedCell:(id)aCell; +- (id)selectedCell; +- (NSRect)selectedCellRect; - (void)setPopUpButton:(NSPopUpButton *)popb; - (void) setIndexOfSelectedItem:(int)itemNum; @end diff --git a/Headers/gnustep/gui/NSTabViewItem.h b/Headers/gnustep/gui/NSTabViewItem.h index 9368640b5..f13cbc34d 100644 --- a/Headers/gnustep/gui/NSTabViewItem.h +++ b/Headers/gnustep/gui/NSTabViewItem.h @@ -30,7 +30,7 @@ #include typedef enum { - NSSelectedTab, + NSSelectedTab = 0, NSBackgroundTab, NSPressedTab } NSTabState; diff --git a/Images/common_3DArrowRight.tiff b/Images/common_3DArrowRight.tiff index 47a857bf6..b46ba2fcd 100644 Binary files a/Images/common_3DArrowRight.tiff and b/Images/common_3DArrowRight.tiff differ diff --git a/Model/GMAppKit.m b/Model/GMAppKit.m index 11f012d03..433ae9b4c 100644 --- a/Model/GMAppKit.m +++ b/Model/GMAppKit.m @@ -773,7 +773,7 @@ void __dummy_GMAppKit_functionForLinking() {} @end /* NSMenu (GMArchiverMethods) */ - +#if 0 @implementation NSPopUpButton (GMArchiverMethods) - (void)encodeWithModelArchiver:(GMArchiver*)archiver @@ -840,7 +840,7 @@ void __dummy_GMAppKit_functionForLinking() {} } @end /* NSPopUpButton (GMArchiverMethods) */ - +#endif @implementation NSResponder (GMArchiverMethods) diff --git a/Source/GNUmakefile b/Source/GNUmakefile index 39800adac..51a15589a 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -79,17 +79,19 @@ NSImageView.m \ NSInterfaceStyle.m \ NSMatrix.m \ NSMenu.m \ +NSMenuView.m \ NSMenuItem.m \ +NSMenuItemCell.m \ NSOpenPanel.m \ NSPageLayout.m \ NSPanel.m \ NSParagraphStyle.m \ +NSPopUpButton.m \ +NSPopUpButtonCell.m \ NSPrinter.m \ NSPrintInfo.m \ NSPrintOperation.m \ NSPrintPanel.m \ -NSPopUpButton.m \ -NSPopUpButtonCell.m \ NSResponder.m \ NSSavePanel.m \ NSScreen.m \ diff --git a/Source/NSBrowserCell.m b/Source/NSBrowserCell.m index ac43b4032..205e76e28 100644 --- a/Source/NSBrowserCell.m +++ b/Source/NSBrowserCell.m @@ -34,7 +34,9 @@ #include #include #include +#include #include +#include // // Class variables diff --git a/Source/NSImageView.m b/Source/NSImageView.m index 92c5c643a..0f8abf6b8 100644 --- a/Source/NSImageView.m +++ b/Source/NSImageView.m @@ -41,9 +41,9 @@ return [self initWithFrame: NSZeroRect]; } -- (id) initWithFrame: (NSRect)frame +- (id) initWithFrame: (NSRect)aFrame { - [super initWithFrame: frame]; + [super initWithFrame: aFrame]; // allocate the image cell [self setCell: [[NSImageCell alloc] init]]; diff --git a/Source/NSMenu.m b/Source/NSMenu.m index 9b41a4d90..3d85c3557 100644 --- a/Source/NSMenu.m +++ b/Source/NSMenu.m @@ -1,30 +1,3 @@ -/* - NSMenu.m - - Copyright (C) 1996 Free Software Foundation, Inc. - - Author: Ovidiu Predescu - Date: May 1997 - A completely rewritten version of the original source by Scott Christley. - - 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. -*/ - #include #include #include @@ -39,463 +12,306 @@ #include #include #include -#include +#include +#include -#ifdef MAX -# undef MAX -#endif -#define MAX(a, b) \ - ({typeof(a) _a = (a); typeof(b) _b = (b); \ - _a > _b ? _a : _b; }) - - -@interface NSMenu (PrivateMethods2) -- (void) _menuChanged; -@end - -@interface NSMenuMatrix (PrivateMethods2) -- (void) _resizeMenuForCellSize; -@end - -//***************************************************************************** -// -// NSMenuMatrix -// -//***************************************************************************** - -@implementation NSMenuMatrix - -// Class variables -static NSFont* menuFont = nil; - -- (BOOL) acceptsFirstMouse: (NSEvent *)theEvent -{ - return YES; -} - -- (id) initWithFrame: (NSRect)rect -{ - [super initWithFrame: rect]; - cells = [NSMutableArray new]; - - /* Don't initialize menuFont in +initialize since we don't know if the - DGS process knows anything about the fonts yet. */ - if (!menuFont) - menuFont = [[NSFont systemFontOfSize: 0] retain]; - - cellSize = NSMakeSize (1, [menuFont pointSize] + [menuFont descender] + 6); - return self; -} - -- (void) dealloc -{ - NSDebugLog (@"NSMenuMatrix of menu '%@' dealloc", [menu title]); - - [cells release]; - [super dealloc]; -} - -- (id) copyWithZone: (NSZone*)zone -{ - NSMenuMatrix* copy = [[isa allocWithZone: zone] initWithFrame: [self frame]]; - int i, count; - - NSDebugLog (@"copy menu matrix of menu with title '%@'", [menu title]); - for (i = 0, count = [cells count]; i < count; i++) - { - id aCell = [cells objectAtIndex: i]; - id cellCopy = [[aCell copyWithZone: zone] autorelease]; - - [copy->cells addObject: cellCopy]; - } - - copy->cellSize = cellSize; - copy->menu = menu; - if (selectedCell) - { - int index = [cells indexOfObject: selectedCell]; - - copy->selectedCell = [[cells objectAtIndex: index] retain]; - } - copy->selectedCellRect = selectedCellRect; - - return copy; -} - -- (void) _resizeMenuForCellSize -{ - int i, count; - float titleWidth; - - /* Compute the new width of the menu cells matrix */ - cellSize.width = 0; - count = [cells count]; - for (i = 0; i < count; i++) - { - titleWidth = [menuFont widthOfString: - [[cells objectAtIndex: i] stringValue]]; - cellSize.width = MAX(titleWidth + ADDITIONAL_WIDTH, cellSize.width); - } - cellSize.width = MAX([menuFont widthOfString: [menu title]] - + ADDITIONAL_WIDTH, - cellSize.width); - - /* Resize the frame to hold all the menu cells */ - [super setFrameSize: NSMakeSize (cellSize.width, - count ? (cellSize.height + INTERCELL_SPACE)*count - INTERCELL_SPACE : 0)]; -} - -- (id )insertItemWithTitle: (NSString*)aString - action: (SEL)aSelector - keyEquivalent: (NSString*)charCode - atIndex: (unsigned int)index -{ - id menuCell = [[[NSMenu cellClass] new] autorelease]; - - [menuCell setFont: menuFont]; - [menuCell setTitle: aString]; - [menuCell setAction: aSelector]; - [menuCell setKeyEquivalent: charCode]; - - [cells insertObject: menuCell atIndex: index]; - - return menuCell; -} - -- (BOOL) performKeyEquivalent: (NSEvent*)theEvent -{ - return [menu performKeyEquivalent: theEvent]; -} - -- (void) removeItem: (id )anItem -{ - int row = [cells indexOfObject: anItem]; - - if (row == -1) - return; - - [cells removeObjectAtIndex: row]; -} - -- (NSArray*) itemArray -{ - return cells; -} - -- (id ) itemWithTitle: (NSString*)aString -{ - unsigned i, count = [cells count]; - id menuCell; - - for (i = 0; i < count; i++) - { - menuCell = [cells objectAtIndex: i]; - if ([[menuCell title] isEqual: aString]) - return menuCell; - } - return nil; -} - -- (id ) itemWithTag: (int)aTag -{ - unsigned i, count = [cells count]; - id menuCell; - - for (i = 0; i < count; i++) - { - menuCell = [cells objectAtIndex: i]; - if ([menuCell tag] == aTag) - return menuCell; - } - return nil; -} - -- (NSRect) cellFrameAtRow: (int)index -{ - unsigned count = [cells count]; - NSRect rect; - - NSAssert(index >= 0 && index < count+1, @"invalid row coordinate"); - - rect.origin.x = 0; - rect.origin.y = (count - index - 1) - * (cellSize.height + INTERCELL_SPACE); - rect.size = cellSize; - - return rect; -} - -- (void)drawRect: (NSRect)rect -{ - unsigned i, count = [cells count]; - int max, howMany; - NSRect intRect = {{0, 0}, {0, 0}}; - - // If there are no cells then just return - if (count == 0) return; - - max = ceil((float)count - rect.origin.y / (cellSize.height + INTERCELL_SPACE)); - howMany = ceil(rect.size.height / (cellSize.height + INTERCELL_SPACE)); - - intRect.origin.y = (count - max) * (cellSize.height + INTERCELL_SPACE); - intRect.size = cellSize; - for (i = max - 1; howMany > 0; i--, howMany--) - { - id aCell = [cells objectAtIndex: i]; - - [aCell drawWithFrame: intRect inView: self]; - intRect.origin.y += cellSize.height + INTERCELL_SPACE; - } -} - -- (NSSize) cellSize -{ - return cellSize; -} - -- (void) setMenu: (NSMenu*)anObject -{ - menu = anObject; -} - -- (void) setSelectedCell: (id)aCell -{ - selectedCell = aCell; -} - -- (id) selectedCell -{ - return selectedCell; -} - -- (NSRect) selectedCellRect -{ - return selectedCellRect; -} - -@end /* NSMenuMatrix */ - - -//***************************************************************************** -// -// NSMenu -// -//***************************************************************************** +static NSZone *menuZone = NULL; @implementation NSMenu -// Class variables -static NSZone *menuZone = NULL; -static Class menuCellClass = nil; - +// Class Methods + (void) initialize { - menuCellClass = [NSMenuItem class]; + if (self == [NSMenu class]) + { + [self setVersion: 1]; + } } -+ (void) setMenuZone: (NSZone*)zone ++ (void)setMenuZone:(NSZone *)zone { menuZone = zone; } -+ (NSZone*) menuZone +// Methods. + +- (id)init { - return menuZone; + [self initWithTitle:@"Menu"]; } -+ (void) setCellClass: (Class)aClass +- (id)initWithTitle:(NSString *)aTitle { - menuCellClass = aClass; -} + [super init]; -+ (Class) cellClass -{ - return menuCellClass; -} + // Keep the title. + ASSIGN(menu_title, aTitle); -- (id) init -{ - return [self initWithTitle: - [[[NSProcessInfo processInfo] processName] lastPathComponent]]; -} + // Create an array to store out cells. + menu_items = [NSMutableArray new]; -- (id) initWithTitle: (NSString*)aTitle -{ - // SUBCLASS to initialize other "instance variables" - NSRect rect = {{0, 0}, {80, 20}}; + // Create a NSMenuView to draw our cells. + menu_view = [[NSMenuView alloc] initWithFrame:NSMakeRect(0,0,50,50)]; + + // Set ourself as the menu for this view. + [menu_view setMenu:self]; + + // We have no supermenu. + menu_supermenu = nil; + menu_is_tornoff = NO; + + menu_changed = YES; - ASSIGN(title, aTitle); - menuCells = [[NSMenuMatrix alloc] initWithFrame: rect]; - [menuCells setMenu: self]; - menuChangedMessagesEnabled = YES; - autoenablesItems = YES; return self; } -- (void) dealloc +- (void)insertItem:(id )newItem + atIndex:(int)index { - NSDebugLog (@"NSMenu '%@' dealloc", title); - - [title release]; - [menuCells release]; - [super dealloc]; + if ([(NSMenuItemCell *)newItem isKindOfClass:[NSMenuItemCell class]]) + [menu_items insertObject:newItem atIndex:index]; + else + NSLog(@"You must use an NSMenuItemCell, or a derivative thereof.\n"); } -- (id) copyWithZone: (NSZone*)zone +- (id )insertItemWithTitle:(NSString *)aString + action:(SEL)aSelector + keyEquivalent:(NSString *)charCode + atIndex:(unsigned int)index { - NSMenu *copy = NSAllocateObject (isa, 0, zone); - unsigned i, count; - NSArray *cells; + id anItem = [NSMenuItemCell new]; + [anItem setTitle:aString]; + [anItem setAction:aSelector]; + [anItem setKeyEquivalent:charCode]; - NSDebugLog (@"copy menu with title '%@'", [self title]); + [menu_items insertObject:anItem atIndex:index]; - copy->title = [title copyWithZone: zone]; + menu_changed = YES; - copy->menuCells = [menuCells copyWithZone: zone]; - [copy->menuCells setMenu: copy]; + return anItem; +} - /* Change the supermenu object of the new cells to the new menu */ - cells = [copy->menuCells itemArray]; - for (i = 0, count = [cells count]; i < count; i++) { - id cell = [cells objectAtIndex: i]; +- (void)addItem:(id )newItem +{ + // The spec says we call [self insertItem]; but why waste the overhead? + if ([(NSMenuItemCell *)newItem isKindOfClass:[NSMenuItemCell class]]) + [menu_items insertObject:newItem atIndex:[menu_items count]]; + else + NSLog(@"You must use an NSMenuItemCell, or a derivative thereof.\n"); - if ([cell hasSubmenu]) { - NSMenu* submenu = [cell target]; + menu_changed = YES; +} - submenu->supermenu = copy; - } +- (id )addItemWithTitle:(NSString *)aString + action:(SEL)aSelector + keyEquivalent:(NSString *)keyEquiv +{ + return [self insertItemWithTitle:aString + action:aSelector + keyEquivalent:keyEquiv + atIndex:[menu_items count]]; +} + +- (void)removeItem:(id )anItem +{ + if ([(NSMenuItemCell *)anItem isKindOfClass:[NSMenuItemCell class]]) + { + int _index = [menu_items indexOfObject:anItem]; + + if (_index == -1) + return; + + [menu_items removeObjectAtIndex:_index]; + } else { + NSLog(@"You must use an NSMenuItemCell, or a derivative thereof.\n"); } - [copy->menuCells setFrame: [menuCells frame]]; - - copy->supermenu = supermenu; - copy->attachedMenu = nil; - copy->autoenablesItems = autoenablesItems; - copy->menuChangedMessagesEnabled = menuChangedMessagesEnabled; - copy->menuHasChanged = menuHasChanged; - - return copy; + menu_changed = YES; } -- (id ) addItemWithTitle: (NSString*)aString - action: (SEL)aSelector - keyEquivalent: (NSString*)charCode +- (void)removeItemAtIndex:(int)index { - return [self insertItemWithTitle: aString - action: aSelector - keyEquivalent: charCode - atIndex: [[menuCells itemArray] count]]; + [menu_items removeObjectAtIndex:index]; + + menu_changed = YES; } -- (id ) insertItemWithTitle: (NSString*)aString - action: (SEL)aSelector - keyEquivalent: (NSString*)charCode - atIndex: (unsigned int)index +- (void)itemChanged:(id )anObject { - id menuCell = [menuCells insertItemWithTitle: aString - action: aSelector - keyEquivalent: charCode - atIndex: index]; - menuHasChanged = YES; - - return menuCell; -} - -- (void) removeItem: (id )anItem -{ - [menuCells removeItem: anItem]; - menuHasChanged = YES; -} - -- (NSArray*) itemArray -{ - return [menuCells itemArray]; + // another nebulous method in NSMenu. } - (id ) itemWithTag: (int)aTag { - return [menuCells itemWithTag: aTag]; + unsigned i, count = [menu_items count]; + id menuCell; + + for (i = 0; i < count; i++) + { + menuCell = [menu_items objectAtIndex:i]; + if ([menuCell tag] == aTag) + return menuCell; + } + return nil; } - (id ) itemWithTitle: (NSString*)aString { - return [menuCells itemWithTitle: aString]; + unsigned i, count = [menu_items count]; + id menuCell; + + for (i = 0; i < count; i++) + { + menuCell = [menu_items objectAtIndex: i]; + if ([[menuCell title] isEqual: aString]) + return menuCell; + } + return nil; } -- (void) setSubmenu: (NSMenu*)aMenu forItem: (id )anItem +- (id )itemAtIndex:(int)index { - NSString *itemTitle = [anItem title]; + // FIXME should raise an exception if out of range. + return [menu_items objectAtIndex:index]; +} - [anItem setTarget: aMenu]; +- (int)numberOfItems +{ + return [menu_items count]; +} + +- (NSArray *)itemArray +{ + return (NSArray *)menu_items; +} + +- (int)indexOfItem:(id )anObject +{ + if (![(NSMenuItemCell *)anObject isKindOfClass:[NSMenuItemCell class]]) + { + NSLog(@"You must use an NSMenuItemCell, or a derivative thereof.\n"); + return -1; + } + return [menu_items indexOfObject:anObject]; +} + +- (int)indexOfItemWithTitle:(NSString *)aTitle +{ + id anItem; + + if ((anItem = [self itemWithTitle:aTitle])) + return [menu_items indexOfObject:anItem]; + else + return -1; +} + +- (int)indexOfItemWithTag:(int)aTag +{ + id anItem; + + if ((anItem = [self itemWithTag:aTag])) + return [menu_items indexOfObject:anItem]; + else + return -1; +} + +- (int)indexOfItemWithTarget:(id)anObject + andAction:(SEL)actionSelector +{ + return -1; +} + +- (int)indexOfItemWithRepresentedObject:(id)anObject +{ + return -1; +} + +- (int)indexOfItemWithSubmenu:(NSMenu *)anObject +{ + return -1; +} + +// Dealing with submenus. + +- (void)setSubmenu:(NSMenu *)aMenu + forItem:(id ) anItem +{ + [anItem setTarget:aMenu]; [anItem setAction: @selector(submenuAction:)]; if (aMenu) - aMenu->supermenu = self; + aMenu->menu_supermenu = self; - ASSIGN(aMenu->title, itemTitle); - [self _menuChanged]; + ASSIGN(aMenu->menu_title, [anItem title]); + + // notification that the menu has changed. } -- (void) submenuAction: (id)sender +- (void)submenuAction:(id)sender { } -- (NSMenu*) attachedMenu +- (NSMenu *)attachedMenu { - return attachedMenu; + return menu_attached_menu; } - (BOOL) isAttached { - return supermenu && [supermenu attachedMenu] == self; + // eh? + return menu_supermenu && [menu_supermenu attachedMenu] == self; } -- (BOOL) isTornOff +- (BOOL)isTornOff { - // SUBCLASS - return NO; + return menu_is_tornoff; } -- (NSPoint) locationForSubmenu: (NSMenu*)aSubmenu +- (NSPoint)locationForSubmenu:(NSMenu *)aSubmenu { - // SUBCLASS return NSZeroPoint; } -- (NSMenu*) supermenu +- (NSMenu *)supermenu { - return supermenu; + return menu_supermenu; } -- (void) setAutoenablesItems: (BOOL)flag +- (void)setSupermenu:(NSMenu *)supermenu { - autoenablesItems = flag; + ASSIGN(menu_supermenu, supermenu); } -- (BOOL) autoenablesItems +- (void)setAutoenablesItems:(BOOL)flag { - return autoenablesItems; + menu_autoenable = flag; } -- (void) update +- (BOOL)autoenablesItems { - // SUBCLASS to redisplay the menu if necessary + return menu_autoenable; +} +- (void)update +{ + // FIXME: needs to be checked. id cells; int i, count; id theApp = [NSApplication sharedApplication]; + + if (menu_changed) + [self sizeToFit]; if (![self autoenablesItems]) return; - - cells = [menuCells itemArray]; - count = [cells count]; - + + count = [menu_items count]; + /* Temporary disable automatic displaying of menu */ [self setMenuChangedMessagesEnabled: NO]; - + for (i = 0; i < count; i++) { - id cell = [cells objectAtIndex: i]; + id cell = [menu_items objectAtIndex: i]; SEL action = [cell action]; id target; NSWindow* keyWindow; @@ -505,55 +321,92 @@ static Class menuCellClass = nil; id validator = nil; BOOL wasEnabled = [cell isEnabled]; BOOL shouldBeEnabled; - + /* Update the submenu items if any */ if ([cell hasSubmenu]) - [[cell target] update]; - + [[cell target] update]; + /* If there is no action - there can be no validator for the cell */ if (action) - { - /* If there is a target use that for validation (or nil). */ - if ((target = [cell target])) - { - if ([target respondsToSelector: action]) - { - validator = target; - } - } - else - { - validator = [theApp targetForAction: action]; - } - } - + { + /* If there is a target use that for validation (or nil). */ + if ((target = [cell target])) + { + if ([target respondsToSelector: action]) + { + validator = target; + } + } + else + { + validator = [theApp targetForAction: action]; + } + } + if (validator == nil) - { - shouldBeEnabled = NO; - } - else if ([validator respondsToSelector: @selector(validateMenuItem:)]) - { - shouldBeEnabled = [validator validateMenuItem: cell]; - } + { + shouldBeEnabled = NO; + } + else if ([validator respondsToSelector:@selector(validateMenuItem:)]) + { + shouldBeEnabled = [validator validateMenuItem: cell]; + } else - { - shouldBeEnabled = YES; - } - + { + shouldBeEnabled = YES; + } + if (shouldBeEnabled != wasEnabled) - { - [cell setEnabled: shouldBeEnabled]; - [menuCells setNeedsDisplayInRect: [menuCells cellFrameAtRow: i]]; - } + { + [cell setEnabled: shouldBeEnabled]; +// FIXME +// [menuCells setNeedsDisplayInRect: [menuCells cellFrameAtRow: i]]; + } } - - if (menuHasChanged) + + if (menu_changed) [self sizeToFit]; - + /* Reenable displaying of menus */ [self setMenuChangedMessagesEnabled: YES]; } +- (BOOL) performKeyEquivalent: (NSEvent*)theEvent +{ + unsigned i; + unsigned count = [menu_items count]; + NSEventType type = [theEvent type]; + + if (type != NSKeyDown && type != NSKeyUp) + return NO; + + for (i = 0; i < count; i++) + { + id cell = [menu_items objectAtIndex: i]; + + if ([cell hasSubmenu]) + { + if ([[cell target] performKeyEquivalent: theEvent]) + { + /* The event has been handled by a cell in submenu */ + return YES; + } + } + else + { + if ([[cell keyEquivalent] isEqual: + [theEvent charactersIgnoringModifiers]]) + { + [menu_view lockFocus]; + [(id)cell performClick: self]; + [menu_view unlockFocus]; + return YES; + } + } + } + return NO; +} + - (void) performActionForItem: (id )cell { NSNotificationCenter *nc; @@ -561,7 +414,7 @@ static Class menuCellClass = nil; if (![cell isEnabled]) return; - + nc = [NSNotificationCenter defaultCenter]; d = [NSDictionary dictionaryWithObject: cell forKey: @"MenuItem"]; [nc postNotificationName: NSMenuWillSendActionNotification @@ -571,81 +424,56 @@ static Class menuCellClass = nil; to: [cell target] from: cell]; [nc postNotificationName: NSMenuDidSendActionNotification - object: self - userInfo: d]; + object: self + userInfo: d]; } -- (BOOL) performKeyEquivalent: (NSEvent*)theEvent +- (void)setTitle: (NSString*)aTitle { - id cells = [menuCells itemArray]; - unsigned i; - unsigned count = [cells count]; - NSEventType type = [theEvent type]; - - if (type != NSKeyDown && type != NSKeyUp) - return NO; - - for (i = 0; i < count; i++) - { - id cell = [cells objectAtIndex: i]; - - if ([cell hasSubmenu]) - { - if ([[cell target] performKeyEquivalent: theEvent]) - { - /* The event has been handled by a cell in submenu */ - return YES; - } - } - else - { - if ([[cell keyEquivalent] isEqual: - [theEvent charactersIgnoringModifiers]]) - { - [menuCells lockFocus]; - [(id)cell performClick: self]; - [menuCells unlockFocus]; - return YES; - } - } - } - return NO; + ASSIGN(menu_title, aTitle); + [self sizeToFit]; +} + +- (NSString*)title +{ + return menu_title; } -- (void) setMenuChangedMessagesEnabled: (BOOL)flag +- (void)setMenuRepresentation:(id)menuRep { - menuChangedMessagesEnabled = flag; + ASSIGN(menu_rep, menuRep); } -- (BOOL) menuChangedMessagesEnabled +- (id)menuRepresentation { - return menuChangedMessagesEnabled; + return menu_rep; +} + +- (void)setMenuChangedMessagesEnabled: (BOOL)flag +{ + menu_ChangedMessagesEnabled = flag; +} + +- (BOOL)menuChangedMessagesEnabled +{ + return menu_ChangedMessagesEnabled; } - (void) sizeToFit -{ - // SUBCLASS - [menuCells _resizeMenuForCellSize]; - [menuCells setNeedsDisplay: YES]; - menuHasChanged = NO; +{ +// NSLog(@"- sizeToFit called in NSMenu\n"); +// +// [menu_view sizeToFit]; +// [menu_view setNeedsDisplay:YES]; +// menu_changed = NO; } -- (void) setTitle: (NSString*)aTitle +- (void)helpRequested:(NSEvent *)event { - ASSIGN(title, aTitle); - [self sizeToFit]; -} - -- (NSString*) title -{ - return title; -} - -- (NSMenuMatrix*) menuCells -{ - return menuCells; + // Won't be implemented until we have NSHelp* } +// NSCoding - (id) initWithCoder: (NSCoder*)aDecoder { return self; @@ -655,21 +483,9 @@ static Class menuCellClass = nil; { } -// non OS spec methods -- (void) _rightMouseDisplay +//NSCopying +- (id) copyWithZone: (NSZone*)zone { + return self; } - -@end /* NSMenu */ - - -@implementation NSMenu (PrivateMethods2) - -- (void) _menuChanged -{ - menuHasChanged = YES; - if (menuChangedMessagesEnabled) - [self sizeToFit]; -} - @end diff --git a/Source/NSMenuItemCell.m b/Source/NSMenuItemCell.m new file mode 100644 index 000000000..f397f9b24 --- /dev/null +++ b/Source/NSMenuItemCell.m @@ -0,0 +1,261 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +static BOOL usesUserKeyEquivalents = YES; + +@implementation NSMenuItemCell ++ (void)initialize +{ + if (self == [NSMenuItemCell class]) + { + // Initial version + [self setVersion:2]; + } +} + +- (id)init +{ + mcell_has_submenu = NO; + [super init]; + [super setTarget:nil]; + return self; +} + +// NSMenuitem protocol +- (void)setTarget:(id)anObject +{ + BOOL hadSubmenu = mcell_has_submenu; + mcell_has_submenu = anObject && [anObject isKindOfClass:[NSMenu class]]; + if (mcell_has_submenu) + [anObject retain]; + if (hadSubmenu) + [target release]; + [super setTarget:anObject]; +} + +- (BOOL)hasSubmenu +{ + return mcell_has_submenu; +} + +- (void)setTitle:(NSString*)aString +{ + [super setStringValue:aString]; +} + +- (NSString*)title +{ + return [super stringValue]; +} + +- (NSString*)keyEquivalent +{ + if (usesUserKeyEquivalents) + return [self userKeyEquivalent]; + else + return [super keyEquivalent]; +} + +- (NSString*)userKeyEquivalent +{ + NSString* userKeyEquivalent = [[[[NSUserDefaults standardUserDefaults] + persistentDomainForName:NSGlobalDomain] + objectForKey:@"NSCommandKeys"] + objectForKey:[self stringValue]]; + + if (!userKeyEquivalent) + userKeyEquivalent = [super keyEquivalent]; + + return userKeyEquivalent; +} + +- (void)setRepresentedObject:(id)anObject +{ + ASSIGN(representedObject, anObject); +} + +- (id)representedObject +{ + return representedObject; +} + +// NSMenuItemCell methods as defined by MacOSX API. + +- (void)setHighlighted:(BOOL)flag +{ + mcell_highlighted = flag; +} + +- (BOOL)isHighlighted +{ + return mcell_highlighted; +} + +- (void)setMenuItem:(NSMenuItem *)item +{ + ASSIGN(mcell_item, item); +} + +- (NSMenuItem *)menuItem +{ + return mcell_item; +} + +- (void)calcSize +{ + //calc sizes of images, title, and cache. + + // At the end we set sizing to NO. + mcell_needs_sizing = NO; +} + +- (void)setNeedsSizing:(BOOL)flag +{ + mcell_needs_sizing = flag; +} + +- (BOOL)needsSizing +{ + return mcell_needs_sizing; +} + +- (float)imageWidth +{ + if (mcell_needs_sizing) + [self calcSize]; + + return mcell_imageWidth; +} + +- (float)titleWidth +{ + if (mcell_needs_sizing) + [self calcSize]; + +// return mcell_titleWidth; + return [[NSFont systemFontOfSize:12] widthOfString:[self title]]; +} + +- (float)keyEquivalentWidth +{ + if (mcell_needs_sizing) + [self calcSize]; + + return mcell_keyEqWidth; +} + +- (float)stateImageWidth +{ + if (mcell_needs_sizing) + [self calcSize]; + + return mcell_stateImgWidth; +} + +// Drawing. + +- (NSRect)imageRectForBounds:(NSRect)cellFrame +{ + return NSZeroRect; +} + +- (NSRect)keyEquivalentRectForBounds:(NSRect)cellFrame +{ + return NSZeroRect; +} + +- (NSRect)stateImageRectForBounds:(NSRect)cellFrame +{ + return NSZeroRect; +} + +- (NSRect)titleRectForBounds:(NSRect)cellFrame +{ + return NSZeroRect; +} + +// Real drawing, + +- (void)drawBorderAndBackgroundWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView +{ +} + +- (void)drawImageWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView +{ +} + +- (void)drawKeyEquivalentWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView +{ +} + +- (void)drawSeparatorItemWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView +{ +} + +- (void)drawStateImageWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView +{ +} + +- (void)drawTitleWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView +{ +} + +- (void)drawWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView +{ + NSGraphicsContext *ctxt = GSCurrentContext(); + NSRect floodRect = cellFrame; + + NSDrawButton(cellFrame, cellFrame); + + floodRect.origin.x += 1; + floodRect.origin.y += 2; + floodRect.size.height -= 3; + floodRect.size.width -= 2; + + if (cell_highlighted) { + [[NSColor whiteColor] set]; + NSRectFill(floodRect); + } else { + [[NSColor lightGrayColor] set]; + NSRectFill(floodRect); + } + + [[NSColor blackColor] set]; + [[NSFont systemFontOfSize:12] set]; + DPSmoveto(ctxt, cellFrame.origin.x + 5, cellFrame.origin.y + 6); + DPSshow(ctxt, [[self title] cString]); + + if (mcell_has_submenu) { + floodRect.origin.x = cellFrame.size.width - 12; + floodRect.origin.y += 5; + floodRect.size.height = 7; + floodRect.size.width = 7; + + [self _drawImage:[NSImage imageNamed:@"common_3DArrowRight"] inFrame:floodRect]; + } +} +@end diff --git a/Source/NSMenuView.m b/Source/NSMenuView.m new file mode 100644 index 000000000..963f81277 --- /dev/null +++ b/Source/NSMenuView.m @@ -0,0 +1,603 @@ +#include +#include +#include +#include +#include + +static float GSMenuBarHeight = 25.0; // a guess. + +@implementation NSMenuView + +// Class methods. + ++ (float)menuBarHeight +{ + return GSMenuBarHeight; +} + +- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent +{ + return YES; +} + +// Init methods. + +- (id)init +{ + return [self initWithFrame:NSZeroRect]; +} + +- (id)initWithFrame:(NSRect)aFrame +{ + cellSize = NSMakeSize(110,20); + menuv_highlightedItemIndex = -1; + + return [super initWithFrame:aFrame]; +} + +// Our menu. + +- (void)setMenu:(NSMenu *)menu +{ + ASSIGN(menuv_menu, menu); +} + +- (NSMenu *)menu +{ + return menuv_menu; +} + +- (void)setHorizontal:(BOOL)flag +{ + menuv_horizontal = flag; +} + +- (BOOL)isHorizontal +{ + return menuv_horizontal; +} + +- (void)setFont:(NSFont *)font +{ + ASSIGN(menuv_font, font); +} + +- (NSFont *)font +{ + return menuv_font; +} + +/* + * - (void)setHighlightedItemIndex:(int)index + * + * MacOS-X defines this function as the central way of switching to a new + * highlighted item. The index value is == to the item you want + * highlighted. When used this method unhighlights the last item (if + * applicable) and selects the new item. If index == -1 highlighting is + * turned off. + * + * NOTES (Michael Hanni): + * + * I modified this method for GNUstep to take submenus into account. This + * way we get maximum performance while still using a method outside the + * loop. + * + */ + +- (void)setHighlightedItemIndex:(int)index +{ + NSArray *menu_items = [menuv_menu itemArray]; + id anItem; + + [self lockFocus]; + + if (index == -1) { + if (menuv_highlightedItemIndex != -1) { + anItem = [menu_items objectAtIndex:menuv_highlightedItemIndex]; + + [anItem highlight:NO + withFrame:[self rectOfItemAtIndex:menuv_highlightedItemIndex] + inView:self]; + [anItem setState:0]; + menuv_highlightedItemIndex = -1; + } + } else if (index >= 0) { + if ( menuv_highlightedItemIndex != -1 ) { + anItem = [menu_items objectAtIndex:menuv_highlightedItemIndex]; + + [anItem highlight:NO + withFrame:[self rectOfItemAtIndex:menuv_highlightedItemIndex] + inView:self]; + + if ([anItem hasSubmenu] && ![[anItem target] isTornOff]) + [[anItem target] close]; + + [anItem setState:0]; + } + + anItem = [menu_items objectAtIndex:index]; + + [anItem highlight:YES + withFrame:[self rectOfItemAtIndex:index] + inView:self]; + + [anItem setState:1]; + + if ([anItem hasSubmenu]) + [[anItem target] display]; + + // set view needs to be redrawn + [window flushWindow]; + + // set ivar to new index + menuv_highlightedItemIndex = index; + } + [self unlockFocus]; + [window flushWindow]; +} + +- (int)highlightedItemIndex +{ + return menuv_highlightedItemIndex; +} + +- (void)setMenuItemCell:(NSMenuItemCell *)cell + forItemAtIndex:(int)index +{ +// [menuv_items insertObject:cell atIndex:index]; + + // resize the cell + [cell setNeedsSizing:YES]; + + // resize menuview + [self setNeedsSizing:YES]; +} + +- (NSMenuItemCell *)menuItemCellForItemAtIndex:(int)index +{ + return [[menuv_menu itemArray] objectAtIndex:index]; +} + +- (NSMenuView *)attachedMenuView +{ + return [[menuv_menu attachedMenu] menuView]; +} + +- (NSMenu *)attachedMenu +{ + return [menuv_menu attachedMenu]; +} + +- (BOOL)isAttached +{ + return [menuv_menu isAttached]; +} + +- (BOOL)isTornOff +{ + return [menuv_menu isTornOff]; +} + +- (void)setHorizontalEdgePadding:(float)pad +{ + menuv_hEdgePad = pad; +} + +- (float)horizontalEdgePadding +{ + return menuv_hEdgePad; +} + +- (void)itemChanged:(NSNotification *)notification +{ +} + +- (void)itemAdded:(NSNotification *)notification +{ +} + +- (void)itemRemoved:(NSNotification *)notification +{ +} + +// Submenus. + +- (void)detachSubmenu +{ +} + +- (void)attachSubmenuForItemAtIndex:(int)index +{ + // create rect to display submenu in. + + // order window with submenu in it to front. +} + +- (void)update +{ +// [menuv_menu update]; + + if (menuv_needsSizing) + [self sizeToFit]; +} + +- (void)setNeedsSizing:(BOOL)flag +{ + menuv_needsSizing = flag; +} + +- (BOOL)needsSizing +{ + return menuv_needsSizing; +} + +- (void)sizeToFit +{ + int i; + int howMany = [[menuv_menu itemArray] count]; + int howHigh = (howMany * cellSize.height) + 21; + float neededWidth = 0; + + for (i=0;i<[[menuv_menu itemArray] count];i++) + { + float aWidth; + + NSMenuItemCell *anItem = [[menuv_menu itemArray] objectAtIndex:i]; + aWidth = [anItem titleWidth]; + + if (aWidth > neededWidth) + neededWidth = aWidth; + } + + cellSize.width = 7 + neededWidth + 7 + 7 + 5; + + [[self window] setFrame:NSMakeRect(300,300,cellSize.width,howHigh) display:YES]; + [self setFrame:NSMakeRect(0,0,cellSize.width,howHigh-21)]; +} + +- (float)stateImageOffset +{ + if (menuv_needsSizing) + [self sizeToFit]; + + return menuv_stateImageOffset; +} + +- (float)stateImageWidth +{ + if (menuv_needsSizing) + [self sizeToFit]; + + return menuv_stateImageWidth; +} + +- (float)imageAndTitleOffset +{ + if (menuv_needsSizing) + [self sizeToFit]; + + return menuv_imageAndTitleOffset; +} + +- (float)imageAndTitleWidth +{ + if (menuv_needsSizing) + [self sizeToFit]; + + return menuv_imageAndTitleWidth; +} + +- (float)keyEquivalentOffset +{ + if (menuv_needsSizing) + [self sizeToFit]; + + return menuv_keyEqOffset; +} + +- (float)keyEquivalentWidth +{ + if (menuv_needsSizing) + [self sizeToFit]; + + return menuv_keyEqWidth; +} + +- (NSRect)innerRect +{ + return [self bounds]; + + // this could change if we drew menuitemcells as + // plain rects with no bezel like in macOSX. Talk to Michael Hanni if + // you would like to see this configurable. +} + +- (NSRect)rectOfItemAtIndex:(int)index +{ + NSRect theRect; + + if (menuv_needsSizing) + [self sizeToFit]; + + if (index == 0) + theRect.origin.y = [self frame].size.height - cellSize.height; + else + theRect.origin.y = [self frame].size.height - (cellSize.height * (index + 1)); + theRect.origin.x = 0; + theRect.size = cellSize; + + return theRect; +} + +- (int)indexOfItemAtPoint:(NSPoint)point +{ + // The MacOSX API says that this method calls - rectOfItemAtIndex for + // *every* cell to figure this out. Well, instead we will just do some + // simple math. + NSRect aRect = [self rectOfItemAtIndex:0]; + + // this will need some finnessing but should be close. + return ([self frame].size.height - point.y) / aRect.size.height; +} + +- (void)setNeedsDisplayForItemAtIndex:(int)index +{ + [[[menuv_menu itemArray] objectAtIndex:index] setNeedsDisplay:YES]; +} + +- (NSPoint)locationForSubmenu:(NSMenu *)aSubmenu +{ + 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; +} + +- (void)resizeWindowWithMaxHeight:(float)maxHeight +{ + // set the menuview's window to max height in order to keep on screen? +} + +- (void)setWindowFrameForAttachingToRect:(NSRect)screenRect + onScreen:(NSScreen *)screen + preferredEdge:(NSRectEdge)edge + popUpSelectedItem:(int)selectedItemIndex +{ + // huh. +} + +// Drawing. + +- (void)drawRect:(NSRect)rect +{ + int i; + NSArray *menuCells = [menuv_menu itemArray]; + NSRect aRect = [self frame]; + + // This code currently doesn't take intercell spacing into account. I'll + // need to fix that. + + aRect.origin.y = cellSize.height * ([menuCells count] - 1); + aRect.size = cellSize; + + for (i=0;i<[menuCells count];i++) + { + id aCell = [menuCells objectAtIndex:i]; + + [aCell drawWithFrame:aRect inView:self]; + aRect.origin.y -= cellSize.height; + } +} + +// Event. + +- (void)performActionWithHighlightingForItemAtIndex:(int)index +{ + // for use with key equivalents. +} + +- (BOOL)trackWithEvent:(NSEvent *)event +{ + NSPoint lastLocation = [event locationInWindow]; + float height = [self frame].size.height; + int index; + int lastIndex = 0; + unsigned eventMask = NSLeftMouseUpMask | NSLeftMouseDownMask + | NSRightMouseUpMask | NSRightMouseDraggedMask + | NSLeftMouseDraggedMask; + BOOL done = NO; + NSApplication *theApp = [NSApplication sharedApplication]; + NSDate *theDistantFuture = [NSDate distantFuture]; + int theCount = [[menuv_menu itemArray] count]; + id selectedCell; + +// These 3 BOOLs are misnomers. I'll rename them later. -Michael. FIXME. + + BOOL weWereOut = NO; + BOOL weLeftMenu = NO; + BOOL weRightMenu = NO; + + // Get our mouse location, regardless of where it may be it the event + // stream. + + lastLocation = [[self window] mouseLocationOutsideOfEventStream]; + + index = (height - lastLocation.y) / cellSize.height; + + if (index >= 0 && index < theCount) { + [self setHighlightedItemIndex:index]; + lastIndex = index; + } + + while (!done) { + + event = [theApp nextEventMatchingMask: eventMask + untilDate: theDistantFuture + inMode: NSEventTrackingRunLoopMode + dequeue: YES]; + + switch ([event type]) + { + case NSRightMouseUp: + case NSLeftMouseUp: + /* right mouse up or left mouse up means we're done */ + done = YES; + break; + case NSRightMouseDragged: + case NSLeftMouseDragged: + lastLocation = [[self window] mouseLocationOutsideOfEventStream]; + +#ifdef 0 + NSLog (@"location = (%f, %f, %f)", lastLocation.x, [[self window] +frame].origin.x, [[self window] frame].size.width); +#endif + + if (lastLocation.x > 0 + && lastLocation.x < [[self window] frame].size.width) { + lastLocation = [self convertPoint: lastLocation fromView:nil]; + + index = (height - lastLocation.y) / cellSize.height; +#ifdef 0 + NSLog (@"location = (%f, %f)", lastLocation.x, lastLocation.y); + NSLog (@"index = %d\n", index); +#endif + if (index >= 0 && index < theCount) { + if (index != lastIndex) { + [self setHighlightedItemIndex:index]; + lastIndex = index; + } else { + if (weWereOut) { + [self setHighlightedItemIndex:index]; + lastIndex = index; + weWereOut = NO; + } + } + } + } else if (lastLocation.x > [[self window] frame].size.width) { + NSRect aRect = [self rectOfItemAtIndex:lastIndex]; + if (lastLocation.y > aRect.origin.y && lastLocation.y < + aRect.origin.y + aRect.size.height && [[[menuv_menu itemArray] objectAtIndex:lastIndex] hasSubmenu]) { + weLeftMenu = YES; + done = YES; + } + } else if (lastLocation.x < 0) { + if ([menuv_menu supermenu]) { + weRightMenu = YES; + done = YES; + } + } else { +// FIXME, Michael. This might be needed... or not? +/* +NSLog(@"This is the final else... its evil\n"); + if (lastIndex >= 0 && lastIndex < theCount) { + [self setHighlightedItemIndex:-1]; + lastIndex = index; + weWereOut = YES; + [window flushWindow]; + } +*/ + } + [window flushWindow]; + default: + break; + } + } + + if (!weLeftMenu && !weRightMenu) { + if (![[[menuv_menu itemArray] objectAtIndex:menuv_highlightedItemIndex] hasSubmenu]) { + BOOL finished = NO; + NSMenu *aMenu = menuv_menu; + selectedCell = [[menuv_menu itemArray] objectAtIndex:index]; + + [self setHighlightedItemIndex:-1]; + + if ([selectedCell action]) + [menuv_menu performActionForItem:[[menuv_menu itemArray] objectAtIndex:index]]; + + if ([selectedCell hasSubmenu]) + [[selectedCell target] close]; + + while (!finished) { // Recursive menu close & deselect. + if ([aMenu supermenu] && ![aMenu isTornOff]) { + [[[aMenu supermenu] menuView] setHighlightedItemIndex:-1]; + [aMenu close]; + aMenu = [aMenu supermenu]; + } + else + finished = YES; + + [window flushWindow]; + } + } + } else if (weRightMenu) { + NSPoint cP = [[self window] convertBaseToScreen:lastLocation]; + + [self setHighlightedItemIndex:-1]; + + if ([menuv_menu supermenu] && ![menuv_menu isTornOff]) { + [self mouseUp: + [NSEvent mouseEventWithType:NSLeftMouseUp + location:cP + modifierFlags:[event modifierFlags] + timestamp:[event timestamp] + windowNumber:[[self window] windowNumber] + context:[event context] + eventNumber:[event eventNumber] + clickCount:[event clickCount] + pressure:[event pressure]]]; + + [[[menuv_menu supermenu] menuView] mouseDown: + [NSEvent mouseEventWithType:NSLeftMouseDragged + location:cP + modifierFlags:[event modifierFlags] + timestamp:[event timestamp] + windowNumber:[[[[menuv_menu supermenu] menuView] window] windowNumber] + context:[event context] + eventNumber:[event eventNumber] + clickCount:[event clickCount] + pressure:[event pressure]]]; + } + } else /* The weLeftMenu case */ { + NSPoint cP = [[self window] convertBaseToScreen:lastLocation]; + + NSLog(@"Urph.\n"); + + selectedCell = [[menuv_menu itemArray] objectAtIndex:lastIndex]; + if ([selectedCell hasSubmenu]) { + [self mouseUp: + [NSEvent mouseEventWithType:NSLeftMouseUp + location:cP + modifierFlags:[event modifierFlags] + timestamp:[event timestamp] + windowNumber:[[self window] windowNumber] + context:[event context] + eventNumber:[event eventNumber] + clickCount:[event clickCount] + pressure:[event pressure]]]; + + [[[selectedCell target] menuView] mouseDown: + [NSEvent mouseEventWithType:NSLeftMouseDragged + location:cP + modifierFlags:[event modifierFlags] + timestamp:[event timestamp] + windowNumber:[[[[selectedCell target] menuView] window] windowNumber] + context:[event context] + eventNumber:[event eventNumber] + clickCount:[event clickCount] + pressure:[event pressure]]]; + } + } + + return YES; +} + +- (void)mouseDown:(NSEvent *)theEvent +{ + [self trackWithEvent:theEvent]; +} +@end diff --git a/Source/NSPopUpButton.m b/Source/NSPopUpButton.m index 28fa73c59..df78d8e1b 100644 --- a/Source/NSPopUpButton.m +++ b/Source/NSPopUpButton.m @@ -29,7 +29,7 @@ */ #include -#include +#import #include #include #include @@ -37,18 +37,83 @@ #include @implementation NSPopUpButtonMatrix + +// Class variables +static NSFont* menuFont = nil; + +- (BOOL) acceptsFirstMouse: (NSEvent *)theEvent +{ + return YES; +} + - (id) initWithFrame: (NSRect)rect { [super initWithFrame: rect]; + cells = [NSMutableArray new]; selected_cell = 0; cellSize = NSMakeSize (rect.size.width, rect.size.height); + return self; } +- (void) dealloc +{ + NSDebugLog (@"NSMenuMatrix of menu '%@' dealloc", [menu title]); + + [cells release]; + [super dealloc]; +} + +- (id) copyWithZone: (NSZone*)zone +{ + NSPopUpButtonMatrix* copy = [[isa allocWithZone: zone] initWithFrame: [self frame]]; + int i, count; + + NSDebugLog (@"copy menu matrix of menu with title '%@'", [menu title]); + for (i = 0, count = [cells count]; i < count; i++) + { + id aCell = [cells objectAtIndex: i]; + id cellCopy = [[aCell copyWithZone: zone] autorelease]; + + [copy->cells addObject: cellCopy]; + } + + copy->cellSize = cellSize; + copy->menu = menu; + if (selectedCell) + { + int index = [cells indexOfObject: selectedCell]; + + copy->selectedCell = [[cells objectAtIndex: index] retain]; + } + copy->selectedCellRect = selectedCellRect; + + return copy; +} + - (void) _resizeMenuForCellSize { + int i, count; + float titleWidth; + + /* Compute the new width of the menu cells matrix */ + cellSize.width = 0; + count = [cells count]; + for (i = 0; i < count; i++) + { + titleWidth = [menuFont widthOfString: + [[cells objectAtIndex: i] stringValue]]; + cellSize.width = MAX(titleWidth + ADDITIONAL_WIDTH, cellSize.width); + } + cellSize.width = MAX([menuFont widthOfString: [menu title]] + + ADDITIONAL_WIDTH, + cellSize.width); + + /* Resize the frame to hold all the menu cells */ + [super setFrameSize: NSMakeSize (cellSize.width, + count ? (cellSize.height + INTERCELL_SPACE)*count - INTERCELL_SPACE : 0)]; } - (id )insertItemWithTitle: (NSString*)aString @@ -92,6 +157,115 @@ { return pull_down; } + +- (BOOL) performKeyEquivalent: (NSEvent*)theEvent +{ + return [menu performKeyEquivalent: theEvent]; +} + +- (void) removeItem: (id )anItem +{ + int row = [cells indexOfObject: anItem]; + + if (row == -1) + return; + + [cells removeObjectAtIndex: row]; +} + +- (NSArray*) itemArray +{ + return cells; +} + +- (id ) itemWithTitle: (NSString*)aString +{ + unsigned i, count = [cells count]; + id menuCell; + + for (i = 0; i < count; i++) + { + menuCell = [cells objectAtIndex: i]; + if ([[menuCell title] isEqual: aString]) + return menuCell; + } + return nil; +} + +- (id ) itemWithTag: (int)aTag +{ + unsigned i, count = [cells count]; + id menuCell; + + for (i = 0; i < count; i++) + { + menuCell = [cells objectAtIndex: i]; + if ([menuCell tag] == aTag) + return menuCell; + } + return nil; +} + +- (NSRect) cellFrameAtRow: (int)index +{ + unsigned count = [cells count]; + NSRect rect; + + NSAssert(index >= 0 && index < count+1, @"invalid row coordinate"); + + rect.origin.x = 0; + rect.origin.y = (count - index - 1) + * (cellSize.height + INTERCELL_SPACE); + rect.size = cellSize; + + return rect; +} + +- (void)drawRect: (NSRect)rect +{ + unsigned i = 0, count = [cells count]; + int max, howMany; + NSRect aRect = [self frame]; + + // If there are no cells then just return + if (count == 0) return; + + aRect.origin.y = cellSize.height * (count - 1); + aRect.size = cellSize; + + for (i=0;i #include #include +#include #include #include #include @@ -29,9 +30,9 @@ NSDrawButton(cellFrame, cellFrame); - arect.size.width -= 4; - arect.size.height -= 4; - arect.origin.x += 2; + arect.size.width -= 3; + arect.size.height -= 3; + arect.origin.x += 1; arect.origin.y += 2; if (cell_highlighted) { diff --git a/Source/NSText.m b/Source/NSText.m index dc6db04eb..db2904171 100644 --- a/Source/NSText.m +++ b/Source/NSText.m @@ -976,7 +976,7 @@ NSLog(@"did set font"); _GNULineLayoutInfo *currentInfo; NSRect retRect=NSMakeRect(0,0,0,0); - for(lineEnum=[linesToDraw objectEnumerator]; currentInfo=[lineEnum nextObject];) + for((lineEnum=[linesToDraw objectEnumerator]); (currentInfo=[lineEnum nextObject]);) { retRect=NSUnionRect(retRect,[currentInfo lineRect]); } return retRect; } @@ -1021,7 +1021,7 @@ NSLog(@"did set font"); [[lineLayoutInformation lastObject] lineRect].size.height) { newY = currentCursorY - tRect.size.height + ([[lineLayoutInformation lastObject] lineRect].size.height * 2); - [[self superview] scrollToPoint:NSMakePoint(sizeToRect.origin.x,newY)]; + [(NSClipView *)[self superview] scrollToPoint:NSMakePoint(sizeToRect.origin.x,newY)]; } else NSLog(@"=========> Oops!\n"); @@ -1150,7 +1150,7 @@ rectForCharacterIndex:[self selectedRange].location], if([lineLayoutInformation count] && anIndex>= NSMaxRange([[lineLayoutInformation lastObject] lineRange])) return [lineLayoutInformation count]-1; - for(lineEnum=[lineLayoutInformation objectEnumerator]; currentInfo=[lineEnum nextObject];) + for((lineEnum=[lineLayoutInformation objectEnumerator]); (currentInfo=[lineEnum nextObject]);) { NSRange lineRange=[currentInfo lineRange]; if(lineRange.location<= anIndex && anIndex<= NSMaxRange(lineRange)-([currentInfo type] == LineLayoutInfoType_Paragraph? 1:0)) return [lineLayoutInformation indexOfObject:currentInfo]; @@ -1432,7 +1432,7 @@ NSLog(NSStringFromRange(redrawLineRange)); { unsigned short keyCode; if(!is_editable) return; // If not editable then don't recognize the key down - if(keyCode=[theEvent keyCode]) + if((keyCode=[theEvent keyCode])) switch(keyCode) { case NSUpArrowFunctionKey: //NSUpArrowFunctionKey: [self moveCursorUp:self]; @@ -1609,7 +1609,7 @@ NSLog(@"keycode:%x",keyCode); point.x=MAX(0,point.x); point.y=MAX(0,point.y); - for(i=0,lineEnum=[lineLayoutInformation objectEnumerator]; currentInfo=[lineEnum nextObject];i++) + for(i=0,(lineEnum=[lineLayoutInformation objectEnumerator]);(currentInfo=[lineEnum nextObject]);i++) { NSRect rect=[currentInfo lineRect]; if(NSMaxY(rect)>=point.y && rect.origin.y= NSMaxX(rect) ) return NSMaxRange([currentInfo lineRange]); if(NSPointInRect(point,rect)) // this loop holds some optimization potential (linear search) @@ -1648,7 +1648,7 @@ NSLog(@"keycode:%x",keyCode); return NSMakeRect(NSMaxX(rect), rect.origin.y,[self frame].size.width-NSMaxX(rect),rect.size.height); } - for(i=0,lineEnum=[lineLayoutInformation objectEnumerator]; currentInfo=[lineEnum nextObject];i++) + for(i=0,(lineEnum=[lineLayoutInformation objectEnumerator]);(currentInfo=[lineEnum nextObject]);i++) { NSRange range=[currentInfo lineRange]; if(NSLocationInRange(index,range)) { NSRect rect=[currentInfo lineRect]; @@ -1677,7 +1677,7 @@ NSLog(@"keycode:%x",keyCode); point.x=MAX(0,point.x); point.y=MAX(0,point.y); - for(i=0,lineEnum=[lineLayoutInformation objectEnumerator]; currentInfo=[lineEnum nextObject];i++) + for(i=0,(lineEnum=[lineLayoutInformation objectEnumerator]); (currentInfo=[lineEnum nextObject]);i++) { NSRect rect=[currentInfo lineRect]; if(NSMaxY(rect)> point.y && rect.origin.y<= point.y && rect.origin.x< point.x && point.x >= NSMaxX(rect) ) return [lineLayoutInformation indexOfObject:currentInfo]; @@ -1743,7 +1743,7 @@ static unsigned _relocLayoutArray(NSMutableArray *lineLayoutInformation,NSArray if(![relocArray count]) return ret; - for(relocEnum=[relocArray objectEnumerator]; currReloc=[relocEnum nextObject];) + for((relocEnum=[relocArray objectEnumerator]); (currReloc=[relocEnum nextObject]);) { NSRange range=[currReloc lineRange]; [currReloc setLineRange:NSMakeRange(range.location+relocOffset,range.length)]; if(yReloc) @@ -2018,7 +2018,7 @@ NSLog(@"opti hook 2"); _GNULineLayoutInfo *currentInfo; NSDictionary *attributes=[self defaultTypingAttributes]; - for(lineEnum=[linesToDraw objectEnumerator]; currentInfo=[lineEnum nextObject];) + for((lineEnum=[linesToDraw objectEnumerator]);(currentInfo=[lineEnum nextObject]);) { if([currentInfo isDontDisplay] || [currentInfo type]== LineLayoutInfoType_Paragraph) continue; // e.g. for nl [[plainContent substringWithRange:[currentInfo lineRange]] drawAtPoint:[currentInfo lineRect].origin withAttributes:attributes]; // make this use drawInRect:withAttributes: in the future (for proper adoption of layout information [e.g. centering]) @@ -2034,7 +2034,7 @@ NSLog(@"opti hook 2"); NSEnumerator *lineEnum; _GNULineLayoutInfo *currentInfo; - for(lineEnum=[linesToDraw objectEnumerator]; currentInfo=[lineEnum nextObject];) + for((lineEnum=[linesToDraw objectEnumerator]);(currentInfo=[lineEnum nextObject]);) { if([currentInfo isDontDisplay] || [currentInfo type] == LineLayoutInfoType_Paragraph) continue; // e.g. for nl [rtfContent drawRange:[currentInfo lineRange] atPoint:[currentInfo lineRect].origin]; // make this use drawRange: inRect: in the future (for proper adoption of layout information [e.g. centering]) diff --git a/Source/NSTextView.m b/Source/NSTextView.m index e4e6f2408..edc93493d 100644 --- a/Source/NSTextView.m +++ b/Source/NSTextView.m @@ -43,9 +43,27 @@ // This variant will create the text network (textStorage, layoutManager, and a container). - initWithFrame:(NSRect)frameRect -{ return [self initWithFrame:frameRect textContainer:nil]; +{ return [self initWithFrame:frameRect textContainer:nil]; } +#ifdef 0 +- initWithFrame:(NSRect)frameRect +{ + + textStorage = [NSTextStorage new]; +// layoutManager = [NSLayoutManager new]; +// [textStorage addLayoutManager:layoutManager]; +// [layoutManager release]; + + textContainer = [[NSTextContainer alloc] + initWithContainerSize:frameRect]; +// [layoutManager addTextContainer:textContainer]; + [textContainer release]; + + return [self initWithFrame:frameRect textContainer:textContainer]; +} +#endif + /***************** Get/Set the container and other stuff *****************/ -(NSTextContainer*) textContainer diff --git a/Source/NSWindow.m b/Source/NSWindow.m index 9b91fbdbf..38b2e5b95 100644 --- a/Source/NSWindow.m +++ b/Source/NSWindow.m @@ -1474,12 +1474,12 @@ static Class responderClass; */ if (content_view == nil) [self setContentView: nil]; - [[content_view superView] registerForDraggedTypes: newTypes]; + [[content_view superview] registerForDraggedTypes: newTypes]; } - (void) unregisterDraggedTypes { - [[content_view superView] unregisterDraggedTypes]; + [[content_view superview] unregisterDraggedTypes]; } /*