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). * * Version: 2.0 * Author: Ken Fromm * History: * 03-07-91 Added this comment. */ #import "DetectApp.h" #import "DocView.h" #import "DrawingView.h" #import "DrawingViewWraps.h" #import <appkit/NXCursor.h> #import <appkit/NXImage.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. Returns the * previous drawing view. */ - addDrawView:subView { id oldView; oldView = drawviewId; [oldView removeFromSuperview]; [self addSubview:subView]; drawviewId = subView; return oldView; } /* * Change the menu title and toggle the trace boolean */ - traceZoom:sender { if (!tracezoom) [[sender selectedCell] setTitle:"Zooming On"]; else [[sender selectedCell] setTitle:"Zooming Off"]; tracezoom = !tracezoom; return self; } /* Returns whether tracing should be turned on when zooming. */ - (BOOL) isTraceZooming { return tracezoom; } /* Sets and returns the scale for the drawing view. */ - setScale:(float)value { scale = value; return self; } - (float) scale { return scale; } /* * Returns the size of the control point scaled to reflect the * current scale. If the scaling were not done, a control point * would look like the USS Enterprise at 400%. (The aircraft * carrier.) * */ - (float) controlPointSize { return FONTSIZE * (1.0/scale); } /* * Returns a scaled the hit setting. Using an unscaled hit setting would be * like using a boxing glove at 400% scale. */ - (float) hitSetting { return [NXApp hitSetting] * (1.0/scale); } - (BOOL) isZooming { return zooming; } /* * 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; } /* * This method is overridden from the View class. When the * user is zooming the cursor rect for the zoom cursor is set * the the frame of the drawing view. */ - resetCursorRects { id imageId, visView; NXPoint hotspot; NXRect cursorRect, visRect; if (zooming) { if (!zoomCursor) { hotspot.x = hotspot.y = 8.0; imageId = [NXImage newFromSection:"zoom.tiff"]; zoomCursor = [NXCursor newFromImage:imageId]; [zoomCursor setHotSpot:&hotspot]; } [self getVisibleRect:&visRect]; visView = [self getDrawViewInRect:&visRect withDrop:NO]; if (visView) { [visView getFrame:&cursorRect]; NXIntersectionRect(&visRect, &cursorRect); [self addCursorRect:&cursorRect cursor:zoomCursor]; } else zooming = NO; } return self; } /* * Messaged from the zoom matrix. Starts the zoom loop. At the next * mouse down in the drawing view, the scaleDrawView:toPoint: method * will be called. */ - zoom:sender { zooming = YES; zoomControl = sender; [self resetCursorRects]; [window makeKeyAndOrderFront:self]; return self; } /* * Sizes the drawing view from the old scale to the new scale. * The frame of the view is used because it provides the size * of the view in default coordinates. The bounds of the view * provides the size in scaled coordinates. As a result, the * bounds will always be the same regardless of the scale. */ - 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. Scroll bars * are added or deleted depending on whether or not they * are needed. (They can always appear but we've chosen * to show them conditionally in this example. * * 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 toPoint:(NXPoint *) p; { float newscale; NXPoint viewPt; [window invalidateCursorRectsForView:self]; newscale = [zoomControl selectedTag] * 0.01; if (hitView && newscale != scale) { /* Convert the point to the hitView's coordinates. */ viewPt = *p; [hitView convertPoint:&viewPt fromView:nil]; [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:p]; [window reenableDisplay]; /* Trace the zoom if the menu option is set. */ if (tracezoom) DPSTraceContext(DPSGetCurrentContext(), YES); [[window contentView] display]; if (tracezoom) DPSTraceContext(DPSGetCurrentContext(), NO); } zooming = NO; 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 the drawingView. */ - drawSelf:(NXRect *)r :(int) count { id visView; NXRect drawRect, dropRect; visView = [self getDrawViewInRect:r withDrop:YES]; if (visView) { [visView getFrame:&drawRect]; if (!NXContainsRect(&drawRect, r)) { dropRect = drawRect; NXOffsetRect(&dropRect, rint(OFFSET * scale), rint(-OFFSET * scale)); PSgsave(); PSsetgray(NX_BLACK); PSsetlinewidth(LINEWIDTH * scale); PSrectclip(r->origin.x, r->origin.y, r->size.width, r->size.height); PSrectfill(dropRect.origin.x, dropRect.origin.y, dropRect.size.width, dropRect.size.height); 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.