/* MiscSwapView.m
 *
 * This subclass of View is able to swap different views into itself. It's
 * used to implement any kind of multipage windows. (Inspectors, Prefs...)
 *
 * For more interface-info see the header file. More in depth information
 * can be found here in the source-code.
 *
 * Notes: There is one Cateogry for this class includes automatic swapping.
 *
 * Improved by:		Thomas Engel
 * First changes:   24.01.1994 (Copyleft)
 * Last modified: 	24.02.1994
 */

#import <misckit/misckit.h>
 
@implementation MiscSwapView

- init
{
	NXRect theFrame = {{0.0, 0.0}, {0.0, 0.0}};
	return [self initFrame:&theFrame];
}

- initFrame:(const NXRect *)frameRect
{
	// Designated initilizer. We will set allow resizing by default and
	// we will draw in Lightgray if we have to swap 'nil' in.

	self = [super initFrame:frameRect];
	if( !self ) return self;

	backgroundGray = NX_LTGRAY;
	[self setAutoresizeSubviews:YES];
	useBuffering = NO;
	
	// Well the ByObject Category want's some other defaults too.
	
	controllers = [List new];	 
 	[self setTagComparison:YES];

	return self;
}

- free
{
	// We do not free the contentsControllers of this list! Well we didin't
	// allocate them..but maybe we should free them...hmmm. I'm not sure yet.
	
	[controllers free];
	return [super free];
}

- setDelegate:(id)anObject
{
	delegate = anObject;
	return self;
}

- delegate
{
	return delegate;
}

- setBackgroundGray:(float)aGray
{
	backgroundGray = aGray;
	return self;
}

- (float)backgroundGray
{
	return backgroundGray;
}

- setUseBuffering:(BOOL)flag
{
	useBuffering = flag;
	return self;
}

- (BOOL)doesUseBuffering
{
	return useBuffering;
}

- setContentView:aView
{
 	// This is the real method !! 
 	// Here we process the finding of the swapping and resizing.
	// If the new view is different from our current contentView we should
	// put the current back where it came from.
	
	NXRect	theFrame;
	id		contentViewsHomeWindow;
	int		gState = 0;
	
	if( aView != contentView )
	{
		if( contentView && contentViewsHomeView )
		{
			[contentView removeFromSuperview];
			[contentViewsHomeView addSubview:contentView];
			[contentView moveTo:contentViewsHomeRect.origin.x
							   :contentViewsHomeRect.origin.y];
			[contentView sizeTo:contentViewsHomeRect.size.width
							   :contentViewsHomeRect.size.height];
		}
	
		// No real subview? So clean up the background. This is done by
		// filling the view bounds with the backgroundGray we did set.
	
		contentView = aView;
		
		if( !contentView )
		{
			contentViewsHomeView = nil;
	
			[self lockFocus];
   		 	PSsetgray( backgroundGray );
   		 	NXRectFill(&bounds);
			[self unlockFocus];
		}

		// Otherwise we have a new subview so lets remove it form its home-
		// window, resize it and align it to our 0,0 corner.
		// If we have to use buffered composing we will now display our self
		// but we will compose into the screen. This might cause problems with
		// views that have to be resized.
		
		else
		{
			// If we use buffering then lets compose the views offscreen
			// if they have no gState which meant that they haven't been
			// drawn yet.
			// Let's ensure the windows are always retained and non deffered.
			// This make easy-offscreen drawing possible.
			
			contentViewsHomeWindow = [contentView window];
			contentViewsHomeView = [contentView superview];
			[contentView getFrame:&contentViewsHomeRect];

			if( useBuffering )
			{
				[contentViewsHomeWindow setBackingType:NX_RETAINED];
	 			
				// Now lets get the views position inside its home.
				// We also need a gState to be able to do the fast copying.
				
				[contentView getFrame:&theFrame];
				gState = [contentViewsHomeView gState];
				if( !gState )
				{
					[contentViewsHomeView allocateGState];
					[contentViewsHomeView display];
					gState = [contentViewsHomeView gState];				
				}
				NXPing();
			}
			
			// The view reorganication is always the same.
			// Resizing is only applyed when we don't use buffering!
			
			[contentView removeFromSuperview];
			[self addSubview:contentView];
			[contentView moveTo:0.0 :0.0];
			
			// The displaying might come with a simple redraw or a quick
			// composing by copying from the offscreen buffer.
			
			if( useBuffering && gState )
			{
				// We will fill our background first to allow swapping of
				// views that don't have the same size.
				// Because they are not resized here to cover the whole
				// area its a must to clear the whole scene before!
				
				[self lockFocus];
 				PSsetgray(backgroundGray);
 				NXRectFill(&bounds);
				PScomposite( (float)theFrame.origin.x,
 							 (float)theFrame.origin.y,
							 (float)theFrame.size.width,
							 (float)theFrame.size.height,
							 (int)gState,
							 (float)0.0,
							 (float)0.0,
							 (int)NX_COPY );
				[self unlockFocus];
			}
			else
			{
				[contentView sizeTo:bounds.size.width :bounds.size.height];
				[self display];
			}
		}
		// Let the windowServer catch up to the changes we made (yawn...)
		// And show our nice new window
		
		NXPing();
		[[self window] flushWindow];
	}
	return self;
}

- contentView
{
	return contentView;
}

- contentViewsHomeView;
{
	return contentViewsHomeView;
}

- write:(NXTypedStream *)stream
{
	return self;
}

- read:(NXTypedStream *)stream
{
	return self;
}

@end

/*
 * History: 24.02.94 Added Greg's quick composing.
 *
 *			24.01.94 Redesign from my old swapView. Added Buffering.
 *
 *			21.01.94 Added the resizing job the Greg's swapView.
 *
 * 
 * Bugs: - Could be. Yes.
 */