]> git.saurik.com Git - wxWidgets.git/blob - src/generic/treelay.cpp
applied (slightly modified) wxToggleButton patch from John Norris and Axel Schlueter
[wxWidgets.git] / src / generic / treelay.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: treelay.h
3 // Purpose: wxTreeLayout class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 7/4/98
7 // RCS-ID: $Id$
8 // Copyright: (c) 1998 Julian Smart
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "wxtree.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include <wx/wxprec.h>
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/wx.h"
25 #endif
26
27 #if wxUSE_TREELAYOUT
28
29 #include <wx/treelay.h>
30
31 /*
32 * Abstract tree
33 *
34 */
35
36 IMPLEMENT_ABSTRACT_CLASS(wxTreeLayout, wxObject)
37
38 wxTreeLayout::wxTreeLayout()
39 {
40 m_xSpacing = 16;
41 m_ySpacing = 20;
42 m_topMargin = 5;
43 m_leftMargin = 5;
44 m_orientation = FALSE;
45 m_parentNode = 0;
46 }
47
48 void wxTreeLayout::DoLayout(wxDC& dc, long topId)
49 {
50 if (topId != -1)
51 SetTopNode(topId);
52
53 long actualTopId = GetTopNode();
54 long id = actualTopId;
55 while (id != -1)
56 {
57 SetNodeX(id, 0);
58 SetNodeY(id, 0);
59 ActivateNode(id, FALSE);
60 id = GetNextNode(id);
61 }
62 m_lastY = m_topMargin;
63 m_lastX = m_leftMargin;
64 CalcLayout(actualTopId, 0, dc);
65 }
66
67 void wxTreeLayout::Draw(wxDC& dc)
68 {
69 dc.Clear();
70 DrawBranches(dc);
71 DrawNodes(dc);
72 }
73
74 void wxTreeLayout::DrawNodes(wxDC& dc)
75 {
76 long id = GetTopNode();
77 while (id != -1)
78 {
79 if (NodeActive(id))
80 DrawNode(id, dc);
81 id = GetNextNode(id);
82 }
83 }
84
85 void wxTreeLayout::DrawBranches(wxDC& dc)
86 {
87 long id = GetTopNode();
88 while (id != -1)
89 {
90 if (GetNodeParent(id) > -1)
91 {
92 long parent = GetNodeParent(id);
93 if (NodeActive(parent))
94 DrawBranch(parent, id, dc);
95 }
96 id = GetNextNode(id);
97 }
98 }
99
100 void wxTreeLayout::DrawNode(long id, wxDC& dc)
101 {
102 wxChar buf[80];
103 wxString name(GetNodeName(id));
104 if (name != wxT(""))
105 wxSprintf(buf, wxT("%s"), (const wxChar*) name);
106 else
107 wxSprintf(buf, wxT("<unnamed>"));
108
109 long x = 80;
110 long y = 20;
111 dc.GetTextExtent(buf, &x, &y);
112 dc.DrawText(buf, GetNodeX(id), (long)(GetNodeY(id) - (y/2.0)));
113 }
114
115 void wxTreeLayout::DrawBranch(long from, long to, wxDC& dc)
116 {
117 long w, h;
118 GetNodeSize(from, &w, &h, dc);
119 dc.DrawLine(GetNodeX(from)+w, GetNodeY(from),
120 GetNodeX(to), GetNodeY(to));
121 }
122
123 void wxTreeLayout::Initialize(void)
124 {
125 }
126
127 void wxTreeLayout::GetNodeSize(long id, long *x, long *y, wxDC& dc)
128 {
129 wxString name(GetNodeName(id));
130 if (name != wxT(""))
131 dc.GetTextExtent(name, x, y);
132 else
133 {
134 *x = 70; *y = 20;
135 }
136 }
137
138 void wxTreeLayout::CalcLayout(long nodeId, int level, wxDC& dc)
139 {
140 wxList children;
141 GetChildren(nodeId, children);
142 int n = children.Number();
143
144 if (m_orientation == FALSE)
145 {
146 // Left to right
147 // X Calculations
148 if (level == 0)
149 SetNodeX(nodeId, m_leftMargin);
150 else
151 {
152 long x = 0;
153 long y = 0;
154 long parentId = GetNodeParent(nodeId);
155 if (parentId != -1)
156 GetNodeSize(parentId, &x, &y, dc);
157 SetNodeX(nodeId, (long)(GetNodeX(parentId) + m_xSpacing + x));
158 }
159
160 wxNode *node = children.First();
161 while (node)
162 {
163 CalcLayout((long)node->Data(), level+1, dc);
164 node = node->Next();
165 }
166
167 // Y Calculations
168 long averageY;
169 ActivateNode(nodeId, TRUE);
170
171 if (n > 0)
172 {
173 averageY = 0;
174 node = children.First();
175 while (node)
176 {
177 averageY += GetNodeY((long)node->Data());
178 node = node->Next();
179 }
180 averageY = averageY / n;
181 SetNodeY(nodeId, averageY);
182 }
183 else
184 {
185 SetNodeY(nodeId, m_lastY);
186 long x, y;
187 GetNodeSize(nodeId, &x, &y, dc);
188
189 m_lastY = m_lastY + y + m_ySpacing;
190 }
191 }
192 else
193 {
194 // Top to bottom
195
196 // Y Calculations
197 if (level == 0)
198 SetNodeY(nodeId, m_topMargin);
199 else
200 {
201 long x = 0;
202 long y = 0;
203 long parentId = GetNodeParent(nodeId);
204 if (parentId != -1)
205 GetNodeSize(parentId, &x, &y, dc);
206 SetNodeY(nodeId, (long)(GetNodeY(parentId) + m_ySpacing + y));
207 }
208
209 wxNode *node = children.First();
210 while (node)
211 {
212 CalcLayout((long)node->Data(), level+1, dc);
213 node = node->Next();
214 }
215
216 // X Calculations
217 long averageX;
218 ActivateNode(nodeId, TRUE);
219
220 if (n > 0)
221 {
222 averageX = 0;
223 node = children.First();
224 while (node)
225 {
226 averageX += GetNodeX((long)node->Data());
227 node = node->Next();
228 }
229 averageX = averageX / n;
230 SetNodeX(nodeId, averageX);
231 }
232 else
233 {
234 SetNodeX(nodeId, m_lastX);
235 long x, y;
236 GetNodeSize(nodeId, &x, &y, dc);
237
238 m_lastX = m_lastX + x + m_xSpacing;
239 }
240 }
241 }
242
243 /*
244 * Tree with storage
245 *
246 */
247
248 IMPLEMENT_DYNAMIC_CLASS(wxTreeLayoutStored, wxTreeLayout)
249
250 wxTreeLayoutStored::wxTreeLayoutStored(int n):wxTreeLayout()
251 {
252 m_nodes = NULL;
253 m_maxNodes = 0;
254 Initialize(n);
255 }
256
257 wxTreeLayoutStored::~wxTreeLayoutStored(void)
258 {
259 if (m_nodes)
260 delete[] m_nodes;
261 }
262
263 void wxTreeLayoutStored::Initialize(int n)
264 {
265 m_maxNodes = n;
266 wxTreeLayout::Initialize();
267 if (m_nodes) delete[] m_nodes;
268 m_nodes = new wxStoredNode[m_maxNodes];
269 int i;
270 for (i = 0; i < n; i++)
271 {
272 m_nodes[i].m_name = "";
273 m_nodes[i].m_active = FALSE;
274 m_nodes[i].m_parentId = -1;
275 m_nodes[i].m_x = 0;
276 m_nodes[i].m_y = 0;
277 }
278 m_num = 0;
279 }
280
281 long wxTreeLayoutStored::AddChild(const wxString& name, const wxString& parent)
282 {
283 if (m_num < (m_maxNodes -1 ))
284 {
285 long i = -1;
286 if (parent != wxT(""))
287 i = NameToId(parent);
288 else m_parentNode = m_num;
289
290 m_nodes[m_num].m_parentId = i;
291 m_nodes[m_num].m_name = name;
292 m_nodes[m_num].m_x = m_nodes[m_num].m_y = 0;
293 m_nodes[m_num].m_clientData = 0;
294 m_num ++;
295
296 return (m_num - 1);
297 }
298 else
299 return -1;
300 }
301
302 long wxTreeLayoutStored::NameToId(const wxString& name)
303 {
304 long i;
305 for (i = 0; i < m_num; i++)
306 if (name == m_nodes[i].m_name)
307 return i;
308 return -1;
309 }
310
311 void wxTreeLayoutStored::GetChildren(long id, wxList& list)
312 {
313 long currentId = GetTopNode();
314 while (currentId != -1)
315 {
316 if (id == GetNodeParent(currentId))
317 list.Append((wxObject *)currentId);
318 currentId = GetNextNode(currentId);
319 }
320 }
321
322 wxStoredNode* wxTreeLayoutStored::GetNode(long idx) const
323 {
324 wxASSERT(idx < m_num);
325
326 return &m_nodes[idx];
327 };
328
329 long wxTreeLayoutStored::GetNodeX(long id)
330 {
331 wxASSERT(id < m_num);
332
333 return (long)m_nodes[id].m_x;
334 }
335
336 long wxTreeLayoutStored::GetNodeY(long id)
337 {
338 wxASSERT(id < m_num);
339
340 return (long)m_nodes[id].m_y;
341 }
342
343 void wxTreeLayoutStored::SetNodeX(long id, long x)
344 {
345 wxASSERT(id < m_num);
346
347 m_nodes[id].m_x = (int)x;
348 }
349
350 void wxTreeLayoutStored::SetNodeY(long id, long y)
351 {
352 wxASSERT(id < m_num);
353
354 m_nodes[id].m_y = (int)y;
355 }
356
357 void wxTreeLayoutStored::SetNodeName(long id, const wxString& name)
358 {
359 wxASSERT(id < m_num);
360
361 m_nodes[id].m_name = name;
362 }
363
364 wxString wxTreeLayoutStored::GetNodeName(long id)
365 {
366 wxASSERT(id < m_num);
367
368 return m_nodes[id].m_name;
369 }
370
371 long wxTreeLayoutStored::GetNodeParent(long id)
372 {
373 if (id != -1)
374 {
375 wxASSERT(id < m_num);
376
377 return m_nodes[id].m_parentId;
378 }
379 else
380 return -1;
381 }
382
383 long wxTreeLayoutStored::GetNextNode(long id)
384 {
385 wxASSERT(id < m_num);
386
387 if ((id != -1) && (id < (m_num - 1)))
388 return id + 1;
389 else
390 return -1;
391 }
392
393 void wxTreeLayoutStored::SetClientData(long id, long clientData)
394 {
395 wxASSERT(id < m_num);
396
397 m_nodes[id].m_clientData = clientData;
398 }
399
400 long wxTreeLayoutStored::GetClientData(long id) const
401 {
402 wxASSERT(id < m_num);
403
404 return m_nodes[id].m_clientData;
405 }
406
407 void wxTreeLayoutStored::ActivateNode(long id, bool active)
408 {
409 wxASSERT(id < m_num);
410
411 m_nodes[id].m_active = active;
412 }
413
414 bool wxTreeLayoutStored::NodeActive(long id)
415 {
416 wxASSERT(id < m_num);
417
418 return m_nodes[id].m_active;
419 }
420
421 wxString wxTreeLayoutStored::HitTest(wxMouseEvent& event, wxDC& dc)
422 {
423 wxPoint pt = event.GetPosition();
424 wxCoord x = pt.x;
425 wxCoord y = pt.y;
426
427 int i;
428 for (i = 0; i < m_maxNodes; i++)
429 {
430 long width, height;
431 dc.GetTextExtent(m_nodes[i].m_name, &width, &height);
432
433 if ( (x >= (m_nodes[i].m_x-10)) && (x < (m_nodes[i].m_x + width+10)) &&
434 (y >= m_nodes[i].m_y-10) && (y < (m_nodes[i].m_y + height+10)) )
435 {
436 return m_nodes[i].m_name;
437 }
438 }
439
440 return wxString("");
441 }
442
443 #endif
444 // wxUSE_TREELAYOUT