ftp.nice.ch/peanuts/GeneralData/Documents/adobe/DPS.Purple.ImportAdv.tar.gz#/NX_ImportAdv/DocView.m

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

/*
 * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
 *
 * (b)  If this Sample Code is distributed as part of the Display PostScript
 *	System Software Development Kit from Adobe Systems Incorporated,
 *	then this copy is designated as Development Software and its use is
 *	subject to the terms of the License Agreement attached to such Kit.
 *
 * (c)  If this Sample Code is distributed independently, then the following
 *	terms apply:
 *
 * (d)  This file may be freely copied and redistributed as long as:
 *	1) Parts (a), (d), (e) and (f) continue to be included in the file,
 *	2) If the file has been modified in any way, a notice of such
 *      modification is conspicuously indicated.
 *
 * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
 *	Adobe Systems Incorporated.
 * 
 * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
 *	CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
 *	AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
 *	ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
 *	OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
 *	WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
 *	WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
 *	DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
 *	FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
 *	OF THIRD PARTY RIGHTS.
 */

/*
 *	DocView.m
 *
 *	This class handles the scaling of the drawing view. It repositions
 *	The drawing view within itself if the drawing view is smaller than the
 *	size of the clip view. The size of the doc view is:
 *	MAX(clip view frame, drawing view frame).
 *
 *	This class is used in several of the other Display PostScript programs.
 *	Some of the methods may be different as the class became more and
 *	more refined but the general operation remains the same.
 *
 *	Version:	2.0
 *	Author:	Ken Fromm
 */

#import "DocView.h"
#import "ImportApp.h"

#import <appkit/Cursor.h>
#import <appkit/Matrix.h>
#import <appkit/ScrollView.h>
#import <dpsclient/wraps.h>
#import <appkit/nextstd.h>

@implementation DocView

/*
*	Since there is only one subview its easier to keep track of it as an
*	instance variable rather than in the subview list. 
*/
- setDrawView:newView
{
	id		oldView;

	oldView = drawviewId;
	[oldView  removeFromSuperview];

	[self  addSubview:newView];
	drawviewId = newView;
	
	return oldView;
}

- drawView
{
	return drawviewId;
}

- setScale:(float)value
{
	scale = value;
	
	return self;
}

- (float) scale
{
	return  scale;
}

/*
*	Check whether the frame of the drawingview is in the rectangle passed in.
*	If drop is true, then include the linewidth and the drop shadow as part of the
*	drawingview frame.
*/
- getDrawViewInRect:(const NXRect *) aRect  withDrop:(BOOL) drop
{
	id		aView = NULL;

	NXRect	viewRect, dropRect;
	
	[drawviewId  getFrame:&viewRect];
	if (drop)
	{	
		dropRect = viewRect;
		NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale));
		NXOffsetRect(&viewRect, rint(LINEWIDTH/2 * scale), rint(LINEWIDTH/2 * scale));
		NXUnionRect(&dropRect, &viewRect);
	}
	if (NXIntersectsRect(aRect, &viewRect))
		aView = drawviewId;

	return  aView;
}

/*
*	Sizes the drawing view from the old scale to the newscale.
*	The frame of the view is used instead of the bounds because
*	the bound will always be the same whereas the frame will
*	provide the size in default coordinates.
*/
- sizeView:viewId withScale:(float) newscale
{
	float			scalefactor, sizewidth, sizeheight;

	NXRect		viewFrame;
	
	[viewId  getFrame:&viewFrame];
	scalefactor = newscale/scale;
	sizewidth = viewFrame.size.width*scalefactor;
	sizeheight = viewFrame.size.height*scalefactor;
	[viewId sizeTo:rint(sizewidth) :rint(sizeheight)];

	return self;
}

/* 
*	Scales the drawing view from the old scale to the new scale.
*	The scale method is relative so we use the ratio
*	of the old scale to the new scale to obtain the scaling factor.
*/
- scaleView:viewId  withScale:(float) newscale
{
	float 	scalefactor;

	scalefactor = newscale/scale;
	[viewId scale:scalefactor  :scalefactor];

	return self;
}

/*
*	Place the view passed in in the center of the doc view
*	if it is smaller than the size of the ClipView. Two passes are made
*	through the loop because adding or removing a horizontal or
*	vertical scrollbar will affect the size of the remaining dimension .
*/
- placeView:viewId
{
	BOOL		vert = NO, horiz = NO, done = NO;

	int			passes = 0, border_type;

	float			margin;
	
	NXSize		contSize, newSize, insetSize, delta;

	NXRect 		viewFrame, scrollFrame;

	margin = 4 * OFFSET * scale;

	[viewId  getFrame:&viewFrame];
	[[superview superview]  getFrame:&scrollFrame];
	border_type = [[superview superview]  borderType];

	while (!done && ++passes <= 2)
	{
		[ScrollView getContentSize:&contSize forFrameSize:&scrollFrame.size
			horizScroller:horiz  vertScroller:vert borderType:border_type];

		newSize.width = MAX(viewFrame.size.width, contSize.width);
		newSize.height = MAX(viewFrame.size.height, contSize.height);

		delta.width = newSize.width - viewFrame.size.width;
		delta.height = newSize.height - viewFrame.size.height;
		if (delta.width != 0.0 || delta.height != 0.0)
		{
			if (delta.width < margin)
				newSize.width += margin - delta.width;
			if (delta.height < margin)
				newSize.height += margin - delta.height;
		}

		horiz = (newSize.width != contSize.width);
		vert = (newSize.height != contSize.height);
		if ((horiz && vert) || (!horiz && !vert))
			done = YES;
		else
			done = NO;
	}
	
	[self  sizeTo:newSize.width  :newSize.height];

	insetSize.width = floor((newSize.width - viewFrame.size.width)/2);
	insetSize.height =  floor((newSize.height - viewFrame.size.height)/2);
	[viewId  moveTo:insetSize.width  :insetSize.height];
	if (insetSize.width != 0 || insetSize.height != 0)
		[viewId  setClipping:YES];
	else
		[viewId setClipping:NO];

	if (horiz)
		[[superview superview] setHorizScrollerRequired:YES];
	else
		[[superview superview] setHorizScrollerRequired:NO];
	
	if (vert)
		[[superview superview] setVertScrollerRequired:YES];
	else
		[[superview superview] setVertScrollerRequired:NO];

	return self;
}

/*
*	Scales the view to the tag of the selected matrix cell and then
*	scrolls to the point. The point is in window coordinates so
*	it must be converted to the drawing view  coordinates in order
*	to position it in the same relative place in the view.
*/
- scaleDrawView:hitView  withEvent:(NXEvent *) event;
{
	float			newscale;

	NXPoint		viewPt;

	[window invalidateCursorRectsForView:self];

	if ((event->flags & NX_ALTERNATEMASK) == NX_ALTERNATEMASK)
		newscale = scale / INCSCALE;
	else
		newscale = scale * INCSCALE;

	if (hitView && newscale >= MINSCALE && newscale <= MAXSCALE)
	{
		viewPt = event->location;
		[self convertPoint:&viewPt fromView:nil];
		[self convertPoint:&viewPt  toView:hitView];
		[window disableDisplay];
			/* Size and then scale the drawing view. The frame of the */
			/* drawing view must reflect the changed size. Scaling */
			/* alone will not change the frame. */
			[self  sizeView:hitView  withScale:newscale];
			[self  scaleView:hitView  withScale:newscale];
			[self  setScale:newscale];
	
			[self  placeView:hitView];
			[self  scrollPoint:&viewPt  inView:hitView  to:&event->location];
		[window reenableDisplay];
		[[window contentView]  display];
	}
	else
		[NXApp  clearOperation];

	return self;
}

/*
 *	Use the point location relative to the window versus the point relative
 *	to the drawing view (before the scale) to determine where to scroll
 *	the drawing view. We want the same location in the drawing view to
 *	appear where the mouse downed occurred.  The window coordinates
 *	are used and then adjusted by the position of the scrolling frame
 *	because the presence or absence of scrollbars throws the use
 *	of the doc views coordinates awry.
 */	
- scrollPoint:(const NXPoint *) aPt  inView:hitView  to:(const NXPoint *) windowPt
{
	NXPoint		viewPt;

	NXSize		contSize;

	NXRect 		viewFrame, visRect, scrollFrame;

	[[superview superview]  getContentSize:&contSize];
	[hitView  getFrame:&viewFrame];

	if (viewFrame.size.width > contSize.width || viewFrame.size.height > contSize.height)
	{
		viewPt = *aPt;
		[self  convertPoint:&viewPt  fromView:hitView];		
		[self getVisibleRect:&visRect];
		[[superview superview] getFrame:&scrollFrame];

		if (viewFrame.size.width > contSize.width)
			viewPt.x  -= windowPt->x - (scrollFrame.origin.x +scrollFrame.size.width -
							visRect.size.width);

		if (viewFrame.size.height > contSize.height)
			viewPt.y  -= windowPt->y - (scrollFrame.origin.y + scrollFrame.size.height -
							visRect.size.height);

		[self  scrollPoint:&viewPt];		
	}

	return self;
}

/*
 * This drawSelf method draws a border around the drawing view as well as a
 * drop shadow.  This is only done if it will be visible however. We tell if it is visible
 * if the rectangle passed in is not contained entirely within drawingView frame.
*/
- drawSelf:(NXRect *)r :(int) count
{
	id			visView;

	NXRect		drawRect, dropRect, bRect, xRect, yRect;

	visView = [self getDrawViewInRect:r  withDrop:YES];
	if (visView)
	{
		/* Calculate the rectangle of the draw view plus its drop shadow. */
		[visView  getFrame:&drawRect];
		dropRect = bRect = drawRect;
		NXOffsetRect(&bRect, -rint(LINEWIDTH/2 * scale), -rint(LINEWIDTH/2 * scale));
		NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale));
		NXUnionRect(&dropRect, &bRect);
		if (!NXContainsRect(&bRect, r))
		{
			bRect = xRect = yRect = dropRect;
			NXIntersectionRect(&drawRect, &bRect);
			NXDivideRect(&xRect, &dropRect, bRect.size.width, 0);
			NXDivideRect(&yRect, &dropRect, bRect.size.height, 3);

			PSgsave();
				PSsetgray(NX_BLACK);
				PSrectclip(r->origin.x, r->origin.y, r->size.width, r->size.height);
				PSrectfill(xRect.origin.x, xRect.origin.y,
					xRect.size.width, xRect.size.height);
				PSrectfill(yRect.origin.x, yRect.origin.y,
					yRect.size.width, yRect.size.height);
				PSsetlinewidth(LINEWIDTH * scale);
				PSrectstroke(drawRect.origin.x, drawRect.origin.y,
					drawRect.size.width, drawRect.size.height);
			PSgrestore();
		}
	}

	return self;			
}

@end

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