/* MiscTabButtonCell.m created by stephane on Sun 15-Dec-1996 */

//
//	MiscTabButtonCell.m --
//		Written by Stephane Corthesy Copyright 1997 by Stephane Corthesy.
//				Version 1.1.  All rights reserved.
//		Based upon MiscTabActionCell 1.5 by Sean Hill, 1995
//
//		This notice may not be removed from this source code.
//
//	This object is included in the MiscKit by permission from the author
//	and its use is governed by the MiscKit license, found in the file
//	"License.rtf" in the MiscKit distribution.  Please refer to that file
//	for a list of all applicable permissions and restrictions.
//	

#ifdef MISCKIT
#import <misckit/MiscTabButtonCell.h>
#import <misckit/MiscDrawTab.h>
#else
#import "MiscTabButtonCell.h"
#import "MiscDrawTab.h"
#endif

#define CURRENT_VERSION		1

#define TAB_ASPECT_RATIO	(14.0 / 17.0)
//Defines the ratio tabBezierImageWidth/tabBezierImageHeight

@interface MiscTabButtonCell(Private)
- (NSRect) _outerRectForCellFrame:(NSRect)aFrame;
- (NSRect) _innerRectForCellFrame:(NSRect)aFrame;
- (void) _finishInitializing;
@end

static float	lightBorderColor;
static float	darkBorderColor;
static float	selectedFillColor;
static float	unselectedFillColor;

@implementation MiscTabButtonCell

+ (void) initialize
{
    [super initialize];
    if(self == [MiscTabButtonCell class])
        [self setVersion:CURRENT_VERSION];
#ifndef STRICT_OPENSTEP
   	lightBorderColor = [[[NSColor controlLightHighlightColor] colorUsingColorSpaceName:NSDeviceWhiteColorSpace] whiteComponent];
   	darkBorderColor = [[[NSColor controlDarkShadowColor] colorUsingColorSpaceName:NSDeviceWhiteColorSpace] whiteComponent];
    selectedFillColor = [[[NSColor controlColor] colorUsingColorSpaceName:NSDeviceWhiteColorSpace] whiteComponent];
#ifdef WIN32
   	unselectedFillColor = 0.5;//Because gridColor is nearly the same as controlColor!
#else    
    unselectedFillColor = [[[NSColor gridColor] colorUsingColorSpaceName:NSDeviceWhiteColorSpace] whiteComponent];
#endif WIN32
#else
    lightBorderColor = NSWhite;
    darkBorderColor = NSBlack;
    selectedFillColor = NSLightGray;
    if([NSWindow defaultDepthLimit] <= NSBestDepth(NSCalibratedWhiteColorSpace, 2, 2, YES, NULL))
        unselectedFillColor = NSDarkGray;
    else
        unselectedFillColor = 0.5;
#endif STRICT_OPENSTEP
}

- (NSRect) _outerRectForCellFrame:(NSRect)cellFrame
// Returns the rectangle envelopping the whole tab, i.e. including overlapping parts
{
    int		row, col;
    int		lastColumn = [(NSMatrix *)[self controlView] numberOfColumns] - 1;
    float	tabBezierImageWidth = NSHeight(cellFrame) * TAB_ASPECT_RATIO;

    (void) [(NSMatrix *)[self controlView] getRow:&row column:&col ofCell:self];

    if(col == 0){
        if(col != lastColumn)
            cellFrame.size.width += tabBezierImageWidth / 2.0;
        return cellFrame;
    }
    else if(col == lastColumn)
        return NSInsetRect(NSOffsetRect(cellFrame, - tabBezierImageWidth / 4.0, 0.0), - tabBezierImageWidth / 4.0, 0.0);
    else
        return NSInsetRect(cellFrame, - tabBezierImageWidth / 2.0, 0.0);
}

- (NSRect) _innerRectForCellFrame:(NSRect)cellFrame
// Returns the rectangle between the two tab ends; it has the same height as the tabs
{
    int		row, col;
    int		lastColumn = [(NSMatrix *)[self controlView] numberOfColumns] - 1;
    NSRect	innerRect = cellFrame;
    float	tabBezierImageWidth = NSHeight(cellFrame) * TAB_ASPECT_RATIO;

    (void) [(NSMatrix *)[self controlView] getRow:&row column:&col ofCell:self];

    if(col == 0)
        if(col == lastColumn)
            innerRect = NSInsetRect(innerRect, tabBezierImageWidth, 0.0);
        else
            innerRect = NSInsetRect(NSOffsetRect(innerRect, tabBezierImageWidth / 4.0, 0.0), (3.0 * tabBezierImageWidth) / 4.0, 0.0);
    else
        if(col == lastColumn)
            innerRect = NSInsetRect(NSOffsetRect(innerRect, - tabBezierImageWidth / 4.0, 0.0), (3.0 * tabBezierImageWidth) / 4.0, 0.0);
    	else
            innerRect = NSInsetRect(innerRect, tabBezierImageWidth / 2.0, 0.0);

	return innerRect;
}

- (void) _finishInitializing
{
    [self setButtonType:NSMomentaryPushButton];
    [self setBordered:NO];
    [self setBezeled:NO];
    [self setHighlightsBy:NSNoCellMask];
// So we can overload super's method -drawInteriorWithFrame:inView:
#ifndef STRICT_OPENSTEP
    [self setImageDimsWhenDisabled:YES];
#endif
}

- (id) init
{
    self = [super init];
    [self _finishInitializing];
    return self;
}

- (id) initTextCell:(NSString *)aString
{
    self = [super initTextCell:aString];
    [self _finishInitializing];
    return self;
}

- (id) initImageCell:(NSImage *)anImage
{
    self = [super initImageCell:anImage];
    [self _finishInitializing];
    return self;
}

- (id) initWithCoder:(NSCoder *)coder
{
    int	version = [coder versionForClassName:NSStringFromClass([MiscTabButtonCell class])];

    self = [super initWithCoder:coder];
    switch(version){
        case 0:
            _tbcFlags.orientation = MiscTopTab;
            _tbcFlags.doNotRotateText = NO;
            _tbcFlags.doNotRotateImage = NO;
            break;
        default:
            [coder decodeValueOfObjCType:@encode(unsigned int) at:&_tbcFlags];
    }
    [self _finishInitializing];
    return self;
}

- (void) encodeWithCoder:(NSCoder *)coder
{
	[super encodeWithCoder:coder];
    [coder encodeValueOfObjCType:@encode(unsigned int) at:&_tbcFlags];
}

- (void) drawInteriorWithFrame:(NSRect)cellFrame inView:controlView
{
    int					row, col, lastRow, lastCol;
    NSRect				innerRect, outerRect, contentRect;
    float				tabBezierImageWidth;
    int					intTabBezierImageWidth;
    MiscTabButtonCell	*neighbourCell;
    BOOL				isSelected;

    if(![controlView isKindOfClass:[NSMatrix class]]){
        [super drawInteriorWithFrame:cellFrame inView:controlView];	
        return;
    }

    lastRow = [controlView numberOfRows] - 1;
    lastCol = [controlView numberOfColumns] - 1;
    (void) [controlView getRow:&row column:&col ofCell:self];
    isSelected = [[controlView selectedCell] isEqual:self];

    innerRect = [self _innerRectForCellFrame:cellFrame];
    contentRect = NSInsetRect(innerRect, 0.0, 1.0);//because of the top and bottom lines
    tabBezierImageWidth = NSHeight(innerRect) * TAB_ASPECT_RATIO;
    intTabBezierImageWidth = (int) (tabBezierImageWidth);
    outerRect = [self _outerRectForCellFrame:cellFrame];

    if(row == 0){
        if([controlView drawsBackground]){
            [[controlView backgroundColor] set];
			NSRectFill(cellFrame);
        }
    }
    else{
        PSsetgray(unselectedFillColor);
		NSRectFill(cellFrame);
    }

    if(isSelected)
		PSsetgray(selectedFillColor);
	else
        PSsetgray(unselectedFillColor);
    NSRectFill(NSInsetRect(innerRect, -1.0, 0.0));
	//Because of some problems with float->int rounding, we need to use NSInsetRect()
    
    [super drawInteriorWithFrame:contentRect inView:controlView];

    if(isSelected){
        //If there is a neighbour cell to the left, draw its right part
        if(col != 0)
            if(neighbourCell = [controlView cellAtRow:row column:col - 1]){
                NSRect	aRect = [neighbourCell _innerRectForCellFrame:[controlView cellFrameAtRow:row column:col - 1]];

                Misc_drawRightTabBezier((int) NSMaxX(aRect), (int) NSMaxY(aRect), intTabBezierImageWidth, (int) NSHeight(aRect), darkBorderColor, unselectedFillColor);//Unselected cell to the left
			}
        
        //Draw my left overlapping selected part
        Misc_drawLeftTabBezier((int) NSMinX(outerRect) -1.0, (int) NSMaxY(outerRect), intTabBezierImageWidth + 1, (int) NSHeight(innerRect), lightBorderColor, selectedFillColor);
        
        if(col != lastCol){
			//If there is a neighbour to the right, draw its left part
            if(neighbourCell = [controlView cellAtRow:row column:col + 1]){
                NSRect	aRect = [neighbourCell _outerRectForCellFrame:[controlView cellFrameAtRow:row column:col + 1]];

                Misc_drawLeftTabBezier((int) NSMinX(aRect), (int) NSMaxY(aRect), intTabBezierImageWidth, (int) NSHeight(aRect), lightBorderColor, unselectedFillColor);//Unselected cell to the right
			}
            
            //Draw my right overlapping selected part
            Misc_drawRightTabBezier((int) NSMaxX(innerRect), (int) NSMaxY(outerRect), intTabBezierImageWidth, (int) NSHeight(innerRect), darkBorderColor, selectedFillColor);
        }
        else{
            //Draw my right selected part
            Misc_drawRightTabBezier((int) NSMaxX(innerRect), (int) NSMaxY(outerRect), intTabBezierImageWidth, (int) NSHeight(innerRect), darkBorderColor, selectedFillColor);
        }
    }
	else{//I'm not selected
		NSRect	bottomLineRect = NSInsetRect(outerRect, -1.0, 0.0);
//Because of some problems with float->int rounding, we need to use NSInsetRect()

        bottomLineRect.origin.y += NSHeight(bottomLineRect) - 1.0;
        bottomLineRect.size.height = 1.0;

        Misc_drawLeftTabBezier((int) NSMinX(outerRect), (int) NSMaxY(outerRect), intTabBezierImageWidth, (int) NSHeight(innerRect), lightBorderColor, unselectedFillColor);
        
        if(col != 0){
            NSRect	aRect;
            
            neighbourCell = [controlView cellAtRow:row column:col - 1];
           	aRect = [neighbourCell _innerRectForCellFrame:[controlView cellFrameAtRow:row column:col - 1]];

            if([[controlView selectedCell] isEqual:neighbourCell] || (col == 1 && [controlView selectedRow] != row)){
                bottomLineRect.size.width -= tabBezierImageWidth;

                bottomLineRect.origin.x += tabBezierImageWidth - 1.0;
                bottomLineRect.size.width += 1.0;
                //Because of some problems with float->int rounding, we need to enlarge it a bit
            }    

            if([[controlView selectedCell] isEqual:neighbourCell]){
                Misc_drawRightTabBezier((int) NSMaxX(aRect), (int) NSMaxY(aRect), intTabBezierImageWidth, (int) NSHeight(aRect), darkBorderColor, selectedFillColor);//Previous cell
            }
            else{
                Misc_drawRightTabBezier((int) NSMaxX(aRect), (int) NSMaxY(aRect), intTabBezierImageWidth, (int) NSHeight(aRect), darkBorderColor, unselectedFillColor);//Previous cell
            }
		}
        
        if(col != lastCol){
            //If next cell is not selected, draw its left part, than my right part.
            //Else  draw only my right part
            if(![[controlView selectedCell] isEqual:(neighbourCell = [controlView cellAtRow:row column:col + 1])]){
                NSRect	aRect = [neighbourCell _outerRectForCellFrame:[controlView cellFrameAtRow:row column:col + 1]];

                Misc_drawLeftTabBezier((int) NSMinX(aRect), (int) NSMaxY(aRect), intTabBezierImageWidth, (int) NSHeight(aRect), lightBorderColor, unselectedFillColor);//Next cell
                Misc_drawRightTabBezier((int) NSMaxX(innerRect), (int) NSMaxY(outerRect), intTabBezierImageWidth, (int) NSHeight(innerRect), darkBorderColor, unselectedFillColor);
            }
            else{
                NSRect	aRect = [neighbourCell _outerRectForCellFrame:[controlView cellFrameAtRow:row column:col + 1]];

                Misc_drawRightTabBezier((int) NSMaxX(innerRect), (int) NSMaxY(outerRect), intTabBezierImageWidth, (int) NSHeight(innerRect), darkBorderColor, unselectedFillColor);

                Misc_drawLeftTabBezier((int) NSMinX(aRect) -1.0, (int) NSMaxY(aRect), intTabBezierImageWidth + 1, (int) NSHeight(aRect), lightBorderColor, selectedFillColor);//Next cell
                bottomLineRect.size.width -= tabBezierImageWidth;

                bottomLineRect.size.width += 1.0;
                //Because of some problems with float->int rounding, we need to enlarge it a bit
           	}        
        }
        else//I'm last on the row
            Misc_drawRightTabBezier((int) NSMaxX(innerRect), (int) NSMaxY(outerRect), intTabBezierImageWidth, (int) NSHeight(innerRect), darkBorderColor, unselectedFillColor);

        if(col == 0 && [controlView selectedRow] != row)
            PSsetgray(unselectedFillColor);
        else
            PSsetgray(lightBorderColor);
        if(col != 0 || [controlView selectedRow] == row)
            NSFrameRect(bottomLineRect);
    }

    //Draw top line
    innerRect.size.height = 1.0;
    innerRect = NSInsetRect(innerRect, -1.0, 0.0);
    //Because of some problems with float->int rounding, we need to use NSInsetRect()
    PSsetgray(lightBorderColor);
    NSFrameRect(innerRect);
}

- (BOOL) trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag
{
    BOOL	boolValue = [super trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:controlView untilMouseUp:(BOOL)flag];

    [controlView display];
    if([theEvent type] == NSLeftMouseUp)
        [self setState:![self state]];

    return boolValue;
}

- (BOOL) startTrackingAt:(NSPoint)startPoint inView:aView
{
    (void)[super startTrackingAt:startPoint inView:aView];

    [aView sendAction];
    return NO;
}

- (BOOL) isOpaque
{
	return YES;
}

- (NSSize) cellSizeForBounds:(NSRect)aRect
{
    NSSize	aSize = [super cellSizeForBounds:aRect];
    int		row, col;
    int		lastColumn = [(NSMatrix *)[self controlView] numberOfColumns] - 1;
    float	tabBezierImageWidth;

	aSize.height += 4.0;
    tabBezierImageWidth = aSize.height * TAB_ASPECT_RATIO;

    (void) [(NSMatrix *)[self controlView] getRow:&row column:&col ofCell:self];
	if(col == 0)
        if(col == lastColumn)
            aSize.width += 2 * tabBezierImageWidth;
        else
            aSize.width += 1.5 * tabBezierImageWidth;
    else
        if(col == lastColumn)
            aSize.width += 1.5 * tabBezierImageWidth;
        else
            aSize.width += tabBezierImageWidth;
    return aSize;
}

- (void) setOrientation:(MiscTabButtonCellOrientation)orientation
{
    _tbcFlags.orientation = orientation;
}

- (MiscTabButtonCellOrientation) orientation
{
    return _tbcFlags.orientation;
}

- (void) setRotateImage:(BOOL)doRotateImage
{
    _tbcFlags.doNotRotateImage = !doRotateImage;
}

- (BOOL) doesRotateImage
{
    return !_tbcFlags.doNotRotateImage;
}

- (void) setRotateText:(BOOL)doRotateText
{
    _tbcFlags.doNotRotateText = !doRotateText;
}

- (BOOL) doesRotateText
{
    return !_tbcFlags.doNotRotateText;
}

@end
