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