]> git.saurik.com Git - wxWidgets.git/blame - src/generic/treectrl.cpp
Added serial code for wxList and wxHashTable to source tree
[wxWidgets.git] / src / generic / treectrl.cpp
CommitLineData
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
24#include "wx/treectrl.h"
25#include "wx/settings.h"
389cdc7a 26#include "wx/log.h"
f135ff73
VZ
27#include "wx/intl.h"
28#include "wx/dynarray.h"
29#include "wx/dcclient.h"
df875e59 30#include "wx/imaglist.h"
c801d85f 31
f135ff73
VZ
32// -----------------------------------------------------------------------------
33// array types
34// -----------------------------------------------------------------------------
c801d85f 35
f135ff73 36WX_DEFINE_ARRAY(wxGenericTreeItem *, wxArrayTreeItems);
c801d85f 37
f135ff73
VZ
38// -----------------------------------------------------------------------------
39// private classes
40// -----------------------------------------------------------------------------
41
42// a tree item
43class WXDLLEXPORT wxGenericTreeItem
c801d85f 44{
f135ff73
VZ
45public:
46 // ctors & dtor
47 wxGenericTreeItem() { m_data = NULL; }
48 wxGenericTreeItem( wxGenericTreeItem *parent,
49 const wxString& text,
50 wxDC& dc,
51 int image, int selImage,
52 wxTreeItemData *data );
53
ff5bf259 54 ~wxGenericTreeItem();
f135ff73
VZ
55
56 // trivial accessors
57 wxArrayTreeItems& GetChildren() { return m_children; }
58
59 const wxString& GetText() const { return m_text; }
60 int GetImage() const { return m_image; }
61 int GetSelectedImage() const { return m_selImage; }
62 wxTreeItemData *GetData() const { return m_data; }
63
64 void SetText( const wxString &text, wxDC& dc );
65 void SetImage(int image) { m_image = image; }
66 void SetSelectedImage(int image) { m_selImage = image; }
67 void SetData(wxTreeItemData *data) { m_data = data; }
68
69 void SetHasPlus(bool has = TRUE) { m_hasPlus = has; }
70
71 int GetX() const { return m_x; }
72 int GetY() const { return m_y; }
73
74 void SetHeight(int h) { m_height = h; }
75
76 void SetX(int x) { m_x = x; }
77 void SetY(int y) { m_y = y; }
78
79 wxGenericTreeItem *GetParent() const { return m_parent; }
c801d85f 80
f135ff73
VZ
81 // operations
82 void Reset();
83
4832f7c0
VZ
84 // get count of all children (and grand children if 'recursively')
85 size_t GetChildrenCount(bool recursively = TRUE) const;
f135ff73
VZ
86
87 void Insert(wxGenericTreeItem *child, size_t index)
88 { m_children.Insert(child, index); }
89
90 void SetCross( int x, int y );
91 void GetSize( int &x, int &y );
92
93 // return the item at given position (or NULL if no item), onButton is TRUE
94 // if the point belongs to the item's button, otherwise it lies on the
95 // button's label
96 wxGenericTreeItem *HitTest( const wxPoint& point, bool &onButton );
97
98 void Expand() { m_isCollapsed = FALSE; }
99 void Collapse() { m_isCollapsed = TRUE; }
100
101 void SetHilight( bool set = TRUE ) { m_hasHilight = set; }
102
103 // status inquiries
104 bool HasChildren() const { return !m_children.IsEmpty(); }
105 bool HasHilight() const { return m_hasHilight; }
106 bool IsExpanded() const { return !m_isCollapsed; }
107 bool HasPlus() const { return m_hasPlus || HasChildren(); }
108
109private:
110 wxString m_text;
111
112 int m_image,
113 m_selImage;
114
115 wxTreeItemData *m_data;
4832f7c0 116
f135ff73
VZ
117 // @@ probably should use bitfields to save size
118 bool m_isCollapsed,
119 m_hasHilight, // same as focused
120 m_hasPlus; // used for item which doesn't have
121 // children but still has a [+] button
122
123 int m_x, m_y;
124 long m_height, m_width;
125 int m_xCross, m_yCross;
126 int m_level;
127 wxArrayTreeItems m_children;
128 wxGenericTreeItem *m_parent;
129};
130
131// =============================================================================
132// implementation
133// =============================================================================
134
135// -----------------------------------------------------------------------------
c801d85f 136// wxTreeEvent
f135ff73 137// -----------------------------------------------------------------------------
c801d85f 138
f135ff73 139IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxCommandEvent)
c801d85f 140
f135ff73
VZ
141wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
142 : wxCommandEvent( commandType, id )
c801d85f
KB
143{
144 m_code = 0;
f135ff73 145 m_itemOld = (wxGenericTreeItem *)NULL;
edaa81ae 146}
c801d85f 147
f135ff73 148// -----------------------------------------------------------------------------
c801d85f 149// wxGenericTreeItem
f135ff73 150// -----------------------------------------------------------------------------
c801d85f 151
f135ff73
VZ
152wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent,
153 const wxString& text,
154 wxDC& dc,
155 int image, int selImage,
156 wxTreeItemData *data)
157 : m_text(text)
c801d85f 158{
f135ff73
VZ
159 m_image = image;
160 m_selImage = selImage;
161 m_data = data;
162 m_x = m_y = 0;
163 m_xCross = m_yCross = 0;
164
165 m_level = 0;
166
167 m_isCollapsed = TRUE;
c801d85f 168 m_hasHilight = FALSE;
df875e59 169 m_hasPlus = FALSE;
c801d85f 170
c801d85f 171 m_parent = parent;
f135ff73
VZ
172
173 dc.GetTextExtent( m_text, &m_width, &m_height );
edaa81ae 174}
c801d85f 175
f135ff73 176wxGenericTreeItem::~wxGenericTreeItem()
c801d85f 177{
f135ff73 178 delete m_data;
4832f7c0 179
f135ff73
VZ
180 size_t count = m_children.Count();
181 for ( size_t n = 0; n < count; n++ )
182 delete m_children[n];
edaa81ae 183}
c801d85f 184
f135ff73 185void wxGenericTreeItem::SetText( const wxString &text, wxDC& dc )
c801d85f
KB
186{
187 m_text = text;
f135ff73
VZ
188
189 dc.GetTextExtent( m_text, &m_width, &m_height );
edaa81ae 190}
c801d85f 191
74bedbeb 192void wxGenericTreeItem::Reset()
c801d85f 193{
f135ff73
VZ
194 m_text.Empty();
195 m_image =
196 m_selImage = -1;
197 m_data = NULL;
198 m_x = m_y =
199 m_height = m_width = 0;
200 m_xCross =
c801d85f 201 m_yCross = 0;
74bedbeb 202
f135ff73 203 m_level = 0;
c801d85f 204
f135ff73
VZ
205 m_children.Empty();
206 m_isCollapsed = TRUE;
c801d85f 207
f135ff73 208 m_parent = (wxGenericTreeItem *)NULL;
edaa81ae 209}
c801d85f 210
4832f7c0 211size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const
c801d85f 212{
f135ff73 213 size_t count = m_children.Count();
4832f7c0
VZ
214 if ( !recursively )
215 return count;
216
f135ff73
VZ
217 size_t total = count;
218 for ( size_t n = 0; n < count; n++ )
c801d85f 219 {
4832f7c0 220 total += m_children[n]->GetChildrenCount();
edaa81ae 221 }
c801d85f 222
f135ff73 223 return total;
edaa81ae 224}
c801d85f
KB
225
226void wxGenericTreeItem::SetCross( int x, int y )
227{
228 m_xCross = x;
229 m_yCross = y;
edaa81ae 230}
c801d85f
KB
231
232void wxGenericTreeItem::GetSize( int &x, int &y )
233{
df875e59 234 if ( y < m_y ) y = m_y;
c801d85f
KB
235 int width = m_x + m_width;
236 if (width > x) x = width;
f135ff73 237
df875e59 238 if (IsExpanded())
c801d85f 239 {
df875e59
RR
240 size_t count = m_children.Count();
241 for ( size_t n = 0; n < count; n++ )
4832f7c0 242 {
df875e59
RR
243 m_children[n]->GetSize( x, y );
244 }
edaa81ae
RR
245 }
246}
c801d85f 247
f135ff73
VZ
248wxGenericTreeItem *wxGenericTreeItem::HitTest( const wxPoint& point,
249 bool &onButton )
c801d85f 250{
f135ff73 251 if ((point.y > m_y) && (point.y < m_y + m_height))
c801d85f 252 {
f135ff73
VZ
253 // FIXME why +5?
254 if ((point.x > m_xCross-5) && (point.x < m_xCross+5) &&
255 (point.y > m_yCross-5) && (point.y < m_yCross+5) &&
f9f950fc 256 (IsExpanded() || HasPlus()))
c801d85f 257 {
f135ff73
VZ
258 onButton = TRUE;
259 return this;
edaa81ae 260 }
f135ff73 261
c801d85f
KB
262 if ((point.x > m_x) && (point.x < m_x+m_width))
263 {
f135ff73
VZ
264 onButton = FALSE;
265 return this;
edaa81ae 266 }
c801d85f
KB
267 }
268 else
269 {
e2414cbe 270 if (!m_isCollapsed)
c801d85f 271 {
f135ff73
VZ
272 size_t count = m_children.Count();
273 for ( size_t n = 0; n < count; n++ )
e2414cbe 274 {
f135ff73
VZ
275 wxGenericTreeItem *res = m_children[n]->HitTest( point, onButton );
276 if ( res != NULL )
277 return res;
edaa81ae
RR
278 }
279 }
280 }
f135ff73
VZ
281
282 return NULL;
edaa81ae 283}
c801d85f 284
f135ff73
VZ
285// -----------------------------------------------------------------------------
286// wxTreeCtrl implementation
287// -----------------------------------------------------------------------------
288
289IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxScrolledWindow)
290
291BEGIN_EVENT_TABLE(wxTreeCtrl,wxScrolledWindow)
292 EVT_PAINT (wxTreeCtrl::OnPaint)
293 EVT_MOUSE_EVENTS (wxTreeCtrl::OnMouse)
294 EVT_CHAR (wxTreeCtrl::OnChar)
295 EVT_SET_FOCUS (wxTreeCtrl::OnSetFocus)
296 EVT_KILL_FOCUS (wxTreeCtrl::OnKillFocus)
3db7be80 297 EVT_IDLE (wxTreeCtrl::OnIdle)
f135ff73
VZ
298END_EVENT_TABLE()
299
300// -----------------------------------------------------------------------------
301// construction/destruction
302// -----------------------------------------------------------------------------
303void wxTreeCtrl::Init()
c801d85f 304{
f135ff73
VZ
305 m_current =
306 m_anchor = (wxGenericTreeItem *) NULL;
307 m_hasFocus = FALSE;
3db7be80 308 m_dirty = FALSE;
f135ff73
VZ
309
310 m_xScroll = 0;
311 m_yScroll = 0;
312 m_lineHeight = 10;
313 m_indent = 15;
314
315 m_hilightBrush = new wxBrush
316 (
317 wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHT),
318 wxSOLID
319 );
320
321 m_imageListNormal =
322 m_imageListState = (wxImageList *) NULL;
edaa81ae 323}
c801d85f 324
f135ff73
VZ
325bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id,
326 const wxPoint& pos, const wxSize& size,
327 long style, const wxString& name )
c801d85f 328{
f135ff73
VZ
329 Init();
330
a367b9b3 331 wxScrolledWindow::Create( parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name );
f135ff73
VZ
332
333 SetBackgroundColour( *wxWHITE );
334 m_dottedPen = wxPen( *wxBLACK, 0, 0 );
335
336 return TRUE;
edaa81ae 337}
c801d85f 338
f135ff73 339wxTreeCtrl::~wxTreeCtrl()
c801d85f 340{
f135ff73
VZ
341 wxDELETE( m_hilightBrush );
342 wxDELETE( m_anchor );
edaa81ae 343}
c801d85f 344
f135ff73
VZ
345// -----------------------------------------------------------------------------
346// accessors
347// -----------------------------------------------------------------------------
348
349size_t wxTreeCtrl::GetCount() const
c801d85f 350{
4832f7c0 351 return m_anchor == NULL ? 0u : m_anchor->GetChildrenCount();
edaa81ae 352}
c801d85f 353
f135ff73 354void wxTreeCtrl::SetIndent(unsigned int indent)
c801d85f 355{
f135ff73
VZ
356 m_indent = indent;
357 Refresh();
358}
74bedbeb 359
4832f7c0
VZ
360size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
361{
362 wxCHECK_MSG( item.IsOk(), 0u, "invalid tree item" );
363
364 return item.m_pItem->GetChildrenCount(recursively);
365}
366
f135ff73
VZ
367// -----------------------------------------------------------------------------
368// functions to work with tree items
369// -----------------------------------------------------------------------------
74bedbeb 370
f135ff73
VZ
371wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
372{
4832f7c0
VZ
373 wxCHECK_MSG( item.IsOk(), "", "invalid tree item" );
374
f135ff73 375 return item.m_pItem->GetText();
edaa81ae 376}
74bedbeb 377
f135ff73 378int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
74bedbeb 379{
4832f7c0
VZ
380 wxCHECK_MSG( item.IsOk(), -1, "invalid tree item" );
381
f135ff73 382 return item.m_pItem->GetImage();
edaa81ae 383}
c801d85f 384
f135ff73 385int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
c801d85f 386{
4832f7c0
VZ
387 wxCHECK_MSG( item.IsOk(), -1, "invalid tree item" );
388
f135ff73 389 return item.m_pItem->GetSelectedImage();
edaa81ae 390}
c801d85f 391
f135ff73 392wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
c801d85f 393{
4832f7c0
VZ
394 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
395
f135ff73 396 return item.m_pItem->GetData();
edaa81ae 397}
c801d85f 398
f135ff73
VZ
399void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
400{
4832f7c0
VZ
401 wxCHECK_RET( item.IsOk(), "invalid tree item" );
402
f135ff73 403 wxClientDC dc(this);
de646ed1 404 item.m_pItem->SetText(text, dc);
f135ff73 405}
c801d85f 406
f135ff73
VZ
407void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
408{
4832f7c0
VZ
409 wxCHECK_RET( item.IsOk(), "invalid tree item" );
410
de646ed1 411 item.m_pItem->SetImage(image);
f135ff73 412}
c801d85f 413
f135ff73 414void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
c801d85f 415{
4832f7c0
VZ
416 wxCHECK_RET( item.IsOk(), "invalid tree item" );
417
de646ed1 418 item.m_pItem->SetSelectedImage(image);
edaa81ae 419}
c801d85f 420
f135ff73 421void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
c801d85f 422{
4832f7c0
VZ
423 wxCHECK_RET( item.IsOk(), "invalid tree item" );
424
de646ed1 425 item.m_pItem->SetData(data);
edaa81ae 426}
c801d85f 427
f135ff73 428void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
c801d85f 429{
4832f7c0
VZ
430 wxCHECK_RET( item.IsOk(), "invalid tree item" );
431
f135ff73 432 item.m_pItem->SetHasPlus(has);
edaa81ae 433}
c801d85f 434
f135ff73
VZ
435// -----------------------------------------------------------------------------
436// item status inquiries
437// -----------------------------------------------------------------------------
438
df875e59 439bool wxTreeCtrl::IsVisible(const wxTreeItemId& WXUNUSED(item)) const
c801d85f 440{
f135ff73
VZ
441 wxFAIL_MSG("not implemented");
442
c801d85f 443 return TRUE;
edaa81ae 444}
c801d85f 445
f135ff73 446bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
c801d85f 447{
4832f7c0
VZ
448 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
449
f135ff73 450 return !item.m_pItem->GetChildren().IsEmpty();
edaa81ae 451}
c801d85f 452
f135ff73 453bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
c801d85f 454{
4832f7c0
VZ
455 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
456
f135ff73
VZ
457 return item.m_pItem->IsExpanded();
458}
29d87bba 459
f135ff73
VZ
460bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
461{
4832f7c0
VZ
462 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
463
f135ff73
VZ
464 return item.m_pItem->HasHilight();
465}
29d87bba 466
f135ff73
VZ
467// -----------------------------------------------------------------------------
468// navigation
469// -----------------------------------------------------------------------------
29d87bba 470
f135ff73
VZ
471wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
472{
473 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
389cdc7a 474
f135ff73
VZ
475 return item.m_pItem->GetParent();
476}
29d87bba 477
f135ff73
VZ
478wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& cookie) const
479{
480 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
29d87bba 481
f135ff73
VZ
482 cookie = 0;
483 return GetNextChild(item, cookie);
484}
29d87bba 485
f135ff73
VZ
486wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) const
487{
488 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
29d87bba 489
4832f7c0
VZ
490 wxArrayTreeItems& children = item.m_pItem->GetChildren();
491 if ( (size_t)cookie < children.Count() )
492 {
493 return item.m_pItem->GetChildren().Item(cookie++);
494 }
495 else
496 {
497 // there are no more of them
498 return NULL;
499 }
f135ff73 500}
29d87bba 501
f135ff73
VZ
502wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
503{
504 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
505
506 wxGenericTreeItem *i = item.m_pItem;
507 wxGenericTreeItem *parent = i->GetParent();
508 if ( parent == NULL )
509 {
510 // root item doesn't have any siblings
511 return NULL;
edaa81ae 512 }
4832f7c0 513
f135ff73
VZ
514 wxArrayTreeItems& siblings = parent->GetChildren();
515 int index = siblings.Index(i);
516 wxASSERT( index != NOT_FOUND ); // I'm not a child of my parent?
29d87bba 517
f135ff73 518 size_t n = (size_t)(index + 1);
de646ed1 519 return n == siblings.Count() ? (wxGenericTreeItem*)NULL : siblings[n];
edaa81ae 520}
c801d85f 521
f135ff73 522wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
c801d85f 523{
f135ff73
VZ
524 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
525
526 wxGenericTreeItem *i = item.m_pItem;
527 wxGenericTreeItem *parent = i->GetParent();
528 if ( parent == NULL )
c801d85f 529 {
f135ff73
VZ
530 // root item doesn't have any siblings
531 return NULL;
edaa81ae 532 }
4832f7c0 533
f135ff73
VZ
534 wxArrayTreeItems& siblings = parent->GetChildren();
535 int index = siblings.Index(i);
536 wxASSERT( index != NOT_FOUND ); // I'm not a child of my parent?
29d87bba 537
de646ed1 538 return index == 0 ? (wxGenericTreeItem*)NULL : siblings[(size_t)(index - 1)];
f135ff73 539}
389cdc7a 540
f135ff73
VZ
541wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
542{
543 wxFAIL_MSG("not implemented");
29d87bba 544
f135ff73
VZ
545 return NULL;
546}
29d87bba 547
f135ff73
VZ
548wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
549{
550 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
29d87bba 551
f135ff73 552 wxFAIL_MSG("not implemented");
29d87bba 553
f135ff73
VZ
554 return NULL;
555}
29d87bba 556
f135ff73
VZ
557wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
558{
559 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
29d87bba 560
f135ff73 561 wxFAIL_MSG("not implemented");
29d87bba 562
f135ff73 563 return NULL;
edaa81ae 564}
c801d85f 565
f135ff73
VZ
566// -----------------------------------------------------------------------------
567// operations
568// -----------------------------------------------------------------------------
569
570wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
571 size_t previous,
572 const wxString& text,
573 int image, int selImage,
574 wxTreeItemData *data)
c801d85f 575{
f135ff73
VZ
576 wxGenericTreeItem *parent = parentId.m_pItem;
577 if ( !parent )
578 {
579 // should we give a warning here?
580 return AddRoot(text, image, selImage, data);
581 }
4832f7c0 582
f135ff73
VZ
583 wxClientDC dc(this);
584 wxGenericTreeItem *item = new wxGenericTreeItem(parent,
585 text, dc,
586 image, selImage,
587 data);
74bedbeb 588
f135ff73 589 if ( data != NULL )
c801d85f 590 {
f135ff73
VZ
591 data->m_pItem = item;
592 }
74bedbeb 593
f135ff73 594 parent->Insert( item, previous );
3db7be80
RR
595
596 m_dirty = TRUE;
389cdc7a 597
f135ff73 598 return item;
4c681997
RR
599}
600
f135ff73
VZ
601wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
602 int image, int selImage,
603 wxTreeItemData *data)
4c681997 604{
f135ff73 605 wxCHECK_MSG( !m_anchor, NULL, "tree can have only one root" );
389cdc7a 606
f135ff73
VZ
607 wxClientDC dc(this);
608 m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, dc,
609 image, selImage, data);
610 if ( data != NULL )
611 {
612 data->m_pItem = m_anchor;
613 }
389cdc7a 614
f135ff73 615 AdjustMyScrollbars();
a32dd690 616 Refresh();
a32dd690 617
f135ff73 618 return m_anchor;
edaa81ae 619}
c801d85f 620
f135ff73
VZ
621wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
622 const wxString& text,
623 int image, int selImage,
624 wxTreeItemData *data)
c801d85f 625{
f135ff73 626 return DoInsertItem(parent, 0u, text, image, selImage, data);
edaa81ae 627}
c801d85f 628
f135ff73
VZ
629wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parentId,
630 const wxTreeItemId& idPrevious,
631 const wxString& text,
632 int image, int selImage,
633 wxTreeItemData *data)
c801d85f 634{
f135ff73
VZ
635 wxGenericTreeItem *parent = parentId.m_pItem;
636 if ( !parent )
637 {
638 // should we give a warning here?
639 return AddRoot(text, image, selImage, data);
640 }
c801d85f 641
f135ff73
VZ
642 int index = parent->GetChildren().Index(idPrevious.m_pItem);
643 wxASSERT_MSG( index != NOT_FOUND,
644 "previous item in wxTreeCtrl::InsertItem() is not a sibling" );
645 return DoInsertItem(parentId, (size_t)index, text, image, selImage, data);
edaa81ae 646}
c801d85f 647
f135ff73
VZ
648wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parentId,
649 const wxString& text,
650 int image, int selImage,
651 wxTreeItemData *data)
74bedbeb 652{
f135ff73
VZ
653 wxGenericTreeItem *parent = parentId.m_pItem;
654 if ( !parent )
655 {
656 // should we give a warning here?
657 return AddRoot(text, image, selImage, data);
658 }
659
660 return DoInsertItem(parent, parent->GetChildren().Count(), text,
661 image, selImage, data);
74bedbeb
VZ
662}
663
f135ff73 664void wxTreeCtrl::Delete(const wxTreeItemId& itemId)
c801d85f 665{
f135ff73 666 wxGenericTreeItem *item = itemId.m_pItem;
ff5bf259
VZ
667 wxGenericTreeItem *parent = item->GetParent();
668
669 if ( parent )
670 {
671 parent->GetChildren().Remove(item);
672 }
f135ff73
VZ
673
674 delete item;
675
676 Refresh();
edaa81ae 677}
c801d85f 678
f135ff73 679void wxTreeCtrl::DeleteAllItems()
c801d85f 680{
f135ff73
VZ
681 if ( m_anchor )
682 {
683 delete m_anchor;
684 m_anchor = NULL;
685
686 Refresh();
687 }
edaa81ae
RR
688}
689
f135ff73 690void wxTreeCtrl::Expand(const wxTreeItemId& itemId)
edaa81ae 691{
f135ff73
VZ
692 wxGenericTreeItem *item = itemId.m_pItem;
693
694 if ( item->IsExpanded() )
695 return;
696
697 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() );
698 event.m_item = item;
699 event.SetEventObject( this );
700 if ( ProcessEvent( event ) && event.m_code )
701 {
702 // cancelled by program
703 return;
704 }
4832f7c0 705
f135ff73
VZ
706 item->Expand();
707
708 RefreshSubtree(item);
709
710 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
711 ProcessEvent( event );
edaa81ae
RR
712}
713
f135ff73 714void wxTreeCtrl::Collapse(const wxTreeItemId& itemId)
edaa81ae 715{
f135ff73
VZ
716 wxGenericTreeItem *item = itemId.m_pItem;
717
718 if ( !item->IsExpanded() )
719 return;
720
721 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() );
722 event.m_item = item;
723 event.SetEventObject( this );
724 if ( ProcessEvent( event ) && event.m_code )
edaa81ae 725 {
f135ff73
VZ
726 // cancelled by program
727 return;
728 }
4832f7c0 729
f135ff73
VZ
730 item->Collapse();
731
732 wxArrayTreeItems& children = item->GetChildren();
733 size_t count = children.Count();
734 for ( size_t n = 0; n < count; n++ )
735 {
736 Collapse(children[n]);
edaa81ae 737 }
f135ff73
VZ
738
739 CalculatePositions();
740
741 RefreshSubtree(item);
742
743 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
744 ProcessEvent( event );
edaa81ae 745}
c801d85f 746
f135ff73 747void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
c801d85f 748{
f135ff73
VZ
749 Collapse(item);
750 Delete(item);
edaa81ae 751}
c801d85f 752
f135ff73 753void wxTreeCtrl::Toggle(const wxTreeItemId& itemId)
c801d85f 754{
f135ff73 755 wxGenericTreeItem *item = itemId.m_pItem;
389cdc7a 756
f135ff73
VZ
757 if ( item->IsExpanded() )
758 Collapse(itemId);
759 else
760 Expand(itemId);
761}
389cdc7a 762
f135ff73
VZ
763void wxTreeCtrl::Unselect()
764{
765 if ( m_current )
766 {
767 m_current->SetHilight( FALSE );
768 RefreshLine( m_current );
769 }
edaa81ae 770}
c801d85f 771
f135ff73 772void wxTreeCtrl::SelectItem(const wxTreeItemId& itemId)
389cdc7a 773{
f135ff73
VZ
774 wxGenericTreeItem *item = itemId.m_pItem;
775
776 if ( m_current != item )
389cdc7a 777 {
f135ff73
VZ
778 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
779 event.m_item = item;
780 event.m_itemOld = m_current;
781 event.SetEventObject( this );
782 if ( ProcessEvent( event ) && event.WasVetoed() )
783 return;
784
785 if ( m_current )
389cdc7a
VZ
786 {
787 m_current->SetHilight( FALSE );
788 RefreshLine( m_current );
edaa81ae 789 }
f135ff73 790
389cdc7a
VZ
791 m_current = item;
792 m_current->SetHilight( TRUE );
793 RefreshLine( m_current );
794
f135ff73
VZ
795 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
796 ProcessEvent( event );
389cdc7a
VZ
797 }
798}
799
df875e59 800void wxTreeCtrl::EnsureVisible(const wxTreeItemId& WXUNUSED(item))
c801d85f 801{
f135ff73 802 wxFAIL_MSG("not implemented");
edaa81ae 803}
c801d85f 804
df875e59 805void wxTreeCtrl::ScrollTo(const wxTreeItemId& WXUNUSED(item))
c801d85f 806{
f135ff73 807 wxFAIL_MSG("not implemented");
edaa81ae 808}
c801d85f 809
df875e59
RR
810wxTextCtrl *wxTreeCtrl::EditLabel( const wxTreeItemId& WXUNUSED(item),
811 wxClassInfo* WXUNUSED(textCtrlClass) )
c801d85f 812{
f135ff73 813 wxFAIL_MSG("not implemented");
c801d85f 814
f135ff73 815 return NULL;
edaa81ae 816}
c801d85f 817
f135ff73 818wxTextCtrl *wxTreeCtrl::GetEditControl() const
c801d85f 819{
f135ff73 820 wxFAIL_MSG("not implemented");
c801d85f 821
f135ff73 822 return NULL;
edaa81ae 823}
c801d85f 824
df875e59 825void wxTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item), bool WXUNUSED(discardChanges))
74bedbeb 826{
f135ff73 827 wxFAIL_MSG("not implemented");
74bedbeb
VZ
828}
829
df875e59
RR
830void wxTreeCtrl::SortChildren( const wxTreeItemId& WXUNUSED(item),
831 wxTreeItemCmpFunc *WXUNUSED(cmpFunction))
edaa81ae 832{
f135ff73 833 wxFAIL_MSG("not implemented");
edaa81ae
RR
834}
835
f135ff73 836wxImageList *wxTreeCtrl::GetImageList() const
edaa81ae 837{
f135ff73 838 return m_imageListNormal;
edaa81ae
RR
839}
840
f135ff73 841wxImageList *wxTreeCtrl::GetStateImageList() const
c801d85f 842{
f135ff73 843 return m_imageListState;
edaa81ae 844}
c801d85f 845
f135ff73 846void wxTreeCtrl::SetImageList(wxImageList *imageList)
e2414cbe 847{
f135ff73 848 m_imageListNormal = imageList;
edaa81ae 849}
e2414cbe 850
f135ff73 851void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
e2414cbe 852{
f135ff73 853 m_imageListState = imageList;
edaa81ae 854}
e2414cbe 855
f135ff73
VZ
856// -----------------------------------------------------------------------------
857// helpers
858// -----------------------------------------------------------------------------
74bedbeb 859void wxTreeCtrl::AdjustMyScrollbars()
c801d85f
KB
860{
861 if (m_anchor)
862 {
863 int x = 0;
864 int y = 0;
865 m_anchor->GetSize( x, y );
866 y += 2*m_lineHeight;
867 int x_pos = GetScrollPos( wxHORIZONTAL );
868 int y_pos = GetScrollPos( wxVERTICAL );
869 SetScrollbars( 10, 10, x/10, y/10, x_pos, y_pos );
870 }
871 else
872 {
873 SetScrollbars( 0, 0, 0, 0 );
edaa81ae
RR
874 }
875}
c801d85f 876
16c1f7f3 877void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
c801d85f 878{
4c681997 879 int horizX = level*m_indent;
389cdc7a 880
f135ff73
VZ
881 item->SetX( horizX+33 );
882 item->SetY( y-m_lineHeight/3 );
883 item->SetHeight( m_lineHeight );
389cdc7a 884
4c681997
RR
885 item->SetCross( horizX+15, y );
886
c801d85f 887 int oldY = y;
389cdc7a 888
d4c99d6f 889 int exposed_x = dc.LogicalToDeviceX( 0 );
f135ff73 890 int exposed_y = dc.LogicalToDeviceY( item->GetY()-2 );
4832f7c0 891
df875e59 892 if (IsExposed( exposed_x, exposed_y, 10000, m_lineHeight+4 )) // 10000 = very much
c801d85f 893 {
4c681997
RR
894 int startX = horizX;
895 int endX = horizX + 10;
29d87bba 896
4c681997 897 if (!item->HasChildren()) endX += 20;
4832f7c0 898
389cdc7a 899 dc.DrawLine( startX, y, endX, y );
29d87bba 900
f135ff73
VZ
901 if (item->HasPlus())
902 {
903 dc.DrawLine( horizX+20, y, horizX+30, y );
904 dc.SetPen( *wxGREY_PEN );
905 dc.DrawRectangle( horizX+10, y-4, 11, 9 );
906 dc.SetPen( *wxBLACK_PEN );
907 dc.DrawLine( horizX+13, y, horizX+18, y );
908
909 if (!item->IsExpanded())
910 dc.DrawLine( horizX+15, y-2, horizX+15, y+3 );
911 }
c801d85f 912
f135ff73
VZ
913 if (item->HasHilight())
914 {
915 dc.SetTextForeground( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) );
a367b9b3 916
f135ff73 917 dc.SetBrush( *m_hilightBrush );
4832f7c0 918
df875e59
RR
919 long text_w = 0;
920 long text_h = 0;
921 dc.GetTextExtent( item->GetText(), &text_w, &text_h );
4832f7c0 922
df875e59
RR
923 int image_h = 0;
924 int image_w = 0;
925 if (item->GetImage() != -1)
c801d85f 926 {
df875e59
RR
927 m_imageListNormal->GetSize( item->GetImage(), image_w, image_h );
928 image_w += 4;
29d87bba 929 }
4832f7c0 930
df875e59
RR
931 if (m_hasFocus)
932 dc.SetPen( *wxBLACK_PEN );
29d87bba 933 else
389cdc7a 934 dc.SetPen( *wxTRANSPARENT_PEN );
4832f7c0 935
df875e59 936 dc.DrawRectangle( item->GetX()-2, item->GetY()-2, image_w+text_w+4, text_h+4 );
4832f7c0 937
df875e59
RR
938 if (item->GetImage() != -1)
939 {
940 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, text_h );
941 m_imageListNormal->Draw( item->GetImage(), dc, item->GetX(), item->GetY()-1, wxIMAGELIST_DRAW_TRANSPARENT );
942 dc.DestroyClippingRegion();
edaa81ae 943 }
df875e59 944 dc.DrawText( item->GetText(), image_w+item->GetX(), item->GetY() );
f135ff73
VZ
945
946 dc.SetPen( *wxBLACK_PEN );
947 dc.SetTextForeground( *wxBLACK );
948 dc.SetBrush( *wxWHITE_BRUSH );
949 }
950 else
951 {
952 dc.SetBrush( *wxWHITE_BRUSH );
953 dc.SetPen( *wxTRANSPARENT_PEN );
4832f7c0 954
df875e59
RR
955 long text_w = 0;
956 long text_h = 0;
957 dc.GetTextExtent( item->GetText(), &text_w, &text_h );
4832f7c0 958
df875e59
RR
959 int image_h = 0;
960 int image_w = 0;
961 if (item->GetImage() != -1)
962 {
963 m_imageListNormal->GetSize( item->GetImage(), image_w, image_h );
964 image_w += 4;
965 }
4832f7c0 966
df875e59 967 dc.DrawRectangle( item->GetX()-2, item->GetY()-2, image_w+text_w+4, text_h+4 );
4832f7c0 968
df875e59
RR
969 if (item->GetImage() != -1)
970 {
971 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, text_h );
972 m_imageListNormal->Draw( item->GetImage(), dc, item->GetX(), item->GetY()-1, wxIMAGELIST_DRAW_TRANSPARENT );
973 dc.DestroyClippingRegion();
974 }
4832f7c0 975
df875e59 976 dc.DrawText( item->GetText(), image_w+item->GetX(), item->GetY() );
f135ff73
VZ
977 dc.SetPen( *wxBLACK_PEN );
978 }
edaa81ae 979 }
4c681997 980
f135ff73
VZ
981 if ( !item->IsExpanded() )
982 return;
e2414cbe 983
389cdc7a
VZ
984 int semiOldY = y;
985
f135ff73
VZ
986 wxArrayTreeItems& children = item->GetChildren();
987 size_t count = children.Count();
988 for ( size_t n = 0; n < count; n++ )
4c681997 989 {
c801d85f 990 y += m_lineHeight;
e2414cbe 991 semiOldY = y;
389cdc7a 992
f135ff73 993 PaintLevel( children[n], dc, level+1, y );
edaa81ae 994 }
4c681997 995
e2414cbe 996 dc.DrawLine( horizX+15, oldY+5, horizX+15, semiOldY );
4c681997 997}
c801d85f 998
f135ff73
VZ
999// -----------------------------------------------------------------------------
1000// wxWindows callbacks
1001// -----------------------------------------------------------------------------
1002
3db7be80 1003void wxTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
c801d85f 1004{
f135ff73
VZ
1005 if ( !m_anchor )
1006 return;
c801d85f 1007
d4c99d6f
RR
1008 wxPaintDC dc(this);
1009 PrepareDC( dc );
29d87bba 1010
d4c99d6f 1011 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_SYSTEM_FONT ) );
29d87bba 1012
d4c99d6f
RR
1013 dc.SetPen( m_dottedPen );
1014 m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 1015
c801d85f 1016 int y = m_lineHeight / 2 + 2;
d4c99d6f 1017 PaintLevel( m_anchor, dc, 0, y );
edaa81ae 1018}
c801d85f 1019
3db7be80 1020void wxTreeCtrl::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f
KB
1021{
1022 m_hasFocus = TRUE;
f135ff73
VZ
1023 if ( m_current )
1024 RefreshLine( m_current );
edaa81ae 1025}
c801d85f 1026
3db7be80 1027void wxTreeCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
c801d85f
KB
1028{
1029 m_hasFocus = FALSE;
f135ff73
VZ
1030 if ( m_current )
1031 RefreshLine( m_current );
edaa81ae 1032}
c801d85f
KB
1033
1034void wxTreeCtrl::OnChar( wxKeyEvent &event )
1035{
f135ff73 1036 // TODO process '+', '-' (expand/collapse branch) and cursor keys
c801d85f 1037 event.Skip();
edaa81ae 1038}
c801d85f 1039
3db7be80 1040void wxTreeCtrl::OnMouse( wxMouseEvent &event )
c801d85f 1041{
f135ff73
VZ
1042 if ( !(event.LeftDown() || event.LeftDClick()) )
1043 return;
1044
1045 if ( !m_anchor )
1046 return;
29d87bba 1047
c801d85f
KB
1048 wxClientDC dc(this);
1049 PrepareDC(dc);
1050 long x = dc.DeviceToLogicalX( (long)event.GetX() );
1051 long y = dc.DeviceToLogicalY( (long)event.GetY() );
29d87bba 1052
f135ff73
VZ
1053 bool onButton = FALSE;
1054 wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), onButton );
1055 if ( item == NULL )
29d87bba 1056 return;
29d87bba 1057
389cdc7a 1058 SelectItem(item);
29d87bba 1059
f135ff73
VZ
1060 if ( event.LeftDClick() )
1061 {
1062 wxTreeEvent event( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() );
1063 event.m_item = item;
1064 event.m_code = 0;
1065 event.SetEventObject( this );
1066 ProcessEvent( event );
1067 }
29d87bba 1068
f135ff73 1069 if ( onButton )
c801d85f 1070 {
f135ff73 1071 Toggle( item );
edaa81ae
RR
1072 }
1073}
c801d85f 1074
3db7be80
RR
1075void wxTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) )
1076{
1077 if (!m_dirty) return;
1078
1079 m_dirty = FALSE;
1080
1081 CalculatePositions();
1082
1083 AdjustMyScrollbars();
1084}
1085
f135ff73
VZ
1086// -----------------------------------------------------------------------------
1087// -----------------------------------------------------------------------------
1088void wxTreeCtrl::CalculateLevel( wxGenericTreeItem *item,
1089 wxDC &dc,
1090 int level,
1091 int &y )
c801d85f 1092{
4c681997 1093 int horizX = level*m_indent;
389cdc7a 1094
f135ff73
VZ
1095 item->SetX( horizX+33 );
1096 item->SetY( y-m_lineHeight/3-2 );
1097 item->SetHeight( m_lineHeight );
4c681997 1098
f135ff73
VZ
1099 if ( item->IsExpanded() )
1100 return;
389cdc7a 1101
f135ff73
VZ
1102 wxArrayTreeItems& children = item->GetChildren();
1103 size_t count = children.Count();
1104 for ( size_t n = 0; n < count; n++ )
c801d85f 1105 {
c801d85f 1106 y += m_lineHeight;
f135ff73 1107 CalculateLevel( children[n], dc, level+1, y );
edaa81ae
RR
1108 }
1109}
c801d85f 1110
74bedbeb 1111void wxTreeCtrl::CalculatePositions()
c801d85f 1112{
f135ff73 1113 if ( !m_anchor )
29d87bba
VZ
1114 return;
1115
c801d85f
KB
1116 wxClientDC dc(this);
1117 PrepareDC( dc );
29d87bba 1118
c801d85f 1119 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_SYSTEM_FONT ) );
29d87bba 1120
c801d85f
KB
1121 dc.SetPen( m_dottedPen );
1122 m_lineHeight = (int)(dc.GetCharHeight() + 4);
29d87bba 1123
c801d85f
KB
1124 int y = m_lineHeight / 2 + 2;
1125 CalculateLevel( m_anchor, dc, 0, y );
edaa81ae 1126}
c801d85f 1127
f135ff73 1128void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
c801d85f 1129{
f135ff73
VZ
1130 wxClientDC dc(this);
1131 PrepareDC(dc);
4832f7c0 1132
f135ff73
VZ
1133 int cw = 0;
1134 int ch = 0;
1135 GetClientSize( &cw, &ch );
4832f7c0 1136
f135ff73
VZ
1137 wxRect rect;
1138 rect.x = dc.LogicalToDeviceX( 0 );
1139 rect.width = cw;
1140 rect.y = dc.LogicalToDeviceY( item->GetY() );
1141 rect.height = ch;
1142
1143 Refresh( TRUE, &rect );
1144
1145 AdjustMyScrollbars();
edaa81ae 1146}
c801d85f
KB
1147
1148void wxTreeCtrl::RefreshLine( wxGenericTreeItem *item )
1149{
c801d85f
KB
1150 wxClientDC dc(this);
1151 PrepareDC( dc );
f135ff73 1152
c801d85f 1153 wxRect rect;
f135ff73
VZ
1154 rect.x = dc.LogicalToDeviceX( item->GetX() - 2 );
1155 rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
c801d85f 1156 rect.width = 1000;
f135ff73 1157 rect.height = dc.GetCharHeight() + 6;
c801d85f 1158 Refresh( TRUE, &rect );
edaa81ae 1159}
c801d85f 1160