|
|
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.