home *** CD-ROM | disk | FTP | other *** search
/ OpenStep (Enterprise) / OpenStepENTCD.toast / OEDEV / DEV.Z / SyncScrollView.m < prev    next >
Text File  |  1995-08-08  |  9KB  |  315 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. - (void)setRulerClass:factoryId
  18. {
  19.     if ([factoryId conformsToProtocol:@protocol(Ruler)]) rulerClass = factoryId; 
  20. }
  21.  
  22. - (void)setRulerWidths:(float)horizontal :(float)vertical
  23. {
  24.     horizontalRulerWidth = horizontal;
  25.     verticalRulerWidth = vertical; 
  26. }
  27.  
  28. - (BOOL)bothRulersAreVisible
  29. {
  30.     return verticalRulerIsVisible && horizontalRulerIsVisible;
  31. }
  32.  
  33. - (BOOL)eitherRulerIsVisible
  34. {
  35.     return verticalRulerIsVisible || horizontalRulerIsVisible;
  36. }
  37.  
  38. - (BOOL)verticalRulerIsVisible
  39. {
  40.     return verticalRulerIsVisible;
  41. }
  42.  
  43. - (BOOL)horizontalRulerIsVisible
  44. {
  45.     return horizontalRulerIsVisible;
  46. }
  47.  
  48. - (void)setRulerOrigin:(RulerOrigin)origin
  49. {
  50.     RulerOrigin oldRulerOrigin = rulerOrigin;
  51.  
  52.     rulerOrigin = origin;
  53.     switch (origin) {
  54.     case LowerRight:
  55.         [[hClipRuler documentView] setZeroAtViewOrigin:NO];
  56.         break;
  57.     case UpperRight:
  58.         [[hClipRuler documentView] setZeroAtViewOrigin:NO];
  59.     case UpperLeft:
  60.         [[vClipRuler documentView] setZeroAtViewOrigin:NO];
  61.     case LowerLeft:
  62.         break;
  63.     default:
  64.         rulerOrigin = oldRulerOrigin;
  65.         break;
  66.     } 
  67. }
  68.  
  69. - makeRulers
  70. /*
  71.  * This makes the rulers.
  72.  * We do this lazily in case the user never asks for the rulers.
  73.  */
  74. {
  75.     NSView <Ruler> *ruler;
  76.     NSRect aRect, bRect;
  77.  
  78.     if (!rulerClass || (!horizontalRulerWidth && !verticalRulerWidth)) return nil;
  79.  
  80.     if (horizontalRulerWidth) {
  81.     aRect = [[_contentView documentView] frame];
  82.     NSDivideRect(aRect, &bRect, &aRect, horizontalRulerWidth, NSMinYEdge);
  83.     hClipRuler = [[NSClipView allocWithZone:(NSZone *)[self zone]] init];
  84.     ruler = [[rulerClass allocWithZone:(NSZone *)[self zone]] initWithFrame:bRect];
  85.     [hClipRuler setDocumentView:ruler];
  86.     }
  87.     if (verticalRulerWidth) {
  88.     aRect = [[_contentView documentView] frame];
  89.     NSDivideRect(aRect, &bRect, &aRect, verticalRulerWidth, NSMinXEdge);
  90.     vClipRuler = [[NSClipView allocWithZone:(NSZone *)[self zone]] init];
  91.     ruler = [[rulerClass allocWithZone:(NSZone *)[self zone]] initWithFrame:bRect];
  92.     [vClipRuler setDocumentView:ruler];
  93.     }
  94.     [self setRulerOrigin:rulerOrigin];
  95.     rulersMade = 1;
  96.  
  97.     return self;
  98. }
  99.  
  100. - (void)updateRulers:(const NSRect *)rect
  101. {
  102.     if (!rect) {
  103.     if (verticalRulerIsVisible) {
  104.         [[vClipRuler documentView] hidePosition];
  105.     }
  106.     if (horizontalRulerIsVisible) {
  107.         [[hClipRuler documentView] hidePosition];
  108.     }
  109.     } else {
  110.     if (verticalRulerIsVisible) {
  111.         [[vClipRuler documentView] showPosition:rect->origin.y :rect->origin.y + rect->size.height];
  112.     }
  113.     if (horizontalRulerIsVisible) {
  114.         [[hClipRuler documentView] showPosition:rect->origin.x :rect->origin.x + rect->size.width];
  115.     }
  116.     } 
  117. }
  118.  
  119. - (void)updateRuler
  120. {
  121.     NSRect aRect, bRect;
  122.  
  123.     if (horizontalRulerIsVisible) {
  124.     aRect = [[_contentView documentView] frame];
  125.     NSDivideRect(aRect, &bRect, &aRect, horizontalRulerWidth, NSMinYEdge);
  126.     bRect.size.width += verticalRulerWidth;
  127.     [[hClipRuler documentView] setFrame:bRect];
  128.     [hClipRuler display];
  129.     }
  130.     if (verticalRulerIsVisible) {
  131.     aRect = [[_contentView documentView] frame];
  132.     NSDivideRect(aRect, &bRect, &aRect, verticalRulerWidth, NSMinXEdge);
  133.     [[vClipRuler documentView] setFrame:bRect];
  134.     [vClipRuler display];
  135.     } 
  136. }
  137.  
  138. - (BOOL)showRuler:(BOOL)showIt isHorizontal:(BOOL)isHorizontal
  139. /*
  140.  * Adds or removes a ruler from the view hierarchy.
  141.  * Returns whether or not it succeeded in doing so.
  142.  */
  143. {
  144.     NSClipView *ruler;
  145.     BOOL isVisible;
  146.     NSRect cRect, rRect;
  147.  
  148.     isVisible = isHorizontal ? horizontalRulerIsVisible : verticalRulerIsVisible;
  149.     if ((showIt && isVisible) || (!showIt && !isVisible)) return NO;
  150.     if (showIt && !rulersMade && ![self makeRulers]) return NO;
  151.     ruler = isHorizontal ? hClipRuler : vClipRuler;
  152.  
  153.     if (!showIt && isVisible) {
  154.     [ruler removeFromSuperview];
  155.     if (isHorizontal) {
  156.         horizontalRulerIsVisible = NO;
  157.     } else {
  158.         verticalRulerIsVisible = NO;
  159.     }
  160.     } else if (showIt && !isVisible && ruler) {
  161.     [self addSubview:ruler];
  162.     cRect = [_contentView bounds];
  163.     rRect = [hClipRuler bounds];
  164.     [hClipRuler setBoundsOrigin:(NSPoint){ cRect.origin.x, rRect.origin.y }];
  165.     rRect = [vClipRuler bounds];
  166.     [vClipRuler setBoundsOrigin:(NSPoint){ rRect.origin.x, cRect.origin.y }];
  167.     if (isHorizontal) {
  168.         horizontalRulerIsVisible = YES;
  169.     } else {
  170.         verticalRulerIsVisible = YES;
  171.     }
  172.     }
  173.  
  174.     return YES;
  175. }
  176.  
  177. - adjustSizes
  178. {
  179.     id windelegate;
  180.     NSRect winFrame;
  181.     NSWindow *window = [self window];
  182.  
  183.     windelegate = [window delegate];
  184.     if ([windelegate respondsToSelector:@selector(windowWillResize:toSize:)]) {
  185.     winFrame = [window frame];
  186.     winFrame.size = [windelegate windowWillResize:window toSize:winFrame.size];
  187.     [window setFrame:winFrame display:YES];
  188.     }
  189.     [self resizeSubviewsWithOldSize:NSZeroSize];
  190.  
  191.     return self;
  192. }
  193.  
  194. - (void)showHorizontalRuler:(BOOL)flag
  195. {
  196.     if ([self showRuler:flag isHorizontal:YES]) [self adjustSizes]; 
  197. }
  198.  
  199. - (void)showVerticalRuler:(BOOL)flag
  200. {
  201.     if ([self showRuler:flag isHorizontal:NO]) [self adjustSizes]; 
  202. }
  203.  
  204. - (void)showHideRulers:sender
  205. /*
  206.  * If both rulers are visible, they are both hidden.
  207.  * Otherwise, both rulers are made visible.
  208.  */
  209. {
  210.     BOOL resize = NO;
  211.  
  212.     if (verticalRulerIsVisible && horizontalRulerIsVisible) {
  213.     resize = [self showRuler:NO isHorizontal:YES];
  214.     resize = [self showRuler:NO isHorizontal:NO] || resize;
  215.     } else {
  216.     if (!horizontalRulerIsVisible) resize = [self showRuler:YES isHorizontal:YES];
  217.     if (!verticalRulerIsVisible) resize = [self showRuler:YES isHorizontal:NO] || resize;
  218.     }
  219.     if (resize) [self adjustSizes]; 
  220. }
  221.  
  222. /* ScrollView-specific stuff */
  223.  
  224. - (void)dealloc
  225. {
  226.     
  227.     if (!horizontalRulerIsVisible) /* TOPS-WARNING!!!  NSObject conversion:  This release used to be a free. */ [hClipRuler release];
  228.     if (!verticalRulerIsVisible) /* TOPS-WARNING!!!  NSObject conversion:  This release used to be a free. */ [vClipRuler release];
  229.     [super dealloc];    
  230.  
  231. }
  232.  
  233. - (void)reflectScrolledClipView:(NSClipView *)cView
  234. /*
  235.  * We only reflect scroll in the contentView, not the rulers.
  236.  */
  237. {
  238.     if (cView != hClipRuler && cView != vClipRuler) [super reflectScrolledClipView:cView];
  239. }
  240.  
  241. - (void)tile
  242. /*
  243.  * Here is where we lay out the subviews of the ScrollView.
  244.  * Note the use of NSDivideRect() to "slice off" a section of
  245.  * a rectangle.  This is useful since the two scrollers each
  246.  * result in slicing a section off the _contentView of the
  247.  * ScrollView.
  248.  */
  249. {
  250.     NSRect aRect, bRect, cRect;
  251.  
  252.     [super tile];
  253.  
  254.     if (horizontalRulerIsVisible || verticalRulerIsVisible) {
  255.     aRect = [_contentView frame];
  256.     cRect = [[self documentView] frame];
  257.     if (horizontalRulerIsVisible && hClipRuler) {
  258.         NSDivideRect(aRect, &bRect, &aRect, horizontalRulerWidth, NSMinYEdge);
  259.         [hClipRuler setFrame:bRect];
  260.         [[hClipRuler documentView] setFrameSize:(NSSize){ cRect.size.width+verticalRulerWidth, bRect.size.height }];
  261.     }
  262.     if (verticalRulerIsVisible && vClipRuler) {
  263.         NSDivideRect(aRect, &bRect, &aRect, verticalRulerWidth, NSMinXEdge);
  264.         [vClipRuler setFrame:bRect];
  265.         [[vClipRuler documentView] setFrameSize:(NSSize){ bRect.size.width, cRect.size.height }];
  266.     }
  267.     [_contentView setFrame:aRect];
  268.     }
  269. }
  270.  
  271. - (void)scrollClipView:(NSClipView *)aClipView toPoint:(NSPoint)aPoint
  272. /*
  273.  * This is sent to us instead of rawScroll:.
  274.  * We scroll the two rulers, then the clipView itself.
  275.  */
  276. {
  277.     id fr;
  278.     NSRect rRect;
  279.  
  280.     if (horizontalRulerIsVisible && hClipRuler) {
  281.     rRect = [hClipRuler bounds];
  282.     rRect.origin.x = aPoint.x;
  283.     [hClipRuler scrollToPoint:(rRect.origin)];
  284.     }
  285.     if (verticalRulerIsVisible && vClipRuler) {
  286.     rRect = [vClipRuler bounds];
  287.     rRect.origin.y = aPoint.y;
  288.     [vClipRuler scrollToPoint:(rRect.origin)];
  289.     }
  290.  
  291.     [aClipView scrollToPoint:aPoint];
  292.  
  293.     fr = [_window firstResponder];
  294.     if ([fr respondsToSelector:@selector(isRulerVisible)] && [fr isRulerVisible]) [fr updateRuler];
  295. }
  296.  
  297. - (void)viewFrameChanged:(NSNotification *)notification {
  298.     NSRect aRect, bRect, cRect;
  299.  
  300.     if (horizontalRulerIsVisible || verticalRulerIsVisible) {
  301.     aRect = [_contentView frame];
  302.     cRect = [[self documentView] frame];
  303.     if (horizontalRulerIsVisible && hClipRuler) {
  304.         NSDivideRect(aRect, &bRect, &aRect, horizontalRulerWidth, NSMinYEdge);
  305.         [[hClipRuler documentView] setFrameSize:(NSSize){ cRect.size.width+verticalRulerWidth, bRect.size.height }];
  306.     }
  307.     if (verticalRulerIsVisible && vClipRuler) {
  308.         NSDivideRect(aRect, &bRect, &aRect, verticalRulerWidth, NSMinXEdge);
  309.         [[vClipRuler documentView] setFrameSize:(NSSize){ bRect.size.width, cRect.size.height }];
  310.     }
  311.     }
  312. }
  313.  
  314. @end
  315.