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