/* 
   NSButton.m

   Button control and associated button cell class

   Copyright (C) 2000 Free Software Foundation, Inc.

   Author:  Felipe A. Rodriguez <far@pcmagic.net>
   Date:    June 2000
   
   This file is part of the mySTEP Library and is provided
   under the terms of the GNU Library General Public License.
*/ 

#import <Foundation/NSString.h>
#import <Foundation/NSException.h>
#import <Foundation/NSValue.h>

#import <AppKit/NSButton.h>
#import <AppKit/NSEvent.h>
#import <AppKit/NSGraphics.h>
#import <AppKit/NSWindow.h>
#import <AppKit/NSApplication.h>
#import <AppKit/NSFont.h>
#import <AppKit/NSImage.h>
#import <AppKit/NSColor.h>
#import <AppKit/NSBezierPath.h>

#import "NSAppKitPrivate.h"

// class variables
id __buttonCellClass = nil;

//*****************************************************************************
//
// 		NSButtonCell 
//
//*****************************************************************************

@implementation NSButtonCell

- (id) init						{ return [self initTextCell:@"Button"]; }

// override

- (id) initTextCell:(NSString *)aString
{
#if 0
	NSLog(@"%@ (NSButtonCell)initTextCell:%@", self, aString);
#endif
	self=[super initTextCell:@"0"];	// aString is not printed but used as the state!
	if(self)
		{
		[self setBordered:YES];		// draw bezel
		[self setShowsFirstResponder:YES];	//default
		[self setTitle:aString];	// replace title default (@"Button")
		_bezelStyle=NSRoundedBezelStyle;	// default style
		[self setButtonType:NSMomentaryPushInButton];
		_periodicDelay = 0.4;
		_periodicInterval = 0.075;
		}
#if 0
	NSLog(@"%@ initTextCell done", self);
#endif
	return self;
}

- (id) initImageCell:(NSImage *)anImage
{
	if((self=[self initTextCell:nil]))
		{ // no title
		_c.imagePosition = NSImageOnly;
		_normalImage = [anImage retain];
		_mixedImage = [[NSImage imageNamed:@"NSMultiStateSwitch"] retain];
		}
	return self;
}

- (void) dealloc
{
	[_alternateTitle release];
	[_alternateImage release];
	[_normalImage release];
	[_keyEquivalent release];
	[_keyEquivalentFont release];
	
	[super dealloc];
}

- (id) copyWithZone:(NSZone *) zone;
{
	NSButtonCell *c = [super copyWithZone:zone];

	c->_alternateTitle = [_alternateTitle copyWithZone:zone];
	if(_alternateImage)
		c->_alternateImage = [_alternateImage retain];
	if(_normalImage)
		c->_normalImage = [_normalImage retain];
	if(_keyEquivalent)
		{
		c->_keyEquivalent = [_keyEquivalent copyWithZone:zone];
		if(_keyEquivalentFont)
			c->_keyEquivalentFont = [_keyEquivalentFont retain];
		c->_keyEquivalentModifierMask = _keyEquivalentModifierMask;
		}
	c->_highlightMask = _highlightMask;
	c->_stateMask = _stateMask;
	c->_periodicDelay = _periodicDelay;
	c->_periodicInterval = _periodicInterval;
	c->_buttonType = _buttonType;
	c->_bezelStyle = _bezelStyle;
	c->_dimsWhenDisabled = _dimsWhenDisabled;
	c->_transparent = _transparent;
	
	return c;
}

- (NSColor *) backgroundColor				{ return _backgroundColor; }
- (void) setBackgroundColor:(NSColor *)col	{ ASSIGN(_backgroundColor,col); }
- (NSString *) alternateTitle				{ return _alternateTitle; }
- (void) setAlternateTitle:(NSString *)aStr	{ ASSIGN(_alternateTitle,aStr); }
- (void) setFont:(NSFont *)fontObject		{ [super setFont:fontObject]; }
- (NSCellImagePosition) imagePosition		{ return _c.imagePosition; }
- (NSImage *) alternateImage				{ return _alternateImage; }
- (NSImage *) image							{ return _normalImage; }
- (NSImage *) _mixedImage					{ return _mixedImage; }
- (void) setAlternateImage:(NSImage*)aImage	{ ASSIGN(_alternateImage,aImage); }
- (void) setImage:(NSImage *)anImage		{ ASSIGN(_normalImage, anImage); }
- (void) _setMixedImage:(NSImage *)anImage	{ ASSIGN(_mixedImage, anImage); }

- (void) setImagePosition:(NSCellImagePosition)aPosition
{
	_c.imagePosition = aPosition;
}

- (NSSize) cellSize
{
	NSSize m=[super cellSize];	// get text size

	if(_normalImage != nil)
		{
		switch (_c.imagePosition) 
			{												
			case NSImageOnly:
				m = [_normalImage size];
			case NSNoImage:
				break;
			case NSImageLeft:
			case NSImageRight:
				m.width += [_normalImage size].width + 8;
				break;
			case NSImageBelow:
			case NSImageAbove:
				m.height += [_normalImage size].height + 4;
				break;
			case NSImageOverlaps:
				{
				NSSize img = [_normalImage size];

				m.width = MAX(img.width + 4, m.width);
				m.height = MAX(img.height + 4, m.height);
				break;
		}	}	}

	return m;
}

- (void) getPeriodicDelay:(float *)delay interval:(float *)interval
{
	if(delay)
		*delay = _periodicDelay;
	if(interval)
		*interval = _periodicInterval;
}

- (void) setPeriodicDelay:(float)delay interval:(float)interval
{
	_periodicDelay = delay;
	_periodicInterval = interval;						// Set Repeat Interval
}

- (void) performClick: (id)sender
{
	[self setNextState];
	[super performClick:sender];
}
															// Key Equivalent 
- (NSFont*) keyEquivalentFont			{ return _keyEquivalentFont; }

- (unsigned int) keyEquivalentModifierMask 	
{ 
	return _keyEquivalentModifierMask;
}

// override default implementation of NSCell
- (NSString*) keyEquivalent				{ return _keyEquivalent; }

- (void) setKeyEquivalent:(NSString*)key	
{ 
	if (_keyEquivalent != key)
		ASSIGN(_keyEquivalent, [[key copy] autorelease]);
}

- (void) setKeyEquivalentModifierMask:(unsigned int)mask
{
	_keyEquivalentModifierMask = mask;
}

- (void) setKeyEquivalentFont:(NSFont*)fontObj
{
	ASSIGN(_keyEquivalentFont, fontObj);
}

- (void) setKeyEquivalentFont:(NSString*)fontName size: (float)fontSize
{
	ASSIGN(_keyEquivalentFont, [NSFont fontWithName:fontName size:fontSize]);
}

- (void) setButtonType:(NSButtonType)buttonType			// Graphic Attributes
{
	switch(_buttonType=buttonType) 
		{
		case NSMomentaryLightButton:
			_highlightMask = NSChangeGrayCellMask | NSChangeBackgroundCellMask;
			_stateMask = NSNoCellMask;
			break;
		case NSMomentaryPushInButton:
			_highlightMask = NSPushInCellMask | NSChangeGrayCellMask | NSChangeBackgroundCellMask;
			_stateMask = NSNoCellMask;
			break;
		case NSMomentaryChangeButton:
			_highlightMask = NSContentsCellMask;
			_stateMask = NSNoCellMask;
			break;
		case NSPushOnPushOffButton:
			_highlightMask = NSPushInCellMask | NSChangeGrayCellMask | NSChangeBackgroundCellMask;
			_stateMask = NSChangeGrayCellMask | NSChangeBackgroundCellMask;
			break;
		case NSOnOffButton:
			_stateMask = _highlightMask = NSChangeGrayCellMask | NSChangeBackgroundCellMask;
			break;
		case NSToggleButton:
			_highlightMask = NSPushInCellMask | NSContentsCellMask;
			_stateMask = NSContentsCellMask;
			break;
		case NSSwitchButton:
			_stateMask = _highlightMask = NSContentsCellMask;
//			[_alternateImage release];
//			_alternateImage=(NSImage *) [[NSButtonImageSource alloc] initWithName:@"NSSwitch"];
			[self setImagePosition:NSImageLeft];
			break;
		case NSRadioButton:
			_stateMask = _highlightMask = NSContentsCellMask;
//			[_alternateImage release];
//			_alternateImage=(NSImage *) [[NSButtonImageSource alloc] initWithName:@"NSRadioButton"];
			[self setImagePosition:NSImageLeft];
			break;
		}
	[self setState:[self state]];		// update our state (to a valid value)
}

#define stateOrHighlight(mask) ((_c.state != 0 && (_stateMask & (mask))) || (_c.highlighted && (_highlightMask & (mask))))

- (BOOL) isTransparent					{ return ![self isOpaque]; }

- (BOOL) isOpaque
	{ 
	return !_transparent || _c.bordered || 
		(_stateMask & NSChangeBackgroundCellMask) || 
		stateOrHighlight(NSChangeGrayCellMask | NSChangeBackgroundCellMask);
	}

- (int) highlightsBy					{ return _highlightMask; }
- (int) showsStateBy					{ return _stateMask; }
- (NSBezelStyle) bezelStyle;			{ return _bezelStyle; }
- (BOOL) imageDimsWhenDisabled;			{ return _dimsWhenDisabled; }
- (void) setTransparent:(BOOL)flag		{ _transparent = flag; }
- (void) setImageDimsWhenDisabled:(BOOL)flag;	{ _dimsWhenDisabled = flag; }
- (void) setHighlightsBy:(int)mask		{ _highlightMask = mask; }
- (void) setShowsStateBy:(int)mask		{ _stateMask = mask; }
- (void) setBezelStyle:(NSBezelStyle) bezelStyle; { _bezelStyle=bezelStyle; }
- (void) setIntValue:(int)anInt			{ [self setState:(anInt != 0)]; }
- (void) setFloatValue:(float)aFloat	{ [self setState:(aFloat != 0)]; }
- (void) setDoubleValue:(double)aDouble	{ [self setState:(aDouble != 0)]; }

- (void) setObjectValue:(id)anObject
{
	if([anObject respondsToSelector:@selector(intValue)])
		[self setState:[anObject intValue]];
	else
		[self setState:(anObject != nil)];
}

// does not use _c.state to allow for subclasses to override -state

- (int) intValue						{ return [self state]; }
- (float) floatValue					{ return [self state]; }
- (double) doubleValue					{ return [self state]; }
- (id) objectValue		{ return [NSNumber numberWithInt:[self state]]; }

- (void) drawBezelWithFrame:(NSRect) cellFrame inView:(NSView *) controlView;
{
	NSColor *backgroundColor;
	if(!_c.bordered)
		{
		if(_backgroundColor)
			{
			[_backgroundColor set];
			NSRectFill(cellFrame);
			}
		return;
		}
	if(stateOrHighlight(NSChangeGrayCellMask | NSChangeBackgroundCellMask))
		backgroundColor = [NSColor whiteColor];		// make background white dependent on state/highlight
	else if(_stateMask & NSChangeBackgroundCellMask)
		backgroundColor = [NSColor controlColor];	// show control background even if not bordered (On/Off and Push On/Push Off buttons)
	else
		backgroundColor = nil;	// default: transparent
	switch(_bezelStyle)
		{
		case 0:	// no Bezel, e.g. Radio button and Checkbox
			break;
		default:
		case NSRecessedBezelStyle:
			NSLog(@"NSButtonCell (%@) unknown bezelStyle:%d", _title, _bezelStyle);
			break;
		case NSRoundRectBezelStyle:
		case NSTexturedRoundBezelStyle:
		case NSRoundedBezelStyle:
			{ // standard Button (half-circle at both ends)
				NSBezierPath *p;
				NSGraphicsContext *ctxt=[NSGraphicsContext currentContext];
				cellFrame=NSInsetRect(cellFrame, 4, floor(cellFrame.size.height*0.1875));	// make smaller than enclosing frame
				if(_c.highlighted != ([_keyEquivalent isEqualToString:@"\r"] || [_keyEquivalent isEqualToString:@"\n"]))
					backgroundColor=[NSColor selectedControlColor];	// selected or default button
				else if(!backgroundColor)
					backgroundColor=[NSColor controlColor];
				p=[NSBezierPath _bezierPathWithRoundedBezelInRect:cellFrame vertical:NO];	// box with halfcircular rounded ends
				[ctxt saveGraphicsState];
				[p addClip];	// clip to contour
								//				[backgroundColor setFill];
				[backgroundColor set];
				[p fill];		// fill with background color
				[ctxt restoreGraphicsState];
				[[NSColor blackColor] setStroke];
				[p stroke];		// and stroke rounded button
				break;
			}
		case NSTexturedSquareBezelStyle:	// Textured
			cellFrame=NSInsetRect(cellFrame, 0, 1);
			// FIXME: handle different pixel width
		case NSSmallSquareBezelStyle:
		case NSShadowlessSquareBezelStyle:
		case NSRegularSquareBezelStyle:		// Square 2 pixels border
		case NSThickSquareBezelStyle:		// 3 px
		case NSThickerSquareBezelStyle:		// 4 px
			{
				if(!backgroundColor && _c.bordered)
					backgroundColor=[NSColor controlColor]; // bordered cell never has transparent background
				if(_bezelStyle == NSTexturedSquareBezelStyle || stateOrHighlight(NSChangeGrayCellMask | NSChangeBackgroundCellMask))
					[[NSColor controlShadowColor] set];
				else
					[backgroundColor set];
				NSRectFill(cellFrame);
				[[NSColor controlShadowColor] set];	// border shadow
				if(_c.bordered)
					{
					switch(_bezelStyle)
						{
						default:		// Square 2 pixels (total) border
							NSFrameRectWithWidth(cellFrame, 1);
							break;
						case NSThickSquareBezelStyle:		// 3 px
							NSFrameRectWithWidth(cellFrame, 1.5);
							break;
						case NSThickerSquareBezelStyle:		// 4 px
							NSFrameRectWithWidth(cellFrame, 2);
							break;
						}
					}
				break;
			}
		case NSDisclosureBezelStyle:		// Disclosure arrow has no bezel/border
		case NSRoundedDisclosureBezelStyle:
			break;
		case NSCircularBezelStyle:			// Round
			cellFrame=NSInsetRect(cellFrame, 3, 3);	// make smaller than Help button
		case NSHelpButtonBezelStyle:		// Help
			{
				NSGraphicsContext *ctxt=[NSGraphicsContext currentContext];
				NSBezierPath *oval=[NSBezierPath bezierPathWithOvalInRect:NSInsetRect(cellFrame, 1, 1)];	// make smaller so that it does not touch frame
				if(!backgroundColor)
					backgroundColor=[NSColor controlColor];
				[backgroundColor set];
				[ctxt saveGraphicsState];
				[oval addClip];
				[oval fill];		// fill oval with background color
				[ctxt restoreGraphicsState];
				[_c.highlighted?[NSColor selectedControlColor]:[NSColor blackColor] set];	// make ring color dependent on highlight state?
				[oval stroke];
				break;
			}
		}
}

- (void) drawImageWithFrame:(NSRect) cellFrame inView:(NSView *) controlView;
{
	NSSize imageSize;
	NSCompositingOperation op = NSCompositeSourceOver;	// default composition

	if(_transparent || _c.imagePosition == NSNoImage)
		return;	// don't draw any image
	if(stateOrHighlight(NSChangeBackgroundCellMask))
		{ // change background
		op = NSCompositeHighlight;
		}
	switch(_bezelStyle)
		{ // special images
		case NSHelpButtonBezelStyle:
			_image=nil;
			break;
		case NSDisclosureBezelStyle:
			if(!_normalImage)
				_normalImage=[[NSButtonImageSource alloc] initWithName:@"NSDisclose"];	// assign as default image source
			_c.imagePosition=NSImageOnly;	// override
		default:
			if([_normalImage isKindOfClass:[NSButtonImageSource class]])
				_image=[(NSButtonImageSource *) _image buttonImageForCell:self];	// substitute
			else
				_image=_normalImage;	// default image
			if(_c.state == NSMixedState && _mixedImage)
				_image=_mixedImage;
			else if(_alternateImage && stateOrHighlight(NSContentsCellMask))	// alternate content
				_image=_alternateImage;
		}
	if(!_image)
		return;	// no image defined
	// shouldn't this be imageRectForBounds?
	imageSize = [_image size];
	switch(_c.imagePosition) 
		{
		case NSImageOnly:			// draw image only - centered
		case NSImageOverlaps: 		// draw title over the centered image
			cellFrame.origin.x += (NSWidth(cellFrame) - imageSize.width)/2;
			cellFrame.origin.y += (NSHeight(cellFrame) - imageSize.height)/2;
			break;
		case NSImageLeft:					 			// draw image to the left of title
			cellFrame.origin.x += 4;
			cellFrame.origin.y += (NSHeight(cellFrame) - imageSize.height)/2;
			break;
		case NSImageRight:					 			// draw image to the right of the title
			cellFrame.origin.x += (NSWidth(cellFrame) - imageSize.width) - 4;
			cellFrame.origin.y += (NSHeight(cellFrame) - imageSize.height)/2;
			break;
		case NSImageBelow:								// draw image below the title
			cellFrame.origin.x += (NSWidth(cellFrame) - imageSize.width)/2;
			cellFrame.origin.y += 4;
			break;
		case NSImageAbove:						 		// draw image above the title
			cellFrame.origin.x += (NSWidth(cellFrame) - imageSize.width)/2;
			cellFrame.origin.y += (NSHeight(cellFrame) - imageSize.height) - 4;
			break;
		}
	if(stateOrHighlight(NSPushInCellMask))
		{ // makes button appear pushed in
		cellFrame.origin.x += 1;
		cellFrame.origin.y += 1;
		}
//	if([controlView isFlipped])
//		cellFrame.origin.y += imageSize.height;
#if 0
	NSLog(@"image %@ at %@", image, NSStringFromPoint(cellFrame.origin));
#endif
	// FIXME: handle imageDimsWhenDisabled
	// shouldn't we drawInRect: to scale properly?
	[_image compositeToPoint:cellFrame.origin operation:op];	
}

- (void) drawTitleWithFrame:(NSRect) cellFrame inView:(NSView *) controlView;
{
	NSString *title = _title;		// default title
	NSColor *titleColor = [NSColor controlTextColor];	// default
	NSRect textFrame;
	id savedContents;
	
	if(_transparent || _c.imagePosition == NSImageOnly)
		return;	// don't draw title
	if(stateOrHighlight(NSChangeGrayCellMask)) 
		{ // change text color by highlight
		titleColor=[NSColor selectedControlTextColor];
		}
	if([title length] == 0 || stateOrHighlight(NSContentsCellMask)) // standard content
		{ // change to alternate text/image (if defined)
		if([_alternateTitle length] != 0)
			title = _alternateTitle;
		}
	if(stateOrHighlight(NSPushInCellMask))
		{ // make button appear pushed in (move text down one pixel?)
		// might have to depend on bezel style
		}
	if(_c.bordered)
		{ // handle special Bezels
		switch(_bezelStyle)
			{ // special
			case NSHelpButtonBezelStyle:
				title=@"?";	// should enforce appropriate font
			case NSCircularBezelStyle:
				break;
			case NSRoundRectBezelStyle:
			case NSTexturedRoundBezelStyle:
			case NSRoundedBezelStyle:
				cellFrame=NSInsetRect(cellFrame, 10.0, 2.0+floor(cellFrame.size.height*0.1875));	// make smaller than enclosing frame
				break;
			default:
				break;
			}
		}

	// FIXME: do we really need to calculate this here?
	// or should we override imageRectForBounds, drawingRectForBounds, titleRectForBounds here and in NSCell?
	
	_d.verticallyCentered=YES;	// within its box
	textFrame=cellFrame;
	if(_image && !(_c.imagePosition == NSNoImage || _c.imagePosition == NSImageOverlaps))
		{ // adjust text field position for image
		NSSize imageSize=[_image size];
		switch(_c.imagePosition) 
			{												
			case NSImageLeft:					 			// draw image to the left of title
				textFrame.origin.x+=imageSize.width+8;
				textFrame.size.width-=imageSize.width+8;
				break;
			case NSImageRight:					 			// draw image to the right of the title
				textFrame.origin.x+=4;
				textFrame.size.width-=imageSize.width+8;
				break;
			case NSImageBelow:								// draw image below the title
				_c.alignment=NSCenterTextAlignment;
				textFrame.origin.y += imageSize.height+4;
				textFrame.size.height-=imageSize.height+8;
				break;
			case NSImageAbove:						 		// draw image above the title
				_c.alignment=NSCenterTextAlignment;
				_d.verticallyCentered=NO;
				textFrame.origin.y += 4;
				textFrame.size.height-=imageSize.height+8;
				break;
			default:
				break;
			}
		}
	savedContents=_contents;	// FIXME: do we really need to save? We don't use it otherwise
#if 0
	NSLog(@"ButtonCell draw: %@", title);
#endif
	ASSIGN(_textColor, titleColor);	// change color as needed
	/* NOTE:
		this code will also work if title is an AttributedString or if a NSFormatter is attached
		i.e. we can easily implement attributedTitle, attributedAlternateTitle etc.
		*/
	_contents=title;	// draw title by superclass
#if 0	// test to find out why NSEnabled is not working properly
	if(!_c.enabled)
		NSLog(@"button not enabled: %@", self);
#endif
	[super drawInteriorWithFrame:textFrame inView:controlView];
	_contents=savedContents;
}

- (void) drawWithFrame:(NSRect)cellFrame				// Draw cell's frame
				inView:(NSView*)controlView
{
	NSDebugLog(@"NSButtonCell drawWithFrame \n");	
	if(_transparent)
		return;	// don't draw
	if(NSWidth(cellFrame) <= 0.0 || NSHeight(cellFrame) <= 0.0)	// do nothing if cell's frame rect is zero
		return;	
	_controlView = controlView;						// Save as last view we have drawn to	
	if(_d.focusRingType != NSFocusRingTypeNone && [self showsFirstResponder])
		{ // button is first responder cell - draw focus ring
		BOOL isFlipped = [controlView isFlipped];
		NSColor *y = [NSColor selectedControlColor];
		NSColor *c[] = {y, y, y, y};
		NSRect cellRing=NSInsetRect(cellFrame, -1, -1);
		NSDrawColorTiledRects(cellRing, cellRing, isFlipped ? BEZEL_EDGES_FLIPPED : BEZEL_EDGES_NORMAL, c, 4);
		}
	[self drawBezelWithFrame:cellFrame inView:controlView];	
	[self drawInteriorWithFrame:cellFrame inView:controlView];
}

- (void) drawInteriorWithFrame:(NSRect) cellFrame inView:(NSView*) controlView
{
	[self drawImageWithFrame:cellFrame inView:controlView];	
	[self drawTitleWithFrame:cellFrame inView:controlView];	
}

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

	[aCoder encodeObject: _alternateTitle];
	[aCoder encodeObject: _alternateImage];
	[aCoder encodeObject: _normalImage];
	[aCoder encodeValueOfObjCType: @encode(BOOL) at: &_transparent];
}

- (id) initWithCoder:(NSCoder *) aDecoder
{
	self=[super initWithCoder:aDecoder];	// NSCell
	if([aDecoder allowsKeyedCoding])
		{
		unsigned int buttonflags=[aDecoder decodeIntForKey:@"NSButtonFlags"];
		unsigned int buttonflags2=[aDecoder decodeIntForKey:@"NSButtonFlags2"];
#if 0
		NSLog(@"%@ controlSize=%d", self, [self controlSize]);
#endif
#define PUSHIN ((buttonflags&0x80000000)!=0)
#define STATEBY ((buttonflags&0x70000000)>>28)
		_stateMask=STATEBY;	// set default
#define HIGHLIGHTSBY ((buttonflags&0x0e000000)>>25)
		_highlightMask=HIGHLIGHTSBY;
#define DRAWING ((buttonflags&0x01000000)!=0)
		// ignored
#define BORDERED ((buttonflags&0x00800000)!=0)
		_c.bordered |= BORDERED;	// combine with cell border (meaning isBezeled...)
#define OVERLAPS ((buttonflags&0x00400000)!=0)
#define IMAGEPOSITION (NSImageAbove-((buttonflags&0x00300000)>>20))
#define IMAGEANDTEXT ((buttonflags&0x00080000)!=0)
#define IMAGESIZEDIFF ((buttonflags&0x00040000)!=0)
#define KEYEQUIVNOIMAGE ((buttonflags&0x00020000)!=0)

		if(OVERLAPS)
			_c.imagePosition=IMAGEANDTEXT?NSImageOverlaps:NSImageOnly;
		else if(IMAGEANDTEXT)
			_c.imagePosition=IMAGEPOSITION;
		else
			_c.imagePosition=NSNoImage;

#define TRANSPARENT ((buttonflags&0x00008000)!=0)
		_transparent=TRANSPARENT;
#define INSET ((buttonflags&0x00006000)>>13)
#define DIMSWHENDISABLED ((buttonflags&0x00001000)==0)
		_dimsWhenDisabled=DIMSWHENDISABLED;
#define GRADIENTTYPE ((buttonflags&0x00000e00)>>9)
#define ALTERNATEMNEMONICLOC ((buttonflags&0x000000ff)>>0)	// 0xff=none

#define KEYEQUIVALENTMASK ((buttonflags2&0xffffff00)>>8)
		_keyEquivalentModifierMask = KEYEQUIVALENTMASK;	// if encoded by flags
#define BORDERWHILEMOUSEINSIDE ((buttonflags2&0x00000010)!=0)
#define BEZELSTYLE (((buttonflags2&0x00000007)>>0)+((buttonflags2&0x00000020)>>2))
		_bezelStyle=BEZELSTYLE;

		ASSIGN(_alternateTitle, [aDecoder decodeObjectForKey:@"NSAlternateContents"]);
		ASSIGN(_alternateImage, [aDecoder decodeObjectForKey:@"NSNormalImage"]);	// appears to be mixed up in IB archive
		ASSIGN(_normalImage, [aDecoder decodeObjectForKey:@"NSAlternateImage"]);
		if(_normalImage==nil || [_normalImage isKindOfClass:[NSFont class]])
			ASSIGN(_normalImage, _alternateImage), [_alternateImage release], _alternateImage=nil;	// bug in IB archiver
		ASSIGN(_title, [aDecoder decodeObjectForKey:@"NSContents"]);		// title string and not _contents
		ASSIGN(_keyEquivalent, [aDecoder decodeObjectForKey:@"NSKeyEquivalent"]);
		if([aDecoder containsValueForKey:@"NSKeyEquiv"])
			ASSIGN(_keyEquivalent, [aDecoder decodeObjectForKey:@"NSKeyEquiv"]);
		if([aDecoder containsValueForKey:@"NSKeyEquivModMask"])
			_keyEquivalentModifierMask = [aDecoder decodeIntForKey:@"NSKeyEquivModMask"];
		_periodicDelay = 0.001*[aDecoder decodeIntForKey:@"NSPeriodicDelay"];
		_periodicInterval = 0.001*[aDecoder decodeIntForKey:@"NSPeriodicInterval"];
#if 0
		NSLog(@"  title=%@", _title);
		NSLog(@"  normalImage=%@", _normalImage);
		NSLog(@"  alternateImage=%@", _alternateImage);
#endif
#if 0
			NSLog(@"%@ initWithCoder", self);
			NSLog(@"  NSMnemonicLoc=%d", [aDecoder decodeIntForKey:@"NSMnemonicLoc"]);
			// encodes the button type&style
			NSLog(@"  NSButtonFlags=%08x", [aDecoder decodeIntForKey:@"NSButtonFlags"]);
			NSLog(@"  NSButtonFlags2=%08x", [aDecoder decodeIntForKey:@"NSButtonFlags2"]);
			NSLog(@"  bezelstyle=%d", BEZELSTYLE);
			NSLog(@"  transparent=%d", TRANSPARENT);
			NSLog(@"  dimsWhenDisabled=%d", DIMSWHENDISABLED);
#endif
		return self;
		}
	_alternateTitle = [[aDecoder decodeObject] retain];
	_alternateImage = [[aDecoder decodeObject] retain];
	_normalImage = [[aDecoder decodeObject] retain];
	[aDecoder decodeValueOfObjCType: @encode(BOOL) at: &_transparent];
	
	return self;
}

@end

//*****************************************************************************
//
// 		NSButton 
//
//*****************************************************************************

@implementation NSButton

+ (void) initialize
{
	if (self == [NSButton class]) 
   		__buttonCellClass = [NSButtonCell class];
}

+ (Class) cellClass						{ return __buttonCellClass; }
+ (void) setCellClass:(Class)aClass		{ __buttonCellClass = aClass; }

- (id) initWithFrame:(NSRect)frameRect
{
	if((self=[super initWithFrame:frameRect]))	// installs a default cell
		{
		_v.autoresizingMask = (NSViewMaxXMargin | NSViewMaxYMargin);
		}
	return self;
}

- (void) getPeriodicDelay:(float*)delay interval:(float*)interval
{
	[_cell getPeriodicDelay:delay interval:interval];
}

- (void) setPeriodicDelay:(float)delay interval:(float)interval
{
	[_cell setPeriodicDelay:delay interval:interval];
}

- (void) setButtonType:(NSButtonType)aType
{
	[_cell setButtonType:aType];
	[self setNeedsDisplay:YES];
}

- (void) setState:(int)value			{ [_cell setState:value]; [self setNeedsDisplay:YES]; }
- (void) setNextState					{ [_cell setNextState]; [self setNeedsDisplay:YES]; }
- (void) setIntValue:(int)anInt			{ [_cell setIntValue:anInt]; }
- (void) setFloatValue:(float)aFloat	{ [_cell setFloatValue:aFloat]; }
- (void) setDoubleValue:(double)aDouble	{ [_cell setDoubleValue:aDouble]; }
- (void) setObjectValue:(NSString *)aString	{ [_cell setObjectValue:aString]; }
- (int) state							{ return [_cell state]; }
- (NSString*) alternateTitle			{ return [_cell alternateTitle]; }
- (NSString*) title						{ return [_cell title]; }
- (NSString*) keyEquivalent				{ return [_cell keyEquivalent]; }
- (NSImage*) image						{ return [_cell image]; }
- (NSImage*) alternateImage				{ return [_cell alternateImage]; }
- (NSCellImagePosition) imagePosition	{ return [_cell imagePosition]; }
- (BOOL) allowsMixedState				{ return [_cell allowsMixedState]; }
- (BOOL) isBordered						{ return [_cell isBordered]; }
- (BOOL) isTransparent					{ return [_cell isTransparent]; }
- (BOOL) isOpaque						{ return [_cell isOpaque]; }
- (NSBezelStyle) bezelStyle;			{ return [_cell bezelStyle]; }

- (void) setAlternateTitle:(NSString *)aString
{
	[_cell setAlternateTitle:aString];
	[self setNeedsDisplay:YES];
}

- (void) setTitle:(NSString *)aString
{
	[_cell setTitle:aString];
	[self setNeedsDisplay:YES];
}

- (void) setAlternateImage:(NSImage *)anImage
{
	[_cell setAlternateImage:anImage];
	[self setNeedsDisplay:YES];
}

- (void) setImage:(NSImage *)anImage
{
	[_cell setImage:anImage];
	[self setNeedsDisplay:YES];
}

- (void) setImagePosition:(NSCellImagePosition)aPosition
{
	[_cell setImagePosition:aPosition];
	[self setNeedsDisplay:YES];
}

- (void) setAllowsMixedState:(BOOL)flag
{
	[_cell setAllowsMixedState:flag];
	[self setNeedsDisplay:YES];
}

- (void) setBezelStyle:(NSBezelStyle) style;
{
	[_cell setBezelStyle:style];
	[self setNeedsDisplay:YES];
}

- (void) setBordered:(BOOL)flag
{
	[_cell setBordered:flag];	// has a different interpretation
	[self setNeedsDisplay:YES];
}

- (void) setTransparent:(BOOL)flag
{
	[_cell setTransparent:flag];
	[self setNeedsDisplay:YES];
}

- (void) highlight:(BOOL)flag
{
	[_cell highlight:flag withFrame:bounds inView:self];
}

- (void) setKeyEquivalent:(NSString*)aKeyEquivalent			// Key Equivalent
{
	[_cell setKeyEquivalent: aKeyEquivalent];
}

- (unsigned int) keyEquivalentModifierMask
{
	return [_cell keyEquivalentModifierMask];
}

- (void) setKeyEquivalentModifierMask:(unsigned int)mask
{
	[_cell setKeyEquivalentModifierMask: mask];
}

- (BOOL) acceptsFirstResponder
{														
	return [_cell acceptsFirstResponder] || ([self keyEquivalent] != nil);				
}														

- (BOOL) resignFirstResponder						// NSResponder overrides
{	
	if(_nextKeyView && [_cell showsFirstResponder])
		{
		[_cell setShowsFirstResponder:NO];
		[self setNeedsDisplay:YES];
		}
	return YES;
}

- (BOOL) becomeFirstResponder
{
	if(_nextKeyView && ![_cell showsFirstResponder])
		{
		[_cell setShowsFirstResponder:YES];
		[self setNeedsDisplay:YES];
		}
	return YES;
}

- (void) keyDown:(NSEvent*)event
{
	// CHECKME - is this reasonable behaviour?
	if(([self isEnabled] && [event keyCode] == ' '))	// Space
		[self performClick: self];
	else
		[super keyDown: event];
}

- (void) performClick:(id)sender							// Handle Events
{
#if 0
	NSLog(@"performClick %@", self);
#endif
	[self lockFocus];
	[_cell performClick: sender];
	[self unlockFocus];
}

- (BOOL) performKeyEquivalent:(NSEvent *)anEvent
{
	if([self isEnabled])
		{
		NSString *key = [self keyEquivalent];
		unsigned int modifiers=[anEvent modifierFlags] & (NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask | NSShiftKeyMask);

		if([anEvent modifierFlags] == modifiers && [key isEqualToString: [anEvent charactersIgnoringModifiers]])
			{
#if 0
			NSLog(@"%@ performKeyEquivalent -> YES", self);
#endif	
			[self performClick:self];
			return YES;
			}
		}
#if 0
	NSLog(@"%@ performKeyEquivalent -> NO", self);
#endif	
	return NO;
}

- (void) encodeWithCoder:(NSCoder *) aCoder		{ [super encodeWithCoder:aCoder]; }
- (id) initWithCoder:(NSCoder *) aDecdr			{ return [super initWithCoder:aDecdr];}

@end /* NSButton */
