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