home *** CD-ROM | disk | FTP | other *** search
- // RuledScrollView.m
- // RuledScrollView is intended as a general purpose class to make it
- // easy to add all kinds of rulers to any view. This class is an
- // extension of the tiledScrollView class, from "ScrollDoodScroll"
- // (by Jayson Adams, NeXT Developer Support Team)
- // This class is intended to be widely useful without needing to
- // modify (or understand) its code, so it provides methods to setup
- // the mainView and its rulerViews, rather than hardcoding the setup.
- // Kevin Brain (ksbrain@zeus.UWaterloo.ca)
-
- #import <appkit/ClipView.h>
- #import <appkit/TextField.h>
- #import <appkit/Panel.h>
-
- #import "RuledScrollView.h"
-
- // Macro to print a rect (for debugging)
- #define PRINTRECT(string,rect) { \
- printf(" %s x = %4.1f y = %4.1f width = %4.1f height = %4.1f\n",string, \
- NX_X(&(rect)), NX_Y(&(rect)), NX_WIDTH(&(rect)), NX_HEIGHT(&(rect))); \
- }
-
- @implementation RuledScrollView
-
- /* instance methods */
-
- - initFrame:(NXRect *)theFrame
- {
- [super initFrame:theFrame];
- rulersOn = YES;
- topRuler = NULL;
- bottomRuler = NULL;
- leftRuler = NULL;
- rightRuler = NULL;
- primaryRulers = TOPBOTTOM;
-
- return self;
- }
-
- - free
- {
- if (leftRuler) {
- [leftRuler free];
- [leftRulerClipView free];
- }
- if (rightRuler) {
- [rightRuler free];
- [rightRulerClipView free];
- }
- if (topRuler) {
- [topRuler free];
- [topRulerClipView free];
- }
- if (bottomRuler) {
- [bottomRuler free];
- [bottomRulerClipView free];
- }
- if (bottomLeftStub) {
- [bottomLeftStub free];
- }
- if (topLeftStub) {
- [topLeftStub free];
- }
- if (bottomRightStub) {
- [bottomRightStub free];
- }
- if (topRightStub) {
- [topRightStub free];
- }
-
- return [super free];
- }
-
- - setLeftRuler:anObject
- {
- leftRuler = anObject;
- [self addRulerView:leftRuler toEdge:LEFTEDGE];
- return self;
- }
-
- - setRightRuler:anObject
- {
- rightRuler = anObject;
- [self addRulerView:rightRuler toEdge:RIGHTEDGE];
- return self;
- }
-
- - setTopRuler:anObject
- {
- topRuler = anObject;
- [self addRulerView:topRuler toEdge:TOPEDGE];
- return self;
- }
-
- - setBottomRuler:anObject
- {
- bottomRuler = anObject;
- [self addRulerView:bottomRuler toEdge:BOTTOMEDGE];
- return self;
- }
-
- - setBottomLeftStub:anObject
- {
- bottomLeftStub = anObject;
- [self addStubView:anObject toCorner: BOTTOMLEFTCORNER];
- return self;
- }
-
- - setTopLeftStub:anObject
- {
- topLeftStub = anObject;
- [self addStubView:anObject toCorner: TOPLEFTCORNER];
- return self;
- }
-
- - setBottomRightStub:anObject
- {
- bottomRightStub = anObject;
- [self addStubView:anObject toCorner: BOTTOMRIGHTCORNER];
- return self;
- }
-
- - setTopRightStub:anObject
- {
- topRightStub = anObject;
- [self addStubView:anObject toCorner: TOPRIGHTCORNER];
- return self;
- }
-
- - addRulerView:(Ruler *)theView toEdge:(int)edge
- {
- NXRect scaleViewRect;
- ClipView *scaleClipView;
-
- /* reset the origin of rulers created in nibs */
- [theView getFrame:&scaleViewRect];
- scaleViewRect.origin.x = 0.0;
- scaleViewRect.origin.y = 0.0;
- [theView setFrame:&scaleViewRect];
-
- NXSetRect(&scaleViewRect,0,0,0,0);
- /* make a clipView to hold the scale view passed in
- * (we'll adjust its size & position in tile) */
- scaleClipView = [[ClipView alloc] initFrame:&scaleViewRect];
- [scaleClipView setDocView:theView];
- [self addSubview:scaleClipView];
-
- switch (edge) {
- case LEFTEDGE:
- // actually, I think we leak here if you add the same ruler twice
- // but I'm about to leave on holidays, so I can't be
- // bothered to change it now. Next version:-)
- if (leftRuler && (leftRuler != theView)) { // the view
- [leftRuler free];
- [leftRulerClipView free];
- }
- leftRuler = theView;
- leftRulerClipView = scaleClipView;
- if([leftRuler respondsTo:@selector(setOrientation:)])
- [leftRuler setOrientation:VERTICAL]; // default is horizontal
- break;
- case RIGHTEDGE:
- if (rightRuler && (rightRuler != theView)) {
- [rightRuler free];
- [rightRulerClipView free];
- }
- rightRuler = theView;
- rightRulerClipView = scaleClipView;
- if([rightRuler respondsTo:@selector(setOrientation:)])
- [rightRuler setOrientation:VERTICAL]; // default is horizontal
- break;
- case TOPEDGE:
- if (topRuler && (topRuler != theView)) {
- [topRuler free];
- [topRulerClipView free];
- }
- topRuler = theView;
- topRulerClipView = scaleClipView;
- break;
- case BOTTOMEDGE:
- if (bottomRuler && (bottomRuler != theView)) {
- [bottomRuler free];
- [bottomRulerClipView free];
- }
- bottomRuler = theView;
- bottomRulerClipView = scaleClipView;
- break;
- }
- rulerVisible[edge] = YES; // turn this ruler on by default
- return self;
- }
-
- - addStubView:(View *)theView toCorner:(int)corner
- {
- switch (corner) {
- case BOTTOMLEFTCORNER:
- if (bottomLeftStub && (bottomLeftStub != theView))
- [bottomLeftStub free];
- bottomLeftStub = theView;
- break;
- case TOPLEFTCORNER:
- if (topLeftStub && (topLeftStub != theView))
- [topLeftStub free];
- topLeftStub = theView;
- break;
- case BOTTOMRIGHTCORNER:
- if (bottomRightStub && (bottomRightStub != theView))
- [bottomRightStub free];
- bottomRightStub = theView;
- break;
- case TOPRIGHTCORNER:
- if (topRightStub && (topRightStub != theView))
- [topRightStub free];
- topRightStub = theView;
- break;
- }
-
- [self addSubview:theView];
- return self;
- }
-
- - sliceEdge:(int)theEdge forRuler:theRuler inClipView:theClipView
- // private method that cuts a slice from the contentView to make room for a ruler
- {
- NXRect contentViewRect, scaleRect, scaleClipRect;
- NXRect cvBoundsRect;
-
- // get bounds of contentView so we can reset it after setting frame
- [contentView getBounds:&cvBoundsRect];
-
- [contentView getFrame:&contentViewRect];
- [theRuler getFrame:&scaleRect];
- if ((theEdge == LEFTEDGE) || (theEdge == RIGHTEDGE))
- NXDivideRect(&contentViewRect, &scaleClipRect, NX_WIDTH(&scaleRect), theEdge);
- else
- NXDivideRect(&contentViewRect, &scaleClipRect, NX_HEIGHT(&scaleRect), theEdge);
- [theClipView setFrame:&scaleClipRect]; // invokes reflectScroll:
-
- // setting contentView's frame changes contentView bounds then invokes reflectScroll:
- [contentView setFrame:&contentViewRect];
-
- // reset bounds of contentView mangled by setting frame
- [self scrollClip:contentView to:(NXPoint *)&cvBoundsRect.origin];
-
- return self;
- }
-
- - tile
- /*
- * tile gets called whenever the scrollView changes size. Its job is to resize
- * all of the scrollView's "tiled" views (scrollers, contentView and any other
- * views we might want to place in the scrollView's bounds).
- */
- {
- NXRect viewRect, scrollerRect, tempRect, cvBounds, newCVBounds;
- NXRect stubRect, rulerClipRect, otherRulerRect, docViewRect;
- float tempFloat=0.0,distanceFromEdge;
-
- [contentView getBounds:&cvBounds];
- [[self docView] getBounds:&docViewRect];
-
- /* resize and arrange the scrollers and contentView as usual */
- [super tile]; // invokes reflectScroll:
-
- // If the scroller knob is closer to the edge than the width or height
- // of the ruler views, the tile method causes the contentView bounds
- // to be incorrectly changed. After many frustrating hours of work,
- // I came up with the following code to correct for this...
-
- [contentView getBounds:&newCVBounds];
- NXSetRect(&otherRulerRect,0,0,0,0);
- [[self leftRuler] getFrame:&otherRulerRect];
- if ([self isRulerVisible:LEFTEDGE])
- tempFloat = otherRulerRect.size.width;
- NXSetRect(&otherRulerRect,0,0,0,0);
- [[self rightRuler] getFrame:&otherRulerRect];
- if ([self isRulerVisible:RIGHTEDGE])
- tempFloat += otherRulerRect.size.width;
- distanceFromEdge = docViewRect.size.width - (cvBounds.origin.x+cvBounds.size.width);
- // if entire width of docView was showing, don't adjust
- if (cvBounds.size.width > docViewRect.size.width)
- distanceFromEdge = tempFloat;
- if ((distanceFromEdge < tempFloat) && (newCVBounds.size.width < docViewRect.size.width))
- newCVBounds.origin.x += (tempFloat-distanceFromEdge);
-
- NXSetRect(&otherRulerRect,0,0,0,0);
- [[self topRuler] getFrame:&otherRulerRect];
- if ([self isRulerVisible:TOPEDGE])
- tempFloat = otherRulerRect.size.height;
- NXSetRect(&otherRulerRect,0,0,0,0);
- [[self bottomRuler] getFrame:&otherRulerRect];
- if ([self isRulerVisible:BOTTOMEDGE])
- tempFloat += otherRulerRect.size.height;
- distanceFromEdge = docViewRect.size.height - (cvBounds.origin.y+cvBounds.size.height);
- // if entire height of docView was showing, don't adjust
- if (cvBounds.size.height > docViewRect.size.height)
- distanceFromEdge = tempFloat;
- if ((distanceFromEdge < tempFloat) && (newCVBounds.size.height < docViewRect.size.height))
- newCVBounds.origin.y += (tempFloat-distanceFromEdge);
-
- // correct contentView Bounds
- [self scrollClip:contentView to:(NXPoint *)&newCVBounds.origin];
-
- /* cut a slice from the contentView to make room for each scaleView */
-
- if (primaryRulers == TOPBOTTOM) {
- if(topRuler && rulerVisible[TOPEDGE]) {
- if ([self isFlipped])
- [self sliceEdge:(int)BOTTOMEDGE forRuler:topRuler inClipView:topRulerClipView];
- else
- [self sliceEdge:(int)TOPEDGE forRuler:topRuler inClipView:topRulerClipView];
- }
-
- if(bottomRuler && rulerVisible[BOTTOMEDGE]) {
- if ([self isFlipped])
- [self sliceEdge:(int)TOPEDGE forRuler:bottomRuler inClipView:bottomRulerClipView];
- else
- [self sliceEdge:(int)BOTTOMEDGE forRuler:bottomRuler
- inClipView:bottomRulerClipView];
- }
- if(leftRuler && rulerVisible[LEFTEDGE])
- [self sliceEdge:(int)LEFTEDGE forRuler:leftRuler inClipView:leftRulerClipView];
- if(rightRuler && rulerVisible[RIGHTEDGE])
- [self sliceEdge:(int)RIGHTEDGE forRuler:rightRuler inClipView:rightRulerClipView];
-
- // Add stub views (now that edge views are present)
- if(topRuler && rulerVisible[TOPEDGE]) {
- if (topLeftStub) {
- [leftRulerClipView getFrame:&otherRulerRect];
- [topRulerClipView getFrame:&rulerClipRect];
- NXDivideRect(&rulerClipRect, &stubRect, otherRulerRect.size.width, LEFTEDGE);
- [topRulerClipView setFrame:&rulerClipRect];
- [topLeftStub setFrame:&stubRect];
- }
- if (topRightStub) {
- [rightRulerClipView getFrame:&otherRulerRect];
- [topRulerClipView getFrame:&rulerClipRect];
- NXDivideRect(&rulerClipRect, &stubRect, otherRulerRect.size.width, RIGHTEDGE);
- [topRulerClipView setFrame:&rulerClipRect];
- [topRightStub setFrame:&stubRect];
- }
- }
- if(bottomRuler && rulerVisible[BOTTOMEDGE]) {
- if (bottomLeftStub) {
- [leftRulerClipView getFrame:&otherRulerRect];
- [bottomRulerClipView getFrame:&rulerClipRect];
- NXDivideRect(&rulerClipRect, &stubRect, otherRulerRect.size.width, LEFTEDGE);
- [bottomRulerClipView setFrame:&rulerClipRect];
- [bottomLeftStub setFrame:&stubRect];
- }
- if (bottomRightStub) {
- [rightRulerClipView getFrame:&otherRulerRect];
- [bottomRulerClipView getFrame:&rulerClipRect];
- NXDivideRect(&rulerClipRect, &stubRect, otherRulerRect.size.width, RIGHTEDGE);
- [bottomRulerClipView setFrame:&rulerClipRect];
- [bottomRightStub setFrame:&stubRect];
- }
- }
- }
- else {
- if(leftRuler && rulerVisible[LEFTEDGE])
- [self sliceEdge:(int)LEFTEDGE forRuler:leftRuler inClipView:leftRulerClipView];
- if(rightRuler && rulerVisible[RIGHTEDGE])
- [self sliceEdge:(int)RIGHTEDGE forRuler:rightRuler inClipView:rightRulerClipView];
- if(topRuler && rulerVisible[TOPEDGE]) {
- if ([self isFlipped])
- [self sliceEdge:(int)BOTTOMEDGE forRuler:topRuler inClipView:topRulerClipView];
- else
- [self sliceEdge:(int)TOPEDGE forRuler:topRuler inClipView:topRulerClipView];
- }
- if(bottomRuler && rulerVisible[BOTTOMEDGE]) {
- if ([self isFlipped])
- [self sliceEdge:(int)TOPEDGE forRuler:bottomRuler inClipView:bottomRulerClipView];
- else
- [self sliceEdge:(int)BOTTOMEDGE forRuler:bottomRuler
- inClipView:bottomRulerClipView];
- }
- /****************************************************************************/
- /* Code to tile StubViews when (primaryRulers != TOPBOTTOM) still missing */
- /****************************************************************************/
- }
-
- // The following imbeds a view (normally a button) in the horizontal scroller
- // if the hScrollerRightEmbeddedView instance variable is connected to some view (in IB)
- // A textfield with Courier-Medium size 10 font will fit into the horizontal scroller.
- if (hScrollerRightEmbeddedView) {
- if ([hScrollerRightEmbeddedView superview] != self) {
- [self addSubview:hScrollerRightEmbeddedView];
- }
-
- [hScrollerRightEmbeddedView getFrame:&tempRect];
- // now make the hScroller smaller and stick the popupList next to it
- [hScroller getFrame:&scrollerRect];
- // width stored during init
- NXDivideRect(&scrollerRect, &viewRect, tempRect.size.width, RIGHTEDGE);
- // Need to force width back to original button width since the above function
- // will not set viewRect.size.width to tempRect.size.width when the
- // tile method is evoked before the correct size of the mainView is set
- viewRect.size.width = tempRect.size.width;
- [hScroller setFrame:&scrollerRect];
- NXInsetRect(&viewRect, 0, 1.0);
- [hScrollerRightEmbeddedView setFrame:&viewRect];
- }
-
- // Do the same as above for a possible second view in the horizontal scroller
- if (hScrollerLeftEmbeddedView) {
- if ([hScrollerLeftEmbeddedView superview] != self) {
- [self addSubview:hScrollerLeftEmbeddedView];
- }
- [hScrollerLeftEmbeddedView getFrame:&tempRect];
- [hScroller getFrame:&scrollerRect];
- NXDivideRect(&scrollerRect, &viewRect, tempRect.size.width, RIGHTEDGE);
- viewRect.size.width = tempRect.size.width;
- [hScroller setFrame:&scrollerRect];
- NXInsetRect(&viewRect, 0, 1.0);
- [hScrollerLeftEmbeddedView setFrame:&viewRect];
- }
-
- // Do the same as above for a view in the vertical scroller
- if (vScrollerTopEmbeddedView) {
- if ([vScrollerTopEmbeddedView superview] != self) {
- [self addSubview:vScrollerTopEmbeddedView];
- }
- [vScrollerTopEmbeddedView getFrame:&tempRect];
- [vScroller getFrame:&scrollerRect];
- if ([self isFlipped])
- NXDivideRect(&scrollerRect, &viewRect, tempRect.size.height, BOTTOMEDGE);
- else
- NXDivideRect(&scrollerRect, &viewRect, tempRect.size.height, TOPEDGE);
- viewRect.size.height = tempRect.size.height;
- [vScroller setFrame:&scrollerRect];
- NXInsetRect(&viewRect, 1.0, 0);
- [vScrollerTopEmbeddedView setFrame:&viewRect];
- }
-
- // Do the same as above for a possible second view in the vertical scroller
- if (vScrollerBottomEmbeddedView) {
- if ([vScrollerBottomEmbeddedView superview] != self) {
- [self addSubview:vScrollerBottomEmbeddedView];
- }
- [vScrollerBottomEmbeddedView getFrame:&tempRect];
- [vScroller getFrame:&scrollerRect];
- if ([self isFlipped])
- NXDivideRect(&scrollerRect, &viewRect, tempRect.size.height, BOTTOMEDGE);
- else
- NXDivideRect(&scrollerRect, &viewRect, tempRect.size.height, TOPEDGE);
- viewRect.size.height = tempRect.size.height;
- [vScroller setFrame:&scrollerRect];
- NXInsetRect(&viewRect, 1.0, 0);
- [vScrollerBottomEmbeddedView setFrame:&viewRect];
- }
-
- // save the size of the docView for setSizeIfNeeded
- [[self docView] getFrame:&oldRect];
-
- return self;
- }
-
- - reflectScroll:cView
- // does not affect contentView bounds...
- /*
- * We only reflect scroll in the contentView, not the scale views.
- */
- {
- return [super reflectScroll:contentView];
- }
-
- - scrollClip:aClipView to:(NXPoint *)aPoint
- {
- NXPoint colOrigin,newPoint;
- NXRect colBounds;
-
- newPoint = *aPoint;
-
- // if it's not the contentView, adjust the point being scrolled to so that
- // it doesn't scroll the contentView except in the direction of the ruler
- [contentView getBounds:&colBounds];
- if (aClipView != contentView)
- if(([aClipView docView] == leftRuler) || ([aClipView docView] == rightRuler))
- newPoint.x = colBounds.origin.x;
- else
- newPoint.y = colBounds.origin.y;
-
- /* turn off drawing (to the screen) */
- [window disableFlushWindow];
-
- /* scroll the contentView to the new origin */
- [contentView rawScroll:&newPoint];
-
- /* compute new origin for the leftRulerView (don't let it scroll horizontally) */
- [leftRulerClipView getBounds:&colBounds];
- colOrigin.x = colBounds.origin.x;
- colOrigin.y = newPoint.y;
- [leftRulerClipView rawScroll:&colOrigin]; // scroll the scale view to that point
-
- /* compute new origin for the rightRulerView (don't let it scroll horizontally) */
- [rightRulerClipView getBounds:&colBounds];
- colOrigin.x = colBounds.origin.x;
- colOrigin.y = newPoint.y;
- [rightRulerClipView rawScroll:&colOrigin]; // scroll the scale view to that point
-
- /* compute new origin for the topRulerView (don't let it scroll vertically) */
- [topRulerClipView getBounds:&colBounds];
- colOrigin.x = newPoint.x ;
- colOrigin.y = colBounds.origin.y;
- [topRulerClipView rawScroll:&colOrigin]; // scroll the scale view to that point
-
- /* compute new origin for the bottomRulerView (don't let it scroll vertically) */
- [bottomRulerClipView getBounds:&colBounds];
- colOrigin.x = newPoint.x ;
- colOrigin.y = colBounds.origin.y;
- [bottomRulerClipView rawScroll:&colOrigin]; // scroll the scale view to that point
-
- /* send results to screen */
- [[window reenableFlushWindow] flushWindow];
-
- return self;
- }
-
- - setSizeIfNeeded
- {
- NXRect theFrame;
-
- [[self docView] getFrame:&theFrame];
- if ((theFrame.size.width != oldRect.size.width) ||
- (theFrame.size.height != oldRect.size.height))
- [self setSize];
- return self;
- }
-
- - setSize
- // This method must be invoked whenever the size
- // of the mainView is changed.
- {
- NXRect theFrame;
-
- [window disableDisplay];
- if (topRuler)
- [topRuler setSize];
- if (bottomRuler)
- [bottomRuler setSize];
- if (leftRuler)
- [leftRuler setSize];
- if (rightRuler)
- [rightRuler setSize];
- [self resizeSubviews:(const NXSize *)&theFrame.size];
- [[window reenableDisplay] displayIfNeeded];
-
- return self;
- }
-
- - showRuler:(int)whichRuler;
- {
- rulerVisible[whichRuler] = YES;
- switch (whichRuler) {
- case TOPEDGE:
- if (topRulerClipView) {
- [self addSubview:topRulerClipView];
- if (leftRulerClipView && rulerVisible[LEFTEDGE]&& topLeftStub)
- [self addSubview:topLeftStub];
- if (rightRulerClipView && rulerVisible[RIGHTEDGE]&& topRightStub)
- [self addSubview:topRightStub];
- }
- break;
- case BOTTOMEDGE:
- if (bottomRulerClipView) {
- [self addSubview:bottomRulerClipView];
- if (leftRulerClipView && rulerVisible[LEFTEDGE]&& bottomLeftStub)
- [self addSubview:bottomLeftStub];
- if (rightRulerClipView && rulerVisible[RIGHTEDGE]&& bottomRightStub)
- [self addSubview:bottomRightStub];
- }
- break;
- case LEFTEDGE:
- if (leftRulerClipView) {
- [self addSubview:leftRulerClipView];
- if (topRulerClipView && rulerVisible[TOPEDGE]&& topLeftStub)
- [self addSubview:topLeftStub];
- if (bottomRulerClipView && rulerVisible[BOTTOMEDGE]&& bottomLeftStub)
- [self addSubview:bottomLeftStub];
- }
- break;
- case RIGHTEDGE:
- if (rightRulerClipView) {
- [self addSubview:leftRulerClipView];
- if (topRulerClipView && rulerVisible[TOPEDGE]&& topRightStub)
- [self addSubview:topRightStub];
- if (bottomRulerClipView && rulerVisible[BOTTOMEDGE]&& bottomRightStub)
- [self addSubview:bottomRightStub];
- }
- break;
- }
-
- return self;
- }
-
- - hideRuler:(int)whichRuler;
- // this should be followed promptly with a setSize
- {
- rulerVisible[whichRuler] = NO;
- switch (whichRuler) {
- case TOPEDGE:
- if (topRulerClipView)
- [topRulerClipView removeFromSuperview];
- if (topLeftStub)
- [topLeftStub removeFromSuperview];
- if (topRightStub)
- [topRightStub removeFromSuperview];
- break;
- case BOTTOMEDGE:
- if (bottomRulerClipView)
- [bottomRulerClipView removeFromSuperview];
- if (bottomLeftStub)
- [bottomLeftStub removeFromSuperview];
- if (bottomRightStub)
- [bottomRightStub removeFromSuperview];
- break;
- case LEFTEDGE:
- if (leftRulerClipView)
- [leftRulerClipView removeFromSuperview];
- if (topLeftStub)
- [topLeftStub removeFromSuperview];
- if (bottomLeftStub)
- [bottomLeftStub removeFromSuperview];
- break;
- case RIGHTEDGE:
- if (rightRulerClipView)
- [rightRulerClipView removeFromSuperview];
- if (bottomRightStub)
- [bottomRightStub removeFromSuperview];
- if (topRightStub)
- [topRightStub removeFromSuperview];
- break;
- }
-
- return self;
- }
-
- - (BOOL)isRulerVisible:(int)whichRuler
- {
- return rulerVisible[whichRuler];
- }
-
- - topRuler { return topRuler; }
-
- - bottomRuler { return bottomRuler; }
-
- - leftRuler { return leftRuler; }
-
- - rightRuler { return rightRuler; }
-
- - setPrimaryRulers:(int)orientation
- {
- primaryRulers = orientation;
- return self;
- }
-
- - bottomLeftStub { return bottomLeftStub; }
-
- - topLeftStub { return topLeftStub; }
-
- - bottomRightStub { return bottomRightStub; }
-
- - topRightStub { return topRightStub; }
-
- - (int)primaryRulers { return primaryRulers; }
-
- - getMinSize:(NXSize *)theSize
- {
- NXRect contentViewRect,ruledScrollViewRect;
-
- [contentView getFrame:&contentViewRect];
- [self getFrame:&ruledScrollViewRect];
- theSize->width = ruledScrollViewRect.size.width - contentViewRect.size.width+1;
- theSize->height = ruledScrollViewRect.size.height - contentViewRect.size.height+1;
-
- return self;
- }
-
- /* methods for printing the visible view */
- /*---------------------------------------*/
- - createPrintView
- // Creates a view for printing the visible part of the trace
- // We do this by adding the rulerViews' ClipViews as subviews to a View object
- // (printView) which is allocated once and added as a subview of
- // an offscreen window. When we are done with them, we return the
- // ClipViews to their former position as subviews of the RuledScrollView object
- // (self). The mainView itself is also taken (rather than its ClipView)
- // and added to another ClipView object (mainPrintClipView), since it proved
- // troublesome to return the mainView (docView) itself when finished with it.
-
- {
- float leftOffset;
- NXRect tempRect, clipFrame;
- NXRect oldMainClipBounds, oldMainFrame;
-
- if (!printWindow) { // create window & setup mainPrintClipView first time through
- // note that size is fixed at 1120 X 832
- NXSetRect(&tempRect, (NXCoord) 0, (NXCoord) 0, (NXCoord) 1120, (NXCoord) 832);
- /* create a window for printView */
- printWindow = [[Window alloc] initContent:(const NXRect *)&tempRect
- style:(int)NX_PLAINSTYLE // no title bar and frame
- backing:(int)NX_BUFFERED
- buttonMask:(int)0 // no controls in title bar and frame
- defer:(BOOL)NO];
- NXSetRect(&tempRect, (NXCoord) 0, (NXCoord) 0, (NXCoord) 0, (NXCoord) 0);
- printView = [[View alloc] initFrame:&tempRect];
- if ([self isFlipped]) [printView setFlipped:YES];
- mainPrintClipView = [[ClipView alloc] initFrame:&tempRect];
- [[printWindow contentView] addSubview:printView];
- }
-
- /* set pointer to the main View */
- mainView = [self docView];
-
- /* get translation information (which part of main view is visible) */
- /* we will scroll the main View in its new clipView (a subview of */
- /* PrintView) by sending a scrollPoint: message to it with the point */
- /* (main View's clipView's bounds.origin) - (main View's Frame.origin) */
- [[mainView superview] getBounds:&oldMainClipBounds];
- [mainView getFrame:&oldMainFrame];
- mainVisiblePoint.x = oldMainClipBounds.origin.x - oldMainFrame.origin.x;
- mainVisiblePoint.y = oldMainClipBounds.origin.y - oldMainFrame.origin.y;
-
- // put mainPrintClipView in the same place as it is in ruledScrollView
- [[mainView superview] getFrame:&oldMainClipRect];
-
- /* get current locations of clipviews */
- // NXSetRect(&oldBottomRect,0,0,0,0);
- // NXSetRect(&oldTopRect,0,0,0,0);
- // NXSetRect(&oldLeftRect,0,0,0,0);
- // NXSetRect(&oldRightRect,0,0,0,0);
- [bottomRulerClipView getFrame:&oldBottomRect];
- [topRulerClipView getFrame:&oldTopRect];
- [leftRulerClipView getFrame:&oldLeftRect];
- [rightRulerClipView getFrame:&oldRightRect];
-
- /* If the mainView itself is smaller (ie., there is some */
- /* of the tiledScrollView's background showing), reduce the*/
- /* size so that none of the background shows */
- // if (oldMainFrame.size.height < clipFrame.size.height)
- // clipFrame.size.height = signalFrame.size.height;
- // if (oldMainFrame.size.width < clipFrame.size.width)
- // clipFrame.size.width = signalFrame.size.width;
- // [signalClipView setFrame:&clipFrame];
-
- // clipFrame.origin.x = 0;
- // clipFrame.size.width = leftRuleFrame.size.width;
- // [scaleClipView setFrame:&clipFrame];
-
- /* temporarily 'steal' the clipviews holding the rulers and the mainView */
- /* - They are given back in printVisible: */
- [mainPrintClipView setDocView:mainView];
- [printView addSubview:mainPrintClipView];
-
- if (bottomRuler)
- [printView addSubview:bottomRulerClipView];
- if (topRuler)
- [printView addSubview:topRulerClipView];
- if (leftRuler)
- [printView addSubview:leftRulerClipView];
- if (rightRuler) {
- [printView addSubview:rightRulerClipView];
- }
-
- if (vScroller) {
- [vScroller getFrame:&tempRect];
- leftOffset = (tempRect.size.width+4); // 4 is the width of the borders
- }
- else
- leftOffset = 0;
- // Now resize the clipviews
- // subtract width of the left vertical scroller since we don't draw it
- tempRect = oldMainClipRect;
- tempRect.origin.x -= leftOffset;
- [mainPrintClipView setFrame:&tempRect];
-
- tempRect = oldBottomRect;
- tempRect.origin.x -= leftOffset;
- [bottomRulerClipView setFrame:&tempRect];
-
- tempRect = oldTopRect;
- tempRect.origin.x -= leftOffset;
- [topRulerClipView setFrame:&tempRect];
-
- tempRect = oldLeftRect;
- tempRect.origin.x -= leftOffset;
- [leftRulerClipView setFrame:&tempRect];
-
- tempRect = oldRightRect;
- tempRect.origin.x -= leftOffset;
- [rightRulerClipView setFrame:&tempRect];
-
- /* scroll the views to the same position as they were in the tiledScrollView */
- [mainView scrollPoint:(const NXPoint *)&mainVisiblePoint];
-
- /* set the frame of the PrintView to be big enough to show everything */
- clipFrame.origin = oldMainFrame.origin;
- clipFrame.origin.x = 0;
- clipFrame.size = oldMainClipBounds.size;
- clipFrame.size.height += (oldTopRect.size.height + oldBottomRect.size.height);
- clipFrame.size.width += (oldLeftRect.size.width + oldRightRect.size.width);
- [printView setFrame:&clipFrame];
-
- return printView;
- }
-
- - printVisible:sender
- {
- if (rulersOn) {
- [window disableFlushWindow];
- [self createPrintView];
- [printView printPSCode:self];
- // mainPrintClipView was setup in docView
- [self setDocView:[mainPrintClipView docView]];
- // return to original views
- [self addSubview:[bottomRuler superview]];
- [self addSubview:[topRuler superview]];
- [self addSubview:[leftRuler superview]];
- [self addSubview:[rightRuler superview]];
- // restore old positions
- [[bottomRuler superview] setFrame:&oldBottomRect];
- [[topRuler superview] setFrame:&oldTopRect];
- [[leftRuler superview] setFrame:&oldLeftRect];
- [[rightRuler superview] setFrame:&oldRightRect];
-
- /* return the view to the origin it was at */
- /* except change the scroll point slightly */
- /* so that the scrollers will update correctly */
- if (rulersOn)
- mainVisiblePoint.y += 1;
- else
- mainVisiblePoint.y -= 1;
- [[self docView] scrollPoint:(const NXPoint *)&mainVisiblePoint];
- [window reenableFlushWindow];
- }
- else
- // remove the message to superview to print the entire main view
- // rather than just the visible portion
- [[[self docView] superview] printPSCode:self];
- return self;
- }
-
- - writeToStream:(NXStream *)stream
- {
- NXRect printRect;
-
- if (rulersOn) {
- [window disableFlushWindow];
- [self createPrintView];
- [printView getFrame:&printRect];
- [printView copyPSCodeInside:(const NXRect *)&printRect to:(NXStream *)stream];
- [self setDocView:[mainPrintClipView docView]];
- // return to original views
- [self addSubview:[bottomRuler superview]];
- [self addSubview:[topRuler superview]];
- [self addSubview:[leftRuler superview]];
- [self addSubview:[rightRuler superview]];
- // restore old positions
- [[bottomRuler superview] setFrame:&oldBottomRect];
- [[topRuler superview] setFrame:&oldTopRect];
- [[leftRuler superview] setFrame:&oldLeftRect];
- [[rightRuler superview] setFrame:&oldRightRect];
-
- /* return the view to the origin it was at */
- /* except change the scroll point slightly */
- /* so that the scrollers will update correctly */
- if (rulersOn)
- mainVisiblePoint.y += 1;
- else
- mainVisiblePoint.y -= 1;
- [[self docView] scrollPoint:(const NXPoint *)&mainVisiblePoint];
- [window reenableFlushWindow];
- }
- else {
- [[[self docView] superview] getBounds:&printRect];
- [[[self docView] superview] copyPSCodeInside:(const NXRect *)&printRect
- to:(NXStream *)stream];
- }
- return self;
- }
-
- @end
-