home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1995 August / NEBULA.mdf / SourceCode / BrainRulers / Source / RuledScrollView.m < prev    next >
Encoding:
Text File  |  1994-06-07  |  27.8 KB  |  884 lines

  1. // RuledScrollView.m
  2. // RuledScrollView is intended as a general purpose class to make it
  3. // easy to add all kinds of rulers to any view.  This class is an 
  4. // extension of the tiledScrollView class, from "ScrollDoodScroll" 
  5. // (by Jayson Adams, NeXT Developer Support Team)
  6. // This class is intended to be widely useful without needing to
  7. // modify (or understand) its code, so it provides methods to setup 
  8. // the mainView and its rulerViews, rather than hardcoding the setup.
  9. // Kevin Brain (ksbrain@zeus.UWaterloo.ca)
  10.  
  11. #import <appkit/ClipView.h>
  12. #import <appkit/TextField.h>
  13. #import <appkit/Panel.h>
  14.  
  15. #import "RuledScrollView.h"
  16.  
  17. // Macro to print a rect (for debugging)
  18. #define PRINTRECT(string,rect) { \
  19.     printf(" %s x = %4.1f y = %4.1f width = %4.1f height = %4.1f\n",string, \
  20.     NX_X(&(rect)), NX_Y(&(rect)), NX_WIDTH(&(rect)), NX_HEIGHT(&(rect))); \
  21.     }
  22.  
  23. @implementation RuledScrollView
  24.  
  25. /* instance methods */
  26.  
  27. - initFrame:(NXRect *)theFrame
  28. {
  29.     [super initFrame:theFrame];
  30.     rulersOn = YES;
  31.     topRuler = NULL;
  32.     bottomRuler = NULL;
  33.     leftRuler = NULL;
  34.     rightRuler = NULL;
  35.     primaryRulers = TOPBOTTOM;
  36.  
  37.     return self;
  38. }
  39.  
  40. - free
  41. {
  42.     if (leftRuler) {
  43.         [leftRuler free];
  44.         [leftRulerClipView free];
  45.         }
  46.     if (rightRuler) {
  47.         [rightRuler free];
  48.         [rightRulerClipView free];
  49.         }
  50.     if (topRuler) {
  51.         [topRuler free];
  52.         [topRulerClipView free];
  53.         }
  54.     if (bottomRuler) {
  55.         [bottomRuler free];
  56.         [bottomRulerClipView free];
  57.         }
  58.     if (bottomLeftStub) {
  59.         [bottomLeftStub free];
  60.         }
  61.     if (topLeftStub) {
  62.         [topLeftStub free];
  63.         }
  64.     if (bottomRightStub) {
  65.         [bottomRightStub free];
  66.         }
  67.     if (topRightStub) {
  68.         [topRightStub free];
  69.         }
  70.  
  71.     return [super free];
  72. }
  73.  
  74. - setLeftRuler:anObject
  75.     {
  76.         leftRuler = anObject;
  77.         [self addRulerView:leftRuler toEdge:LEFTEDGE];
  78.          return self;
  79.     }
  80.  
  81. - setRightRuler:anObject
  82.     {
  83.         rightRuler = anObject;
  84.         [self addRulerView:rightRuler toEdge:RIGHTEDGE];
  85.          return self;
  86.     }
  87.  
  88. - setTopRuler:anObject
  89.     {
  90.         topRuler = anObject;
  91.         [self addRulerView:topRuler toEdge:TOPEDGE];
  92.          return self;
  93.     }
  94.  
  95. - setBottomRuler:anObject
  96.     {
  97.         bottomRuler = anObject;
  98.         [self addRulerView:bottomRuler toEdge:BOTTOMEDGE];
  99.          return self;
  100.     }
  101.  
  102. - setBottomLeftStub:anObject
  103.     {
  104.         bottomLeftStub = anObject;
  105.         [self addStubView:anObject toCorner: BOTTOMLEFTCORNER];
  106.          return self;
  107.     }
  108.  
  109. - setTopLeftStub:anObject
  110.     {
  111.         topLeftStub = anObject;
  112.         [self addStubView:anObject toCorner: TOPLEFTCORNER];
  113.          return self;
  114.     }
  115.  
  116. - setBottomRightStub:anObject
  117.     {
  118.         bottomRightStub = anObject;
  119.         [self addStubView:anObject toCorner: BOTTOMRIGHTCORNER];
  120.          return self;
  121.     }
  122.  
  123. - setTopRightStub:anObject
  124.     {
  125.         topRightStub = anObject;
  126.         [self addStubView:anObject toCorner: TOPRIGHTCORNER];
  127.          return self;
  128.     }
  129.  
  130. - addRulerView:(Ruler *)theView toEdge:(int)edge
  131. {
  132.     NXRect    scaleViewRect;
  133.     ClipView *scaleClipView;
  134.     
  135.   /* reset the origin of rulers created in nibs */
  136.     [theView getFrame:&scaleViewRect];
  137.     scaleViewRect.origin.x = 0.0;
  138.     scaleViewRect.origin.y = 0.0;
  139.     [theView setFrame:&scaleViewRect];
  140.  
  141.     NXSetRect(&scaleViewRect,0,0,0,0);   
  142.   /* make a clipView to hold the scale view passed in
  143.    * (we'll adjust its size & position in tile) */
  144.     scaleClipView = [[ClipView alloc] initFrame:&scaleViewRect];
  145.     [scaleClipView setDocView:theView];
  146.     [self addSubview:scaleClipView];
  147.     
  148.     switch (edge) {
  149.         case LEFTEDGE:
  150.             // actually, I think we leak here if you add the same ruler twice
  151.             // but I'm about to leave on holidays, so I can't be 
  152.             // bothered to change it now.  Next version:-)
  153.             if (leftRuler && (leftRuler != theView)) {    // the view 
  154.                 [leftRuler free];
  155.                 [leftRulerClipView free];
  156.                 }
  157.             leftRuler = theView;
  158.             leftRulerClipView = scaleClipView;
  159.             if([leftRuler respondsTo:@selector(setOrientation:)])
  160.                 [leftRuler setOrientation:VERTICAL];    // default is horizontal
  161.             break;
  162.         case RIGHTEDGE:
  163.             if (rightRuler && (rightRuler != theView)) {
  164.                 [rightRuler free];
  165.                 [rightRulerClipView free];
  166.                 }
  167.             rightRuler = theView;
  168.             rightRulerClipView = scaleClipView;
  169.             if([rightRuler respondsTo:@selector(setOrientation:)])
  170.                 [rightRuler setOrientation:VERTICAL];    // default is horizontal
  171.             break;
  172.         case TOPEDGE:
  173.             if (topRuler && (topRuler != theView)) {
  174.                 [topRuler free];
  175.                 [topRulerClipView free];
  176.                 }
  177.             topRuler = theView;
  178.             topRulerClipView = scaleClipView;
  179.             break;
  180.         case BOTTOMEDGE:
  181.             if (bottomRuler && (bottomRuler != theView)) {
  182.                 [bottomRuler free];
  183.                 [bottomRulerClipView free];
  184.                 }
  185.             bottomRuler = theView;
  186.             bottomRulerClipView = scaleClipView;
  187.             break;
  188.         }
  189.     rulerVisible[edge] = YES;    // turn this ruler on by default
  190.     return self;
  191. }
  192.  
  193. - addStubView:(View *)theView toCorner:(int)corner
  194. {
  195.     switch (corner) {
  196.         case BOTTOMLEFTCORNER:
  197.             if (bottomLeftStub && (bottomLeftStub != theView)) 
  198.                 [bottomLeftStub free];
  199.             bottomLeftStub = theView;
  200.             break;
  201.         case TOPLEFTCORNER:
  202.             if (topLeftStub && (topLeftStub != theView)) 
  203.                 [topLeftStub free];
  204.             topLeftStub = theView;
  205.             break;
  206.         case BOTTOMRIGHTCORNER:
  207.             if (bottomRightStub && (bottomRightStub != theView)) 
  208.                 [bottomRightStub free];
  209.             bottomRightStub = theView;
  210.             break;
  211.         case TOPRIGHTCORNER:
  212.             if (topRightStub && (topRightStub != theView)) 
  213.                 [topRightStub free];
  214.             topRightStub = theView;
  215.             break;
  216.         }
  217.  
  218.     [self addSubview:theView];
  219.     return self;
  220. }
  221.  
  222. - sliceEdge:(int)theEdge forRuler:theRuler inClipView:theClipView
  223. // private method that cuts a slice from the contentView to make room for a ruler
  224. {
  225.     NXRect    contentViewRect, scaleRect, scaleClipRect;
  226.     NXRect    cvBoundsRect;
  227.  
  228.     // get bounds of contentView so we can reset it after setting frame
  229.     [contentView getBounds:&cvBoundsRect];
  230.  
  231.     [contentView getFrame:&contentViewRect];
  232.     [theRuler getFrame:&scaleRect];
  233.     if ((theEdge == LEFTEDGE) || (theEdge == RIGHTEDGE))
  234.         NXDivideRect(&contentViewRect, &scaleClipRect, NX_WIDTH(&scaleRect), theEdge);
  235.     else
  236.         NXDivideRect(&contentViewRect, &scaleClipRect, NX_HEIGHT(&scaleRect), theEdge);
  237.     [theClipView setFrame:&scaleClipRect];        // invokes reflectScroll:
  238.  
  239.     // setting contentView's frame changes contentView bounds then invokes reflectScroll:
  240.     [contentView setFrame:&contentViewRect];
  241.  
  242.     // reset bounds of contentView mangled by setting frame
  243.     [self scrollClip:contentView to:(NXPoint *)&cvBoundsRect.origin];
  244.         
  245.     return self;
  246. }
  247.  
  248. - tile
  249. /*
  250.  * tile gets called whenever the scrollView changes size.  Its job is to resize
  251.  * all of the scrollView's "tiled" views (scrollers, contentView and any other
  252.  * views we might want to place in the scrollView's bounds).
  253.  */
  254. {
  255.     NXRect    viewRect, scrollerRect, tempRect, cvBounds, newCVBounds;
  256.     NXRect    stubRect, rulerClipRect, otherRulerRect, docViewRect;
  257.     float    tempFloat=0.0,distanceFromEdge;
  258.     
  259.     [contentView getBounds:&cvBounds];
  260.     [[self docView] getBounds:&docViewRect];
  261.  
  262.   /* resize and arrange the scrollers and contentView as usual */ 
  263.     [super tile];        // invokes reflectScroll:
  264.  
  265.     // If the scroller knob is closer to the edge than the width or height
  266.     // of the ruler views, the tile method causes the contentView bounds
  267.     // to be incorrectly changed.  After many frustrating hours of work,
  268.     // I came up with the following code to correct for this...
  269.     
  270.     [contentView getBounds:&newCVBounds];
  271.     NXSetRect(&otherRulerRect,0,0,0,0);
  272.     [[self leftRuler] getFrame:&otherRulerRect];
  273.     if ([self isRulerVisible:LEFTEDGE])
  274.         tempFloat = otherRulerRect.size.width;
  275.     NXSetRect(&otherRulerRect,0,0,0,0);
  276.     [[self rightRuler] getFrame:&otherRulerRect];
  277.     if ([self isRulerVisible:RIGHTEDGE])
  278.         tempFloat += otherRulerRect.size.width;
  279.     distanceFromEdge = docViewRect.size.width - (cvBounds.origin.x+cvBounds.size.width);
  280.     // if entire width of docView was showing, don't adjust
  281.     if (cvBounds.size.width > docViewRect.size.width) 
  282.         distanceFromEdge = tempFloat;
  283.     if ((distanceFromEdge < tempFloat) && (newCVBounds.size.width < docViewRect.size.width))
  284.         newCVBounds.origin.x += (tempFloat-distanceFromEdge);
  285.     
  286.     NXSetRect(&otherRulerRect,0,0,0,0);
  287.     [[self topRuler] getFrame:&otherRulerRect];
  288.     if ([self isRulerVisible:TOPEDGE])
  289.         tempFloat = otherRulerRect.size.height;
  290.     NXSetRect(&otherRulerRect,0,0,0,0);
  291.     [[self bottomRuler] getFrame:&otherRulerRect];
  292.     if ([self isRulerVisible:BOTTOMEDGE])
  293.         tempFloat += otherRulerRect.size.height;
  294.     distanceFromEdge = docViewRect.size.height - (cvBounds.origin.y+cvBounds.size.height);
  295.     // if entire height of docView was showing, don't adjust
  296.     if (cvBounds.size.height > docViewRect.size.height) 
  297.         distanceFromEdge = tempFloat;
  298.     if ((distanceFromEdge < tempFloat) && (newCVBounds.size.height < docViewRect.size.height))
  299.         newCVBounds.origin.y += (tempFloat-distanceFromEdge);
  300.     
  301.     // correct contentView Bounds
  302.     [self scrollClip:contentView to:(NXPoint *)&newCVBounds.origin];
  303.  
  304.   /* cut a slice from the contentView to make room for each scaleView */
  305.  
  306.     if (primaryRulers == TOPBOTTOM) {
  307.         if(topRuler && rulerVisible[TOPEDGE]) { 
  308.             if ([self isFlipped])
  309.                 [self sliceEdge:(int)BOTTOMEDGE forRuler:topRuler inClipView:topRulerClipView];
  310.             else
  311.                 [self sliceEdge:(int)TOPEDGE forRuler:topRuler inClipView:topRulerClipView];
  312.             }
  313.  
  314.         if(bottomRuler && rulerVisible[BOTTOMEDGE]) { 
  315.             if ([self isFlipped])
  316.                 [self sliceEdge:(int)TOPEDGE forRuler:bottomRuler inClipView:bottomRulerClipView];
  317.             else
  318.                 [self sliceEdge:(int)BOTTOMEDGE forRuler:bottomRuler 
  319.                     inClipView:bottomRulerClipView];
  320.             }
  321.         if(leftRuler && rulerVisible[LEFTEDGE])
  322.             [self sliceEdge:(int)LEFTEDGE forRuler:leftRuler inClipView:leftRulerClipView];
  323.         if(rightRuler && rulerVisible[RIGHTEDGE])
  324.             [self sliceEdge:(int)RIGHTEDGE forRuler:rightRuler inClipView:rightRulerClipView];
  325.  
  326.         // Add stub views (now that edge views are present)
  327.         if(topRuler && rulerVisible[TOPEDGE]) { 
  328.             if (topLeftStub) {
  329.                 [leftRulerClipView getFrame:&otherRulerRect];
  330.                 [topRulerClipView getFrame:&rulerClipRect];
  331.                 NXDivideRect(&rulerClipRect, &stubRect, otherRulerRect.size.width, LEFTEDGE);
  332.                 [topRulerClipView setFrame:&rulerClipRect];
  333.                 [topLeftStub setFrame:&stubRect];
  334.                 }
  335.             if (topRightStub) {
  336.                 [rightRulerClipView getFrame:&otherRulerRect];
  337.                 [topRulerClipView getFrame:&rulerClipRect];
  338.                 NXDivideRect(&rulerClipRect, &stubRect, otherRulerRect.size.width, RIGHTEDGE);
  339.                 [topRulerClipView setFrame:&rulerClipRect];
  340.                 [topRightStub setFrame:&stubRect];
  341.                 }
  342.             }
  343.         if(bottomRuler && rulerVisible[BOTTOMEDGE]) { 
  344.             if (bottomLeftStub) {
  345.                 [leftRulerClipView getFrame:&otherRulerRect];
  346.                 [bottomRulerClipView getFrame:&rulerClipRect];
  347.                 NXDivideRect(&rulerClipRect, &stubRect, otherRulerRect.size.width, LEFTEDGE);
  348.                 [bottomRulerClipView setFrame:&rulerClipRect];
  349.                 [bottomLeftStub setFrame:&stubRect];
  350.                 }
  351.             if (bottomRightStub) {
  352.                 [rightRulerClipView getFrame:&otherRulerRect];
  353.                 [bottomRulerClipView getFrame:&rulerClipRect];
  354.                 NXDivideRect(&rulerClipRect, &stubRect, otherRulerRect.size.width, RIGHTEDGE);
  355.                 [bottomRulerClipView setFrame:&rulerClipRect];
  356.                 [bottomRightStub setFrame:&stubRect];
  357.                 }
  358.             }
  359.         }
  360.     else {
  361.         if(leftRuler && rulerVisible[LEFTEDGE])
  362.             [self sliceEdge:(int)LEFTEDGE forRuler:leftRuler inClipView:leftRulerClipView];
  363.         if(rightRuler && rulerVisible[RIGHTEDGE]) 
  364.             [self sliceEdge:(int)RIGHTEDGE forRuler:rightRuler inClipView:rightRulerClipView];
  365.         if(topRuler && rulerVisible[TOPEDGE]) { 
  366.             if ([self isFlipped])
  367.                 [self sliceEdge:(int)BOTTOMEDGE forRuler:topRuler inClipView:topRulerClipView];
  368.             else
  369.                 [self sliceEdge:(int)TOPEDGE forRuler:topRuler inClipView:topRulerClipView];
  370.             }
  371.         if(bottomRuler && rulerVisible[BOTTOMEDGE]) { 
  372.             if ([self isFlipped])
  373.                 [self sliceEdge:(int)TOPEDGE forRuler:bottomRuler inClipView:bottomRulerClipView];
  374.             else
  375.                 [self sliceEdge:(int)BOTTOMEDGE forRuler:bottomRuler 
  376.                     inClipView:bottomRulerClipView];
  377.             }
  378. /****************************************************************************/
  379. /*  Code to tile StubViews when (primaryRulers != TOPBOTTOM) still missing  */
  380. /****************************************************************************/
  381.         }
  382.  
  383.     // The following imbeds a view (normally a button) in the horizontal scroller 
  384.     // if the hScrollerRightEmbeddedView instance variable is connected to some view (in IB)
  385.     // A textfield with Courier-Medium size 10 font will fit into the horizontal scroller.
  386.     if (hScrollerRightEmbeddedView) {
  387.         if ([hScrollerRightEmbeddedView superview] != self) {
  388.             [self addSubview:hScrollerRightEmbeddedView];
  389.             }
  390.             
  391.         [hScrollerRightEmbeddedView getFrame:&tempRect];
  392.         // now make the hScroller smaller and stick the popupList next to it 
  393.         [hScroller getFrame:&scrollerRect];
  394.         // width stored during init
  395.         NXDivideRect(&scrollerRect, &viewRect, tempRect.size.width, RIGHTEDGE);
  396.         // Need to force width back to original button width since the above function
  397.         // will not set viewRect.size.width to tempRect.size.width when the
  398.         // tile method is evoked before the correct size of the mainView is set
  399.         viewRect.size.width = tempRect.size.width;
  400.         [hScroller setFrame:&scrollerRect];
  401.         NXInsetRect(&viewRect, 0, 1.0);
  402.         [hScrollerRightEmbeddedView setFrame:&viewRect];
  403.         }
  404.  
  405.     // Do the same as above for a possible second view in the horizontal scroller 
  406.     if (hScrollerLeftEmbeddedView) {
  407.         if ([hScrollerLeftEmbeddedView superview] != self) {
  408.             [self addSubview:hScrollerLeftEmbeddedView];
  409.             }
  410.         [hScrollerLeftEmbeddedView getFrame:&tempRect];
  411.         [hScroller getFrame:&scrollerRect];
  412.         NXDivideRect(&scrollerRect, &viewRect, tempRect.size.width, RIGHTEDGE);
  413.         viewRect.size.width = tempRect.size.width;
  414.         [hScroller setFrame:&scrollerRect];
  415.         NXInsetRect(&viewRect, 0, 1.0);
  416.         [hScrollerLeftEmbeddedView setFrame:&viewRect];
  417.         }
  418.  
  419.     // Do the same as above for a view in the vertical scroller 
  420.     if (vScrollerTopEmbeddedView) {
  421.         if ([vScrollerTopEmbeddedView superview] != self) {
  422.             [self addSubview:vScrollerTopEmbeddedView];
  423.             }
  424.         [vScrollerTopEmbeddedView getFrame:&tempRect];
  425.         [vScroller getFrame:&scrollerRect];
  426.         if ([self isFlipped])
  427.             NXDivideRect(&scrollerRect, &viewRect, tempRect.size.height, BOTTOMEDGE);
  428.         else
  429.             NXDivideRect(&scrollerRect, &viewRect, tempRect.size.height, TOPEDGE);
  430.         viewRect.size.height = tempRect.size.height;
  431.         [vScroller setFrame:&scrollerRect];
  432.         NXInsetRect(&viewRect, 1.0, 0);
  433.         [vScrollerTopEmbeddedView setFrame:&viewRect];
  434.         }
  435.  
  436.     // Do the same as above for a possible second view in the vertical scroller 
  437.     if (vScrollerBottomEmbeddedView) {
  438.         if ([vScrollerBottomEmbeddedView superview] != self) {
  439.             [self addSubview:vScrollerBottomEmbeddedView];
  440.             }
  441.         [vScrollerBottomEmbeddedView getFrame:&tempRect];
  442.         [vScroller getFrame:&scrollerRect];
  443.         if ([self isFlipped])
  444.             NXDivideRect(&scrollerRect, &viewRect, tempRect.size.height, BOTTOMEDGE);
  445.         else
  446.             NXDivideRect(&scrollerRect, &viewRect, tempRect.size.height, TOPEDGE);
  447.         viewRect.size.height = tempRect.size.height;
  448.         [vScroller setFrame:&scrollerRect];
  449.         NXInsetRect(&viewRect, 1.0, 0);
  450.         [vScrollerBottomEmbeddedView setFrame:&viewRect];
  451.         }
  452.  
  453.     // save the size of the docView for setSizeIfNeeded
  454.     [[self docView]    getFrame:&oldRect];
  455.  
  456.     return self;
  457. }
  458.  
  459. - reflectScroll:cView
  460. // does not affect contentView bounds...
  461. /*
  462.  * We only reflect scroll in the contentView, not the scale views.
  463.  */
  464. {
  465.     return [super reflectScroll:contentView];
  466. }
  467.  
  468. - scrollClip:aClipView to:(NXPoint *)aPoint
  469. {
  470.     NXPoint    colOrigin,newPoint;
  471.     NXRect    colBounds;
  472.     
  473.     newPoint = *aPoint;
  474.     
  475.   // if it's not the contentView, adjust the point being scrolled to so that
  476.   // it doesn't scroll the contentView except in the direction of the ruler
  477.     [contentView getBounds:&colBounds];
  478.     if (aClipView != contentView)
  479.         if(([aClipView docView] == leftRuler) || ([aClipView docView] == rightRuler))
  480.             newPoint.x = colBounds.origin.x;
  481.         else
  482.             newPoint.y = colBounds.origin.y;
  483.     
  484.   /* turn off drawing (to the screen) */
  485.     [window disableFlushWindow];
  486.     
  487.   /* scroll the contentView to the new origin */
  488.     [contentView rawScroll:&newPoint];
  489.     
  490.   /* compute new origin for the leftRulerView (don't let it scroll horizontally) */
  491.     [leftRulerClipView getBounds:&colBounds];
  492.     colOrigin.x = colBounds.origin.x;
  493.     colOrigin.y = newPoint.y;
  494.     [leftRulerClipView rawScroll:&colOrigin];    // scroll the scale view to that point
  495.     
  496.   /* compute new origin for the rightRulerView (don't let it scroll horizontally) */
  497.     [rightRulerClipView getBounds:&colBounds];
  498.     colOrigin.x = colBounds.origin.x;
  499.     colOrigin.y = newPoint.y;
  500.     [rightRulerClipView rawScroll:&colOrigin];    // scroll the scale view to that point
  501.     
  502.   /* compute new origin for the topRulerView (don't let it scroll vertically) */
  503.     [topRulerClipView getBounds:&colBounds];
  504.     colOrigin.x = newPoint.x ;
  505.     colOrigin.y = colBounds.origin.y;
  506.     [topRulerClipView rawScroll:&colOrigin];    // scroll the scale view to that point
  507.     
  508.   /* compute new origin for the bottomRulerView (don't let it scroll vertically) */
  509.     [bottomRulerClipView getBounds:&colBounds];
  510.     colOrigin.x = newPoint.x ;
  511.     colOrigin.y = colBounds.origin.y;
  512.     [bottomRulerClipView rawScroll:&colOrigin];    // scroll the scale view to that point
  513.     
  514.  /* send results to screen */
  515.     [[window reenableFlushWindow] flushWindow];
  516.     
  517.     return self;
  518. }
  519.  
  520. - setSizeIfNeeded
  521. {
  522.     NXRect    theFrame;
  523.  
  524.     [[self docView]    getFrame:&theFrame];
  525.     if ((theFrame.size.width != oldRect.size.width) || 
  526.             (theFrame.size.height != oldRect.size.height))
  527.         [self setSize];
  528.     return self;
  529. }
  530.  
  531. - setSize
  532. // This method must be invoked whenever the size 
  533. // of the mainView is changed.
  534. {
  535.     NXRect    theFrame;
  536.  
  537.     [window disableDisplay];
  538.     if (topRuler) 
  539.         [topRuler setSize];
  540.     if (bottomRuler) 
  541.         [bottomRuler setSize];
  542.     if (leftRuler) 
  543.         [leftRuler setSize];
  544.     if (rightRuler) 
  545.         [rightRuler setSize];
  546.     [self resizeSubviews:(const NXSize *)&theFrame.size];
  547.     [[window reenableDisplay] displayIfNeeded];
  548.  
  549.     return self;
  550. }
  551.  
  552. - showRuler:(int)whichRuler;
  553. {
  554.     rulerVisible[whichRuler] = YES;
  555.     switch (whichRuler) {
  556.         case TOPEDGE:
  557.             if (topRulerClipView) {
  558.                 [self addSubview:topRulerClipView];
  559.                 if (leftRulerClipView && rulerVisible[LEFTEDGE]&& topLeftStub)
  560.                     [self addSubview:topLeftStub];
  561.                 if (rightRulerClipView && rulerVisible[RIGHTEDGE]&& topRightStub)
  562.                     [self addSubview:topRightStub];
  563.                 }
  564.             break;
  565.         case BOTTOMEDGE:
  566.             if (bottomRulerClipView) {
  567.                 [self addSubview:bottomRulerClipView];
  568.                 if (leftRulerClipView && rulerVisible[LEFTEDGE]&& bottomLeftStub)
  569.                     [self addSubview:bottomLeftStub];
  570.                 if (rightRulerClipView && rulerVisible[RIGHTEDGE]&& bottomRightStub)
  571.                     [self addSubview:bottomRightStub];
  572.                 }
  573.             break;
  574.         case LEFTEDGE:
  575.             if (leftRulerClipView) {
  576.                 [self addSubview:leftRulerClipView];
  577.                 if (topRulerClipView && rulerVisible[TOPEDGE]&& topLeftStub)
  578.                     [self addSubview:topLeftStub];
  579.                 if (bottomRulerClipView && rulerVisible[BOTTOMEDGE]&& bottomLeftStub)
  580.                     [self addSubview:bottomLeftStub];
  581.                 }
  582.             break;
  583.         case RIGHTEDGE:
  584.             if (rightRulerClipView) {
  585.                 [self addSubview:leftRulerClipView];
  586.                 if (topRulerClipView && rulerVisible[TOPEDGE]&& topRightStub)
  587.                     [self addSubview:topRightStub];
  588.                 if (bottomRulerClipView && rulerVisible[BOTTOMEDGE]&& bottomRightStub)
  589.                     [self addSubview:bottomRightStub];
  590.                 }
  591.             break;
  592.         }
  593.  
  594.     return self;
  595. }
  596.  
  597. - hideRuler:(int)whichRuler;
  598. // this should be followed promptly with a setSize
  599. {
  600.     rulerVisible[whichRuler] = NO;
  601.     switch (whichRuler) {
  602.         case TOPEDGE:
  603.             if (topRulerClipView)
  604.                 [topRulerClipView removeFromSuperview];
  605.             if (topLeftStub)
  606.                 [topLeftStub removeFromSuperview];
  607.             if (topRightStub)
  608.                 [topRightStub removeFromSuperview];
  609.             break;
  610.         case BOTTOMEDGE:
  611.             if (bottomRulerClipView)
  612.                 [bottomRulerClipView removeFromSuperview];
  613.             if (bottomLeftStub)
  614.                 [bottomLeftStub removeFromSuperview];
  615.             if (bottomRightStub)
  616.                 [bottomRightStub removeFromSuperview];
  617.             break;
  618.         case LEFTEDGE:
  619.             if (leftRulerClipView)
  620.                 [leftRulerClipView removeFromSuperview];
  621.             if (topLeftStub)
  622.                 [topLeftStub removeFromSuperview];
  623.             if (bottomLeftStub)
  624.                 [bottomLeftStub removeFromSuperview];
  625.             break;
  626.         case RIGHTEDGE:
  627.             if (rightRulerClipView)
  628.                 [rightRulerClipView removeFromSuperview];
  629.             if (bottomRightStub)
  630.                 [bottomRightStub removeFromSuperview];
  631.             if (topRightStub)
  632.                 [topRightStub removeFromSuperview];
  633.             break;
  634.         }
  635.  
  636.     return self;
  637. }
  638.  
  639. - (BOOL)isRulerVisible:(int)whichRuler 
  640.     return rulerVisible[whichRuler];
  641. }
  642.  
  643. - topRuler { return topRuler; }
  644.  
  645. - bottomRuler { return bottomRuler; }
  646.  
  647. - leftRuler { return leftRuler; }
  648.  
  649. - rightRuler { return rightRuler; }
  650.  
  651. - setPrimaryRulers:(int)orientation
  652. {
  653.     primaryRulers = orientation;
  654.     return self;
  655. }
  656.  
  657. - bottomLeftStub { return bottomLeftStub; }
  658.  
  659. - topLeftStub { return topLeftStub; }
  660.  
  661. - bottomRightStub { return bottomRightStub; }
  662.  
  663. - topRightStub { return topRightStub; }
  664.  
  665. - (int)primaryRulers { return primaryRulers; }
  666.  
  667. - getMinSize:(NXSize *)theSize
  668. {
  669.     NXRect    contentViewRect,ruledScrollViewRect;
  670.  
  671.     [contentView getFrame:&contentViewRect];
  672.     [self getFrame:&ruledScrollViewRect];
  673.     theSize->width = ruledScrollViewRect.size.width - contentViewRect.size.width+1;
  674.     theSize->height = ruledScrollViewRect.size.height - contentViewRect.size.height+1;
  675.  
  676.     return    self;
  677. }
  678.  
  679. /* methods for printing the visible view */ 
  680. /*---------------------------------------*/
  681. - createPrintView
  682. // Creates a view for printing the visible part of the trace
  683. // We do this by adding the rulerViews' ClipViews as subviews to a View object
  684. // (printView) which is allocated once and added as a subview of
  685. // an offscreen window.  When we are done with them, we return the 
  686. // ClipViews to their former position as subviews of the RuledScrollView object
  687. // (self).  The mainView itself is also taken (rather than its ClipView)
  688. // and added to another ClipView object (mainPrintClipView), since it proved
  689. // troublesome to return the mainView (docView) itself when finished with it.
  690.  
  691. {
  692.     float    leftOffset;
  693.     NXRect    tempRect, clipFrame;
  694.     NXRect    oldMainClipBounds, oldMainFrame;
  695.     
  696.     if (!printWindow) {    // create window & setup mainPrintClipView first time through
  697.                         // note that size is fixed at 1120 X 832 
  698.         NXSetRect(&tempRect, (NXCoord) 0, (NXCoord) 0, (NXCoord) 1120, (NXCoord) 832);
  699.         /* create a window for printView */
  700.         printWindow = [[Window alloc] initContent:(const NXRect *)&tempRect
  701.             style:(int)NX_PLAINSTYLE    // no title bar and frame
  702.             backing:(int)NX_BUFFERED
  703.             buttonMask:(int)0    // no controls in title bar and frame 
  704.             defer:(BOOL)NO];
  705.         NXSetRect(&tempRect, (NXCoord) 0, (NXCoord) 0, (NXCoord) 0, (NXCoord) 0);
  706.         printView = [[View alloc] initFrame:&tempRect];
  707.         if ([self isFlipped]) [printView setFlipped:YES];
  708.         mainPrintClipView = [[ClipView alloc] initFrame:&tempRect];
  709.         [[printWindow contentView] addSubview:printView];
  710.         }
  711.                 
  712.     /* set pointer to the main View */
  713.     mainView = [self docView];
  714.  
  715.     /* get translation information (which part of main view is visible) */
  716.     /* we will scroll the main View in its new clipView (a subview of */
  717.     /* PrintView) by sending a scrollPoint: message to it with the point */ 
  718.     /* (main View's clipView's bounds.origin) - (main View's Frame.origin) */
  719.     [[mainView superview] getBounds:&oldMainClipBounds];
  720.     [mainView getFrame:&oldMainFrame];
  721.     mainVisiblePoint.x = oldMainClipBounds.origin.x - oldMainFrame.origin.x;
  722.     mainVisiblePoint.y = oldMainClipBounds.origin.y - oldMainFrame.origin.y;
  723.  
  724.     // put mainPrintClipView in the same place as it is in ruledScrollView
  725.     [[mainView superview] getFrame:&oldMainClipRect];
  726.  
  727.     /* get current locations of clipviews */
  728. //    NXSetRect(&oldBottomRect,0,0,0,0);
  729. //    NXSetRect(&oldTopRect,0,0,0,0);
  730. //    NXSetRect(&oldLeftRect,0,0,0,0);
  731. //    NXSetRect(&oldRightRect,0,0,0,0);
  732.     [bottomRulerClipView getFrame:&oldBottomRect];
  733.     [topRulerClipView getFrame:&oldTopRect];
  734.     [leftRulerClipView getFrame:&oldLeftRect];
  735.     [rightRulerClipView getFrame:&oldRightRect];
  736.  
  737.     /* If the mainView itself is smaller (ie., there is some */
  738.     /* of the tiledScrollView's background showing), reduce the*/
  739.     /* size so that none of the background shows */
  740. //    if (oldMainFrame.size.height < clipFrame.size.height)
  741. //        clipFrame.size.height = signalFrame.size.height;
  742. //    if (oldMainFrame.size.width < clipFrame.size.width)
  743. //        clipFrame.size.width = signalFrame.size.width;
  744. //    [signalClipView setFrame:&clipFrame];
  745.     
  746. //    clipFrame.origin.x = 0;
  747. //    clipFrame.size.width = leftRuleFrame.size.width;
  748. //    [scaleClipView setFrame:&clipFrame];
  749.     
  750.     /* temporarily 'steal' the clipviews holding the rulers and the mainView */
  751.     /* - They are given back in printVisible: */
  752.     [mainPrintClipView setDocView:mainView];
  753.     [printView addSubview:mainPrintClipView];
  754.  
  755.     if (bottomRuler)
  756.         [printView addSubview:bottomRulerClipView];
  757.     if (topRuler)
  758.         [printView addSubview:topRulerClipView];
  759.     if (leftRuler)
  760.         [printView addSubview:leftRulerClipView];
  761.     if (rightRuler) {
  762.         [printView addSubview:rightRulerClipView];
  763.         }
  764.  
  765.     if (vScroller) { 
  766.         [vScroller getFrame:&tempRect];
  767.         leftOffset = (tempRect.size.width+4);    // 4 is the width of the borders
  768.         }
  769.     else 
  770.         leftOffset = 0;
  771.     // Now resize the clipviews
  772.     // subtract width of the left vertical scroller since we don't draw it
  773.     tempRect = oldMainClipRect;
  774.     tempRect.origin.x -= leftOffset;    
  775.     [mainPrintClipView setFrame:&tempRect];
  776.  
  777.     tempRect = oldBottomRect;
  778.     tempRect.origin.x -= leftOffset;
  779.     [bottomRulerClipView setFrame:&tempRect];
  780.  
  781.     tempRect = oldTopRect;
  782.     tempRect.origin.x -= leftOffset;
  783.     [topRulerClipView setFrame:&tempRect];
  784.  
  785.     tempRect = oldLeftRect;
  786.     tempRect.origin.x -= leftOffset;
  787.     [leftRulerClipView setFrame:&tempRect];
  788.  
  789.     tempRect = oldRightRect;
  790.     tempRect.origin.x -= leftOffset;
  791.     [rightRulerClipView setFrame:&tempRect];
  792.  
  793.     /* scroll the views to the same position as they were in the tiledScrollView */
  794.     [mainView scrollPoint:(const NXPoint *)&mainVisiblePoint];
  795.  
  796.     /* set the frame of the PrintView to be big enough to show everything */
  797.     clipFrame.origin = oldMainFrame.origin;
  798.     clipFrame.origin.x = 0;
  799.     clipFrame.size = oldMainClipBounds.size;
  800.     clipFrame.size.height += (oldTopRect.size.height + oldBottomRect.size.height);
  801.     clipFrame.size.width += (oldLeftRect.size.width + oldRightRect.size.width);
  802.     [printView setFrame:&clipFrame];
  803.  
  804.     return printView;
  805. }
  806.  
  807. - printVisible:sender
  808. {
  809.     if (rulersOn) {
  810.         [window disableFlushWindow];
  811.         [self createPrintView];
  812.         [printView printPSCode:self];
  813.         // mainPrintClipView was setup in docView
  814.         [self setDocView:[mainPrintClipView docView]];
  815.         // return to original views
  816.         [self addSubview:[bottomRuler superview]];
  817.         [self addSubview:[topRuler superview]];
  818.         [self addSubview:[leftRuler superview]];
  819.         [self addSubview:[rightRuler superview]];
  820.         // restore old positions
  821.         [[bottomRuler superview] setFrame:&oldBottomRect];
  822.         [[topRuler superview] setFrame:&oldTopRect];
  823.         [[leftRuler superview] setFrame:&oldLeftRect];
  824.         [[rightRuler superview] setFrame:&oldRightRect];
  825.     
  826.         /* return the view to the origin it was at */
  827.         /* except change the scroll point slightly */
  828.         /* so that the scrollers will update correctly */
  829.         if (rulersOn)
  830.             mainVisiblePoint.y += 1;
  831.         else
  832.             mainVisiblePoint.y -= 1;
  833.         [[self docView] scrollPoint:(const NXPoint *)&mainVisiblePoint];
  834.         [window reenableFlushWindow];
  835.         }
  836.     else
  837.         // remove the message to superview to print the entire main view
  838.         // rather than just the visible portion
  839.         [[[self docView] superview] printPSCode:self];
  840.     return self;
  841. }
  842.  
  843. - writeToStream:(NXStream *)stream
  844. {
  845.     NXRect    printRect;
  846.     
  847.     if (rulersOn) {
  848.         [window disableFlushWindow];
  849.         [self createPrintView];
  850.         [printView getFrame:&printRect];
  851.         [printView copyPSCodeInside:(const NXRect *)&printRect to:(NXStream *)stream];
  852.         [self setDocView:[mainPrintClipView docView]];
  853.         // return to original views
  854.         [self addSubview:[bottomRuler superview]];
  855.         [self addSubview:[topRuler superview]];
  856.         [self addSubview:[leftRuler superview]];
  857.         [self addSubview:[rightRuler superview]];
  858.         // restore old positions
  859.         [[bottomRuler superview] setFrame:&oldBottomRect];
  860.         [[topRuler superview] setFrame:&oldTopRect];
  861.         [[leftRuler superview] setFrame:&oldLeftRect];
  862.         [[rightRuler superview] setFrame:&oldRightRect];
  863.     
  864.         /* return the view to the origin it was at */
  865.         /* except change the scroll point slightly */
  866.         /* so that the scrollers will update correctly */
  867.         if (rulersOn)
  868.             mainVisiblePoint.y += 1;
  869.         else
  870.             mainVisiblePoint.y -= 1;
  871.         [[self docView] scrollPoint:(const NXPoint *)&mainVisiblePoint];
  872.         [window reenableFlushWindow];
  873.         }
  874.     else {
  875.         [[[self docView] superview] getBounds:&printRect];
  876.         [[[self docView] superview] copyPSCodeInside:(const NXRect *)&printRect 
  877.             to:(NXStream *)stream];
  878.         }
  879.     return self;
  880. }
  881.  
  882. @end
  883.