163
|
1
|
|
2 #import "TreeView.h"
|
|
3 #import "TreeButton.h"
|
|
4 #import "NamedTree.h"
|
|
5 #import "Line.h"
|
|
6
|
|
7 // constants to determine how the buttons are laid out
|
|
8 #define BUTTONWIDTH 155.0
|
|
9 #define BUTTONHEIGHT 24.0
|
|
10 #define VERTSPACING 8.0
|
|
11 #define HORIZSPACING 40.0
|
|
12
|
|
13 @implementation TreeView
|
|
14
|
|
15 - initFrame:(const NXRect *)frameRect
|
|
16 {
|
|
17 [super initFrame:frameRect];
|
|
18 [self setAutosizing:(unsigned int) (NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE)];
|
|
19
|
|
20 currentButton = nil;
|
|
21 lineList = nil;
|
|
22 priorButton = nil;
|
|
23 [selectedField setNextText: selectedField];
|
|
24 [selectedField setPreviousText: selectedField];
|
|
25 currScale = 1.0;
|
|
26
|
|
27 [self registerForDragging];
|
|
28 [self setOpaque:YES];
|
|
29
|
|
30 return self;
|
|
31 }
|
|
32
|
|
33 - buildTreeFromNode:aNode bottom:(double)ybot
|
|
34 top:(double)ytop atX:(double)xpos parent:(NXPoint *)pos
|
|
35 { // add a button representing the node to the View
|
|
36 // This method is recursive.
|
|
37 NXRect butFrame = {{(xpos + HORIZSPACING),
|
|
38 (ybot + (ytop - ybot) / 2 - BUTTONHEIGHT / 2)},
|
|
39 {BUTTONWIDTH, BUTTONHEIGHT}};
|
|
40 id newButton = [[[TreeButton alloc] initFrame:&butFrame]
|
|
41 setTreeNode:aNode];
|
|
42 id kid, kids = [aNode branches];
|
|
43 int numBranches = [kids count];
|
|
44 int i, treeWidth; double diff, accum = ybot;
|
|
45 NXPoint myCenter = {(NX_X(&butFrame)),
|
|
46 (NX_Y(&butFrame) + BUTTONHEIGHT / 2)};
|
|
47 id newLine;
|
|
48
|
|
49 [newButton setTitle:[aNode label]];
|
|
50 [self addSubview:newButton];
|
|
51 // line to parent:
|
|
52 if (pos) { // NULL if root, so no line
|
|
53 NXPoint parentRight = { pos->x + BUTTONWIDTH, pos->y };
|
|
54 newLine = [[Line alloc] init];
|
|
55 [newLine setStart:&parentRight end:&myCenter];
|
|
56 [lineList addObject:newLine];
|
|
57 }
|
|
58 // now add any children and the lines to them.
|
|
59 for (i=numBranches - 1; i >= 0; i--) { // loop isn't entered if no kids.
|
|
60 kid = [kids objectAt:i];
|
|
61 treeWidth = [kid width];
|
|
62 diff = (treeWidth * (BUTTONHEIGHT + VERTSPACING));
|
|
63 [self buildTreeFromNode:kid bottom:accum
|
|
64 top:(accum + diff + VERTSPACING)
|
|
65 atX:(xpos + BUTTONWIDTH + HORIZSPACING)
|
|
66 parent:&myCenter];
|
|
67 accum += diff;
|
|
68 }
|
|
69 return self;
|
|
70 }
|
|
71
|
|
72 - attachTree:aTree
|
|
73 {
|
|
74 int treeWidth = [aTree width];
|
|
75 int treeDepth = [aTree depth];
|
|
76 double height = (treeWidth * (BUTTONHEIGHT + VERTSPACING) + VERTSPACING);
|
|
77 double width = (treeDepth * (BUTTONWIDTH + HORIZSPACING) + HORIZSPACING);
|
|
78
|
|
79 treeRoot = aTree;
|
|
80 if (lineList) [[lineList freeObjects] free];
|
|
81 lineList = [[List alloc] init];
|
|
82 // resize the View to accomodate the Buttons
|
|
83 [self sizeTo:width :height];
|
|
84 [self buildTreeFromNode:aTree bottom:0.0 top:height atX:0.0 parent:NULL];
|
|
85
|
|
86 return self;
|
|
87 }
|
|
88
|
|
89 - drawSelf:(NXRect *)rects :(int)rectCount // standard rendering method
|
|
90 {
|
|
91 NXColor color = [[self window] backgroundColor];
|
|
92
|
|
93 if (NXEqualColor(color, NX_COLORLTGRAY))
|
|
94 color = NX_COLORDKGRAY;
|
|
95
|
|
96 // PSsetgray(NX_DKGRAY);
|
|
97 NXSetColor(color);
|
|
98 NXRectFill(&bounds);
|
|
99 // PSsetgray(NX_BLACK);
|
|
100 NXSetColor(NX_COLORBLACK);
|
|
101 PSsetlinewidth(2.0);
|
|
102
|
|
103 [lineList makeObjectsPerform:@selector(render)];
|
|
104 [[self subviews] makeObjectsPerform:@selector(display)];
|
|
105 return self;
|
|
106 }
|
|
107
|
|
108 - scale:sender
|
|
109 {
|
|
110 id popUp = [sender window];
|
|
111 short index = [popUp indexOfItem:[popUp selectedItem]];
|
|
112 // 25% 50% 75% 100% 125% 150% 200% SizeToFit
|
|
113 // 0 1 2 3 4 5 6 7
|
|
114 float factors[] = {0.25, 0.50, 0.75, 1.0, 1.25, 1.50, 2.0, 0.20};
|
|
115 NXPoint center;
|
|
116 NXCoord scale = factors[index];
|
|
117
|
|
118 // Initialize width and height bounds when view is not scaled.
|
|
119 if (currScale == 1.0)
|
|
120 {
|
|
121 origWidth = NX_WIDTH(&bounds);
|
|
122 origHeight = NX_HEIGHT(&bounds);
|
|
123 }
|
|
124
|
|
125 // Remember the center to we can reset it after the scaling.
|
|
126 center.x = NX_X(&bounds) + NX_WIDTH(&bounds) / 2;
|
|
127 center.y = NX_Y(&bounds) + NX_HEIGHT(&bounds) / 2;
|
|
128
|
|
129 // Scale the view to its new size
|
|
130 if (index == 3) // 100% (Normal Size)
|
|
131 {
|
|
132 [self setDrawSize:origWidth :origHeight];
|
|
133 currScale = 1.0;
|
|
134 }
|
|
135 else
|
|
136 {
|
|
137 currScale *= scale;
|
|
138 [self setDrawSize:NX_WIDTH(&bounds) / currScale
|
|
139 :NX_HEIGHT(&bounds) / currScale];
|
|
140 }
|
|
141
|
|
142 // Reset the center point
|
|
143 [self setDrawOrigin:center.x - NX_WIDTH(&bounds) / 2
|
|
144 :center.y - NX_HEIGHT(&bounds) / 2];
|
|
145
|
|
146 // Ensure that selected button, if any, is visible.
|
|
147 [self displayBut:currentButton];
|
|
148
|
|
149 [self update];
|
|
150
|
|
151 return self;
|
|
152 }
|
|
153
|
|
154 - setCurrentButton:but
|
|
155 {
|
|
156 if (but)
|
|
157 {
|
|
158 priorButton = currentButton;
|
|
159 if (priorButton)
|
|
160 {
|
|
161 [priorButton setType:NX_MOMENTARYPUSH];
|
|
162 [priorButton setState:0];
|
|
163 }
|
|
164 currentButton = but;
|
|
165 [currentButton setType:NX_ONOFF]; [currentButton setState:1];
|
|
166 // [selectedField setStringValueNoCopy: [but title]];
|
|
167 }
|
|
168 return but;
|
|
169 }
|
|
170
|
|
171 - setCurrButtonByName:sender
|
|
172 {
|
|
173 id currBut = [self getButByName:[sender stringValue]];
|
|
174
|
|
175 [self displayBut:[self setCurrentButton:currBut]];
|
|
176 [treeRoot act:currBut];
|
|
177 return currBut;
|
|
178 }
|
|
179
|
|
180 - getButByName:(const char*)name
|
|
181 {
|
|
182 id butList = [self subviews];
|
|
183 id but = nil;
|
|
184 id currBut = nil;
|
|
185 int i = 0;
|
|
186
|
|
187 while (!currBut && (but = [butList objectAt:i++]))
|
|
188 {
|
|
189 if (!strcmp([but title], name))
|
|
190 currBut = but;
|
|
191 }
|
|
192 return currBut;
|
|
193 }
|
|
194
|
|
195 - displayButByName:sender
|
|
196 {
|
|
197 id but = [self getButByName:[sender stringValue]];
|
|
198
|
|
199 if (but)
|
|
200 [self displayBut:but];
|
|
201 return but;
|
|
202 }
|
|
203
|
|
204 - displayBut:but
|
|
205 {
|
|
206 NXRect butRect;
|
|
207
|
|
208 if (but)
|
|
209 {
|
|
210 [[but getBounds:&butRect] convertRectToSuperview:&butRect];
|
|
211 [self scrollRectToVisible:&butRect];
|
|
212 }
|
|
213 return self;
|
|
214 }
|
|
215
|
|
216 @end
|
|
217
|
|
218
|
|
219
|
|
220 // Color dragging support
|
|
221
|
|
222 BOOL includesType(const NXAtom *types, NXAtom type)
|
|
223 {
|
|
224 if (types)
|
|
225 while (*types)
|
|
226 if (*types++ == type)
|
|
227 return YES;
|
|
228 return NO;
|
|
229 }
|
|
230
|
|
231 @implementation TreeView(Drag)
|
|
232
|
|
233 - registerForDragging
|
|
234 {
|
|
235 [self registerForDraggedTypes:&NXColorPboardType count:1];
|
|
236 return self;
|
|
237 }
|
|
238
|
|
239 - (NXDragOperation)draggingEntered:(id <NXDraggingInfo>)sender
|
|
240 {
|
|
241 NXDragOperation sourceMask = [sender draggingSourceOperationMask];
|
|
242 Pasteboard *pboard = [sender draggingPasteboard];
|
|
243
|
|
244 return ((includesType([pboard types], NXColorPboardType))
|
|
245 ? NX_DragOperationGeneric : NX_DragOperationNone);
|
|
246 }
|
|
247
|
|
248 - (BOOL)prepareForDragOperation:(id <NXDraggingInfo>)sender
|
|
249 {
|
|
250 return YES;
|
|
251 }
|
|
252
|
|
253 - (BOOL)performDragOperation:(id <NXDraggingInfo>)sender
|
|
254 {
|
|
255 Pasteboard *pboard = [sender draggingPasteboard];
|
|
256
|
|
257 if (includesType([pboard types], NXColorPboardType))
|
|
258 {
|
|
259 NXColor color = NXReadColorFromPasteboard(pboard);
|
|
260 [[self window] setBackgroundColor:color];
|
|
261 [self display]; // reflect color change
|
|
262 return YES;
|
|
263 }
|
|
264 else
|
|
265 return NO;
|
|
266 }
|
|
267
|
|
268 - concludeDragOperation:(id <NXDraggingInfo>)sender
|
|
269 {
|
|
270 // Return value ignored.
|
|
271 return nil;
|
|
272 }
|
|
273
|
|
274 @end
|