ftp.nice.ch/pub/next/developer/resources/classes/misckit/MiscKit.1.10.0.s.gnutar.gz#/MiscKit/Palettes/MiscSwapKitPalette/MiscSwapKit.subproj/MiscSwapView.m

This is MiscSwapView.m in view mode; [Download] [Up]

/* 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: 	25.09.1994
 * Copyright (C) 1995 Thomas Engel
 */

#import <apps/InterfaceBuilder.h>
#import <misckit/MiscSwapView.h>

// The following are for keeping track of versions when archiving instances
// of this class. If you change the write: method, make sure to
// bump up the version below and make the appropriate changes to the read:
// method so all previously archived instances will be unarchivable.

#define MISC_SV_VERSION 0
#define MISC_SV_CLASSNAME "MiscSwapView"

 
@implementation MiscSwapView

+ initialize
{
	// Initialize the current version number which is used when archiving 
	// objects. This way we will be able to read all versions if we are 
	// careful.

	if (self == [MiscSwapView class])
		[self setVersion: MISC_SV_VERSION];
		
	return self;
}

- 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;

	contentView = nil;
	contentViewsHomeView = nil;
	[self setDelegate: nil];
	trigger = nil;
	currentController = nil;
	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];
		if( !contentView )
		{
			contentViewsHomeView = nil;
		}


		// 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
{
	[super write: stream];
	NXWriteObjectReference (stream, contentView);
	NXWriteObjectReference (stream, contentViewsHomeView);
	NXWriteObjectReference (stream, delegate);
	NXWriteTypes (stream, "fc", &backgroundGray, &useBuffering);
	NXWriteObjectReference (stream, trigger);
	NXWriteType (stream, "c", &tagComparison);

	return self;
}

- read:(NXTypedStream *)stream
{
  int  version;
  
	[super read: stream];
	
	version = NXTypedStreamClassVersion(stream, MISC_SV_CLASSNAME);
	
	switch (version)
	{
	  case 0:
		contentView = NXReadObject (stream);
		contentViewsHomeView = NXReadObject (stream);
		delegate = NXReadObject (stream);
		NXReadTypes (stream, "fc", &backgroundGray, &useBuffering);
		trigger = NXReadObject (stream);
		NXReadType (stream, "c", &tagComparison);
		break;
		
	  default:
	  	break;
	}

	return self;
}

- awake
{
	[super awake];
	currentController = nil;
	controllers = [List new];

	return self;
}

- drawSelf:(const NXRect *)rects :(int)rectCount
{
	// As long as you have a trigger connected to the trigger outlet, this
	// should select an initial view for you.

	if( contentView == nil )
	{
		[self swapContentView:[self trigger] ];
	}
	return self;
}


@end

/*
 * History: 25.09.94 Added archiving. (read:, write: awake, initialize)
 *					 Also added drawSelf:: so it would select an initial view.
 *
 *			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.
 */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.