|
|
1.1 ! root 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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.