]> git.saurik.com Git - wxWidgets.git/blame - src/generic/treelay.cpp
give frame a reasonable default size if none specified
[wxWidgets.git] / src / generic / treelay.cpp
CommitLineData
babc9758
JS
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
f6bcfd97 24#include "wx/wx.h"
babc9758
JS
25#endif
26
27#if wxUSE_TREELAYOUT
28
29#include <wx/treelay.h>
30
31/*
32 * Abstract tree
33 *
34 */
35
36IMPLEMENT_ABSTRACT_CLASS(wxTreeLayout, wxObject)
37
38wxTreeLayout::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
48void 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
67void wxTreeLayout::Draw(wxDC& dc)
68{
69 dc.Clear();
70 DrawBranches(dc);
71 DrawNodes(dc);
72}
73
74void 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
85void 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
100void wxTreeLayout::DrawNode(long id, wxDC& dc)
101{
f6bcfd97 102 wxChar buf[80];
babc9758 103 wxString name(GetNodeName(id));
f6bcfd97
BP
104 if (name != wxT(""))
105 wxSprintf(buf, wxT("%s"), (const wxChar*) name);
babc9758 106 else
f6bcfd97 107 wxSprintf(buf, wxT("<unnamed>"));
babc9758
JS
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
115void 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
123void wxTreeLayout::Initialize(void)
124{
125}
126
127void wxTreeLayout::GetNodeSize(long id, long *x, long *y, wxDC& dc)
128{
129 wxString name(GetNodeName(id));
f6bcfd97 130 if (name != wxT(""))
babc9758
JS
131 dc.GetTextExtent(name, x, y);
132 else
133 {
134 *x = 70; *y = 20;
135 }
136}
137
138void 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
94799627 248IMPLEMENT_DYNAMIC_CLASS(wxTreeLayoutStored, wxTreeLayout)
babc9758 249
94799627 250wxTreeLayoutStored::wxTreeLayoutStored(int n):wxTreeLayout()
babc9758
JS
251{
252 m_nodes = NULL;
253 m_maxNodes = 0;
254 Initialize(n);
255}
256
94799627 257wxTreeLayoutStored::~wxTreeLayoutStored(void)
babc9758
JS
258{
259 if (m_nodes)
260 delete[] m_nodes;
261}
262
94799627 263void wxTreeLayoutStored::Initialize(int n)
babc9758
JS
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
94799627 281long wxTreeLayoutStored::AddChild(const wxString& name, const wxString& parent)
babc9758
JS
282{
283 if (m_num < (m_maxNodes -1 ))
284 {
285 long i = -1;
f6bcfd97 286 if (parent != wxT(""))
babc9758
JS
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
94799627 302long wxTreeLayoutStored::NameToId(const wxString& name)
babc9758
JS
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
94799627 311void wxTreeLayoutStored::GetChildren(long id, wxList& list)
babc9758
JS
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
94799627 322wxStoredNode* wxTreeLayoutStored::GetNode(long idx) const
babc9758
JS
323{
324 wxASSERT(idx < m_num);
325
326 return &m_nodes[idx];
327};
328
94799627 329long wxTreeLayoutStored::GetNodeX(long id)
babc9758
JS
330{
331 wxASSERT(id < m_num);
332
333 return (long)m_nodes[id].m_x;
334}
335
94799627 336long wxTreeLayoutStored::GetNodeY(long id)
babc9758
JS
337{
338 wxASSERT(id < m_num);
339
340 return (long)m_nodes[id].m_y;
341}
342
94799627 343void wxTreeLayoutStored::SetNodeX(long id, long x)
babc9758
JS
344{
345 wxASSERT(id < m_num);
346
347 m_nodes[id].m_x = (int)x;
348}
349
94799627 350void wxTreeLayoutStored::SetNodeY(long id, long y)
babc9758
JS
351{
352 wxASSERT(id < m_num);
353
354 m_nodes[id].m_y = (int)y;
355}
356
94799627 357void wxTreeLayoutStored::SetNodeName(long id, const wxString& name)
babc9758
JS
358{
359 wxASSERT(id < m_num);
360
361 m_nodes[id].m_name = name;
362}
363
94799627 364wxString wxTreeLayoutStored::GetNodeName(long id)
babc9758
JS
365{
366 wxASSERT(id < m_num);
367
368 return m_nodes[id].m_name;
369}
370
94799627 371long wxTreeLayoutStored::GetNodeParent(long id)
babc9758
JS
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
94799627 383long wxTreeLayoutStored::GetNextNode(long id)
babc9758
JS
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
94799627 393void wxTreeLayoutStored::SetClientData(long id, long clientData)
babc9758
JS
394{
395 wxASSERT(id < m_num);
396
397 m_nodes[id].m_clientData = clientData;
398}
399
94799627 400long wxTreeLayoutStored::GetClientData(long id) const
babc9758
JS
401{
402 wxASSERT(id < m_num);
403
404 return m_nodes[id].m_clientData;
405}
406
94799627 407void wxTreeLayoutStored::ActivateNode(long id, bool active)
babc9758
JS
408{
409 wxASSERT(id < m_num);
410
411 m_nodes[id].m_active = active;
412}
413
94799627 414bool wxTreeLayoutStored::NodeActive(long id)
babc9758
JS
415{
416 wxASSERT(id < m_num);
417
418 return m_nodes[id].m_active;
419}
420
94799627 421wxString wxTreeLayoutStored::HitTest(wxMouseEvent& event, wxDC& dc)
babc9758
JS
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 {
babc9758
JS
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