/* 
   NSPopUpButton.m

   Popup list class

   Copyright (C) 1996 Free Software Foundation, Inc.

   Author:	Michael Hanni <mhanni@sprintmail.com>
   Date:	June 1999
   
   This file is part of the mySTEP Library and is provided
   under the terms of the GNU Library General Public License.
*/

#import <Foundation/NSException.h>
#import <Foundation/NSArray.h>

#import <AppKit/NSPopUpButton.h>
#import <AppKit/NSApplication.h>
#import <AppKit/NSMenu.h>
#import <AppKit/NSMenuView.h>
#import <AppKit/NSPopUpButtonCell.h>
#import <AppKit/NSEvent.h>
#import <AppKit/NSWindow.h>
#import <AppKit/NSFont.h>
#import <AppKit/NSImage.h>
#import <AppKit/NSColor.h>

#import "NSAppKitPrivate.h"

@implementation NSPopUpButtonCell

- (IBAction) _popUpItemAction:(id) sender;
{
	// popup item selected
	NSLog(@"%@ _popUpItemAction:%@", self, sender);
	[self selectItem:sender];
	[_controlView setNeedsDisplay:YES];
	[_controlView performClick:_controlView];	// and notify whoever wants to know
}

- (void) drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView  
{ // overlay the popup/pulldown icon
	NSRect b, t;
	NSImage *image;
#if 0
	NSLog(@"drawInteriorWithFrame %@", self);
#endif
	_controlView = controlView;							// last view drawn in
	NSDivideRect(cellFrame, &b, &t, 17, NSMaxXEdge);
	[super drawInteriorWithFrame:t inView:controlView];	// text part to the left
		
	if(_pullsDown)
		{
		if([[self itemTitleAtIndex:0] isEqualToString:[self stringValue]])
			{
			if([self isHighlighted]) 
				image=[NSImage imageNamed:@"GSPullDownH"];
			else
				image=[NSImage imageNamed:@"GSPullDown"];
			}
		}
	else
		{
//		if ([[self titleOfSelectedItem] isEqualToString:[self stringValue]])
			image=[NSImage imageNamed:@"GSPopup"];
		}
	if(image)
		{													// Draw the image
		NSSize sz = [image size];
		
		b.origin.x += (b.size.width - sz.width) / 2;	// center
		b.origin.y += (b.size.height - sz.height) / 2;
#if 0
		NSLog(@"NSPopUpButton image=%@ rect=%@", image, NSStringFromRect(rect));
#endif
		[image compositeToPoint:b.origin operation:NSCompositeSourceOver];
		}
}

- (id) initTextCell:(NSString *)value pullsDown:(BOOL)flag;
{
	self=[self initTextCell:value];
	if(self)
		{
		_menu=[NSMenu new];	// empty menu
		[self setPullsDown:flag];
		_preferredEdge=NSMinYEdge;
		// other inits
		}
	return self;
}

#if 0
- (void) release
{
	NSLog(@"%08x: %@ release (%d)", self, self, [self retainCount]);
//	if([self retainCount] == 1)
//		abort();
	[super release];
}

- (id) autorelease
{
	NSLog(@"%08x: %@ autorelease", self, self);
	return [super autorelease];
}
#endif

- (void) dealloc
{
	[_menu release];
	[super dealloc];
}

- (void) addItemWithTitle:(NSString *)title
{
	[self insertItemWithTitle:title atIndex:[_menu numberOfItems]];
	[self synchronizeTitleAndSelectedItem];
}

- (void) addItemsWithTitles:(NSArray *)itemTitles
{
	int i, count = [itemTitles count];	
	for (i = 0; i < count; i++)
		[self addItemWithTitle:[itemTitles objectAtIndex:i]];
}

- (void) insertItemWithTitle:(NSString *)title atIndex:(unsigned int)index
{
	int i;
	NSMenuItem *c;
#if 0
	NSLog(@"insertItemWithTitle:%@ atIndex:%d", title, index);
#endif
	if(!title)
		[NSException raise: NSInvalidArgumentException
					format: @"attempt to insertItemWithTitle with nil title."];
	c=[[[NSMenuItem alloc] initWithTitle:title 
								  action:@selector(_popUpItemAction:)
						   keyEquivalent:@""] autorelease];
	[c setTarget:self];
	i=[self indexOfItemWithTitle:title];	// already defined?
#if 0
	NSLog(@"i=%d", i);
#endif
	if(i >= 0)
		{ // remove if title already exists
		[self removeItemAtIndex:i];
		if(index > i)
			index--;	// has been referring to index list including the one we just have deleted
		}
#if 0
	NSLog(@"insert item %@", c);
#endif
	[_menu insertItem:c atIndex:index];
	[self synchronizeTitleAndSelectedItem];
}

- (void) removeItemWithTitle:(NSString *)title
{
	[_menu removeItemAtIndex:[self indexOfItemWithTitle:title]];
}

- (int) indexOfItem:(id <NSMenuItem>)item; { return [_menu indexOfItem:item]; }
- (int) indexOfItemWithTitle:(NSString *)title { return [_menu indexOfItemWithTitle:title]; }
- (int) indexOfItemWithTag:(int)t; { return [_menu indexOfItemWithTag:t]; }
- (int) indexOfItemWithRepresentedObject:(id)obj; { return [_menu indexOfItemWithRepresentedObject:obj]; }
- (int) indexOfItemWithTarget:(id)t andAction:(SEL)a; { return [_menu indexOfItemWithTarget:t andAction:a]; }

- (void) removeItemAtIndex:(int)index;
{
	if(index < 0 || index >= [_menu numberOfItems])
	   [_menu removeItemAtIndex:index];
	[self synchronizeTitleAndSelectedItem];
}

- (void) removeAllItems	
{
	while([_menu numberOfItems] > 0)
		[_menu removeItemAtIndex:0];
	[self synchronizeTitleAndSelectedItem];
}

- (int) indexOfSelectedItem				{ return _selectedItem; }
- (int) numberOfItems					{ return [_menu numberOfItems]; }
- (NSArray *) itemArray					{ return [_menu itemArray]; }

// - (NSMenu *) menu						{ return _menu; }
- (void) setMenu:(NSMenu *) m
{
	int i, cnt=[m numberOfItems];
#if 0
	NSLog(@"%@ setMenu %@", self, m);
	//	if(!m)
	//		abort();
#endif
	for(i=0; i<cnt; i++)
		{
		NSMenuItem *item=(NSMenuItem *)[m itemAtIndex:i];
		if([NSStringFromSelector([item action]) isEqualToString:@"_popUpItemAction:"])
			[item setTarget:self];	// adjust target
		}
	//	ASSIGN(_menu, m);
	[super setMenu:m];
}

- (id <NSMenuItem>) itemAtIndex:(int)index
{
	if(index < 0 || index >= [_menu numberOfItems])
		return nil;
	return [_menu itemAtIndex:index];
}

- (NSString *) itemTitleAtIndex:(int)index
{
	return [[_menu itemAtIndex:index] title];
}

- (NSArray *) itemTitles
{
	int i, count = [_menu numberOfItems];
	NSMutableArray *titles = [NSMutableArray arrayWithCapacity:count];
	for (i = 0; i < count; i++)
		[titles addObject:[[_menu itemAtIndex:i] title]];
	return titles;
}

- (id <NSMenuItem>) itemWithTitle:(NSString *)title
{
	int i = [self indexOfItemWithTitle:title];
	return (i != NSNotFound) ? [_menu itemAtIndex:i] : nil;
}

- (id <NSMenuItem>) lastItem
{
	return ([_menu numberOfItems]) ? [_menu itemAtIndex:[_menu numberOfItems]-1] : nil;
}

- (id <NSMenuItem>) selectedItem
{
	if(_selectedItem < 0 || _selectedItem >= [_menu numberOfItems])
		return nil;	// out of bounds
	return [_menu itemAtIndex:_selectedItem];
}

- (id <NSCopying>) objectValue;
{
	return [NSNumber numberWithInt:_selectedItem];
}

- (NSString *) titleOfSelectedItem
{
	return [(NSMenuItem*)[self selectedItem] title];
}

- (void) selectItemAtIndex:(int)index
{
#if 0
	NSLog(@"selectItemAtIndex: %d [0,%d]", index, [_menu numberOfItems]-1);
#endif
	if(_selectedItem >= 0 && !_pullsDown)
		[[self selectedItem] setState:NSOffState];	// deselect previous
	_selectedItem = index;
	if(_selectedItem >= 0 && !_pullsDown)
		[[self selectedItem] setState:NSOnState];	// select new
#if 0
	NSLog(@"selectedItem=%d:%@ state=%d", _selectedItem, [self selectedItem], [[self selectedItem] state]);
#endif
	[self synchronizeTitleAndSelectedItem];
}

- (void) setObjectValue:(id <NSCopying>) obj;
{
	[self selectItemAtIndex:[(id) obj intValue]];
}

- (void) selectItem:(id <NSMenuItem>) item;
{
#if 0
	NSLog(@"selectItem: %@", item);
#endif
	[self selectItemAtIndex: [self indexOfItem:item]];
}

- (void) selectItemWithTitle:(NSString *)title
{
#if 0
	NSLog(@"selectItemWithTitle:%@", title);
#endif
	[self selectItemAtIndex: [self indexOfItemWithTitle:title]];
}

- (void) setImage:(NSImage *) img { /* no effect */ }
- (void) setAltersStateOfSelectedItem:(BOOL)flag	{ _altersStateOfSelectedItem = flag; }
- (void) setAutoenablesItems:(BOOL)flag			{ _autoenablesItems = flag; }
- (void) setPullsDown:(BOOL)flag				{ _pullsDown = flag; }
- (void) setArrowPosition:(NSPopUpArrowPosition) position;	{ _arrowPosition=position; }
- (void) setPreferredEdge:(NSRectEdge) edge;	{ _preferredEdge=edge; }
- (void) setUsesItemFromMenu:(BOOL)flag;	{ _usesItemFromMenu=flag; }

- (BOOL) altersStateOfSelectedItem				{ return _altersStateOfSelectedItem; }
- (BOOL) autoenablesItems						{ return _autoenablesItems; }
- (BOOL) pullsDown								{ return _pullsDown; }
- (NSPopUpArrowPosition) arrowPosition;		{ return _arrowPosition; }
- (NSRectEdge) preferredEdge;				{ return _preferredEdge; }
- (BOOL) usesItemFromMenu;					{ return _usesItemFromMenu; }

- (void) setTitle:(NSString *)aString			
{
	int i = [self indexOfItemWithTitle:aString];
#if 0
	NSLog(@"setTitle:%@ -> %d", aString, i);
#endif
	if (i == NSNotFound)
		{
		[self addItemWithTitle:aString];
		i = [_menu numberOfItems];	// has been appended
		}
	[self selectItemAtIndex: i];
}

- (void) synchronizeTitleAndSelectedItem
{
	int i = (_pullsDown) ? 0 : _selectedItem;
#if 0
	NSLog(@"synchronizeTitleAndSelectedItem i=%d", i);
#endif
	if(i < 0 || i >= [_menu numberOfItems])
		[super setTitle:@"?"];	// nothing/invalid
	else
		[super setTitle: [[_menu itemAtIndex: i] title]]; 
}

- (void) attachPopUpWithFrame:(NSRect) cellFrame inView:(NSView *) controlView;
{
	NSWindow *win;
//	NSMenuView *menuView; - inherited from NSMenuItemCell
	NSRect r;
#if 1
	NSLog(@"attachPopUpWithFrame %08x", _menu);
	NSLog(@"attachPopUpWithFrame %@", [_menu title]);
	NSLog(@"attachPopUpWithFrame view %@", controlView);
#endif
	if(!_menu || !controlView)
		return;
	//	[[NSMenuView _currentOpenMenuView] detachSubmenu];	// close if any other is open
	[_menu update];		// enable/disable menu items
	menuView=[[[NSMenuView class] alloc] initWithFrame:NSMakeRect(0.0, 0.0, 50.0, 50.0)];	// make new NSMenuView
	[menuView setFont:_font];			// same font as the popup button
	[menuView setHorizontal:NO];		// make popup menu vertical
	[menuView _setContextMenu:YES];		// close on selection
	win=[[[NSWindow alloc] initWithContentRect:NSMakeRect(50.0, 50.0, 50.0, 50.0)
									 styleMask:NSBorderlessWindowMask
									   backing:NSBackingStoreBuffered
										 defer:YES] retain];	// will be released on close
	[win setLevel:NSSubmenuWindowLevel];
#if 1
	NSLog(@"win=%@", win);
	NSLog(@"autodisplay=%d", [win isAutodisplay]);
#endif
#if 1
	[win setTitle:@"PopUpButton Menu"];
#endif
	[[win contentView] addSubview:menuView];	// add to view hiearachy
	[menuView setMenu:_menu];			// define to manage selected menu
#if 1
	NSLog(@"cellFrame=%@", NSStringFromRect(cellFrame));
	NSLog(@"view Frame=%@", NSStringFromRect([controlView frame]));
	NSLog(@"view's window Frame=%@", NSStringFromRect([[controlView window] frame]));
#endif
	if(!_pullsDown)
		{ // overlay to popup button
		cellFrame.size.width=0;		// zero width so that the menu attaches to the right side
		cellFrame.origin.x -= 10;	// shift left
		}
	r=[controlView convertRect:cellFrame toView:nil];				// convert to view's frame
	r.origin=[[controlView window] convertBaseToScreen:r.origin];	// to screen coordinates
#if 1
	NSLog(@"menu to be attached to %@", NSStringFromRect(r));
#endif
	if(_pullsDown)
		[menuView setWindowFrameForAttachingToRect:r
										  onScreen:[win screen]
									 preferredEdge:_preferredEdge	// attach below
								 popUpSelectedItem:-1];
	else
		[menuView setWindowFrameForAttachingToRect:r
										  onScreen:[win screen]
									 preferredEdge:NSMaxXEdge	// attach to the right
								 popUpSelectedItem:_selectedItem];
	[win orderFront:self];		// make visible
}

- (void) dismissPopUp;
{
	[[menuView window] close];
	menuView=nil;
}

- (void) performClickWithFrame:(NSRect) frame inView:(NSView *) controlView;
{ // pop up as context menu
	NSEvent *event=[NSApp currentEvent];
	NSLog(@"performClickWithFrame %@ - %@ - %@", _menu, event, controlView);
	// how to handle frame? Simulate as a mouseDown event and use frame as the location?
	[NSMenu popUpContextMenu:_menu withEvent:event forView:controlView withFont:nil];
}

#if 0

// FIXME: where do we get mouseDown events from???
// we have to override
// -startTrackingAt:
// -continueTrackingAt:
// -stopTrackingAt:

- (void) mouseDown:(NSEvent*) event
{ // pop up in my control view
	NSLog(@"NSPopUpButtonCell mouseDown");
  // send NSPopUpButtonCellWillPopUpNotification
	// should somehow determine my location within the control view
//	[self performClickWithFrame:(NSRect){{0, 0}, [self cellSize]} inView:[self controlView]];
	
	// check if controlView is a matrix -> then get location of current item so that we pop up at the right vertical position 
	
	[self attachPopUpWithFrame:(NSRect){{0, 0}, [self cellSize]} inView:[self controlView]];
}
#endif

- (BOOL) trackMouse:(NSEvent *)event
			 inRect:(NSRect)cellFrame
			 ofView:(NSView *)controlView
	   untilMouseUp:(BOOL)flag
{
	NSLog(@"NSPopUpButtonCell trackMouse:inRect:...");
	[self attachPopUpWithFrame:cellFrame inView:controlView];	// open menu
	[menuView mouseDown:event];	// pass event down
	return YES;
}

- (id) initWithCoder:(NSCoder *) aDecoder
{
	self=[super initWithCoder:aDecoder];
	if(![aDecoder allowsKeyedCoding])
		return NIMP;
	_altersStateOfSelectedItem=[aDecoder decodeBoolForKey:@"NSAltersState"];
	_usesItemFromMenu=[aDecoder decodeBoolForKey:@"NSUsesItemFromMenu"];
	// _pullsDown=?
	// _autoenablesItems=?
	_arrowPosition=[aDecoder decodeIntForKey:@"NSArrowPosition"];
	_preferredEdge=[aDecoder decodeIntForKey:@"NSPreferredEdge"];
	_selectedItem=[aDecoder decodeIntForKey:@"NSSelectedIndex"];
	return self;
}

@end

//*****************************************************************************
//
// 		NSPopUpButton 
//
//*****************************************************************************

@implementation NSPopUpButton

- (BOOL) isHorizontal; { return NO; }	// behaves like a vertical menu (NSPopUpButtonCell assumes we are a NSMenuView)
- (float) horizontalEdgePadding; { return 0.0; }
- (float) imageAndTitleOffset; { return 0.0; }

- (id) init
{
	return [self initWithFrame:NSZeroRect pullsDown:NO];
}

- (id) initWithFrame:(NSRect)frameRect
{
	return [self initWithFrame:frameRect pullsDown:NO];
}

- (id) initWithFrame:(NSRect)frameRect pullsDown:(BOOL)flag
{
	self=[super initWithFrame:frameRect];
	if(self)
		{
//		NSLog(@"cell %@", _cell);
		[self setCell:[[NSPopUpButtonCell new] autorelease]];
//		NSLog(@"cell %@", _cell);
		[self setPullsDown:flag];
		[self setEnabled:YES];
		}
	return self;
}

- (void) dealloc
{
	[super dealloc];
}

- (void) addItemWithTitle:(NSString *)title { [_cell addItemWithTitle:title]; }
- (void) addItemsWithTitles:(NSArray *)itemTitles
					{ [_cell addItemsWithTitles:itemTitles]; }
- (void) insertItemWithTitle:(NSString *)title atIndex:(unsigned int)index
{
	[_cell insertItemWithTitle:title atIndex:index];
}

- (void) removeItemWithTitle:(NSString *)title { [_cell removeItemWithTitle:title]; }
- (int) indexOfItemWithTitle:(NSString *)title { return [_cell indexOfItemWithTitle:title]; }
- (int) indexOfItemWithTag:(int)tag; { return [_cell indexOfItemWithTag:tag]; }
- (int) indexOfItemWithRepresentedObject:(id)obj; { return [_cell indexOfItemWithRepresentedObject:obj]; }
- (int) indexOfItemWithTarget:(id)target andAction:(SEL)action; { return [_cell indexOfItemWithTarget:target andAction:action]; }
- (void) removeItemAtIndex:(int)index	{ [_cell removeItemAtIndex:index]; }
- (void) removeAllItems					{ [_cell removeAllItems]; }
- (int) indexOfSelectedItem				{ return [_cell indexOfSelectedItem]; }
- (int) numberOfItems					{ return [_cell numberOfItems]; }
- (NSArray *) itemArray					{ return [_cell itemArray]; }
- (NSMenu *) menu						{ return [_cell menu]; }
- (void) setMenu:(NSMenu *) m		
{ 
	NSLog(@"NSPopupButton %08x setMenu:%@", self, m);
	[_cell setMenu:m]; 
}
- (id <NSMenuItem>) itemAtIndex:(int)index			{ return [_cell itemAtIndex:index]; }
- (NSString *) itemTitleAtIndex:(int)index			{ return [_cell itemTitleAtIndex:index]; }
- (NSArray *) itemTitles							{ return [_cell itemTitles]; }
- (id <NSMenuItem>) itemWithTitle:(NSString *)title	{ return [_cell itemWithTitle:title]; }
- (id <NSMenuItem>) lastItem						{ return [_cell lastItem]; }
- (id <NSMenuItem>) selectedItem					{ return [_cell selectedItem]; }
- (NSString *) titleOfSelectedItem					{ return [_cell titleOfSelectedItem]; }
- (void) selectItem:(id <NSMenuItem>)item			{ [_cell selectItem:item]; }
- (void) selectItemAtIndex:(int)index				{ [_cell selectItemAtIndex:index]; }
- (void) selectItemWithTitle:(NSString *)title		{ [_cell selectItemWithTitle:title]; }
- (void) setPullsDown:(BOOL)flag					{ [_cell setPullsDown:flag]; }
- (void) setAutoenablesItems:(BOOL)flag				{ [_cell setAutoenablesItems:flag]; }
- (void) setArrowPosition:(NSPopUpArrowPosition) position;	{ [_cell setArrowPosition:position]; }
- (void) setPreferredEdge:(NSRectEdge) edge;		{ [_cell setPreferredEdge:edge]; }
// - (NSString *) stringValue						{ return nil; }
- (BOOL) autoenablesItems							{ return [_cell autoenablesItems]; }
- (BOOL) pullsDown									{ return [_cell pullsDown]; }
- (NSPopUpArrowPosition) arrowPosition;				{ return [_cell arrowPosition]; }
- (NSRectEdge) preferredEdge;						{ return [_cell preferredEdge]; }
- (void) setTitle:(NSString *)aString				{ [_cell setTitle:aString]; }
- (void) setImage:(NSImage *)anImage				{ [_cell setImage:anImage]; }
- (void) setObjectValue:(id <NSCopying>)anValue		{ [_cell setObjectValue:anValue]; }
- (void) synchronizeTitleAndSelectedItem			{ [_cell synchronizeTitleAndSelectedItem]; }
- (id <NSCopying>) objectValue						{ return [_cell objectValue]; }

- (void) mouseDown:(NSEvent*)event
{
	// send NSPopUpButtonWillPopUpNotification
	[_cell attachPopUpWithFrame:(NSRect){{0,0}, [self frame].size} inView:self];
}

- (void) encodeWithCoder:(NSCoder*)aCoder
{
	[super encodeWithCoder: aCoder];
}

- (id) initWithCoder:(NSCoder*)aDecoder
{
	self=[super initWithCoder: aDecoder];
	return self;
}

@end /* NSPopUpButton */
