From f6a85c5407ba4ccb3ab36e13c4c364cb893e56d6 Mon Sep 17 00:00:00 2001 From: michael Date: Mon, 22 Nov 1999 21:48:03 +0000 Subject: [PATCH] Fixes git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@5262 72102866-910b-0410-8b05-ffd578937521 --- ChangeLog | 6 + Headers/gnustep/gui/AppKit.h | 3 + Headers/gnustep/gui/NSPopUpButtonCell.h | 100 +++- Source/NSAttributedString.m | 2 +- Source/NSLayoutManager.m | 5 +- Source/NSMenu.m | 68 +-- Source/NSMenuItemCell.m | 7 + Source/NSMenuView.m | 9 + Source/NSPopUpButton.m | 310 ++---------- Source/NSPopUpButtonCell.m | 609 ++++++++++++++++++------ Source/externs.m | 1 + 11 files changed, 670 insertions(+), 450 deletions(-) diff --git a/ChangeLog b/ChangeLog index 31b910b2c..003e48e94 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +1999-11-22 Michael Hanni + + * Source/NSPopUpButton.m: rewrite. + * Source/NSPopUpButtonCell.m: ditto. + * Source/?.m: a few other misc fixes. will document. + Mon Nov 22 17:05:33:00 1999 Richard Frith-Macdonald * Source/NSApplication.m: Start listening for window notifications diff --git a/Headers/gnustep/gui/AppKit.h b/Headers/gnustep/gui/AppKit.h index a4baf8872..4ec3f6688 100644 --- a/Headers/gnustep/gui/AppKit.h +++ b/Headers/gnustep/gui/AppKit.h @@ -114,6 +114,7 @@ #include #include #include +#include #include #include #include @@ -149,8 +150,10 @@ #include #include #include +#include #include #include +#include #include #include #include diff --git a/Headers/gnustep/gui/NSPopUpButtonCell.h b/Headers/gnustep/gui/NSPopUpButtonCell.h index 7cd2a6732..bcaf13968 100644 --- a/Headers/gnustep/gui/NSPopUpButtonCell.h +++ b/Headers/gnustep/gui/NSPopUpButtonCell.h @@ -1,6 +1,102 @@ -#include +#import +#import + +@class NSMenu; + +typedef enum { + NSPopUpNoArrow = 0, + NSPopUpArrowAtCenter = 1, + NSPopUpArrowAtBottom = 2, +} NSPopUpArrowPosition; @interface NSPopUpButtonCell : NSMenuItemCell { + NSMenu *_menu; + int _selectedIndex; + struct __pbcFlags { + unsigned int pullsDown:1; + unsigned int preferredEdge:3; + unsigned int menuIsAttached:1; + unsigned int usesItemFromMenu:1; + unsigned int altersStateOfSelectedItem:1; + unsigned int decoding:1; + unsigned int arrowPosition:2; + } _pbcFlags; } -@end + +- (id)initTextCell:(NSString *)stringValue pullsDown:(BOOL)pullDown; + +// Overrides behavior of NSCell. This is the menu for the popup, not a +// context menu. PopUpButtonCells do not have context menus. +- (void)setMenu:(NSMenu *)menu; +- (NSMenu *)menu; + +// Behavior settings +- (void)setPullsDown:(BOOL)flag; +- (BOOL)pullsDown; + +- (void)setAutoenablesItems:(BOOL)flag; +- (BOOL)autoenablesItems; + +- (void)setPreferredEdge:(NSRectEdge)edge; +- (NSRectEdge)preferredEdge; + +- (void)setUsesItemFromMenu:(BOOL)flag; +- (BOOL)usesItemFromMenu; + +- (void)setAltersStateOfSelectedItem:(BOOL)flag; +- (BOOL)altersStateOfSelectedItem; + +// Adding and removing items +- (void)addItemWithTitle:(NSString *)title; +- (void)addItemsWithTitles:(NSArray *)itemTitles; +- (void)insertItemWithTitle:(NSString *)title atIndex:(int)index; + +- (void)removeItemWithTitle:(NSString *)title; +- (void)removeItemAtIndex:(int)index; +- (void)removeAllItems; + + +// Accessing the items +- (NSArray *)itemArray; +- (int)numberOfItems; + +- (int)indexOfItem:(id )item; +- (int)indexOfItemWithTitle:(NSString *)title; +- (int)indexOfItemWithTag:(int)tag; +- (int)indexOfItemWithRepresentedObject:(id)obj; +- (int)indexOfItemWithTarget:(id)target andAction:(SEL)actionSelector; + +- (id )itemAtIndex:(int)index; +- (id )itemWithTitle:(NSString *)title; +- (id )lastItem; + + +// Dealing with selection +- (void)selectItem:(id )item; +- (void)selectItemAtIndex:(int)index; +- (void)selectItemWithTitle:(NSString *)title; +- (void)setTitle:(NSString *)aString; + +- (id )selectedItem; +- (int)indexOfSelectedItem; +- (void)synchronizeTitleAndSelectedItem; + + +// Title conveniences +- (NSString *)itemTitleAtIndex:(int)index; +- (NSArray *)itemTitles; +- (NSString *)titleOfSelectedItem; + +- (void)attachPopUpWithFrame:(NSRect)cellFrame inView:(NSView *)controlView; + +- (void)dismissPopUp; +- (void)performClickWithFrame:(NSRect)frame inView:(NSView *)controlView; + +// Arrow position for bezel style and borderless popups. +- (NSPopUpArrowPosition)arrowPosition; +- (void)setArrowPosition:(NSPopUpArrowPosition)position; +@end + +/* Notifications */ +extern const NSString *NSPopUpButtonCellWillPopUpNotification; diff --git a/Source/NSAttributedString.m b/Source/NSAttributedString.m index cb2980914..005fc9751 100644 --- a/Source/NSAttributedString.m +++ b/Source/NSAttributedString.m @@ -413,7 +413,7 @@ documentAttributes: (NSDictionary**)dict { [self fixFontAttributeInRange: range]; // [self fixParagraphStyleAttributeInRange: range]; - [self fixAttachmentAttributeInRange: range]; +// [self fixAttachmentAttributeInRange: range]; } - (void) fixFontAttributeInRange: (NSRange)range diff --git a/Source/NSLayoutManager.m b/Source/NSLayoutManager.m index 58c27f6ea..cb091ac56 100644 --- a/Source/NSLayoutManager.m +++ b/Source/NSLayoutManager.m @@ -394,6 +394,9 @@ static NSComparisonResult aSort(GSIArrayItem i0, GSIArrayItem i1) { NSLog(@"NSLayoutManager was just notified that a change in the text storage occured."); + NSLog(@"range: (%d, %d) changeInLength: %d invalidatedRange (%d, %d)", +range.location, range.length, lengthChange, invalidatedRange.location, +invalidatedRange.length); /* if (mask == NSTextStorageEditedCharacters) @@ -1164,7 +1167,7 @@ previousParagraphLocation, beginLineIndex, indexToAdd); - ourLines += 14.0; + ourLines += 20.0; // 14 lineWidth = 0.0; [lineStarts addObject: [NSNumber diff --git a/Source/NSMenu.m b/Source/NSMenu.m index 08fc7c81f..97b1cca6e 100644 --- a/Source/NSMenu.m +++ b/Source/NSMenu.m @@ -86,59 +86,16 @@ static NSString* NSMenuLocationsKey = @"NSMenuLocations"; return [self initWithTitle: @"Menu"]; } -- (id) initWithPopUpButton: (NSPopUpButton *)popb -{ - NSRect aRect; - NSRect winRect = {{0, 0}, {20, 17}}; - - [super init]; - - // Create an array to store out cells. - menu_items = [NSMutableArray new]; - - // Create a NSMenuView to draw our cells. - aRect = [popb frame]; - - menu_view = [[NSMenuView alloc] initWithFrame: NSMakeRect(0,0,50,50) - cellSize: aRect.size]; - - // Set ourself as the menu for this view. - [menu_view setMenu: self]; - - // We have no supermenu. - menu_supermenu = nil; - menu_is_tornoff = NO; - menu_is_visible = NO; - menu_follow_transient = NO; - menu_is_beholdenToPopUpButton = YES; - menu_changedMessagesEnabled = YES; - ASSIGN(menu_popb, popb); - menu_notifications = [NSMutableArray new]; - menu_is_beholdenToPopUpButton = NO; - menu_changed = YES; - // According to the spec, menus do autoenable by default. - menu_autoenable = YES; - - - aWindow = [[NSMenuWindow alloc] initWithContentRect:winRect - styleMask: NSBorderlessWindowMask - backing: NSBackingStoreRetained - defer: NO]; - [[aWindow contentView] addSubview:menu_view]; - - return self; -} - -- (id) popupButton -{ - return menu_popb; -} - -- (BOOL) _isBeholdenToPopUpButton +- (BOOL)_ownedByPopUp { return menu_is_beholdenToPopUpButton; } +- (void)_setOwnedByPopUp:(BOOL)flag +{ + menu_is_beholdenToPopUpButton = flag; +} + - (id) initWithTitle: (NSString *)aTitle { NSNotificationCenter *theCenter = [NSNotificationCenter defaultCenter]; @@ -252,12 +209,13 @@ static NSString* NSMenuLocationsKey = @"NSMenuLocations"; { id anItem; - if (menu_is_beholdenToPopUpButton) - { - anItem = [NSPopUpButtonCell new]; - [anItem setTarget: menu_popb]; - } - else +// FIXME +// if (menu_is_beholdenToPopUpButton) +// { +// anItem = [NSPopUpButtonCell new]; +// [anItem setTarget: menu_popb]; +// } +// else anItem = [NSMenuItem new]; [anItem setTitle: aString]; diff --git a/Source/NSMenuItemCell.m b/Source/NSMenuItemCell.m index f42cf5af6..2ca8cc585 100644 --- a/Source/NSMenuItemCell.m +++ b/Source/NSMenuItemCell.m @@ -93,8 +93,15 @@ { if (mcell_highlighted != flag) { + // Save last view drawn to + [self setControlView: controlView]; + + [controlView lockFocus]; + mcell_highlighted = flag; [self drawInteriorWithFrame: cellFrame inView: controlView]; + + [controlView unlockFocus]; } } diff --git a/Source/NSMenuView.m b/Source/NSMenuView.m index 52d21ca3c..2eec19f6a 100644 --- a/Source/NSMenuView.m +++ b/Source/NSMenuView.m @@ -40,6 +40,10 @@ static float GSMenuBarHeight = 25.0; // A wild guess. // 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. +// Michael: This simply means that for popups the menu code cannot +// arbitraily decide the cellSize. The size of the popup must be +// consistent. + @implementation NSMenuView // @@ -79,6 +83,11 @@ static float GSMenuBarHeight = 25.0; // A wild guess. return [super initWithFrame: aFrame]; } +- (void)_setCellSize:(NSSize)aSize +{ + cellSize = aSize; +} + - (id)initWithFrame: (NSRect)aFrame cellSize: (NSSize)aSize { diff --git a/Source/NSPopUpButton.m b/Source/NSPopUpButton.m index b45489638..8a24a6991 100644 --- a/Source/NSPopUpButton.m +++ b/Source/NSPopUpButton.m @@ -37,6 +37,11 @@ #include #include +// +// class variables +// +id _nspopupbuttonCellClass = nil; + // // NSPopUpButton implementation // @@ -53,13 +58,14 @@ { // Initial version [self setVersion:1]; - } + [self setCellClass: [NSPopUpButtonCell class]]; + } } - + // // Initializing an NSPopUpButton // -- init +- (id)init { return [self initWithFrame:NSZeroRect pullsDown:NO]; } @@ -76,21 +82,6 @@ [super initWithFrame:frameRect]; - /* Create our menu */ - - popb_menu = [[NSMenu alloc] initWithPopUpButton:self]; - - is_up = NO; - popb_pullsDown = flag; - popb_selectedItem = 0; - - [super setTarget: self]; - - /* - * Set ourselves up to recieve the notification when we need to popup - * the menu. - */ - [defaultCenter addObserver: self selector: @selector(_popup:) name: NSPopUpButtonWillPopUpNotification @@ -101,282 +92,190 @@ - (void)setMenu:(NSMenu *)menu { + [cell setMenu: menu]; } - (NSMenu *)menu { - return popb_menu; + return [cell menu]; } - (void)setPullsDown:(BOOL)flag { - popb_pullsDown = flag; + [cell setPullsDown: flag]; } - (BOOL)pullsDown { - return popb_pullsDown; + return [cell pullsDown]; } - (void)setAutoenablesItems:(BOOL)flag { - popb_autoenableItems = flag; + [cell setAutoenablesItems: flag]; } - (BOOL)autoenablesItems { - return popb_autoenableItems; + return [cell autoenablesItems]; } - (void)addItemWithTitle:(NSString *)title { - [self insertItemWithTitle: title atIndex: [self numberOfItems]]; + [cell addItemWithTitle: title]; + + [self synchronizeTitleAndSelectedItem]; } - (void)addItemsWithTitles:(NSArray *)itemTitles { - int i; + [cell addItemWithTitles: itemTitles]; - for (i=0;i<[itemTitles count];i++) - { - [self addItemWithTitle:[itemTitles objectAtIndex:i]]; - } + [self synchronizeTitleAndSelectedItem]; } - (void)insertItemWithTitle:(NSString *)title atIndex:(int)index { - [popb_menu insertItemWithTitle: title - action: @selector(_buttonPressed:) - keyEquivalent: @"" - atIndex: index]; + [cell insertItemWithTitle: title adIndex: index]; [self synchronizeTitleAndSelectedItem]; } - (void)removeAllItems { - [(NSMutableArray *)[popb_menu itemArray] removeAllObjects]; - -/* - for (i=0;i<[self numberOfItems];i++) - { - [popb_menu removeItemAtIndex:i]; - } -*/ + [cell removeAllItems]; [self synchronizeTitleAndSelectedItem]; } - (void)removeItemWithTitle:(NSString *)title { - [popb_menu removeItemAtIndex: [self indexOfItemWithTitle: title]]; + [cell removeItemWithTitle]; [self synchronizeTitleAndSelectedItem]; } - (void)removeItemAtIndex:(int)index { - [popb_menu removeItemAtIndex: index]; + [cell removeItemAtIndex: index]; [self synchronizeTitleAndSelectedItem]; } - (id )selectedItem { - if (popb_selectedItem >= 0) - return [[popb_menu itemArray] objectAtIndex: popb_selectedItem]; - else - return nil; + return [cell selectedItem]; } - (NSString *)titleOfSelectedItem { -// FIXME - return [[[popb_menu itemArray] objectAtIndex: popb_selectedItem] title]; + return [cell titleOfSelectedItem]; } - (int)indexOfSelectedItem { - if (popb_selectedItem >= 0) - return popb_selectedItem; - - return -1; + return [cell indexOfSelectedItem]; } - (void)selectItem:(id )anObject { - [self selectItemAtIndex:[self indexOfItem: anObject]]; + [cell selectedItem: anObject]; } - (void)selectItemAtIndex:(int)index { - if (popb_selectedItem != index) - { - if (index == -1) - { - popb_selectedItem = -1; - } - else - { - popb_selectedItem = index; - } - // This works fine - [self setNeedsDisplay: YES]; - // but replace it with the following - // [self synchronizeTitleAndSelectedItem]; - // as soon as it works. - } + [cell selectItemAtIndex: index]; + + [self synchronizeTitleAndSelectedItem]; } - (void)selectItemWithTitle:(NSString *)title { - [self selectItemAtIndex:[self indexOfItemWithTitle: title]]; + [cell selectItemWithTitle: title]; + + [self synchronizeTitleAndSelectedItem]; } - (int)numberOfItems { - return [popb_menu numberOfItems]; + return [cell numberOfItems]; } - (NSArray *)itemArray { - return [popb_menu itemArray]; + return [cell itemArray]; } - (id )itemAtIndex:(int)index { - return [popb_menu itemAtIndex: index]; + return [cell itemAtIndex: index]; } - (NSString *)itemTitleAtIndex:(int)index { - return [[self itemAtIndex: index] title]; + return [cell itemTitleAtIndex: index]; } - (NSArray *)itemTitles { - NSMutableArray *anArray = [NSMutableArray new]; - int i; - - for (i=0;i<[self numberOfItems];i++) - { - [anArray addObject:[[self itemAtIndex:i] title]]; - } - - return anArray; + return [cell itemTitles]; } - (id )itemWithTitle:(NSString *)title { - return [popb_menu itemWithTitle: title]; + return [cell itemWithTitle: title]; } - (id )lastItem { - return [[popb_menu itemArray] lastObject]; + return [cell lastItem]; } - (int)indexOfItem:(id )anObject { - return [popb_menu indexOfItem: anObject]; + return [cell indexOfItem: anObject]; } - (int)indexOfItemWithTag:(int)tag { - return [popb_menu indexOfItemWithTag: tag]; + return [cell indexOfItemWithTag: tag]; } - (int)indexOfItemWithTitle:(NSString *)title { - return [popb_menu indexOfItemWithTitle: title]; + return [cell indexOfItemWithTitle: title]; } - (int)indexOfItemWithRepresentedObject:(id)anObject { - return [popb_menu indexOfItemWithRepresentedObject: anObject]; + return [cell indexOfItemWithRepresentedObject: anObject]; } - (int)indexOfItemWithTarget:(id)target andAction:(SEL)actionSelector { - return [popb_menu indexOfItemWithTarget: target andAction: actionSelector]; + return [cell indexOfItemWithTarget: target andAction: actionSelector]; } - (void)setPreferredEdge:(NSRectEdge)edge { - // urph + [cell setPreferredEdge: edge]; } - (NSRectEdge)preferredEdge { - // urph - return -1; + return [cell preferredEdge]; } - (void)setTitle:(NSString *)aString { - if (!popb_pullsDown) - { - int aIndex = [self indexOfItemWithTitle:aString]; - - if (aIndex >= 0) - popb_selectedItem = aIndex; - else - { - [self addItemWithTitle:aString]; - popb_selectedItem = [self indexOfItemWithTitle:aString]; - [self setNeedsDisplay:YES]; - } - } - else - { - [self setNeedsDisplay:YES]; - } -} - -- (SEL)action -{ - return pub_action; -} - -- (void)setAction:(SEL)aSelector -{ - pub_action = aSelector; -} - -- (id)target -{ - return pub_target; -} - -- (void)setTarget:(id)anObject -{ - pub_target = anObject; -} - -- (void)_buttonPressed:(id)sender -{ - popb_selectedItem = [self indexOfItemWithRepresentedObject:[sender representedObject]]; - - [self synchronizeTitleAndSelectedItem]; - - [self setNeedsDisplay:YES]; - - if (pub_target && pub_action) - [pub_target performSelector:pub_action withObject:self]; - - if (popb_pullsDown) - popb_selectedItem = 0; + [cell setTitle: aString]; } - (void)synchronizeTitleAndSelectedItem { - // urph - if (popb_selectedItem > [self numberOfItems] - 1) - { - popb_selectedItem = 0; - } + [cell synchronizeTitleAndSelectedItem]; [self sizeToFit]; } @@ -388,44 +287,8 @@ - (void)_popup:(NSNotification*)notification { - NSPopUpButton *popb = [notification object]; - NSRect butf; - NSRect winf; - - butf = [popb frame]; - butf = [[popb superview] convertRect: butf toView: nil]; - butf.origin = [[popb window] convertBaseToScreen: butf.origin]; - - [[popb_menu menuRepresentation] sizeToFit]; - - winf = [NSMenuWindow - frameRectForContentRect: [[popb_menu menuRepresentation] frame] - styleMask: [[popb_menu window] styleMask]]; - /* - * Set popup window frame origin so that the top-left corner of the - * window lines up with the top-left corner of this button. - */ - winf.origin = butf.origin; - winf.origin.y += butf.size.height - winf.size.height; - - /* - * Small hack to fix line up. - */ - - winf.origin.x += 1; - winf.origin.y -= 1; - -//NSLog(@"butf %@", NSStringFromRect(butf)); -//NSLog(@"winf %@", NSStringFromRect(winf)); - - if (popb_pullsDown == NO) - { - winf.origin.y += (popb_selectedItem * butf.size.height); - } - -// [[popb menu] sizeToFit]; - [[[popb menu] window] setFrame: winf display:YES]; - [[[popb menu] window] orderFront:nil]; + [cell performClickWithFrame: [[notification object] frame] + inView: self]; } - (void)mouseDown:(NSEvent *)theEvent @@ -436,75 +299,6 @@ [nc postNotificationName: NSPopUpButtonWillPopUpNotification object: self userInfo: nil]; - - [[popb_menu menuRepresentation] mouseDown: - [NSEvent mouseEventWithType: NSLeftMouseDown - location: [[popb_menu window] mouseLocationOutsideOfEventStream] - modifierFlags: [theEvent modifierFlags] - timestamp: [theEvent timestamp] - windowNumber: [[popb_menu window] windowNumber] - context: [theEvent context] - eventNumber: [theEvent eventNumber] - clickCount: [theEvent clickCount] - pressure: [theEvent pressure]]]; - -} - -/* -- (void)mouseUp:(NSEvent *)theEvent -{ - NSPoint cP; - - cP = [window convertBaseToScreen: [theEvent locationInWindow]]; - cP = [popb_win convertScreenToBase: cP]; - -//NSLog(@"location x = %d, y = %d\n", (int)cP.x, (int)cP.y); - - [popb_view mouseUp: - [NSEvent mouseEventWithType: NSLeftMouseUp - location: cP - modifierFlags: [theEvent modifierFlags] - timestamp: [theEvent timestamp] - windowNumber: [popb_win windowNumber] - context: [theEvent context] - eventNumber: [theEvent eventNumber] - clickCount: [theEvent clickCount] - pressure: [theEvent pressure]]]; - - [popb_win orderOut: nil]; -} -*/ - -- (NSView *)hitTest:(NSPoint)aPoint -{ - // First check ourselves -// if ([self mouse:aPoint inRect:bounds]) return self; - if ([self mouse:aPoint inRect: frame]) return self; - - return nil; -} - -// -// Displaying -// -- (void)drawRect:(NSRect)rect -{ - id aCell; - - if ([popb_menu numberOfItems] == 0) - { - [[NSPopUpButtonCell new] drawWithFrame:bounds inView:self]; - return; - } - - if (!popb_pullsDown) - aCell = [[popb_menu menuRepresentation] - menuItemCellForItemAtIndex: popb_selectedItem]; - else - aCell = [[popb_menu menuRepresentation] - menuItemCellForItemAtIndex: 0]; - - [aCell drawWithFrame:bounds inView:self]; } // diff --git a/Source/NSPopUpButtonCell.m b/Source/NSPopUpButtonCell.m index 9c051538e..21e9af1f6 100644 --- a/Source/NSPopUpButtonCell.m +++ b/Source/NSPopUpButtonCell.m @@ -25,6 +25,7 @@ */ #include +#include #include #include #include @@ -34,162 +35,504 @@ #include #include +@interface NSPopUpButtonCell (GNUstepPrivate) +- (void)_popUpItemAction:(id)sender; +@end + @implementation NSPopUpButtonCell -+ (void) initialize +- (id)initTextCell:(NSString *)stringValue { - if (self == [NSPopUpButtonCell class]) - [self setVersion: 1]; + return [self initTextCell: stringValue pullsDown: NO]; } -- (id)init +- (id)initTextCell:(NSString *)stringValue + pullsDown:(BOOL)pullDown { - return [super init]; -} + [super initTextCell: stringValue]; -- (id)representedObject -{ - if (cell_image) + _pbcFlags.pullsDown = pullDown; + _pbcFlags.usesItemFromMenu = YES; + _pbcFlags.altersStateOfSelectedItem = YES; + + if ([stringValue length] > 0) { - return cell_image; + id anItem; + + [self insertItemWithTitle:stringValue atIndex:0]; + + anItem = [self itemAtIndex:0]; + [anItem setTarget: self]; + [anItem setAction: @selector(_popUpItemAction:)]; } - return contents; + _menu = [NSMenu initWithTitle:@""]; + [_menu _setOwnedByPopUp: YES]; + + return self; +} + +- (void)setMenu:(NSMenu *)menu +{ + ASSIGN(_menu, menu); +} + +- (NSMenu *)menu +{ + return _menu; +} + +// Behavior settings +- (void)setPullsDown:(BOOL)flag +{ + _pbcFlags.pullsDown = flag; +} + +- (BOOL)pullsDown +{ + return _pbcFlags.pullsDown; +} + +- (void)setAutoenablesItems:(BOOL)flag +{ + [_menu setAutoenablesItems: flag]; +} + +- (BOOL)autoenablesItems +{ + return [_menu autoenablesItems]; +} + +// The preferred edge is used for pull down menus and for popups under +// severe screen position restrictions. It indicates what edge of the +// cell the menu should pop out from. + +- (void)setPreferredEdge:(NSRectEdge)edge +{ + _pbcFlags.preferredEdge = edge; +} + +- (NSRectEdge)preferredEdge +{ + return _pbcFlags.preferredEdge; +} + +// If YES (the default) the popup button will display an item from the +// menu. This will be the selected item for a popup or the first item for +// a pull-down. If this is NO, then the menu item set with -setMenuItem: +// is always displayed. This can be useful for a popup button that is an +// icon button that pops up a menu full of textual items, for example. + +- (void)setUsesItemFromMenu:(BOOL)flag +{ + _pbcFlags.usesItemFromMenu = flag; +} + +- (BOOL)usesItemFromMenu +{ + return _pbcFlags.usesItemFromMenu; +} + +// This only has an effect for popups (it is ignored for pulldowns). +// If YES (the default) then the selected item gets its state set to +// NSOnState. If NO the items in the menu are left alone. + +- (void)setAltersStateOfSelectedItem:(BOOL)flag +{ + _pbcFlags.altersStateOfSelectedItem = flag; +} + +- (BOOL)altersStateOfSelectedItem +{ + return _pbcFlags.altersStateOfSelectedItem; +} + +// Adding and removing items +- (void)addItemWithTitle:(NSString *)title +{ + NSMenuItem *anItem = [NSMenuItem new]; + + [anItem setTitle:title]; + [anItem setTarget: self]; + [anItem setAction: @selector(_popUpItemAction:)]; + + [_menu insertItem: anItem atIndex: [_menu numberOfItems]]; +} + +- (void)addItemsWithTitles:(NSArray *)itemTitles +{ + int i; + + for (i=0; i<[itemTitles count]; i++) + { + [self addItemWithTitle: [itemTitles objectAtIndex:i]]; + } +} + +- (void)insertItemWithTitle:(NSString *)title atIndex:(int)index +{ + NSMenuItem *anItem = [NSMenuItem new]; + + [anItem setTitle:title]; + [anItem setTarget: self]; + [anItem setAction: @selector(_popUpItemAction:)]; + + [[_menu itemArray] insertObject: anItem atIndex: index]; +} + +- (void)removeItemWithTitle:(NSString *)title +{ + [_menu removeItemWithTitle: title]; +} + +- (void)removeItemAtIndex:(int)index +{ + [[_menu itemArray] removeObjectAtIndex: index]; +} + +- (void)removeAllItems +{ + [_menu removeAllItems]; +} + +// Accessing the items +- (NSArray *)itemArray +{ + return [_menu itemArray]; +} + +- (int)numberOfItems +{ + return [_menu numberOfItems]; +} + +- (int)indexOfItem:(id )item +{ + return [_menu indexOfItem: item]; +} + +- (int)indexOfItemWithTitle:(NSString *)title +{ + return [_menu indexOfItemWithTitle: title]; +} + +- (int)indexOfItemWithTag:(int)tag +{ + return [_menu indexOfItemWithTag: tag]; +} + +- (int)indexOfItemWithRepresentedObject:(id)obj +{ + return [_menu indexOfItemWithRepresentedObject: obj]; +} + +- (int)indexOfItemWithTarget:(id)target andAction:(SEL)actionSelector +{ + return [_menu indexOfItemWithTarget: target andAction: actionSelector]; +} + +- (id )itemAtIndex:(int)index +{ + return [_menu itemAtIndex: index]; +} + +- (id )itemWithTitle:(NSString *)title +{ + return [_menu itemWithTitle: title]; +} + +- (id )lastItem +{ + return [_menu lastItem]; +} + +// Dealing with selection +- (void)selectItem:(id )item +{ + if (!item) + { + if (_pbcFlags.altersStateOfSelectedItem) + [[self itemAtIndex: _selectedIndex] setState: NSOffState]; + + _selectedIndex = -1; + } + else + { + int aIndex = [self indexOfItem: item]; + + if (_pbcFlags.altersStateOfSelectedItem) + { + [[self itemAtIndex: _selectedIndex] setState: NSOffState]; + [[self itemAtIndex: aIndex] setState: NSOnState]; + } + + _selectedIndex = aIndex; + } +} + +- (void)selectItemAtIndex:(int)index +{ + if (index == -1) + { + if (_pbcFlags.altersStateOfSelectedItem) + [[self itemAtIndex: _selectedIndex] setState: NSOffState]; + + _selectedIndex = -1; + } + else + { + if (_pbcFlags.altersStateOfSelectedItem) + { + [[self itemAtIndex: _selectedIndex] setState: NSOffState]; + [[self itemAtIndex: index] setState: NSOnState]; + } + + _selectedIndex = index; + } +} + +- (void)selectItemWithTitle:(NSString *)title +{ + + if ([title length] < 1) + { + if (_pbcFlags.altersStateOfSelectedItem) + [[self itemAtIndex: _selectedIndex] setState: NSOffState]; + + _selectedIndex = -1; + } + else + { + int aIndex = [self indexOfItemWithTitle: title]; + + if (_pbcFlags.altersStateOfSelectedItem) + { + [[self itemAtIndex: _selectedIndex] setState: NSOffState]; + [[self itemAtIndex: aIndex] setState: NSOnState]; + } + + _selectedIndex = aIndex; + } +} + +- (void)setTitle:(NSString *)aString +{ + if (_pbcFlags.pullsDown) + { + } + else + { + int aIndex; + + if (aIndex = [self indexOfItemWithTitle: aString]) + { + [self selectItemAtIndex: aIndex]; + } + else + { + [self addItemWithTitle: aString]; + [self selectItemWithTitle: aString]; + } + } +} + +- (id )selectedItem +{ + if (_selectedIndex != -1) + return [self itemAtIndex: _selectedIndex]; + else + return nil; +} + +- (int)indexOfSelectedItem +{ + return _selectedIndex; +} + +- (void)synchronizeTitleAndSelectedItem +{ + if (!_pbcFlags.usesItemFromMenu) + return; + + // Add test for null menus. + + if (_pbcFlags.pullsDown) + { + [self selectItem: [self itemAtIndex: 0]]; + } + else + { + if (_selectedIndex >= 0) + [self selectItem: [self itemAtIndex: _selectedIndex]]; + else + [self selectItem: [self itemAtIndex: 0]]; + } +} + +// Title conveniences +- (NSString *)itemTitleAtIndex:(int)index +{ + return [[self itemAtIndex: index] title]; +} + +- (NSArray *)itemTitles +{ + NSMutableArray *anArray = [NSMutableArray new]; + int i; + + for (i=0; i<[[_menu itemArray] count]; i++) + { + [anArray addObject: [[[_menu itemArray] objectAtIndex: i] title]]; + } + + return (NSArray *)anArray; +} + +- (NSString *)titleOfSelectedItem +{ + if (_selectedIndex >= 0) + return [[self itemAtIndex: _selectedIndex] title]; + else + return @""; +} + +- (void)attachPopUpWithFrame:(NSRect)cellFrame + inView:(NSView *)controlView +{ + NSNotificationCenter *_aCenter = [NSNotificationCenter defaultCenter]; + NSNotification *_aNotif; + NSRect scratchRect = cellFrame; + NSRect winf; + + _aNotif = [NSNotification + notificationWithName: NSPopUpButtonCellWillPopUpNotification + object: controlView + userInfo: nil]; + + [_aCenter postNotification: _aNotif]; + + _aNotif = [NSNotification + notificationWithName: NSPopUpButtonCellWillPopUpNotification + object: self + userInfo: nil]; + + [_aCenter postNotification: _aNotif]; + + scratchRect.origin = [[controlView window] convertBaseToScreen: cellFrame.origin]; + + [[_menu menuRepresentation] _setCellSize: cellFrame.size]; + [_menu sizeToFit]; + + winf = [NSMenuWindow + frameRectForContentRect: [[_menu menuRepresentation] frame] + styleMask: [[_menu window] styleMask]]; + /* + * Set popup window frame origin so that the top-left corner of the + * window lines up with the top-left corner of this button. + */ + winf.origin = scratchRect.origin; + winf.origin.y += scratchRect.size.height - winf.size.height; + + /* + * Small hack to fix line up. + */ + + winf.origin.x += 1; + winf.origin.y -= 1; + +//NSLog(@"butf %@", NSStringFromRect(butf)); + + if (!_pbcFlags.pullsDown) + { + winf.origin.y += (_selectedIndex * scratchRect.size.height); + } + +NSLog(@"winf %@", NSStringFromRect(winf)); + + NSLog(@"here comes the popup."); + + [[_menu window] setFrame: winf display: YES]; + [[_menu window] orderFrontRegardless]; +} + +- (void)dismissPopUp +{ + [[_menu window] orderOut: nil]; +} + +- (BOOL)trackMouse:(NSEvent *)theEvent + inRect:(NSRect)cellFrame + ofView:(NSView *)controlView + untilMouseUp:(BOOL)untilMouseUp +{ +} + +- (void)performClickWithFrame:(NSRect)frame + inView:(NSView *)controlView +{ + int indexToClick; + + [self attachPopUpWithFrame: frame + inView: controlView]; + indexToClick = [[_menu menuRepresentation] indexOfItemAtPoint: + [[_menu window] mouseLocationOutsideOfEventStream]]; + [[_menu menuRepresentation] mouseDown: [NSApp currentEvent]]; + +// [[[_menu menuRepresentation] menuItemCellForItemAtIndex: indexToClick] +// performClick: nil]; +} + +// Arrow position for bezel style and borderless popups. +- (NSPopUpArrowPosition)arrowPosition +{ + return _pbcFlags.arrowPosition; +} + +- (void)setArrowPosition:(NSPopUpArrowPosition)position +{ + _pbcFlags.arrowPosition = position; } - (void) drawWithFrame: (NSRect)cellFrame inView: (NSView*)view { - NSGraphicsContext *ctxt; - NSColor *backColor; - NSImage *toDraw = nil; - NSRect rect = cellFrame; - NSRect arect = cellFrame; - NSPoint point; + NSSize size; + NSPoint position; + NSImage *aImage; + + // Save last view drawn to + [self setControlView: view]; [view lockFocus]; - ctxt = GSCurrentContext(); - NSDrawButton(cellFrame, cellFrame); - - arect.size.width -= 3; - arect.size.height -= 3; - arect.origin.x += 1; - arect.origin.y += 2; - - if (cell_highlighted) + + [super drawWithFrame: cellFrame inView: view]; + + if (_pbcFlags.pullsDown) { - backColor = [NSColor selectedMenuItemColor]; + aImage = [NSImage imageNamed:@"common_3DArrowDown"]; } else { - backColor = [NSColor controlColor]; - } - [backColor set]; - NSRectFill(arect); - - if (cell_image) - { - NSSize size; - NSPoint position; - - [cell_image setBackgroundColor: backColor]; - size = [cell_image size]; - position.x = MAX(NSMidX(cellFrame) - (size.width/2.),0.); - position.y = MAX(NSMidY(cellFrame) - (size.height/2.),0.); - /* - * Images are always drawn with their bottom-left corner at the origin - * so we must adjust the position to take account of a flipped view. - */ - if ([control_view isFlipped]) - position.y += size.height; - [cell_image compositeToPoint: position operation: NSCompositeCopy]; - - rect.size.width = 5; // calc image rect - rect.size.height = 11; - rect.origin.x = cellFrame.origin.x + cellFrame.size.width - 8; - rect.origin.y = cellFrame.origin.y + 3; - } - else - { - [cell_font set]; - - point.y = rect.origin.y + (rect.size.height/2) - 4; - point.x = rect.origin.x + xDist; - rect.origin = point; - - if (cell_highlighted) - { - [[NSColor selectedMenuItemTextColor] set]; - } - else - { - [[NSColor controlTextColor] set]; - } - - // Draw the title. - - DPSmoveto(ctxt, rect.origin.x, rect.origin.y); - DPSshow(ctxt, [contents cString]); - - rect.size.width = 15; // calc image rect - rect.size.height = cellFrame.size.height; - rect.origin.x = cellFrame.origin.x + cellFrame.size.width - (6 + 11); - rect.origin.y = cellFrame.origin.y; + aImage = [NSImage imageNamed:@"common_Nibble"]; } - if ([view isKindOfClass:[NSMenuView class]]) - { - NSPopUpButton *popb = [[(NSMenuView *)view menu] popupButton]; + size = [aImage size]; + position.x = cellFrame.origin.x + cellFrame.size.width - size.width - 4; + position.y = MAX(NSMidY(cellFrame) - (size.height/2.), 0.); + /* + * Images are always drawn with their bottom-left corner at the origin + * so we must adjust the position to take account of a flipped view. + */ + if ([control_view isFlipped]) + position.y += size.height; + [aImage compositeToPoint: position operation: NSCompositeCopy]; - if ([[[popb selectedItem] representedObject] isEqual: contents]) - { - if ([popb pullsDown] == NO) - toDraw = [NSImage imageNamed:@"common_Nibble"]; - else - toDraw = [NSImage imageNamed:@"common_3DArrowDown"]; - } - else if ([[[popb selectedItem] representedObject] isEqual: cell_image]) - { - if ([popb pullsDown] == NO) - toDraw = [NSImage imageNamed:@"common_UpAndDownArrowSmall.tiff"]; - else - toDraw = [NSImage imageNamed:@"common_DownArrowSmall"]; - } - } - else if ([view isKindOfClass:[NSPopUpButton class]]) - { - if ([[[(NSPopUpButton *)view selectedItem] representedObject] - isEqual: contents]) - { - if ([(NSPopUpButton *)view pullsDown] == NO) - toDraw = [NSImage imageNamed:@"common_Nibble"]; - else - toDraw = [NSImage imageNamed:@"common_3DArrowDown"]; - } - else if ([[[(NSPopUpButton *)view selectedItem] representedObject] isEqual: cell_image]) - { - if ([(NSPopUpButton *)view pullsDown] == NO) - toDraw = [NSImage imageNamed:@"common_UpAndDownArrowSmall"]; - else - toDraw = [NSImage imageNamed:@"common_DownArrowSmall"]; - } - } - if (toDraw != nil) - { - NSSize size; - NSPoint position; + [view unlockFocus]; +} - [toDraw setBackgroundColor: backColor]; - size = [toDraw size]; - position.x = MAX(NSMidX(rect) - (size.width/2.),0.); - position.y = MAX(NSMidY(rect) - (size.height/2.),0.); - /* - * Images are always drawn with their bottom-left corner at the origin - * so we must adjust the position to take account of a flipped view. - */ - if ([control_view isFlipped]) - position.y += size.height; - [toDraw compositeToPoint: position operation: NSCompositeCopy]; - } - [view unlockFocus]; +- (void)_popUpItemAction:(id)sender +{ + [self selectItemWithTitle: [sender title]]; + NSLog(@"%@", [sender title]); + [self dismissPopUp]; } @end diff --git a/Source/externs.m b/Source/externs.m index 2ab2f618a..e206863c7 100644 --- a/Source/externs.m +++ b/Source/externs.m @@ -273,6 +273,7 @@ NSString* const NSMenuDidChangeItemNotification = @"MenuDidChangeItem"; // NSPopUpButton notification NSString *NSPopUpButtonWillPopUpNotification = @"PopUpButtonWillPopUp"; +NSString *NSPopUpButtonCellWillPopUpNotification = @"PopUpButtonCellWillPopUp"; // NSTable notifications NSString *NSTableViewSelectionDidChangeNotification = @"TableViewSelectionDidChange";