]>
Commit | Line | Data |
---|---|---|
c801d85f KB |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: treectrl.cpp | |
f135ff73 | 3 | // Purpose: generic tree control implementation |
c801d85f KB |
4 | // Author: Robert Roebling |
5 | // Created: 01/02/97 | |
f135ff73 | 6 | // Modified: 22/10/98 - almost total rewrite, simpler interface (VZ) |
389cdc7a | 7 | // Id: $Id$ |
c801d85f | 8 | // Copyright: (c) 1998 Robert Roebling, Julian Smart and Markus Holzem |
29d87bba | 9 | // Licence: wxWindows licence |
c801d85f KB |
10 | ///////////////////////////////////////////////////////////////////////////// |
11 | ||
f135ff73 VZ |
12 | // ============================================================================= |
13 | // declarations | |
14 | // ============================================================================= | |
15 | ||
16 | // ----------------------------------------------------------------------------- | |
17 | // headers | |
18 | // ----------------------------------------------------------------------------- | |
19 | ||
c801d85f | 20 | #ifdef __GNUG__ |
f135ff73 | 21 | #pragma implementation "treectrl.h" |
c801d85f KB |
22 | #endif |
23 | ||
1e6d9499 JS |
24 | // For compilers that support precompilation, includes "wx.h". |
25 | #include "wx/wxprec.h" | |
26 | ||
27 | #ifdef __BORLANDC__ | |
28 | #pragma hdrstop | |
29 | #endif | |
30 | ||
31 | #include "wx/generic/treectrl.h" | |
f60d0f94 | 32 | #include "wx/generic/imaglist.h" |
c801d85f | 33 | #include "wx/settings.h" |
389cdc7a | 34 | #include "wx/log.h" |
f135ff73 VZ |
35 | #include "wx/intl.h" |
36 | #include "wx/dynarray.h" | |
37 | #include "wx/dcclient.h" | |
0659e7ee | 38 | #include "wx/msgdlg.h" |
c801d85f | 39 | |
f135ff73 VZ |
40 | // ----------------------------------------------------------------------------- |
41 | // array types | |
42 | // ----------------------------------------------------------------------------- | |
c801d85f | 43 | |
1e6d9499 JS |
44 | class WXDLLEXPORT wxGenericTreeItem; |
45 | ||
f135ff73 | 46 | WX_DEFINE_ARRAY(wxGenericTreeItem *, wxArrayTreeItems); |
c801d85f | 47 | |
f135ff73 VZ |
48 | // ----------------------------------------------------------------------------- |
49 | // private classes | |
50 | // ----------------------------------------------------------------------------- | |
51 | ||
52 | // a tree item | |
53 | class WXDLLEXPORT wxGenericTreeItem | |
c801d85f | 54 | { |
f135ff73 VZ |
55 | public: |
56 | // ctors & dtor | |
57 | wxGenericTreeItem() { m_data = NULL; } | |
58 | wxGenericTreeItem( wxGenericTreeItem *parent, | |
59 | const wxString& text, | |
60 | wxDC& dc, | |
61 | int image, int selImage, | |
62 | wxTreeItemData *data ); | |
63 | ||
ff5bf259 | 64 | ~wxGenericTreeItem(); |
f135ff73 VZ |
65 | |
66 | // trivial accessors | |
67 | wxArrayTreeItems& GetChildren() { return m_children; } | |
68 | ||
69 | const wxString& GetText() const { return m_text; } | |
70 | int GetImage() const { return m_image; } | |
71 | int GetSelectedImage() const { return m_selImage; } | |
72 | wxTreeItemData *GetData() const { return m_data; } | |
73 | ||
74 | void SetText( const wxString &text, wxDC& dc ); | |
75 | void SetImage(int image) { m_image = image; } | |
76 | void SetSelectedImage(int image) { m_selImage = image; } | |
77 | void SetData(wxTreeItemData *data) { m_data = data; } | |
78 | ||
79 | void SetHasPlus(bool has = TRUE) { m_hasPlus = has; } | |
80 | ||
ef44a621 VZ |
81 | void SetBold(bool bold) { m_isBold = bold; } |
82 | ||
f135ff73 VZ |
83 | int GetX() const { return m_x; } |
84 | int GetY() const { return m_y; } | |
85 | ||
86 | void SetHeight(int h) { m_height = h; } | |
87 | ||
88 | void SetX(int x) { m_x = x; } | |
89 | void SetY(int y) { m_y = y; } | |
90 | ||
91 | wxGenericTreeItem *GetParent() const { return m_parent; } | |
c801d85f | 92 | |
f135ff73 | 93 | // operations |
a43a4f9d VZ |
94 | // deletes all children notifying the treectrl about it if !NULL pointer |
95 | // given | |
96 | void DeleteChildren(wxTreeCtrl *tree = NULL); | |
97 | // FIXME don't know what is it for | |
f135ff73 VZ |
98 | void Reset(); |
99 | ||
4832f7c0 VZ |
100 | // get count of all children (and grand children if 'recursively') |
101 | size_t GetChildrenCount(bool recursively = TRUE) const; | |
f135ff73 VZ |
102 | |
103 | void Insert(wxGenericTreeItem *child, size_t index) | |
104 | { m_children.Insert(child, index); } | |
105 | ||
106 | void SetCross( int x, int y ); | |
107 | void GetSize( int &x, int &y ); | |
108 | ||
109 | // return the item at given position (or NULL if no item), onButton is TRUE | |
110 | // if the point belongs to the item's button, otherwise it lies on the | |
111 | // button's label | |
112 | wxGenericTreeItem *HitTest( const wxPoint& point, bool &onButton ); | |
113 | ||
114 | void Expand() { m_isCollapsed = FALSE; } | |
115 | void Collapse() { m_isCollapsed = TRUE; } | |
116 | ||
117 | void SetHilight( bool set = TRUE ) { m_hasHilight = set; } | |
118 | ||
119 | // status inquiries | |
120 | bool HasChildren() const { return !m_children.IsEmpty(); } | |
121 | bool HasHilight() const { return m_hasHilight; } | |
122 | bool IsExpanded() const { return !m_isCollapsed; } | |
123 | bool HasPlus() const { return m_hasPlus || HasChildren(); } | |
ef44a621 | 124 | bool IsBold() const { return m_isBold; } |
f135ff73 VZ |
125 | |
126 | private: | |
127 | wxString m_text; | |
128 | ||
129 | int m_image, | |
130 | m_selImage; | |
131 | ||
132 | wxTreeItemData *m_data; | |
4832f7c0 | 133 | |
ef44a621 VZ |
134 | // use bitfields to save size |
135 | int m_isCollapsed :1; | |
136 | int m_hasHilight :1; // same as focused | |
137 | int m_hasPlus :1; // used for item which doesn't have | |
138 | // children but still has a [+] button | |
139 | int m_isBold :1; // render the label in bold font | |
f135ff73 VZ |
140 | |
141 | int m_x, m_y; | |
142 | long m_height, m_width; | |
143 | int m_xCross, m_yCross; | |
144 | int m_level; | |
145 | wxArrayTreeItems m_children; | |
146 | wxGenericTreeItem *m_parent; | |
147 | }; | |
148 | ||
149 | // ============================================================================= | |
150 | // implementation | |
151 | // ============================================================================= | |
152 | ||
153 | // ----------------------------------------------------------------------------- | |
c801d85f | 154 | // wxTreeEvent |
f135ff73 | 155 | // ----------------------------------------------------------------------------- |
c801d85f | 156 | |
92976ab6 | 157 | IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent) |
c801d85f | 158 | |
f135ff73 | 159 | wxTreeEvent::wxTreeEvent( wxEventType commandType, int id ) |
92976ab6 | 160 | : wxNotifyEvent( commandType, id ) |
c801d85f KB |
161 | { |
162 | m_code = 0; | |
f135ff73 | 163 | m_itemOld = (wxGenericTreeItem *)NULL; |
edaa81ae | 164 | } |
c801d85f | 165 | |
f135ff73 | 166 | // ----------------------------------------------------------------------------- |
c801d85f | 167 | // wxGenericTreeItem |
f135ff73 | 168 | // ----------------------------------------------------------------------------- |
c801d85f | 169 | |
f135ff73 VZ |
170 | wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent, |
171 | const wxString& text, | |
172 | wxDC& dc, | |
173 | int image, int selImage, | |
174 | wxTreeItemData *data) | |
175 | : m_text(text) | |
c801d85f | 176 | { |
f135ff73 VZ |
177 | m_image = image; |
178 | m_selImage = selImage; | |
179 | m_data = data; | |
180 | m_x = m_y = 0; | |
181 | m_xCross = m_yCross = 0; | |
182 | ||
183 | m_level = 0; | |
184 | ||
185 | m_isCollapsed = TRUE; | |
c801d85f | 186 | m_hasHilight = FALSE; |
df875e59 | 187 | m_hasPlus = FALSE; |
ef44a621 | 188 | m_isBold = FALSE; |
c801d85f | 189 | |
c801d85f | 190 | m_parent = parent; |
f135ff73 VZ |
191 | |
192 | dc.GetTextExtent( m_text, &m_width, &m_height ); | |
edaa81ae | 193 | } |
c801d85f | 194 | |
f135ff73 | 195 | wxGenericTreeItem::~wxGenericTreeItem() |
c801d85f | 196 | { |
f135ff73 | 197 | delete m_data; |
4832f7c0 | 198 | |
a43a4f9d VZ |
199 | wxASSERT_MSG( m_children.IsEmpty(), |
200 | "please call DeleteChildren() before deleting the item" ); | |
372edb9d VZ |
201 | } |
202 | ||
a43a4f9d | 203 | void wxGenericTreeItem::DeleteChildren(wxTreeCtrl *tree) |
372edb9d | 204 | { |
f135ff73 VZ |
205 | size_t count = m_children.Count(); |
206 | for ( size_t n = 0; n < count; n++ ) | |
a43a4f9d VZ |
207 | { |
208 | wxGenericTreeItem *child = m_children[n]; | |
209 | if ( tree ) | |
210 | { | |
211 | tree->SendDeleteEvent(child); | |
212 | } | |
213 | ||
214 | child->DeleteChildren(tree); | |
215 | delete child; | |
216 | } | |
372edb9d VZ |
217 | |
218 | m_children.Empty(); | |
edaa81ae | 219 | } |
c801d85f | 220 | |
f135ff73 | 221 | void wxGenericTreeItem::SetText( const wxString &text, wxDC& dc ) |
c801d85f KB |
222 | { |
223 | m_text = text; | |
f135ff73 VZ |
224 | |
225 | dc.GetTextExtent( m_text, &m_width, &m_height ); | |
edaa81ae | 226 | } |
c801d85f | 227 | |
74bedbeb | 228 | void wxGenericTreeItem::Reset() |
c801d85f | 229 | { |
f135ff73 VZ |
230 | m_text.Empty(); |
231 | m_image = | |
232 | m_selImage = -1; | |
233 | m_data = NULL; | |
234 | m_x = m_y = | |
235 | m_height = m_width = 0; | |
236 | m_xCross = | |
c801d85f | 237 | m_yCross = 0; |
74bedbeb | 238 | |
f135ff73 | 239 | m_level = 0; |
c801d85f | 240 | |
372edb9d | 241 | DeleteChildren(); |
f135ff73 | 242 | m_isCollapsed = TRUE; |
c801d85f | 243 | |
f135ff73 | 244 | m_parent = (wxGenericTreeItem *)NULL; |
edaa81ae | 245 | } |
c801d85f | 246 | |
4832f7c0 | 247 | size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const |
c801d85f | 248 | { |
f135ff73 | 249 | size_t count = m_children.Count(); |
4832f7c0 VZ |
250 | if ( !recursively ) |
251 | return count; | |
252 | ||
f135ff73 VZ |
253 | size_t total = count; |
254 | for ( size_t n = 0; n < count; n++ ) | |
c801d85f | 255 | { |
4832f7c0 | 256 | total += m_children[n]->GetChildrenCount(); |
edaa81ae | 257 | } |
c801d85f | 258 | |
f135ff73 | 259 | return total; |
edaa81ae | 260 | } |
c801d85f KB |
261 | |
262 | void wxGenericTreeItem::SetCross( int x, int y ) | |
263 | { | |
264 | m_xCross = x; | |
265 | m_yCross = y; | |
edaa81ae | 266 | } |
c801d85f KB |
267 | |
268 | void wxGenericTreeItem::GetSize( int &x, int &y ) | |
269 | { | |
df875e59 | 270 | if ( y < m_y ) y = m_y; |
c801d85f KB |
271 | int width = m_x + m_width; |
272 | if (width > x) x = width; | |
f135ff73 | 273 | |
df875e59 | 274 | if (IsExpanded()) |
c801d85f | 275 | { |
df875e59 RR |
276 | size_t count = m_children.Count(); |
277 | for ( size_t n = 0; n < count; n++ ) | |
4832f7c0 | 278 | { |
df875e59 RR |
279 | m_children[n]->GetSize( x, y ); |
280 | } | |
edaa81ae RR |
281 | } |
282 | } | |
c801d85f | 283 | |
f135ff73 VZ |
284 | wxGenericTreeItem *wxGenericTreeItem::HitTest( const wxPoint& point, |
285 | bool &onButton ) | |
c801d85f | 286 | { |
f135ff73 | 287 | if ((point.y > m_y) && (point.y < m_y + m_height)) |
c801d85f | 288 | { |
f135ff73 VZ |
289 | // FIXME why +5? |
290 | if ((point.x > m_xCross-5) && (point.x < m_xCross+5) && | |
291 | (point.y > m_yCross-5) && (point.y < m_yCross+5) && | |
f9f950fc | 292 | (IsExpanded() || HasPlus())) |
c801d85f | 293 | { |
f135ff73 VZ |
294 | onButton = TRUE; |
295 | return this; | |
edaa81ae | 296 | } |
a93109d5 RR |
297 | |
298 | int w = m_width; | |
299 | if (m_image != -1) w += 20; | |
f135ff73 | 300 | |
a93109d5 | 301 | if ((point.x > m_x) && (point.x < m_x+w)) |
c801d85f | 302 | { |
f135ff73 VZ |
303 | onButton = FALSE; |
304 | return this; | |
edaa81ae | 305 | } |
c801d85f KB |
306 | } |
307 | else | |
308 | { | |
e2414cbe | 309 | if (!m_isCollapsed) |
c801d85f | 310 | { |
f135ff73 VZ |
311 | size_t count = m_children.Count(); |
312 | for ( size_t n = 0; n < count; n++ ) | |
e2414cbe | 313 | { |
f135ff73 VZ |
314 | wxGenericTreeItem *res = m_children[n]->HitTest( point, onButton ); |
315 | if ( res != NULL ) | |
316 | return res; | |
edaa81ae RR |
317 | } |
318 | } | |
319 | } | |
f135ff73 VZ |
320 | |
321 | return NULL; | |
edaa81ae | 322 | } |
c801d85f | 323 | |
f135ff73 VZ |
324 | // ----------------------------------------------------------------------------- |
325 | // wxTreeCtrl implementation | |
326 | // ----------------------------------------------------------------------------- | |
327 | ||
328 | IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxScrolledWindow) | |
329 | ||
330 | BEGIN_EVENT_TABLE(wxTreeCtrl,wxScrolledWindow) | |
331 | EVT_PAINT (wxTreeCtrl::OnPaint) | |
332 | EVT_MOUSE_EVENTS (wxTreeCtrl::OnMouse) | |
333 | EVT_CHAR (wxTreeCtrl::OnChar) | |
334 | EVT_SET_FOCUS (wxTreeCtrl::OnSetFocus) | |
335 | EVT_KILL_FOCUS (wxTreeCtrl::OnKillFocus) | |
3db7be80 | 336 | EVT_IDLE (wxTreeCtrl::OnIdle) |
f135ff73 VZ |
337 | END_EVENT_TABLE() |
338 | ||
339 | // ----------------------------------------------------------------------------- | |
340 | // construction/destruction | |
341 | // ----------------------------------------------------------------------------- | |
342 | void wxTreeCtrl::Init() | |
c801d85f | 343 | { |
f135ff73 VZ |
344 | m_current = |
345 | m_anchor = (wxGenericTreeItem *) NULL; | |
346 | m_hasFocus = FALSE; | |
3db7be80 | 347 | m_dirty = FALSE; |
f135ff73 VZ |
348 | |
349 | m_xScroll = 0; | |
350 | m_yScroll = 0; | |
351 | m_lineHeight = 10; | |
352 | m_indent = 15; | |
353 | ||
354 | m_hilightBrush = new wxBrush | |
355 | ( | |
356 | wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT), | |
357 | wxSOLID | |
358 | ); | |
359 | ||
360 | m_imageListNormal = | |
361 | m_imageListState = (wxImageList *) NULL; | |
edaa81ae | 362 | } |
c801d85f | 363 | |
f135ff73 VZ |
364 | bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id, |
365 | const wxPoint& pos, const wxSize& size, | |
4f22cf8d RR |
366 | long style, |
367 | const wxValidator &validator, | |
368 | const wxString& name ) | |
c801d85f | 369 | { |
f135ff73 VZ |
370 | Init(); |
371 | ||
a367b9b3 | 372 | wxScrolledWindow::Create( parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name ); |
4f22cf8d RR |
373 | |
374 | SetValidator( validator ); | |
f135ff73 VZ |
375 | |
376 | SetBackgroundColour( *wxWHITE ); | |
377 | m_dottedPen = wxPen( *wxBLACK, 0, 0 ); | |
378 | ||
379 | return TRUE; | |
edaa81ae | 380 | } |
c801d85f | 381 | |
f135ff73 | 382 | wxTreeCtrl::~wxTreeCtrl() |
c801d85f | 383 | { |
f135ff73 | 384 | wxDELETE( m_hilightBrush ); |
a43a4f9d VZ |
385 | |
386 | DeleteAllItems(); | |
edaa81ae | 387 | } |
c801d85f | 388 | |
f135ff73 VZ |
389 | // ----------------------------------------------------------------------------- |
390 | // accessors | |
391 | // ----------------------------------------------------------------------------- | |
392 | ||
393 | size_t wxTreeCtrl::GetCount() const | |
c801d85f | 394 | { |
4832f7c0 | 395 | return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount(); |
edaa81ae | 396 | } |
c801d85f | 397 | |
f135ff73 | 398 | void wxTreeCtrl::SetIndent(unsigned int indent) |
c801d85f | 399 | { |
f135ff73 VZ |
400 | m_indent = indent; |
401 | Refresh(); | |
402 | } | |
74bedbeb | 403 | |
4832f7c0 VZ |
404 | size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively) |
405 | { | |
406 | wxCHECK_MSG( item.IsOk(), 0u, "invalid tree item" ); | |
407 | ||
408 | return item.m_pItem->GetChildrenCount(recursively); | |
409 | } | |
410 | ||
f135ff73 VZ |
411 | // ----------------------------------------------------------------------------- |
412 | // functions to work with tree items | |
413 | // ----------------------------------------------------------------------------- | |
74bedbeb | 414 | |
f135ff73 VZ |
415 | wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const |
416 | { | |
4832f7c0 VZ |
417 | wxCHECK_MSG( item.IsOk(), "", "invalid tree item" ); |
418 | ||
f135ff73 | 419 | return item.m_pItem->GetText(); |
edaa81ae | 420 | } |
74bedbeb | 421 | |
f135ff73 | 422 | int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const |
74bedbeb | 423 | { |
4832f7c0 VZ |
424 | wxCHECK_MSG( item.IsOk(), -1, "invalid tree item" ); |
425 | ||
f135ff73 | 426 | return item.m_pItem->GetImage(); |
edaa81ae | 427 | } |
c801d85f | 428 | |
f135ff73 | 429 | int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const |
c801d85f | 430 | { |
4832f7c0 VZ |
431 | wxCHECK_MSG( item.IsOk(), -1, "invalid tree item" ); |
432 | ||
f135ff73 | 433 | return item.m_pItem->GetSelectedImage(); |
edaa81ae | 434 | } |
c801d85f | 435 | |
f135ff73 | 436 | wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const |
c801d85f | 437 | { |
4832f7c0 VZ |
438 | wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" ); |
439 | ||
f135ff73 | 440 | return item.m_pItem->GetData(); |
edaa81ae | 441 | } |
c801d85f | 442 | |
f135ff73 VZ |
443 | void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text) |
444 | { | |
4832f7c0 VZ |
445 | wxCHECK_RET( item.IsOk(), "invalid tree item" ); |
446 | ||
f135ff73 | 447 | wxClientDC dc(this); |
de646ed1 | 448 | item.m_pItem->SetText(text, dc); |
f135ff73 | 449 | } |
c801d85f | 450 | |
f135ff73 VZ |
451 | void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image) |
452 | { | |
4832f7c0 VZ |
453 | wxCHECK_RET( item.IsOk(), "invalid tree item" ); |
454 | ||
de646ed1 | 455 | item.m_pItem->SetImage(image); |
f135ff73 | 456 | } |
c801d85f | 457 | |
f135ff73 | 458 | void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image) |
c801d85f | 459 | { |
4832f7c0 VZ |
460 | wxCHECK_RET( item.IsOk(), "invalid tree item" ); |
461 | ||
de646ed1 | 462 | item.m_pItem->SetSelectedImage(image); |
edaa81ae | 463 | } |
c801d85f | 464 | |
f135ff73 | 465 | void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data) |
c801d85f | 466 | { |
4832f7c0 VZ |
467 | wxCHECK_RET( item.IsOk(), "invalid tree item" ); |
468 | ||
de646ed1 | 469 | item.m_pItem->SetData(data); |
edaa81ae | 470 | } |
c801d85f | 471 | |
f135ff73 | 472 | void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has) |
c801d85f | 473 | { |
4832f7c0 VZ |
474 | wxCHECK_RET( item.IsOk(), "invalid tree item" ); |
475 | ||
f135ff73 | 476 | item.m_pItem->SetHasPlus(has); |
edaa81ae | 477 | } |
c801d85f | 478 | |
ef44a621 VZ |
479 | void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold) |
480 | { | |
481 | wxCHECK_RET( item.IsOk(), "invalid tree item" ); | |
482 | ||
483 | // avoid redrawing the tree if no real change | |
484 | wxGenericTreeItem *pItem = item.m_pItem; | |
485 | if ( pItem->IsBold() != bold ) | |
486 | { | |
487 | pItem->SetBold(bold); | |
488 | RefreshLine(pItem); | |
489 | } | |
490 | } | |
491 | ||
f135ff73 VZ |
492 | // ----------------------------------------------------------------------------- |
493 | // item status inquiries | |
494 | // ----------------------------------------------------------------------------- | |
495 | ||
df875e59 | 496 | bool wxTreeCtrl::IsVisible(const wxTreeItemId& WXUNUSED(item)) const |
c801d85f | 497 | { |
f135ff73 VZ |
498 | wxFAIL_MSG("not implemented"); |
499 | ||
c801d85f | 500 | return TRUE; |
edaa81ae | 501 | } |
c801d85f | 502 | |
f135ff73 | 503 | bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const |
c801d85f | 504 | { |
4832f7c0 VZ |
505 | wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" ); |
506 | ||
f135ff73 | 507 | return !item.m_pItem->GetChildren().IsEmpty(); |
edaa81ae | 508 | } |
c801d85f | 509 | |
f135ff73 | 510 | bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const |
c801d85f | 511 | { |
4832f7c0 VZ |
512 | wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" ); |
513 | ||
f135ff73 VZ |
514 | return item.m_pItem->IsExpanded(); |
515 | } | |
29d87bba | 516 | |
f135ff73 VZ |
517 | bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const |
518 | { | |
4832f7c0 VZ |
519 | wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" ); |
520 | ||
f135ff73 VZ |
521 | return item.m_pItem->HasHilight(); |
522 | } | |
29d87bba | 523 | |
ef44a621 VZ |
524 | bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const |
525 | { | |
526 | wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" ); | |
527 | ||
528 | return item.m_pItem->IsBold(); | |
529 | } | |
530 | ||
f135ff73 VZ |
531 | // ----------------------------------------------------------------------------- |
532 | // navigation | |
533 | // ----------------------------------------------------------------------------- | |
29d87bba | 534 | |
f135ff73 VZ |
535 | wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const |
536 | { | |
1e6d9499 | 537 | wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" ); |
389cdc7a | 538 | |
f135ff73 VZ |
539 | return item.m_pItem->GetParent(); |
540 | } | |
29d87bba | 541 | |
f135ff73 VZ |
542 | wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& cookie) const |
543 | { | |
1e6d9499 | 544 | wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" ); |
29d87bba | 545 | |
f135ff73 VZ |
546 | cookie = 0; |
547 | return GetNextChild(item, cookie); | |
548 | } | |
29d87bba | 549 | |
f135ff73 VZ |
550 | wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) const |
551 | { | |
1e6d9499 | 552 | wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" ); |
29d87bba | 553 | |
4832f7c0 VZ |
554 | wxArrayTreeItems& children = item.m_pItem->GetChildren(); |
555 | if ( (size_t)cookie < children.Count() ) | |
556 | { | |
557 | return item.m_pItem->GetChildren().Item(cookie++); | |
558 | } | |
559 | else | |
560 | { | |
561 | // there are no more of them | |
1e6d9499 | 562 | return wxTreeItemId(); |
4832f7c0 | 563 | } |
f135ff73 | 564 | } |
29d87bba | 565 | |
f135ff73 VZ |
566 | wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const |
567 | { | |
1e6d9499 | 568 | wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" ); |
f135ff73 VZ |
569 | |
570 | wxGenericTreeItem *i = item.m_pItem; | |
571 | wxGenericTreeItem *parent = i->GetParent(); | |
572 | if ( parent == NULL ) | |
573 | { | |
574 | // root item doesn't have any siblings | |
1e6d9499 | 575 | return wxTreeItemId(); |
edaa81ae | 576 | } |
4832f7c0 | 577 | |
f135ff73 VZ |
578 | wxArrayTreeItems& siblings = parent->GetChildren(); |
579 | int index = siblings.Index(i); | |
580 | wxASSERT( index != NOT_FOUND ); // I'm not a child of my parent? | |
29d87bba | 581 | |
f135ff73 | 582 | size_t n = (size_t)(index + 1); |
fdd8d7b5 | 583 | return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]); |
edaa81ae | 584 | } |
c801d85f | 585 | |
f135ff73 | 586 | wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const |
c801d85f | 587 | { |
1e6d9499 | 588 | wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" ); |
f135ff73 VZ |
589 | |
590 | wxGenericTreeItem *i = item.m_pItem; | |
591 | wxGenericTreeItem *parent = i->GetParent(); | |
592 | if ( parent == NULL ) | |
c801d85f | 593 | { |
f135ff73 | 594 | // root item doesn't have any siblings |
1e6d9499 | 595 | return wxTreeItemId(); |
edaa81ae | 596 | } |
4832f7c0 | 597 | |
f135ff73 VZ |
598 | wxArrayTreeItems& siblings = parent->GetChildren(); |
599 | int index = siblings.Index(i); | |
600 | wxASSERT( index != NOT_FOUND ); // I'm not a child of my parent? | |
29d87bba | 601 | |
fdd8d7b5 VZ |
602 | return index == 0 ? wxTreeItemId() |
603 | : wxTreeItemId(siblings[(size_t)(index - 1)]); | |
f135ff73 | 604 | } |
389cdc7a | 605 | |
f135ff73 VZ |
606 | wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const |
607 | { | |
608 | wxFAIL_MSG("not implemented"); | |
29d87bba | 609 | |
1e6d9499 | 610 | return wxTreeItemId(); |
f135ff73 | 611 | } |
29d87bba | 612 | |
f135ff73 VZ |
613 | wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const |
614 | { | |
1e6d9499 | 615 | wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" ); |
29d87bba | 616 | |
f135ff73 | 617 | wxFAIL_MSG("not implemented"); |
29d87bba | 618 | |
1e6d9499 | 619 | return wxTreeItemId(); |
f135ff73 | 620 | } |
29d87bba | 621 | |
f135ff73 VZ |
622 | wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const |
623 | { | |
1e6d9499 | 624 | wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" ); |
29d87bba | 625 | |
f135ff73 | 626 | wxFAIL_MSG("not implemented"); |
29d87bba | 627 | |
1e6d9499 | 628 | return wxTreeItemId(); |
edaa81ae | 629 | } |
c801d85f | 630 | |
f135ff73 VZ |
631 | // ----------------------------------------------------------------------------- |
632 | // operations | |
633 | // ----------------------------------------------------------------------------- | |
634 | ||
635 | wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parentId, | |
636 | size_t previous, | |
637 | const wxString& text, | |
638 | int image, int selImage, | |
639 | wxTreeItemData *data) | |
c801d85f | 640 | { |
f135ff73 VZ |
641 | wxGenericTreeItem *parent = parentId.m_pItem; |
642 | if ( !parent ) | |
643 | { | |
644 | // should we give a warning here? | |
645 | return AddRoot(text, image, selImage, data); | |
646 | } | |
4832f7c0 | 647 | |
f135ff73 VZ |
648 | wxClientDC dc(this); |
649 | wxGenericTreeItem *item = new wxGenericTreeItem(parent, | |
650 | text, dc, | |
651 | image, selImage, | |
652 | data); | |
74bedbeb | 653 | |
f135ff73 | 654 | if ( data != NULL ) |
c801d85f | 655 | { |
f135ff73 VZ |
656 | data->m_pItem = item; |
657 | } | |
74bedbeb | 658 | |
f135ff73 | 659 | parent->Insert( item, previous ); |
ef44a621 | 660 | |
3db7be80 | 661 | m_dirty = TRUE; |
389cdc7a | 662 | |
f135ff73 | 663 | return item; |
4c681997 RR |
664 | } |
665 | ||
f135ff73 VZ |
666 | wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text, |
667 | int image, int selImage, | |
668 | wxTreeItemData *data) | |
4c681997 | 669 | { |
1e6d9499 | 670 | wxCHECK_MSG( !m_anchor, wxTreeItemId(), "tree can have only one root" ); |
389cdc7a | 671 | |
f135ff73 VZ |
672 | wxClientDC dc(this); |
673 | m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, dc, | |
674 | image, selImage, data); | |
675 | if ( data != NULL ) | |
676 | { | |
677 | data->m_pItem = m_anchor; | |
678 | } | |
389cdc7a | 679 | |
f135ff73 | 680 | AdjustMyScrollbars(); |
a32dd690 | 681 | Refresh(); |
a32dd690 | 682 | |
f135ff73 | 683 | return m_anchor; |
edaa81ae | 684 | } |
c801d85f | 685 | |
f135ff73 VZ |
686 | wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent, |
687 | const wxString& text, | |
688 | int image, int selImage, | |
689 | wxTreeItemData *data) | |
c801d85f | 690 | { |
f135ff73 | 691 | return DoInsertItem(parent, 0u, text, image, selImage, data); |
edaa81ae | 692 | } |
c801d85f | 693 | |
f135ff73 VZ |
694 | wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parentId, |
695 | const wxTreeItemId& idPrevious, | |
696 | const wxString& text, | |
697 | int image, int selImage, | |
698 | wxTreeItemData *data) | |
c801d85f | 699 | { |
f135ff73 VZ |
700 | wxGenericTreeItem *parent = parentId.m_pItem; |
701 | if ( !parent ) | |
702 | { | |
703 | // should we give a warning here? | |
704 | return AddRoot(text, image, selImage, data); | |
705 | } | |
c801d85f | 706 | |
f135ff73 VZ |
707 | int index = parent->GetChildren().Index(idPrevious.m_pItem); |
708 | wxASSERT_MSG( index != NOT_FOUND, | |
709 | "previous item in wxTreeCtrl::InsertItem() is not a sibling" ); | |
710 | return DoInsertItem(parentId, (size_t)index, text, image, selImage, data); | |
edaa81ae | 711 | } |
c801d85f | 712 | |
f135ff73 VZ |
713 | wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parentId, |
714 | const wxString& text, | |
715 | int image, int selImage, | |
716 | wxTreeItemData *data) | |
74bedbeb | 717 | { |
f135ff73 VZ |
718 | wxGenericTreeItem *parent = parentId.m_pItem; |
719 | if ( !parent ) | |
720 | { | |
721 | // should we give a warning here? | |
722 | return AddRoot(text, image, selImage, data); | |
723 | } | |
724 | ||
725 | return DoInsertItem(parent, parent->GetChildren().Count(), text, | |
726 | image, selImage, data); | |
74bedbeb VZ |
727 | } |
728 | ||
a43a4f9d VZ |
729 | void wxTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item) |
730 | { | |
731 | wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() ); | |
732 | event.m_item = item; | |
733 | event.SetEventObject( this ); | |
734 | ProcessEvent( event ); | |
735 | } | |
736 | ||
372edb9d VZ |
737 | void wxTreeCtrl::DeleteChildren(const wxTreeItemId& itemId) |
738 | { | |
739 | wxGenericTreeItem *item = itemId.m_pItem; | |
a43a4f9d | 740 | item->DeleteChildren(this); |
372edb9d VZ |
741 | |
742 | m_dirty = TRUE; | |
743 | } | |
744 | ||
f135ff73 | 745 | void wxTreeCtrl::Delete(const wxTreeItemId& itemId) |
c801d85f | 746 | { |
f135ff73 | 747 | wxGenericTreeItem *item = itemId.m_pItem; |
ff5bf259 VZ |
748 | wxGenericTreeItem *parent = item->GetParent(); |
749 | ||
750 | if ( parent ) | |
751 | { | |
752 | parent->GetChildren().Remove(item); | |
753 | } | |
f135ff73 | 754 | |
a43a4f9d VZ |
755 | item->DeleteChildren(this); |
756 | SendDeleteEvent(item); | |
f135ff73 VZ |
757 | delete item; |
758 | ||
4bb19cfb | 759 | m_dirty = TRUE; |
edaa81ae | 760 | } |
c801d85f | 761 | |
f135ff73 | 762 | void wxTreeCtrl::DeleteAllItems() |
c801d85f | 763 | { |
f135ff73 VZ |
764 | if ( m_anchor ) |
765 | { | |
a43a4f9d | 766 | m_anchor->DeleteChildren(this); |
f135ff73 | 767 | delete m_anchor; |
a43a4f9d | 768 | |
f135ff73 VZ |
769 | m_anchor = NULL; |
770 | ||
4bb19cfb | 771 | m_dirty = TRUE; |
f135ff73 | 772 | } |
edaa81ae RR |
773 | } |
774 | ||
f135ff73 | 775 | void wxTreeCtrl::Expand(const wxTreeItemId& itemId) |
edaa81ae | 776 | { |
f135ff73 VZ |
777 | wxGenericTreeItem *item = itemId.m_pItem; |
778 | ||
4bb19cfb RR |
779 | if ( !item->HasPlus() ) |
780 | return; | |
781 | ||
f135ff73 VZ |
782 | if ( item->IsExpanded() ) |
783 | return; | |
784 | ||
785 | wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() ); | |
786 | event.m_item = item; | |
787 | event.SetEventObject( this ); | |
788 | if ( ProcessEvent( event ) && event.m_code ) | |
789 | { | |
790 | // cancelled by program | |
791 | return; | |
792 | } | |
4832f7c0 | 793 | |
f135ff73 | 794 | item->Expand(); |
28ab302b | 795 | CalculatePositions(); |
f135ff73 VZ |
796 | |
797 | RefreshSubtree(item); | |
798 | ||
799 | event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED); | |
800 | ProcessEvent( event ); | |
edaa81ae RR |
801 | } |
802 | ||
f135ff73 | 803 | void wxTreeCtrl::Collapse(const wxTreeItemId& itemId) |
edaa81ae | 804 | { |
f135ff73 VZ |
805 | wxGenericTreeItem *item = itemId.m_pItem; |
806 | ||
807 | if ( !item->IsExpanded() ) | |
808 | return; | |
809 | ||
810 | wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() ); | |
811 | event.m_item = item; | |
812 | event.SetEventObject( this ); | |
813 | if ( ProcessEvent( event ) && event.m_code ) | |
edaa81ae | 814 | { |
f135ff73 VZ |
815 | // cancelled by program |
816 | return; | |
817 | } | |
4832f7c0 | 818 | |
f135ff73 VZ |
819 | item->Collapse(); |
820 | ||
821 | wxArrayTreeItems& children = item->GetChildren(); | |
822 | size_t count = children.Count(); | |
823 | for ( size_t n = 0; n < count; n++ ) | |
824 | { | |
825 | Collapse(children[n]); | |
edaa81ae | 826 | } |
f135ff73 VZ |
827 | |
828 | CalculatePositions(); | |
829 | ||
830 | RefreshSubtree(item); | |
831 | ||
832 | event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED); | |
833 | ProcessEvent( event ); | |
edaa81ae | 834 | } |
c801d85f | 835 | |
f135ff73 | 836 | void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item) |
c801d85f | 837 | { |
f135ff73 | 838 | Collapse(item); |
372edb9d | 839 | DeleteChildren(item); |
edaa81ae | 840 | } |
c801d85f | 841 | |
f135ff73 | 842 | void wxTreeCtrl::Toggle(const wxTreeItemId& itemId) |
c801d85f | 843 | { |
f135ff73 | 844 | wxGenericTreeItem *item = itemId.m_pItem; |
389cdc7a | 845 | |
f135ff73 VZ |
846 | if ( item->IsExpanded() ) |
847 | Collapse(itemId); | |
848 | else | |
849 | Expand(itemId); | |
850 | } | |
389cdc7a | 851 | |
f135ff73 VZ |
852 | void wxTreeCtrl::Unselect() |
853 | { | |
854 | if ( m_current ) | |
855 | { | |
856 | m_current->SetHilight( FALSE ); | |
857 | RefreshLine( m_current ); | |
858 | } | |
edaa81ae | 859 | } |
c801d85f | 860 | |
f135ff73 | 861 | void wxTreeCtrl::SelectItem(const wxTreeItemId& itemId) |
389cdc7a | 862 | { |
f135ff73 VZ |
863 | wxGenericTreeItem *item = itemId.m_pItem; |
864 | ||
865 | if ( m_current != item ) | |
389cdc7a | 866 | { |
f135ff73 VZ |
867 | wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() ); |
868 | event.m_item = item; | |
869 | event.m_itemOld = m_current; | |
870 | event.SetEventObject( this ); | |
6daa0637 | 871 | if ( GetEventHandler()->ProcessEvent( event ) && event.WasVetoed() ) |
f135ff73 VZ |
872 | return; |
873 | ||
874 | if ( m_current ) | |
389cdc7a VZ |
875 | { |
876 | m_current->SetHilight( FALSE ); | |
877 | RefreshLine( m_current ); | |
edaa81ae | 878 | } |
f135ff73 | 879 | |
389cdc7a VZ |
880 | m_current = item; |
881 | m_current->SetHilight( TRUE ); | |
882 | RefreshLine( m_current ); | |
883 | ||
f135ff73 | 884 | event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED); |
6daa0637 | 885 | GetEventHandler()->ProcessEvent( event ); |
389cdc7a VZ |
886 | } |
887 | } | |
888 | ||
6daa0637 | 889 | void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item) |
c801d85f | 890 | { |
0659e7ee | 891 | wxGenericTreeItem *gitem = item.m_pItem; |
ef44a621 | 892 | |
0659e7ee | 893 | int item_y = gitem->GetY(); |
ef44a621 | 894 | |
0659e7ee RR |
895 | int start_x = 0; |
896 | int start_y = 0; | |
897 | ViewStart( &start_x, &start_y ); | |
898 | start_y *= 10; | |
a93109d5 RR |
899 | |
900 | int client_h = 0; | |
901 | int client_w = 0; | |
902 | GetClientSize( &client_w, &client_h ); | |
ef44a621 | 903 | |
0659e7ee RR |
904 | if (item_y < start_y+3) |
905 | { | |
906 | int x = 0; | |
907 | int y = 0; | |
908 | m_anchor->GetSize( x, y ); | |
909 | y += 2*m_lineHeight; | |
910 | int x_pos = GetScrollPos( wxHORIZONTAL ); | |
a93109d5 | 911 | SetScrollbars( 10, 10, x/10, y/10, x_pos, (item_y-client_h/2)/10 ); |
0659e7ee RR |
912 | return; |
913 | } | |
ef44a621 | 914 | |
a93109d5 | 915 | if (item_y > start_y+client_h-16) |
0659e7ee RR |
916 | { |
917 | int x = 0; | |
918 | int y = 0; | |
919 | m_anchor->GetSize( x, y ); | |
920 | y += 2*m_lineHeight; | |
921 | int x_pos = GetScrollPos( wxHORIZONTAL ); | |
a93109d5 | 922 | SetScrollbars( 10, 10, x/10, y/10, x_pos, (item_y-client_h/2)/10 ); |
0659e7ee RR |
923 | return; |
924 | } | |
edaa81ae | 925 | } |
c801d85f | 926 | |
df875e59 | 927 | void wxTreeCtrl::ScrollTo(const wxTreeItemId& WXUNUSED(item)) |
c801d85f | 928 | { |
f135ff73 | 929 | wxFAIL_MSG("not implemented"); |
edaa81ae | 930 | } |
c801d85f | 931 | |
df875e59 RR |
932 | wxTextCtrl *wxTreeCtrl::EditLabel( const wxTreeItemId& WXUNUSED(item), |
933 | wxClassInfo* WXUNUSED(textCtrlClass) ) | |
c801d85f | 934 | { |
f135ff73 | 935 | wxFAIL_MSG("not implemented"); |
c801d85f | 936 | |
0659e7ee | 937 | return (wxTextCtrl*)NULL; |
edaa81ae | 938 | } |
c801d85f | 939 | |
f135ff73 | 940 | wxTextCtrl *wxTreeCtrl::GetEditControl() const |
c801d85f | 941 | { |
0659e7ee | 942 | wxFAIL_MSG("not implemented"); |
c801d85f | 943 | |
0659e7ee | 944 | return (wxTextCtrl*)NULL; |
edaa81ae | 945 | } |
c801d85f | 946 | |
df875e59 | 947 | void wxTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item), bool WXUNUSED(discardChanges)) |
74bedbeb | 948 | { |
0659e7ee | 949 | wxFAIL_MSG("not implemented"); |
74bedbeb VZ |
950 | } |
951 | ||
e1ee62bd VZ |
952 | // FIXME: tree sorting functions are not reentrant and not MT-safe! |
953 | static wxTreeCtrl *s_treeBeingSorted = NULL; | |
0659e7ee | 954 | |
e1ee62bd VZ |
955 | static int tree_ctrl_compare_func(wxGenericTreeItem **item1, |
956 | wxGenericTreeItem **item2) | |
edaa81ae | 957 | { |
e1ee62bd VZ |
958 | wxCHECK_MSG( s_treeBeingSorted, 0, "bug in wxTreeCtrl::SortChildren()" ); |
959 | ||
960 | return s_treeBeingSorted->OnCompareItems(*item1, *item2); | |
0659e7ee RR |
961 | } |
962 | ||
e1ee62bd VZ |
963 | int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1, |
964 | const wxTreeItemId& item2) | |
0659e7ee | 965 | { |
e1ee62bd VZ |
966 | return strcmp(GetItemText(item1), GetItemText(item2)); |
967 | } | |
968 | ||
969 | void wxTreeCtrl::SortChildren(const wxTreeItemId& itemId) | |
970 | { | |
971 | wxCHECK_RET( itemId.IsOk(), "invalid tree item" ); | |
972 | ||
973 | wxGenericTreeItem *item = itemId.m_pItem; | |
0659e7ee | 974 | |
e1ee62bd VZ |
975 | wxCHECK_RET( !s_treeBeingSorted, |
976 | "wxTreeCtrl::SortChildren is not reentrant" ); | |
977 | ||
978 | wxArrayTreeItems& children = item->GetChildren(); | |
979 | if ( children.Count() > 1 ) | |
980 | { | |
981 | s_treeBeingSorted = this; | |
982 | children.Sort(tree_ctrl_compare_func); | |
983 | s_treeBeingSorted = NULL; | |
0659e7ee | 984 | |
e1ee62bd VZ |
985 | m_dirty = TRUE; |
986 | } | |
987 | //else: don't make the tree dirty as nothing changed | |
edaa81ae RR |
988 | } |
989 | ||
f135ff73 | 990 | wxImageList *wxTreeCtrl::GetImageList() const |
edaa81ae | 991 | { |
f135ff73 | 992 | return m_imageListNormal; |
edaa81ae RR |
993 | } |
994 | ||
f135ff73 | 995 | wxImageList *wxTreeCtrl::GetStateImageList() const |
c801d85f | 996 | { |
f135ff73 | 997 | return m_imageListState; |
edaa81ae | 998 | } |
c801d85f | 999 | |
f135ff73 | 1000 | void wxTreeCtrl::SetImageList(wxImageList *imageList) |
e2414cbe | 1001 | { |
f135ff73 | 1002 | m_imageListNormal = imageList; |
edaa81ae | 1003 | } |
e2414cbe | 1004 | |
f135ff73 | 1005 | void wxTreeCtrl::SetStateImageList(wxImageList *imageList) |
e2414cbe | 1006 | { |
f135ff73 | 1007 | m_imageListState = imageList; |
edaa81ae | 1008 | } |
e2414cbe | 1009 | |
f135ff73 VZ |
1010 | // ----------------------------------------------------------------------------- |
1011 | // helpers | |
1012 | // ----------------------------------------------------------------------------- | |
0659e7ee | 1013 | |
74bedbeb | 1014 | void wxTreeCtrl::AdjustMyScrollbars() |
c801d85f | 1015 | { |
0659e7ee RR |
1016 | if (m_anchor) |
1017 | { | |
1018 | int x = 0; | |
1019 | int y = 0; | |
1020 | m_anchor->GetSize( x, y ); | |
1021 | y += 2*m_lineHeight; | |
1022 | int x_pos = GetScrollPos( wxHORIZONTAL ); | |
1023 | int y_pos = GetScrollPos( wxVERTICAL ); | |
1024 | SetScrollbars( 10, 10, x/10, y/10, x_pos, y_pos ); | |
1025 | } | |
1026 | else | |
1027 | { | |
1028 | SetScrollbars( 0, 0, 0, 0 ); | |
1029 | } | |
edaa81ae | 1030 | } |
c801d85f | 1031 | |
ef44a621 VZ |
1032 | void wxTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc) |
1033 | { | |
1034 | // render bold items in bold | |
c59e2a82 RR |
1035 | wxFont fontOld; |
1036 | wxFont fontNew; | |
1037 | ||
ef44a621 VZ |
1038 | if ( item->IsBold() ) |
1039 | { | |
1040 | fontOld = dc.GetFont(); | |
c59e2a82 | 1041 | if (fontOld.Ok()) |
ef44a621 VZ |
1042 | { |
1043 | // @@ is there any better way to make a bold variant of old font? | |
c59e2a82 RR |
1044 | fontNew = wxFont( fontOld.GetPointSize(), |
1045 | fontOld.GetFamily(), | |
1046 | fontOld.GetStyle(), | |
1047 | wxBOLD, | |
1048 | fontOld.GetUnderlined()); | |
ef44a621 VZ |
1049 | dc.SetFont(fontNew); |
1050 | } | |
1051 | else | |
1052 | { | |
1053 | wxFAIL_MSG("wxDC::GetFont() failed!"); | |
1054 | } | |
1055 | } | |
1056 | ||
1057 | long text_w = 0; | |
1058 | long text_h = 0; | |
1059 | dc.GetTextExtent( item->GetText(), &text_w, &text_h ); | |
1060 | ||
1061 | int image_h = 0; | |
1062 | int image_w = 0; | |
0659e7ee RR |
1063 | if ((item->IsExpanded()) && (item->GetSelectedImage() != -1)) |
1064 | { | |
1065 | m_imageListNormal->GetSize( item->GetSelectedImage(), image_w, image_h ); | |
1066 | image_w += 4; | |
1067 | } | |
1068 | else if (item->GetImage() != -1) | |
ef44a621 VZ |
1069 | { |
1070 | m_imageListNormal->GetSize( item->GetImage(), image_w, image_h ); | |
1071 | image_w += 4; | |
1072 | } | |
1073 | ||
1074 | dc.DrawRectangle( item->GetX()-2, item->GetY()-2, image_w+text_w+4, text_h+4 ); | |
1075 | ||
0659e7ee RR |
1076 | if ((item->IsExpanded()) && (item->GetSelectedImage() != -1)) |
1077 | { | |
1078 | dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, text_h ); | |
1079 | m_imageListNormal->Draw( item->GetSelectedImage(), dc, | |
1080 | item->GetX(), item->GetY()-1, | |
1081 | wxIMAGELIST_DRAW_TRANSPARENT ); | |
1082 | dc.DestroyClippingRegion(); | |
1083 | } | |
1084 | else if (item->GetImage() != -1) | |
ef44a621 VZ |
1085 | { |
1086 | dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, text_h ); | |
1087 | m_imageListNormal->Draw( item->GetImage(), dc, | |
1088 | item->GetX(), item->GetY()-1, | |
1089 | wxIMAGELIST_DRAW_TRANSPARENT ); | |
1090 | dc.DestroyClippingRegion(); | |
1091 | } | |
1092 | ||
f60d0f94 | 1093 | dc.SetBackgroundMode(wxTRANSPARENT); |
ef44a621 VZ |
1094 | dc.DrawText( item->GetText(), image_w + item->GetX(), item->GetY() ); |
1095 | ||
1096 | // restore normal font for bold items | |
c59e2a82 | 1097 | if (fontOld.Ok()) |
ef44a621 | 1098 | { |
c59e2a82 | 1099 | dc.SetFont( fontOld); |
ef44a621 VZ |
1100 | } |
1101 | } | |
1102 | ||
16c1f7f3 | 1103 | void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y ) |
c801d85f | 1104 | { |
4c681997 | 1105 | int horizX = level*m_indent; |
389cdc7a | 1106 | |
f135ff73 VZ |
1107 | item->SetX( horizX+33 ); |
1108 | item->SetY( y-m_lineHeight/3 ); | |
1109 | item->SetHeight( m_lineHeight ); | |
389cdc7a | 1110 | |
4c681997 RR |
1111 | item->SetCross( horizX+15, y ); |
1112 | ||
c801d85f | 1113 | int oldY = y; |
389cdc7a | 1114 | |
d4c99d6f | 1115 | int exposed_x = dc.LogicalToDeviceX( 0 ); |
f135ff73 | 1116 | int exposed_y = dc.LogicalToDeviceY( item->GetY()-2 ); |
4832f7c0 | 1117 | |
df875e59 | 1118 | if (IsExposed( exposed_x, exposed_y, 10000, m_lineHeight+4 )) // 10000 = very much |
c801d85f | 1119 | { |
4c681997 RR |
1120 | int startX = horizX; |
1121 | int endX = horizX + 10; | |
29d87bba | 1122 | |
4c681997 | 1123 | if (!item->HasChildren()) endX += 20; |
4832f7c0 | 1124 | |
389cdc7a | 1125 | dc.DrawLine( startX, y, endX, y ); |
29d87bba | 1126 | |
f135ff73 VZ |
1127 | if (item->HasPlus()) |
1128 | { | |
1129 | dc.DrawLine( horizX+20, y, horizX+30, y ); | |
1130 | dc.SetPen( *wxGREY_PEN ); | |
4bb19cfb | 1131 | dc.SetBrush( *wxWHITE_BRUSH ); |
f135ff73 VZ |
1132 | dc.DrawRectangle( horizX+10, y-4, 11, 9 ); |
1133 | dc.SetPen( *wxBLACK_PEN ); | |
1134 | dc.DrawLine( horizX+13, y, horizX+18, y ); | |
1135 | ||
1136 | if (!item->IsExpanded()) | |
1137 | dc.DrawLine( horizX+15, y-2, horizX+15, y+3 ); | |
1138 | } | |
c801d85f | 1139 | |
f135ff73 VZ |
1140 | if (item->HasHilight()) |
1141 | { | |
1142 | dc.SetTextForeground( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) ); | |
a367b9b3 | 1143 | |
f135ff73 | 1144 | dc.SetBrush( *m_hilightBrush ); |
4832f7c0 | 1145 | |
df875e59 RR |
1146 | if (m_hasFocus) |
1147 | dc.SetPen( *wxBLACK_PEN ); | |
29d87bba | 1148 | else |
389cdc7a | 1149 | dc.SetPen( *wxTRANSPARENT_PEN ); |
4832f7c0 | 1150 | |
ef44a621 | 1151 | PaintItem(item, dc); |
f135ff73 VZ |
1152 | |
1153 | dc.SetPen( *wxBLACK_PEN ); | |
1154 | dc.SetTextForeground( *wxBLACK ); | |
1155 | dc.SetBrush( *wxWHITE_BRUSH ); | |
1156 | } | |
1157 | else | |
1158 | { | |
1159 | dc.SetBrush( *wxWHITE_BRUSH ); | |
1160 | dc.SetPen( *wxTRANSPARENT_PEN ); | |
4832f7c0 | 1161 | |
ef44a621 | 1162 | PaintItem(item, dc); |
4832f7c0 | 1163 | |
f135ff73 VZ |
1164 | dc.SetPen( *wxBLACK_PEN ); |
1165 | } | |
edaa81ae | 1166 | } |
4c681997 | 1167 | |
372edb9d VZ |
1168 | if ( item->IsExpanded() ) |
1169 | { | |
1170 | int semiOldY = y; | |
e2414cbe | 1171 | |
372edb9d VZ |
1172 | wxArrayTreeItems& children = item->GetChildren(); |
1173 | size_t count = children.Count(); | |
1174 | for ( size_t n = 0; n < count; n++ ) | |
1175 | { | |
1176 | y += m_lineHeight; | |
1177 | semiOldY = y; | |
389cdc7a | 1178 | |
372edb9d VZ |
1179 | PaintLevel( children[n], dc, level+1, y ); |
1180 | } | |
389cdc7a | 1181 | |
372edb9d VZ |
1182 | // it may happen that the item is expanded but has no items (when you |
1183 | // delete all its children for example) - don't draw the vertical line | |
1184 | // in this case | |
1185 | if ( count > 0 ) | |
1186 | dc.DrawLine( horizX+15, oldY+5, horizX+15, semiOldY ); | |
edaa81ae | 1187 | } |
4c681997 | 1188 | } |
c801d85f | 1189 | |
f135ff73 VZ |
1190 | // ----------------------------------------------------------------------------- |
1191 | // wxWindows callbacks | |
1192 | // ----------------------------------------------------------------------------- | |
1193 | ||
3db7be80 | 1194 | void wxTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) ) |
c801d85f | 1195 | { |
0659e7ee RR |
1196 | if ( !m_anchor ) |
1197 | return; | |
c801d85f | 1198 | |
0659e7ee RR |
1199 | wxPaintDC dc(this); |
1200 | PrepareDC( dc ); | |
29d87bba | 1201 | |
f60d0f94 | 1202 | dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ) ); |
29d87bba | 1203 | |
0659e7ee RR |
1204 | dc.SetPen( m_dottedPen ); |
1205 | m_lineHeight = (int)(dc.GetCharHeight() + 4); | |
29d87bba | 1206 | |
0659e7ee RR |
1207 | int y = m_lineHeight / 2 + 2; |
1208 | PaintLevel( m_anchor, dc, 0, y ); | |
edaa81ae | 1209 | } |
c801d85f | 1210 | |
3db7be80 | 1211 | void wxTreeCtrl::OnSetFocus( wxFocusEvent &WXUNUSED(event) ) |
c801d85f | 1212 | { |
0659e7ee RR |
1213 | m_hasFocus = TRUE; |
1214 | if ( m_current ) | |
1215 | RefreshLine( m_current ); | |
edaa81ae | 1216 | } |
c801d85f | 1217 | |
3db7be80 | 1218 | void wxTreeCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) ) |
c801d85f | 1219 | { |
0659e7ee RR |
1220 | m_hasFocus = FALSE; |
1221 | if ( m_current ) | |
1222 | RefreshLine( m_current ); | |
edaa81ae | 1223 | } |
c801d85f KB |
1224 | |
1225 | void wxTreeCtrl::OnChar( wxKeyEvent &event ) | |
1226 | { | |
435fe83e RR |
1227 | wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() ); |
1228 | te.m_code = event.KeyCode(); | |
1229 | te.SetEventObject( this ); | |
1230 | GetEventHandler()->ProcessEvent( te ); | |
1231 | ||
6daa0637 | 1232 | if (m_current == 0) |
ef44a621 | 1233 | { |
6daa0637 RR |
1234 | event.Skip(); |
1235 | return; | |
1236 | } | |
ef44a621 | 1237 | |
6daa0637 RR |
1238 | switch (event.KeyCode()) |
1239 | { | |
1240 | case '+': | |
1241 | case WXK_ADD: | |
4bb19cfb | 1242 | if (m_current->HasPlus() && !IsExpanded(m_current)) |
6daa0637 RR |
1243 | { |
1244 | Expand(m_current); | |
1245 | } | |
ef44a621 VZ |
1246 | break; |
1247 | ||
6daa0637 RR |
1248 | case '-': |
1249 | case WXK_SUBTRACT: | |
6daa0637 RR |
1250 | if (IsExpanded(m_current)) |
1251 | { | |
1252 | Collapse(m_current); | |
1253 | } | |
ef44a621 VZ |
1254 | break; |
1255 | ||
1256 | case '*': | |
1257 | case WXK_MULTIPLY: | |
1258 | Toggle(m_current); | |
1259 | break; | |
1260 | ||
6daa0637 RR |
1261 | case ' ': |
1262 | case WXK_RETURN: | |
ef44a621 | 1263 | { |
435fe83e | 1264 | wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() ); |
ef44a621 VZ |
1265 | event.m_item = m_current; |
1266 | event.m_code = 0; | |
1267 | event.SetEventObject( this ); | |
1268 | GetEventHandler()->ProcessEvent( event ); | |
1269 | } | |
1270 | break; | |
1271 | ||
6daa0637 | 1272 | case WXK_UP: |
a93109d5 RR |
1273 | { |
1274 | wxTreeItemId prev = GetPrevSibling( m_current ); | |
1275 | if (!prev) | |
1276 | { | |
1277 | prev = GetParent( m_current ); | |
1278 | long cockie = 0; | |
1279 | wxTreeItemId current = m_current; | |
1280 | if (current == GetFirstChild( prev, cockie )) | |
1281 | { | |
1282 | // otherwise we return to where we came from | |
1283 | SelectItem( prev ); | |
1284 | EnsureVisible( prev ); | |
1285 | break; | |
1286 | } | |
1287 | } | |
1288 | if (prev) | |
1289 | { | |
1290 | while (IsExpanded(prev)) | |
1291 | { | |
1292 | int c = (int)GetChildrenCount( prev, FALSE ); | |
1293 | long cockie = 0; | |
1294 | prev = GetFirstChild( prev, cockie ); | |
1295 | for (int i = 0; i < c-1; i++) | |
1296 | prev = GetNextSibling( prev ); | |
1297 | } | |
1298 | SelectItem( prev ); | |
1299 | EnsureVisible( prev ); | |
1300 | } | |
1301 | } | |
1302 | break; | |
1303 | case WXK_LEFT: | |
6daa0637 | 1304 | { |
ef44a621 VZ |
1305 | wxTreeItemId prev = GetPrevSibling( m_current ); |
1306 | if (prev != 0) | |
1307 | { | |
1308 | SelectItem( prev ); | |
1309 | EnsureVisible( prev ); | |
1310 | } | |
1311 | else | |
1312 | { | |
1313 | prev = GetParent( m_current ); | |
1314 | if (prev) | |
1315 | { | |
1316 | EnsureVisible( prev ); | |
1317 | SelectItem( prev ); | |
1318 | } | |
1319 | } | |
6daa0637 | 1320 | } |
ef44a621 VZ |
1321 | break; |
1322 | ||
1323 | case WXK_RIGHT: | |
1324 | // this works the same as the down arrow except that we also expand the | |
1325 | // item if it wasn't expanded yet | |
1326 | Expand(m_current); | |
1327 | // fall through | |
1328 | ||
1329 | case WXK_DOWN: | |
6daa0637 | 1330 | { |
ef44a621 VZ |
1331 | if (IsExpanded(m_current)) |
1332 | { | |
1333 | long cookie = 0; | |
1334 | wxTreeItemId child = GetFirstChild( m_current, cookie ); | |
1335 | SelectItem( child ); | |
1336 | EnsureVisible( child ); | |
1337 | } | |
1338 | else | |
1339 | { | |
1340 | wxTreeItemId next = GetNextSibling( m_current ); | |
1341 | if (next == 0) | |
1342 | { | |
1343 | wxTreeItemId current = m_current; | |
1344 | while (current && !next) | |
1345 | { | |
1346 | current = GetParent( current ); | |
1347 | if (current) next = GetNextSibling( current ); | |
1348 | } | |
1349 | } | |
1350 | if (next != 0) | |
1351 | { | |
1352 | SelectItem( next ); | |
1353 | EnsureVisible( next ); | |
1354 | } | |
1355 | } | |
6daa0637 | 1356 | } |
ef44a621 VZ |
1357 | break; |
1358 | ||
1359 | default: | |
1360 | event.Skip(); | |
6daa0637 | 1361 | } |
edaa81ae | 1362 | } |
c801d85f | 1363 | |
4f22cf8d RR |
1364 | wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& WXUNUSED(flags)) |
1365 | { | |
1366 | bool onButton = FALSE; | |
1367 | return m_anchor->HitTest( point, onButton ); | |
1368 | } | |
1369 | ||
3db7be80 | 1370 | void wxTreeCtrl::OnMouse( wxMouseEvent &event ) |
c801d85f | 1371 | { |
f135ff73 VZ |
1372 | if ( !(event.LeftDown() || event.LeftDClick()) ) |
1373 | return; | |
1374 | ||
1375 | if ( !m_anchor ) | |
1376 | return; | |
29d87bba | 1377 | |
c801d85f KB |
1378 | wxClientDC dc(this); |
1379 | PrepareDC(dc); | |
1380 | long x = dc.DeviceToLogicalX( (long)event.GetX() ); | |
1381 | long y = dc.DeviceToLogicalY( (long)event.GetY() ); | |
29d87bba | 1382 | |
f135ff73 VZ |
1383 | bool onButton = FALSE; |
1384 | wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), onButton ); | |
1385 | if ( item == NULL ) | |
29d87bba | 1386 | return; |
29d87bba | 1387 | |
6daa0637 | 1388 | if (!IsSelected(item)) SelectItem(item); |
29d87bba | 1389 | |
f135ff73 VZ |
1390 | if ( event.LeftDClick() ) |
1391 | { | |
435fe83e | 1392 | wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() ); |
f135ff73 VZ |
1393 | event.m_item = item; |
1394 | event.m_code = 0; | |
1395 | event.SetEventObject( this ); | |
6daa0637 | 1396 | GetEventHandler()->ProcessEvent( event ); |
f135ff73 | 1397 | } |
29d87bba | 1398 | |
f135ff73 | 1399 | if ( onButton ) |
c801d85f | 1400 | { |
f135ff73 | 1401 | Toggle( item ); |
edaa81ae RR |
1402 | } |
1403 | } | |
c801d85f | 1404 | |
3db7be80 RR |
1405 | void wxTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) ) |
1406 | { | |
1407 | if (!m_dirty) return; | |
ef44a621 | 1408 | |
3db7be80 | 1409 | m_dirty = FALSE; |
ef44a621 | 1410 | |
3db7be80 RR |
1411 | CalculatePositions(); |
1412 | ||
1413 | AdjustMyScrollbars(); | |
1414 | } | |
1415 | ||
f135ff73 VZ |
1416 | // ----------------------------------------------------------------------------- |
1417 | // ----------------------------------------------------------------------------- | |
1418 | void wxTreeCtrl::CalculateLevel( wxGenericTreeItem *item, | |
1419 | wxDC &dc, | |
1420 | int level, | |
1421 | int &y ) | |
c801d85f | 1422 | { |
4c681997 | 1423 | int horizX = level*m_indent; |
389cdc7a | 1424 | |
f135ff73 VZ |
1425 | item->SetX( horizX+33 ); |
1426 | item->SetY( y-m_lineHeight/3-2 ); | |
1427 | item->SetHeight( m_lineHeight ); | |
4c681997 | 1428 | |
28ab302b JS |
1429 | // if ( item->IsExpanded() ) |
1430 | // return; | |
1431 | if ( !item->IsExpanded() ) // Surely this is correct? JACS | |
1432 | return; | |
389cdc7a | 1433 | |
f135ff73 VZ |
1434 | wxArrayTreeItems& children = item->GetChildren(); |
1435 | size_t count = children.Count(); | |
1436 | for ( size_t n = 0; n < count; n++ ) | |
c801d85f | 1437 | { |
c801d85f | 1438 | y += m_lineHeight; |
f135ff73 | 1439 | CalculateLevel( children[n], dc, level+1, y ); |
edaa81ae RR |
1440 | } |
1441 | } | |
c801d85f | 1442 | |
74bedbeb | 1443 | void wxTreeCtrl::CalculatePositions() |
c801d85f | 1444 | { |
f135ff73 | 1445 | if ( !m_anchor ) |
29d87bba VZ |
1446 | return; |
1447 | ||
c801d85f KB |
1448 | wxClientDC dc(this); |
1449 | PrepareDC( dc ); | |
29d87bba | 1450 | |
fdd8d7b5 | 1451 | dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ) ); |
29d87bba | 1452 | |
c801d85f KB |
1453 | dc.SetPen( m_dottedPen ); |
1454 | m_lineHeight = (int)(dc.GetCharHeight() + 4); | |
29d87bba | 1455 | |
c801d85f KB |
1456 | int y = m_lineHeight / 2 + 2; |
1457 | CalculateLevel( m_anchor, dc, 0, y ); | |
edaa81ae | 1458 | } |
c801d85f | 1459 | |
f135ff73 | 1460 | void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem *item) |
c801d85f | 1461 | { |
f135ff73 VZ |
1462 | wxClientDC dc(this); |
1463 | PrepareDC(dc); | |
4832f7c0 | 1464 | |
f135ff73 VZ |
1465 | int cw = 0; |
1466 | int ch = 0; | |
1467 | GetClientSize( &cw, &ch ); | |
4832f7c0 | 1468 | |
f135ff73 VZ |
1469 | wxRect rect; |
1470 | rect.x = dc.LogicalToDeviceX( 0 ); | |
1471 | rect.width = cw; | |
1472 | rect.y = dc.LogicalToDeviceY( item->GetY() ); | |
1473 | rect.height = ch; | |
1474 | ||
1475 | Refresh( TRUE, &rect ); | |
1476 | ||
1477 | AdjustMyScrollbars(); | |
edaa81ae | 1478 | } |
c801d85f KB |
1479 | |
1480 | void wxTreeCtrl::RefreshLine( wxGenericTreeItem *item ) | |
1481 | { | |
c801d85f KB |
1482 | wxClientDC dc(this); |
1483 | PrepareDC( dc ); | |
f135ff73 | 1484 | |
c801d85f | 1485 | wxRect rect; |
f135ff73 VZ |
1486 | rect.x = dc.LogicalToDeviceX( item->GetX() - 2 ); |
1487 | rect.y = dc.LogicalToDeviceY( item->GetY() - 2 ); | |
c801d85f | 1488 | rect.width = 1000; |
f135ff73 | 1489 | rect.height = dc.GetCharHeight() + 6; |
c801d85f | 1490 | Refresh( TRUE, &rect ); |
edaa81ae | 1491 | } |
c801d85f | 1492 |