home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer) / NeXT_Developer-3.3.iso / NextDeveloper / Examples / AppKit / Draw / SyncScrollView.m < prev    next >
Encoding:
Text File  |  1992-07-22  |  8.7 KB  |  340 lines

  1. #import "draw.h"
  2.  
  3. @implementation SyncScrollView
  4. /*
  5.  * This subclass of ScrollView is extremely useful for programmers
  6.  * who want some View to scroll along with a main docView.  A good
  7.  * example is a spreadsheet that wants its column and row headings
  8.  * to scroll along with the cells in the spreadsheet itself.
  9.  * It is actually quite simple.  We simply override tile to place
  10.  * two ClipViews with our views (rulers in this case) in them into
  11.  * the view hierarchy, then override scrollClip:to: to update their
  12.  * drawing origins when the docView is scrolled.  We also override
  13.  * reflectScroll: since we don't want that to apply to our little
  14.  * ruler views, only to the main docView.
  15.  */
  16.  
  17. - setRulerClass:factoryId
  18. {
  19.     if ([factoryId conformsTo:@protocol(Ruler)]) rulerClass = factoryId;
  20.     return self;
  21. }
  22.  
  23. - setRulerWidths:(NXCoord)horizontal :(NXCoord)vertical
  24. {
  25.     horizontalRulerWidth = horizontal;
  26.     verticalRulerWidth = vertical;
  27.     return self;
  28. }
  29.  
  30. - (BOOL)bothRulersAreVisible
  31. {
  32.     return verticalRulerIsVisible && horizontalRulerIsVisible;
  33. }
  34.  
  35. - (BOOL)eitherRulerIsVisible
  36. {
  37.     return verticalRulerIsVisible || horizontalRulerIsVisible;
  38. }
  39.  
  40. - (BOOL)verticalRulerIsVisible
  41. {
  42.     return verticalRulerIsVisible;
  43. }
  44.  
  45. - (BOOL)horizontalRulerIsVisible
  46. {
  47.     return horizontalRulerIsVisible;
  48. }
  49.  
  50. - setRulerOrigin:(RulerOrigin)origin
  51. {
  52.     RulerOrigin oldRulerOrigin = rulerOrigin;
  53.  
  54.     rulerOrigin = origin;
  55.     switch (origin) {
  56.     case LowerRight:
  57.         [[hClipRuler docView] setFlipped:YES];
  58.         break;
  59.     case UpperRight:
  60.         [[hClipRuler docView] setFlipped:YES];
  61.     case UpperLeft:
  62.         [[vClipRuler docView] setFlipped:YES];
  63.     case LowerLeft:
  64.         break;
  65.     default:
  66.         rulerOrigin = oldRulerOrigin;
  67.         break;
  68.     }
  69.  
  70.     return self;
  71. }
  72.  
  73. - makeRulers
  74. /*
  75.  * This makes the rulers.
  76.  * We do this lazily in case the user never asks for the rulers.
  77.  */
  78. {
  79.     View <Ruler> *ruler;
  80.     NXRect aRect, bRect;
  81.  
  82.     if (!rulerClass || (!horizontalRulerWidth && !verticalRulerWidth)) return nil;
  83.  
  84.     if (horizontalRulerWidth) {
  85.     [[contentView docView] getFrame:&aRect];
  86.     NXDivideRect(&aRect, &bRect, horizontalRulerWidth, NX_YMIN);
  87.     hClipRuler = [[ClipView allocFromZone:[self zone]] init];
  88.     ruler = [[rulerClass allocFromZone:[self zone]] initFrame:&bRect];
  89.     [hClipRuler setDocView:ruler];
  90.     }
  91.     if (verticalRulerWidth) {
  92.     [[contentView docView] getFrame:&aRect];
  93.     NXDivideRect(&aRect, &bRect, verticalRulerWidth, NX_XMIN);
  94.     vClipRuler = [[ClipView allocFromZone:[self zone]] init];
  95.     ruler = [[rulerClass allocFromZone:[self zone]] initFrame:&bRect];
  96.     [vClipRuler setDocView:ruler];
  97.     }
  98.     [self setRulerOrigin:rulerOrigin];
  99.     rulersMade = 1;
  100.  
  101.     return self;
  102. }
  103.  
  104. - updateRulers:(const NXRect *)rect
  105. {
  106.     if (!rect) {
  107.     if (verticalRulerIsVisible) {
  108.         [[vClipRuler docView] hidePosition];
  109.     }
  110.     if (horizontalRulerIsVisible) {
  111.         [[hClipRuler docView] hidePosition];
  112.     }
  113.     } else {
  114.     if (verticalRulerIsVisible) {
  115.         [[vClipRuler docView] showPosition:rect->origin.y :rect->origin.y + rect->size.height];
  116.     }
  117.     if (horizontalRulerIsVisible) {
  118.         [[hClipRuler docView] showPosition:rect->origin.x :rect->origin.x + rect->size.width];
  119.     }
  120.     }
  121.  
  122.     return self;
  123. }
  124.  
  125. - updateRuler
  126. {
  127.     NXRect aRect, bRect;
  128.  
  129.     if (horizontalRulerIsVisible) {
  130.     [[contentView docView] getFrame:&aRect];
  131.     NXDivideRect(&aRect, &bRect, horizontalRulerWidth, NX_YMIN);
  132.     bRect.size.width += verticalRulerWidth;
  133.     [[hClipRuler docView] setFrame:&bRect];
  134.     [hClipRuler display];
  135.     }
  136.     if (verticalRulerIsVisible) {
  137.     [[contentView docView] getFrame:&aRect];
  138.     NXDivideRect(&aRect, &bRect, verticalRulerWidth, NX_XMIN);
  139.     [[vClipRuler docView] setFrame:&bRect];
  140.     [vClipRuler display];
  141.     }
  142.  
  143.     return self;
  144. }
  145.  
  146. - (BOOL)showRuler:(BOOL)showIt isHorizontal:(BOOL)isHorizontal
  147. /*
  148.  * Adds or removes a ruler from the view hierarchy.
  149.  * Returns whether or not it succeeded in doing so.
  150.  */
  151. {
  152.     ClipView *ruler;
  153.     BOOL isVisible;
  154.     NXRect cRect, rRect;
  155.  
  156.     isVisible = isHorizontal ? horizontalRulerIsVisible : verticalRulerIsVisible;
  157.     if ((showIt && isVisible) || (!showIt && !isVisible)) return NO;
  158.     if (showIt && !rulersMade && ![self makeRulers]) return NO;
  159.     ruler = isHorizontal ? hClipRuler : vClipRuler;
  160.  
  161.     if (!showIt && isVisible) {
  162.     [ruler removeFromSuperview];
  163.     if (isHorizontal) {
  164.         horizontalRulerIsVisible = NO;
  165.     } else {
  166.         verticalRulerIsVisible = NO;
  167.     }
  168.     } else if (showIt && !isVisible && ruler) {
  169.     [self addSubview:ruler];
  170.     [window disableDisplay];
  171.     [contentView getBounds:&cRect];
  172.     [hClipRuler getBounds:&rRect];
  173.     [hClipRuler setDrawOrigin:cRect.origin.x :rRect.origin.y];
  174.     [vClipRuler getBounds:&rRect];
  175.     [vClipRuler setDrawOrigin:rRect.origin.x :cRect.origin.y];
  176.     [window reenableDisplay];
  177.     if (isHorizontal) {
  178.         horizontalRulerIsVisible = YES;
  179.     } else {
  180.         verticalRulerIsVisible = YES;
  181.     }
  182.     }
  183.  
  184.     return YES;
  185. }
  186.  
  187. - adjustSizes
  188. {
  189.     id windelegate;
  190.     NXRect winFrame;
  191.  
  192.     windelegate = [window delegate];
  193.     if ([windelegate respondsTo:@selector(windowWillResize:toSize:)]) {
  194.     [window getFrame:&winFrame];
  195.     [windelegate windowWillResize:window toSize:&winFrame.size];
  196.     [window placeWindow:&winFrame];
  197.     }
  198.     [self resizeSubviews:(NXSize *)nil];
  199.  
  200.     return self;
  201. }
  202.  
  203. - showHorizontalRuler:(BOOL)flag
  204. {
  205.     if ([self showRuler:flag isHorizontal:YES]) [self adjustSizes];
  206.     return self;
  207. }
  208.  
  209. - showVerticalRuler:(BOOL)flag
  210. {
  211.     if ([self showRuler:flag isHorizontal:NO]) [self adjustSizes];
  212.     return self;
  213. }
  214.  
  215. - showHideRulers:sender
  216. /*
  217.  * If both rulers are visible, they are both hidden.
  218.  * Otherwise, both rulers are made visible.
  219.  */
  220. {
  221.     BOOL resize = NO;
  222.  
  223.     if (verticalRulerIsVisible && horizontalRulerIsVisible) {
  224.     resize = [self showRuler:NO isHorizontal:YES];
  225.     resize = [self showRuler:NO isHorizontal:NO] || resize;
  226.     } else {
  227.     if (!horizontalRulerIsVisible) resize = [self showRuler:YES isHorizontal:YES];
  228.     if (!verticalRulerIsVisible) resize = [self showRuler:YES isHorizontal:NO] || resize;
  229.     }
  230.     if (resize) [self adjustSizes];
  231.  
  232.     return self;
  233. }
  234.  
  235. /* ScrollView-specific stuff */
  236.  
  237. - free
  238. {
  239.     if (!horizontalRulerIsVisible) [hClipRuler free];
  240.     if (!verticalRulerIsVisible) [vClipRuler free];
  241.     return [super free];    
  242. }
  243.  
  244. - reflectScroll:cView
  245. /*
  246.  * We only reflect scroll in the contentView, not the rulers.
  247.  */
  248. {
  249.     if (cView == hClipRuler || cView == vClipRuler) return self;
  250.     return [super reflectScroll:cView];
  251. }
  252.  
  253. - tile
  254. /*
  255.  * Here is where we lay out the subviews of the ScrollView.
  256.  * Note the use of NXDivideRect() to "slice off" a section of
  257.  * a rectangle.  This is useful since the two scrollers each
  258.  * result in slicing a section off the contentView of the
  259.  * ScrollView.
  260.  */
  261. {
  262.     NXRect aRect, bRect, cRect;
  263.  
  264.     [super tile];
  265.  
  266.     if (horizontalRulerIsVisible || verticalRulerIsVisible) {
  267.     [contentView getFrame:&aRect];
  268.     [[self docView] getFrame:&cRect];
  269.     if (horizontalRulerIsVisible && hClipRuler) {
  270.         NXDivideRect(&aRect, &bRect, horizontalRulerWidth, NX_YMIN);
  271.         [hClipRuler setFrame:&bRect];
  272.         [[hClipRuler docView] sizeTo:cRect.size.width+verticalRulerWidth :bRect.size.height];
  273.     }
  274.     if (verticalRulerIsVisible && vClipRuler) {
  275.         NXDivideRect(&aRect, &bRect, verticalRulerWidth, NX_XMIN);
  276.         [vClipRuler setFrame:&bRect];
  277.         [[vClipRuler docView] sizeTo:bRect.size.width :cRect.size.height];
  278.     }
  279.     [contentView setFrame:&aRect];
  280.     }
  281.  
  282.     return self;
  283. }
  284.  
  285. - scrollClip:(ClipView *)aClipView to:(const NXPoint *)aPoint
  286. /*
  287.  * This is sent to us instead of rawScroll:.
  288.  * We scroll the two rulers, then the clipView itself.
  289.  */
  290. {
  291.     id fr;
  292.     NXRect rRect;
  293.  
  294.     if (horizontalRulerIsVisible && hClipRuler) {
  295.     [hClipRuler getBounds:&rRect];
  296.     rRect.origin.x = aPoint->x;
  297.     [hClipRuler rawScroll:&(rRect.origin)];
  298.     }
  299.     if (verticalRulerIsVisible && vClipRuler) {
  300.     [vClipRuler getBounds:&rRect];
  301.     rRect.origin.y = aPoint->y;
  302.     [vClipRuler rawScroll:&(rRect.origin)];
  303.     }
  304.  
  305.     [aClipView rawScroll:aPoint];
  306.  
  307.     fr = [window firstResponder];
  308.     if ([fr respondsTo:@selector(isRulerVisible)] && [fr isRulerVisible]) [fr updateRuler]; // keeps Text ruler up-to-date
  309.  
  310.     return self;
  311. }
  312.  
  313. - descendantFrameChanged:sender
  314. /*
  315.  * Any time the docView is resized, this method is
  316.  * called to update the size of the rulers to be equal to
  317.  * the size of the docView.
  318.  */
  319. {
  320.     NXRect aRect, bRect, cRect;
  321.  
  322.     [super descendantFrameChanged:sender];
  323.     if (horizontalRulerIsVisible || verticalRulerIsVisible) {
  324.     [contentView getFrame:&aRect];
  325.     [[self docView] getFrame:&cRect];
  326.     if (horizontalRulerIsVisible && hClipRuler) {
  327.         NXDivideRect(&aRect, &bRect, horizontalRulerWidth, NX_YMIN);
  328.         [[hClipRuler docView] sizeTo:cRect.size.width+verticalRulerWidth :bRect.size.height];
  329.     }
  330.     if (verticalRulerIsVisible && vClipRuler) {
  331.         NXDivideRect(&aRect, &bRect, verticalRulerWidth, NX_XMIN);
  332.         [[vClipRuler docView] sizeTo:bRect.size.width :cRect.size.height];
  333.     }
  334.     }
  335.  
  336.     return self;
  337. }
  338.  
  339. @end
  340.