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