//=============================================================================
//
//		Copyright (C) 1995,1996 by Paul S. McCarthy and Eric Sunshine.
//				Written by Paul S. McCarthy and Eric Sunshine.
//							All Rights Reserved.
//
//		This notice may not be removed from this source code.
//
//		This object is included in the MiscKit by permission from the authors
//		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.
//		
//=============================================================================
//-----------------------------------------------------------------------------
// MiscTableScrollInspector.M
//
//		Interface Builder inspector for MiscTableScroll.
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// $Id: MiscTableScrollInspector.M,v 1.10 96/08/30 15:22:43 sunshine Exp $
// $Log:		MiscTableScrollInspector.M,v $
//	Revision 1.10  96/08/30	 15:22:43  sunshine
//	Fixed bugs where setting min/max/current slot sizes would crash IB.
//	
//	Revision 1.9  96/05/02	18:12:22  zarnuk
//	Now performs a revert after toggling lazy-mode to recognize the fact
//	that the rows get deleted when toggling from non-lazy to lazy.
//	
//	Revision 1.8  96/04/20	01:29:13  zarnuk
//	Fixed bug where toggling titles on/off was not enabling/disabling
//	slot controls properly.
//-----------------------------------------------------------------------------
#import "MiscTableScrollInspector.h"
#import "MiscTableBorder.h"
#import <misckit/MiscTableScroll.h>

//=============================================================================
// IB-ONLY METHODS FOR MiscTableScroll
//=============================================================================

@interface MiscTableScroll(IB)
- (char const*)getInspectorClassName;
- editSelf:sender in:owner;
@end

@implementation MiscTableScroll(IB)
- (char const*) getInspectorClassName
	{ return "MiscTableScrollInspector"; }
// Prevent IB from allowing double-click to edit Scroll View
- editSelf:sender in:owner
	{ return 0; }
@end

//=============================================================================
// CONVENIENCE CATAGORIES
//=============================================================================
@interface Button(MiscPopUpList)
- (int) popUpTag;
- (void) setPopUpTag: (int) new_tag;
@end

@interface Matrix(MiscPopUpList)
- (int) popUpTag;
@end

@implementation Button(MiscPopUpList)

- (int) popUpTag
	{
	id popUp = [self target];
	return [[[popUp itemList] selectedCell] tag];
	}

- (void) setPopUpTag: (int) new_tag
	{
	id popUp = [self target];
	Matrix* matrix = [popUp itemList];
	MenuCell* m_cell = [matrix findCellWithTag: new_tag];
	[matrix selectCell: m_cell];
	[self setTitle: [m_cell title]];
	}

@end

@implementation Matrix(MiscPopUpList)

- (int) popUpTag
	{
	return [[self selectedCell] tag];
	}

@end


//=============================================================================
// IMPLEMENTATION
//=============================================================================
@interface MiscTableScrollInspector(Forward)
- doSlot:sender;
- doTitleMode:sender;
@end

@implementation MiscTableScrollInspector

//-----------------------------------------------------------------------------
// init
//-----------------------------------------------------------------------------
- init
	{
	[super init];
	char buf[ MAXPATHLEN + 1 ];
	id bundle = [NXBundle bundleForClass: [MiscTableScrollInspector class]];
	[bundle getPath: buf forResource: [[self class] name] ofType: "nib"];
	[NXApp loadNibFile: buf owner: self withNames: NO fromZone: [self zone]];
	border_type = MISC_COL_BORDER;
	dirty = NO;
	return self;
	}


//-----------------------------------------------------------------------------
// wantsButtons
//-----------------------------------------------------------------------------
- (BOOL) wantsButtons
	{
	return NO;
	}


//-----------------------------------------------------------------------------
// setTitleControls
//-----------------------------------------------------------------------------
- (void) setTitleControls
	{
	if ([object borderTitlesOn:border_type])
		{
		BOOL sizable = border->isSizeable();
		[titlesSwitch setState:1];
		[[sizableSwitch setEnabled: YES] setState:sizable];
		[[draggableSwitch setEnabled:YES] setState:border->isDraggable()];
		[[titleModePopUp setEnabled:YES]
				setPopUpTag:(int)[object borderTitleMode:border_type]];
		[uniformSizeField setEnabled:!sizable];
		if (sizable)
			[uniformSizeField setStringValueNoCopy:""];
		else
			[uniformSizeField setIntValue:
								int([object uniformSizeSlots:border_type])];
		}
	else
		{
		[titlesSwitch setState:0];
		[[sizableSwitch setEnabled:NO] setState:0];
		[[draggableSwitch setEnabled:NO] setState:0];
		[[titleModePopUp setEnabled:NO]
				setPopUpTag:(int)[object borderTitleMode:border_type]];
		[[uniformSizeField setEnabled: YES]
				setIntValue: int([object uniformSizeSlots:border_type])];
		}
	}


//-----------------------------------------------------------------------------
// fillScroll
//-----------------------------------------------------------------------------
- (void) fillScroll
	{
	[window disableFlushWindow];
	num_slots = [object numSlots:border_type];
	if (num_slots == 0)
		{
		[slotScroll clearSelectedCell];
		[slotScroll renewRows:0 cols:0]; // Gets rid of horiz scroller knob
		}
	else
		{
		[slotScroll renewRows:num_slots cols:1];
		for (int i = 0;	 i < num_slots;	 i++)
			{
			int const pslot = [object border:border_type slotAtPosition:i];
			[[slotScroll cellAt:i:0] setTitle: [object border:border_type
						slotTitle:pslot]];
			}
		}
	[slotScroll sizeToCells];
	[slotScroll display];

	if (num_slots > 0)
		{
		if (slot < 0) slot = 0;
		[slotScroll selectCellAt:slot:0];
		[slotScroll scrollCellToVisible:slot:0];
		}
	else
		{
		slot = -1;
		}
	[self doSlot:self];
	[[window reenableFlushWindow] flushWindow];
	}


//-----------------------------------------------------------------------------
// setConstrainSwitches
//-----------------------------------------------------------------------------
- (void) setConstrainSwitches
	{
	[constrainMaxSwitch setState:
				[object maxTotalSizeIsConstrained:border_type]];
	[constrainMinSwitch setState:
				[object minTotalSizeIsConstrained:border_type]];
	}



//-----------------------------------------------------------------------------
// doConstrainMax:
//-----------------------------------------------------------------------------
- doConstrainMax:sender
	{
	[object border:border_type
				constrainMaxTotalSize:[constrainMaxSwitch state]];
	return [self ok:sender];
	}



//-----------------------------------------------------------------------------
// doConstrainMin:
//-----------------------------------------------------------------------------
- doConstrainMin:sender
	{
	[object border:border_type
				constrainMinTotalSize:[constrainMinSwitch state]];
	return [self ok:sender];
	}



//-----------------------------------------------------------------------------
// doEnabled:
//-----------------------------------------------------------------------------
- doEnabled: sender
	{
	[object setEnabled: [enabledSwitch state]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doLazy:
//-----------------------------------------------------------------------------
- doLazy: sender
	{
	[object setLazy: [lazySwitch state]];
	[self ok:sender];
	[self revert:self];
	return self;
	}


//-----------------------------------------------------------------------------
// doMode:
//-----------------------------------------------------------------------------
- doMode: sender
	{
	[object setSelectionMode: MiscSelectionMode([modePopUp popUpTag])];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doBorder:
//-----------------------------------------------------------------------------
- doBorder:sender
	{
	MiscBorderType bt = MiscBorderType([borderPopUp popUpTag]);
	if (bt != border_type)
		{
		border_type = bt;
		[self revert:sender];
		}
	return self;
	}


//-----------------------------------------------------------------------------
// doTitles:
//-----------------------------------------------------------------------------
- doTitles: sender
	{
	BOOL const isOn = [titlesSwitch state];
	[object border:border_type setTitlesOn:isOn];
	[self setTitleControls];
	[self doSlot:self];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doSizable:
//-----------------------------------------------------------------------------
- doSizable: sender
	{
	BOOL const val = [sizableSwitch state];
	[object border:border_type setSizeableSlots:val];
	if (val)
		{
		[[uniformSizeField setStringValue:""] setEnabled:NO];
		[object border:border_type setUniformSizeSlots:0];
		}
	else
		{
		[[uniformSizeField setEnabled: YES]
				setIntValue: int([object uniformSizeSlots:border_type])];
		}
	[self doSlot:0];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doDraggable:
//-----------------------------------------------------------------------------
- doDraggable: sender
	{
	[object border:border_type setDraggableSlots:[draggableSwitch state]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doAutoSort:
//-----------------------------------------------------------------------------
- doAutoSort: sender
	{
	[object border:border_type setAutoSortSlots:[autoSortSwitch state]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doTitleMode:
//-----------------------------------------------------------------------------
- doTitleMode:sender
	{
	[object border:border_type
		setTitleMode: (MiscTableTitleMode) [titleModePopUp popUpTag]];
	[self fillScroll];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doDelete:
//-----------------------------------------------------------------------------
- doDelete: sender
	{
	[object border:border_type
				deleteSlotAt:[object border:border_type slotAtPosition:slot]];
	[object tile];
	[object display];
	slot--;
	num_slots--;
	if (slot < 0 && num_slots > 0)
		slot = 0;
	[self fillScroll];
	[self ok:sender];
	return self;
	}


//-----------------------------------------------------------------------------
// doNew:
//-----------------------------------------------------------------------------
- doNew: sender
	{
	[object addSlot:border_type];
	[object tile];
	[object display];
	slot = num_slots;
	[self fillScroll];
	[self ok:sender];
	return self;
	}


//-----------------------------------------------------------------------------
// doUserSizeable:
//-----------------------------------------------------------------------------
- doUserSizeable: sender
	{
	[object border:border_type
				setSlot:[object border:border_type slotAtPosition:slot]
				sizeable:[userSizeableSwitch state]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doExpandToData:
//-----------------------------------------------------------------------------
- doExpandToData: sender
	{
	[object border:border_type
				setSlot:[object border:border_type slotAtPosition:slot]
				expandsToData:[expandToDataSwitch state]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doAutosize:
//-----------------------------------------------------------------------------
- doAutosize: sender
	{
	[object border:border_type
				setSlot:[object border:border_type slotAtPosition:slot]
				autosize:[autosizeSwitch state]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doCellClass:
//-----------------------------------------------------------------------------
- doCellClass: sender
	{
	[object border:border_type
		setSlot:[object border:border_type slotAtPosition:slot]
		cellType: (MiscTableCellStyle) [cellClassPopUp popUpTag]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doSortType:
//-----------------------------------------------------------------------------
- doSortType: sender
	{
	[object border:border_type
		setSlot:[object border:border_type slotAtPosition:slot]
		sortType: (MiscSortType) [sortTypePopUp popUpTag]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doSortDirection:
//-----------------------------------------------------------------------------
- doSortDirection: sender
	{
	[object border:border_type
		setSlot:[object border:border_type slotAtPosition:slot]
		sortDirection: (MiscSortDirection) [sortDirectionPopUp popUpTag]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doSlot:
//-----------------------------------------------------------------------------
- doSlot: sender
	{
	slot = [slotScroll selectedRow];
	if (slot >= 0)
		{
		BOOL const titlesOn = [object borderTitlesOn:border_type];
		BOOL const notUniform = ([object uniformSizeSlots:border_type] == 0);
		int pslot = [object border:border_type slotAtPosition:slot];
		[deleteButton setEnabled:YES];
		[upButton setEnabled:(slot > 0)];
		[downButton setEnabled:(slot < num_slots - 1)];
		[[cellClassPopUp setEnabled:YES]
				setPopUpTag:(int)
						[object border:border_type slotCellType:pslot]];
		[[sortTypePopUp setEnabled:YES]
				setPopUpTag:(int)
						[object border:border_type slotSortType:pslot]];
		[[sortDirectionPopUp setEnabled:YES]
				setPopUpTag:(int)
						[object border:border_type slotSortDirection:pslot]];
		[[autosizeSwitch setEnabled:notUniform]
				setState:[object border:border_type slotIsAutosize:pslot]];
		[[expandToDataSwitch setEnabled:notUniform]
				setState:[object border:border_type slotExpandsToData:pslot]];
		BOOL const enabled = titlesOn && notUniform &&
								[object sizeableSlots:border_type];
		[[userSizeableSwitch setEnabled: enabled]
				setState: enabled &&
						[object border:border_type slotIsSizeable:pslot]];
		[[sizeField setEnabled:notUniform]
				setIntValue: (int)
						[object border:border_type slotSize:pslot]];
		[[sizeMinField setEnabled:notUniform]
				setIntValue: (int)
						[object border:border_type slotMinSize:pslot]];
		[[sizeMaxField setEnabled:notUniform]
				setIntValue: (int)
						[object border:border_type slotMaxSize:pslot]];
		[[titleField setEnabled: titlesOn &&
				([object borderTitleMode:border_type] == MISC_CUSTOM_TITLE)]
				setStringValue: [object border:border_type slotTitle:pslot]];
		[titleField selectText: self];
		}
	else
		{
		[deleteButton setEnabled:NO];
		[upButton setEnabled:NO];
		[downButton setEnabled:NO];
		[[cellClassPopUp setEnabled:NO] setPopUpTag:0];
		[[sortTypePopUp setEnabled:NO] setPopUpTag:0];
		[[sortDirectionPopUp setEnabled:NO] setPopUpTag:0];
		[[autosizeSwitch setEnabled:NO] setState:0];
		[[expandToDataSwitch setEnabled:NO] setState:0];
		[[userSizeableSwitch setEnabled:NO] setState:0];
		[[sizeField setEnabled:NO] setStringValue:""];
		[[sizeMinField setEnabled:NO] setStringValue:""];
		[[sizeMaxField setEnabled:NO] setStringValue:""];
		[[titleField setEnabled:NO] setStringValue:""];
		}
	return self;
	}


//-----------------------------------------------------------------------------
// doUp:
//-----------------------------------------------------------------------------
- doUp: sender
	{
	if (slot > 0)
		{
		[object border:border_type moveSlotFrom:slot to:slot-1];
		border->clearVMap();
		slot--;
		[self fillScroll];
		[self ok:sender];
		}
	return self;
	}


//-----------------------------------------------------------------------------
// doDown:
//-----------------------------------------------------------------------------
- doDown: sender
	{
	if (slot < num_slots - 1)
		{
		[object border:border_type moveSlotFrom:slot to:slot+1];
		border->clearVMap();
		slot++;
		[self fillScroll];
		[self ok:sender];
		}
	return self;
	}


//-----------------------------------------------------------------------------
// get_pslot
//		Get the physical slot-id of the current slot.
//-----------------------------------------------------------------------------
- (int) get_pslot
	{
	return [object border:border_type slotAtPosition:slot];
	}


//-----------------------------------------------------------------------------
// textDidChange:
//-----------------------------------------------------------------------------
- textDidChange:sender
	{
	dirty = YES;
	return [super textDidChange:sender];
	}


//-----------------------------------------------------------------------------
// textDidEnd:endChar:
//-----------------------------------------------------------------------------
- textDidEnd: sender endChar: (unsigned short) whyEnd
	{
	if (dirty)
		{
		dirty = NO;
		id field = 0;
		if ([sender respondsTo:@selector(delegate)])
			field = [sender delegate];
		if (field == (id)titleField)
			{
			int const pslot = [self get_pslot];
			[object border:border_type setSlot:pslot
											title:[titleField stringValue]];
			[[slotScroll cellAt:slot:0] setTitle:[titleField stringValue]];
			[slotScroll drawCellAt:slot:0];
			}
		else if (field == (id)uniformSizeField)
			{
			int old_size = (int) [object uniformSizeSlots:border_type];
			int new_size = [uniformSizeField intValue];
			if (new_size != 0)
				{
				if (new_size < MISC_MIN_PIXELS_SIZE)
					new_size = MISC_MIN_PIXELS_SIZE;
				if (new_size > MISC_MAX_PIXELS_SIZE)
					new_size = MISC_MAX_PIXELS_SIZE;
				[uniformSizeField setIntValue:new_size];
				}
			if (old_size != new_size)
				{
				[object border:border_type
						setUniformSizeSlots:(NXCoord)new_size];
				[self ok:sender];
				[self revert:0];
				}
			}
		else if (field == (id)sizeField)
			{
			int const pslot = [self get_pslot];
			int i = [sizeField intValue];
			int const imin = (int)[object border:border_type slotMinSize:pslot];
			int const imax = (int)[object border:border_type slotMaxSize:pslot];

			if (i < imin || i > imax)
				{
				if (i < imin) i = imin;
				if (i > imax) i = imax;
				[sizeField setIntValue:i];
				}
			[object border:border_type setSlot:pslot size:(NXCoord)i];
			}
		else if (field == (id)sizeMinField)
			{
			int const pslot = [self get_pslot];
			int const i = (int)[object border:border_type slotSize:pslot];
			int imin = [sizeMinField intValue];
			int const imax = (int)[object border:border_type slotMaxSize:pslot];

			if (imin < MISC_MIN_PIXELS_SIZE)
				imin = MISC_MIN_PIXELS_SIZE;
			else if (imin > imax)
				imin = imax;
			if (imin > i)		// Not an 'else if'
				imin = i;

			[sizeMinField setIntValue:imin];
			[object border:border_type setSlot:pslot minSize:(NXCoord)imin];
			}
		else if (field == (id)sizeMaxField)
			{
			int const pslot = [self get_pslot];
			int const i = (int)[object border:border_type slotSize:pslot];
			int const imin = (int)[object border:border_type slotMinSize:pslot];
			int imax = [sizeMaxField intValue];

			if (imax > MISC_MAX_PIXELS_SIZE)
				imax = MISC_MAX_PIXELS_SIZE;
			else if (imax < imin)
				imax = imin;
			if (imax < i)		// Not an 'else if'
				imax = i;

			[sizeMaxField setIntValue:imax];
			[object border:border_type setSlot:pslot maxSize:(NXCoord)imax];
			}
		[self ok: sender];
		}
	return self;
	}


//-----------------------------------------------------------------------------
// doColorText
//-----------------------------------------------------------------------------
- doColorText: sender
	{
	[object setTextColor: [sender color]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doColorBack
//-----------------------------------------------------------------------------
- doColorBack: sender
	{
	[object setBackgroundColor: [sender color]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doColorTextH
//-----------------------------------------------------------------------------
- doColorTextH: sender
	{
	[object setHighlightTextColor: [sender color]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// doColorBackH
//-----------------------------------------------------------------------------
- doColorBackH: sender
	{
	[object setHighlightBackgroundColor: [sender color]];
	return [self ok:sender];
	}


//-----------------------------------------------------------------------------
// ok:
//-----------------------------------------------------------------------------
- ok: sender
	{
	return [super ok: sender];
	}


//-----------------------------------------------------------------------------
// revert:
//-----------------------------------------------------------------------------
- revert: sender
	{
	dirty = NO;
	[super revert: sender];
	[window disableFlushWindow];

	border = [object border:border_type];
	[autoSortSwitch setState:[object autoSortSlots:border_type]];
	[self setTitleControls];

	[self setConstrainSwitches];

	[enabledSwitch setState: [object isEnabled]];
	[lazySwitch setState: [object isLazy]];
	[modePopUp setPopUpTag:(int) [object selectionMode]];

	[colorText	setColor: [object textColor]];
	[colorTextH setColor: [object highlightTextColor]];
	[colorBack	setColor: [object backgroundColor]];
	[colorBackH setColor: [object highlightBackgroundColor]];

	slot = -1;
	[self fillScroll];

	id fr = [window firstResponder];
	if (fr == 0 || fr == window)
		[titleField selectText: self];
	[[window reenableFlushWindow] flushWindow];
	return self;
	}

@end
