]> git.saurik.com Git - wxWidgets.git/blob - src/generic/treectrl.cpp
Motif cell highlighting problem fixed
[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 wxGenericTreeItem *pItem = item.m_pItem;
451 pItem->SetText(text, dc);
452 RefreshLine(pItem);
453 }
454
455 void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
456 {
457 wxCHECK_RET( item.IsOk(), "invalid tree item" );
458
459 wxGenericTreeItem *pItem = item.m_pItem;
460 pItem->SetImage(image);
461 RefreshLine(pItem);
462 }
463
464 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
465 {
466 wxCHECK_RET( item.IsOk(), "invalid tree item" );
467
468 wxGenericTreeItem *pItem = item.m_pItem;
469 pItem->SetSelectedImage(image);
470 RefreshLine(pItem);
471 }
472
473 void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
474 {
475 wxCHECK_RET( item.IsOk(), "invalid tree item" );
476
477 item.m_pItem->SetData(data);
478 }
479
480 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
481 {
482 wxCHECK_RET( item.IsOk(), "invalid tree item" );
483
484 wxGenericTreeItem *pItem = item.m_pItem;
485 pItem->SetHasPlus(has);
486 RefreshLine(pItem);
487 }
488
489 void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
490 {
491 wxCHECK_RET( item.IsOk(), "invalid tree item" );
492
493 // avoid redrawing the tree if no real change
494 wxGenericTreeItem *pItem = item.m_pItem;
495 if ( pItem->IsBold() != bold )
496 {
497 pItem->SetBold(bold);
498 RefreshLine(pItem);
499 }
500 }
501
502 // -----------------------------------------------------------------------------
503 // item status inquiries
504 // -----------------------------------------------------------------------------
505
506 bool wxTreeCtrl::IsVisible(const wxTreeItemId& WXUNUSED(item)) const
507 {
508 wxFAIL_MSG("not implemented");
509
510 return TRUE;
511 }
512
513 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
514 {
515 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
516
517 return !item.m_pItem->GetChildren().IsEmpty();
518 }
519
520 bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
521 {
522 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
523
524 return item.m_pItem->IsExpanded();
525 }
526
527 bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
528 {
529 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
530
531 return item.m_pItem->HasHilight();
532 }
533
534 bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const
535 {
536 wxCHECK_MSG( item.IsOk(), FALSE, "invalid tree item" );
537
538 return item.m_pItem->IsBold();
539 }
540
541 // -----------------------------------------------------------------------------
542 // navigation
543 // -----------------------------------------------------------------------------
544
545 wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
546 {
547 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
548
549 return item.m_pItem->GetParent();
550 }
551
552 wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& cookie) const
553 {
554 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
555
556 cookie = 0;
557 return GetNextChild(item, cookie);
558 }
559
560 wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) const
561 {
562 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
563
564 wxArrayTreeItems& children = item.m_pItem->GetChildren();
565 if ( (size_t)cookie < children.Count() )
566 {
567 return children.Item(cookie++);
568 }
569 else
570 {
571 // there are no more of them
572 return wxTreeItemId();
573 }
574 }
575
576 wxTreeItemId wxTreeCtrl::GetLastChild(const wxTreeItemId& item) const
577 {
578 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
579
580 wxArrayTreeItems& children = item.m_pItem->GetChildren();
581 return (children.IsEmpty() ? wxTreeItemId() : wxTreeItemId(children.Last()));
582 }
583
584 wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
585 {
586 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
587
588 wxGenericTreeItem *i = item.m_pItem;
589 wxGenericTreeItem *parent = i->GetParent();
590 if ( parent == NULL )
591 {
592 // root item doesn't have any siblings
593 return wxTreeItemId();
594 }
595
596 wxArrayTreeItems& siblings = parent->GetChildren();
597 int index = siblings.Index(i);
598 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
599
600 size_t n = (size_t)(index + 1);
601 return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]);
602 }
603
604 wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
605 {
606 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
607
608 wxGenericTreeItem *i = item.m_pItem;
609 wxGenericTreeItem *parent = i->GetParent();
610 if ( parent == NULL )
611 {
612 // root item doesn't have any siblings
613 return wxTreeItemId();
614 }
615
616 wxArrayTreeItems& siblings = parent->GetChildren();
617 int index = siblings.Index(i);
618 wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
619
620 return index == 0 ? wxTreeItemId()
621 : wxTreeItemId(siblings[(size_t)(index - 1)]);
622 }
623
624 wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
625 {
626 wxFAIL_MSG("not implemented");
627
628 return wxTreeItemId();
629 }
630
631 wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
632 {
633 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
634
635 wxFAIL_MSG("not implemented");
636
637 return wxTreeItemId();
638 }
639
640 wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
641 {
642 wxCHECK_MSG( item.IsOk(), wxTreeItemId(), "invalid tree item" );
643
644 wxFAIL_MSG("not implemented");
645
646 return wxTreeItemId();
647 }
648
649 // -----------------------------------------------------------------------------
650 // operations
651 // -----------------------------------------------------------------------------
652
653 wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
654 size_t previous,
655 const wxString& text,
656 int image, int selImage,
657 wxTreeItemData *data)
658 {
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 }
665
666 wxClientDC dc(this);
667 wxGenericTreeItem *item = new wxGenericTreeItem(parent,
668 text, dc,
669 image, selImage,
670 data);
671
672 if ( data != NULL )
673 {
674 data->m_pItem = item;
675 }
676
677 parent->Insert( item, previous );
678
679 m_dirty = TRUE;
680
681 return item;
682 }
683
684 wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
685 int image, int selImage,
686 wxTreeItemData *data)
687 {
688 wxCHECK_MSG( !m_anchor, wxTreeItemId(), "tree can have only one root" );
689
690 wxClientDC dc(this);
691 m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, dc,
692 image, selImage, data);
693 if ( data != NULL )
694 {
695 data->m_pItem = m_anchor;
696 }
697
698 AdjustMyScrollbars();
699 Refresh();
700
701 return m_anchor;
702 }
703
704 wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
705 const wxString& text,
706 int image, int selImage,
707 wxTreeItemData *data)
708 {
709 return DoInsertItem(parent, 0u, text, image, selImage, data);
710 }
711
712 wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parentId,
713 const wxTreeItemId& idPrevious,
714 const wxString& text,
715 int image, int selImage,
716 wxTreeItemData *data)
717 {
718 wxGenericTreeItem *parent = parentId.m_pItem;
719 if ( !parent )
720 {
721 // should we give a warning here?
722 return AddRoot(text, image, selImage, data);
723 }
724
725 int index = parent->GetChildren().Index(idPrevious.m_pItem);
726 wxASSERT_MSG( index != wxNOT_FOUND,
727 "previous item in wxTreeCtrl::InsertItem() is not a sibling" );
728 return DoInsertItem(parentId, (size_t)index, text, image, selImage, data);
729 }
730
731 wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parentId,
732 const wxString& text,
733 int image, int selImage,
734 wxTreeItemData *data)
735 {
736 wxGenericTreeItem *parent = parentId.m_pItem;
737 if ( !parent )
738 {
739 // should we give a warning here?
740 return AddRoot(text, image, selImage, data);
741 }
742
743 return DoInsertItem(parent, parent->GetChildren().Count(), text,
744 image, selImage, data);
745 }
746
747 void wxTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
748 {
749 wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() );
750 event.m_item = item;
751 event.SetEventObject( this );
752 ProcessEvent( event );
753 }
754
755 void wxTreeCtrl::DeleteChildren(const wxTreeItemId& itemId)
756 {
757 wxGenericTreeItem *item = itemId.m_pItem;
758 item->DeleteChildren(this);
759
760 m_dirty = TRUE;
761 }
762
763 void wxTreeCtrl::Delete(const wxTreeItemId& itemId)
764 {
765 wxGenericTreeItem *item = itemId.m_pItem;
766 wxGenericTreeItem *parent = item->GetParent();
767
768 if ( parent )
769 {
770 parent->GetChildren().Remove(item);
771 }
772
773 item->DeleteChildren(this);
774 SendDeleteEvent(item);
775 delete item;
776
777 m_dirty = TRUE;
778 }
779
780 void wxTreeCtrl::DeleteAllItems()
781 {
782 if ( m_anchor )
783 {
784 m_anchor->DeleteChildren(this);
785 delete m_anchor;
786
787 m_anchor = NULL;
788
789 m_dirty = TRUE;
790 }
791 }
792
793 void wxTreeCtrl::Expand(const wxTreeItemId& itemId)
794 {
795 wxGenericTreeItem *item = itemId.m_pItem;
796
797 if ( !item->HasPlus() )
798 return;
799
800 if ( item->IsExpanded() )
801 return;
802
803 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() );
804 event.m_item = item;
805 event.SetEventObject( this );
806 if ( ProcessEvent( event ) && event.m_code )
807 {
808 // cancelled by program
809 return;
810 }
811
812 item->Expand();
813 CalculatePositions();
814
815 RefreshSubtree(item);
816
817 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
818 ProcessEvent( event );
819 }
820
821 void wxTreeCtrl::Collapse(const wxTreeItemId& itemId)
822 {
823 wxGenericTreeItem *item = itemId.m_pItem;
824
825 if ( !item->IsExpanded() )
826 return;
827
828 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() );
829 event.m_item = item;
830 event.SetEventObject( this );
831 if ( ProcessEvent( event ) && event.m_code )
832 {
833 // cancelled by program
834 return;
835 }
836
837 item->Collapse();
838
839 wxArrayTreeItems& children = item->GetChildren();
840 size_t count = children.Count();
841 for ( size_t n = 0; n < count; n++ )
842 {
843 Collapse(children[n]);
844 }
845
846 CalculatePositions();
847
848 RefreshSubtree(item);
849
850 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
851 ProcessEvent( event );
852 }
853
854 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
855 {
856 Collapse(item);
857 DeleteChildren(item);
858 }
859
860 void wxTreeCtrl::Toggle(const wxTreeItemId& itemId)
861 {
862 wxGenericTreeItem *item = itemId.m_pItem;
863
864 if ( item->IsExpanded() )
865 Collapse(itemId);
866 else
867 Expand(itemId);
868 }
869
870 void wxTreeCtrl::Unselect()
871 {
872 if ( m_current )
873 {
874 m_current->SetHilight( FALSE );
875 RefreshLine( m_current );
876 }
877 }
878
879 void wxTreeCtrl::SelectItem(const wxTreeItemId& itemId)
880 {
881 wxGenericTreeItem *item = itemId.m_pItem;
882
883 if ( m_current != item )
884 {
885 wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
886 event.m_item = item;
887 event.m_itemOld = m_current;
888 event.SetEventObject( this );
889 if ( GetEventHandler()->ProcessEvent( event ) && event.WasVetoed() )
890 return;
891
892 if ( m_current )
893 {
894 m_current->SetHilight( FALSE );
895 RefreshLine( m_current );
896 }
897
898 m_current = item;
899 m_current->SetHilight( TRUE );
900 RefreshLine( m_current );
901
902 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
903 GetEventHandler()->ProcessEvent( event );
904 }
905 }
906
907 void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
908 {
909 wxGenericTreeItem *gitem = item.m_pItem;
910
911 // first expand all parent branches
912 wxGenericTreeItem *parent = gitem->GetParent();
913 while ( parent && !parent->IsExpanded() )
914 {
915 Expand(parent);
916
917 parent = parent->GetParent();
918 }
919
920 // now scroll to the item
921 int item_y = gitem->GetY();
922
923 int start_x = 0;
924 int start_y = 0;
925 ViewStart( &start_x, &start_y );
926 start_y *= 10;
927
928 int client_h = 0;
929 int client_w = 0;
930 GetClientSize( &client_w, &client_h );
931
932 if (item_y < start_y+3)
933 {
934 int x = 0;
935 int y = 0;
936 m_anchor->GetSize( x, y );
937 y += 2*m_lineHeight;
938 int x_pos = GetScrollPos( wxHORIZONTAL );
939 SetScrollbars( 10, 10, x/10, y/10, x_pos, (item_y-client_h/2)/10 );
940 }
941 else if (item_y > start_y+client_h-16)
942 {
943 int x = 0;
944 int y = 0;
945 m_anchor->GetSize( x, y );
946 y += 2*m_lineHeight;
947 int x_pos = GetScrollPos( wxHORIZONTAL );
948 SetScrollbars( 10, 10, x/10, y/10, x_pos, (item_y-client_h/2)/10 );
949 }
950 }
951
952 void wxTreeCtrl::ScrollTo(const wxTreeItemId& WXUNUSED(item))
953 {
954 wxFAIL_MSG("not implemented");
955 }
956
957 wxTextCtrl *wxTreeCtrl::EditLabel( const wxTreeItemId& WXUNUSED(item),
958 wxClassInfo* WXUNUSED(textCtrlClass) )
959 {
960 wxFAIL_MSG("not implemented");
961
962 return (wxTextCtrl*)NULL;
963 }
964
965 wxTextCtrl *wxTreeCtrl::GetEditControl() const
966 {
967 wxFAIL_MSG("not implemented");
968
969 return (wxTextCtrl*)NULL;
970 }
971
972 void wxTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item), bool WXUNUSED(discardChanges))
973 {
974 wxFAIL_MSG("not implemented");
975 }
976
977 // FIXME: tree sorting functions are not reentrant and not MT-safe!
978 static wxTreeCtrl *s_treeBeingSorted = NULL;
979
980 static int tree_ctrl_compare_func(wxGenericTreeItem **item1,
981 wxGenericTreeItem **item2)
982 {
983 wxCHECK_MSG( s_treeBeingSorted, 0, "bug in wxTreeCtrl::SortChildren()" );
984
985 return s_treeBeingSorted->OnCompareItems(*item1, *item2);
986 }
987
988 int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
989 const wxTreeItemId& item2)
990 {
991 return strcmp(GetItemText(item1), GetItemText(item2));
992 }
993
994 void wxTreeCtrl::SortChildren(const wxTreeItemId& itemId)
995 {
996 wxCHECK_RET( itemId.IsOk(), "invalid tree item" );
997
998 wxGenericTreeItem *item = itemId.m_pItem;
999
1000 wxCHECK_RET( !s_treeBeingSorted,
1001 "wxTreeCtrl::SortChildren is not reentrant" );
1002
1003 wxArrayTreeItems& children = item->GetChildren();
1004 if ( children.Count() > 1 )
1005 {
1006 s_treeBeingSorted = this;
1007 children.Sort(tree_ctrl_compare_func);
1008 s_treeBeingSorted = NULL;
1009
1010 m_dirty = TRUE;
1011 }
1012 //else: don't make the tree dirty as nothing changed
1013 }
1014
1015 wxImageList *wxTreeCtrl::GetImageList() const
1016 {
1017 return m_imageListNormal;
1018 }
1019
1020 wxImageList *wxTreeCtrl::GetStateImageList() const
1021 {
1022 return m_imageListState;
1023 }
1024
1025 void wxTreeCtrl::SetImageList(wxImageList *imageList)
1026 {
1027 m_imageListNormal = imageList;
1028 }
1029
1030 void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
1031 {
1032 m_imageListState = imageList;
1033 }
1034
1035 // -----------------------------------------------------------------------------
1036 // helpers
1037 // -----------------------------------------------------------------------------
1038
1039 void wxTreeCtrl::AdjustMyScrollbars()
1040 {
1041 if (m_anchor)
1042 {
1043 int x = 0;
1044 int y = 0;
1045 m_anchor->GetSize( x, y );
1046 y += 2*m_lineHeight;
1047 int x_pos = GetScrollPos( wxHORIZONTAL );
1048 int y_pos = GetScrollPos( wxVERTICAL );
1049 SetScrollbars( 10, 10, x/10, y/10, x_pos, y_pos );
1050 }
1051 else
1052 {
1053 SetScrollbars( 0, 0, 0, 0 );
1054 }
1055 }
1056
1057 void wxTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
1058 {
1059 // render bold items in bold
1060 wxFont fontOld;
1061 wxFont fontNew;
1062
1063 if (item->IsBold())
1064 {
1065 fontOld = dc.GetFont();
1066 if (fontOld.Ok())
1067 {
1068 // VZ: is there any better way to make a bold variant of old font?
1069 fontNew = wxFont( fontOld.GetPointSize(),
1070 fontOld.GetFamily(),
1071 fontOld.GetStyle(),
1072 wxBOLD,
1073 fontOld.GetUnderlined());
1074 dc.SetFont(fontNew);
1075 }
1076 else
1077 {
1078 wxFAIL_MSG("wxDC::GetFont() failed!");
1079 }
1080 }
1081
1082 long text_w = 0;
1083 long text_h = 0;
1084 dc.GetTextExtent( item->GetText(), &text_w, &text_h );
1085
1086 int image_h = 0;
1087 int image_w = 0;
1088 if ((item->IsExpanded()) && (item->GetSelectedImage() != -1))
1089 {
1090 m_imageListNormal->GetSize( item->GetSelectedImage(), image_w, image_h );
1091 image_w += 4;
1092 }
1093 else if (item->GetImage() != -1)
1094 {
1095 m_imageListNormal->GetSize( item->GetImage(), image_w, image_h );
1096 image_w += 4;
1097 }
1098
1099 dc.DrawRectangle( item->GetX()-2, item->GetY()-2, image_w+text_w+4, text_h+4 );
1100
1101 if ((item->IsExpanded()) && (item->GetSelectedImage() != -1))
1102 {
1103 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, text_h );
1104 m_imageListNormal->Draw( item->GetSelectedImage(), dc,
1105 item->GetX(), item->GetY()-1,
1106 wxIMAGELIST_DRAW_TRANSPARENT );
1107 dc.DestroyClippingRegion();
1108 }
1109 else if (item->GetImage() != -1)
1110 {
1111 dc.SetClippingRegion( item->GetX(), item->GetY(), image_w-2, text_h );
1112 m_imageListNormal->Draw( item->GetImage(), dc,
1113 item->GetX(), item->GetY()-1,
1114 wxIMAGELIST_DRAW_TRANSPARENT );
1115 dc.DestroyClippingRegion();
1116 }
1117
1118 dc.SetBackgroundMode(wxTRANSPARENT);
1119 dc.DrawText( item->GetText(), image_w + item->GetX(), item->GetY() );
1120
1121 // restore normal font for bold items
1122 if (fontOld.Ok())
1123 {
1124 dc.SetFont( fontOld);
1125 }
1126 }
1127
1128 void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
1129 {
1130 int horizX = level*m_indent;
1131
1132 item->SetX( horizX+33 );
1133 item->SetY( y-m_lineHeight/3 );
1134 item->SetHeight( m_lineHeight );
1135
1136 item->SetCross( horizX+15, y );
1137
1138 int oldY = y;
1139
1140 int exposed_x = dc.LogicalToDeviceX( 0 );
1141 int exposed_y = dc.LogicalToDeviceY( item->GetY()-2 );
1142
1143 if (IsExposed( exposed_x, exposed_y, 10000, m_lineHeight+4 )) // 10000 = very much
1144 {
1145 int startX = horizX;
1146 int endX = horizX + 10;
1147
1148 if (!item->HasChildren()) endX += 20;
1149
1150 dc.DrawLine( startX, y, endX, y );
1151
1152 if (item->HasPlus())
1153 {
1154 dc.DrawLine( horizX+20, y, horizX+30, y );
1155 dc.SetPen( *wxGREY_PEN );
1156 dc.SetBrush( *wxWHITE_BRUSH );
1157 dc.DrawRectangle( horizX+10, y-4, 11, 9 );
1158 dc.SetPen( *wxBLACK_PEN );
1159 dc.DrawLine( horizX+13, y, horizX+18, y );
1160
1161 if (!item->IsExpanded())
1162 {
1163 dc.DrawLine( horizX+15, y-2, horizX+15, y+3 );
1164 }
1165 }
1166
1167 if (item->HasHilight())
1168 {
1169 dc.SetTextForeground( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_HIGHLIGHTTEXT ) );
1170
1171 dc.SetBrush( *m_hilightBrush );
1172
1173 if (m_hasFocus)
1174 dc.SetPen( *wxBLACK_PEN );
1175 else
1176 dc.SetPen( *wxTRANSPARENT_PEN );
1177
1178 PaintItem(item, dc);
1179
1180 dc.SetPen( *wxBLACK_PEN );
1181 dc.SetTextForeground( *wxBLACK );
1182 dc.SetBrush( *wxWHITE_BRUSH );
1183 }
1184 else
1185 {
1186 dc.SetBrush( *wxWHITE_BRUSH );
1187 dc.SetPen( *wxTRANSPARENT_PEN );
1188
1189 PaintItem(item, dc);
1190
1191 dc.SetPen( *wxBLACK_PEN );
1192 }
1193 }
1194
1195 if (item->IsExpanded())
1196 {
1197 int semiOldY = y;
1198
1199 wxArrayTreeItems& children = item->GetChildren();
1200 size_t count = children.Count();
1201 for ( size_t n = 0; n < count; n++ )
1202 {
1203 y += m_lineHeight;
1204 semiOldY = y;
1205 PaintLevel( children[n], dc, level+1, y );
1206 }
1207
1208 // it may happen that the item is expanded but has no items (when you
1209 // delete all its children for example) - don't draw the vertical line
1210 // in this case
1211 if (count > 0)
1212 dc.DrawLine( horizX+15, oldY+5, horizX+15, semiOldY );
1213 }
1214 }
1215
1216 // -----------------------------------------------------------------------------
1217 // wxWindows callbacks
1218 // -----------------------------------------------------------------------------
1219
1220 void wxTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
1221 {
1222 if ( !m_anchor )
1223 return;
1224
1225 wxPaintDC dc(this);
1226 PrepareDC( dc );
1227
1228 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ) );
1229
1230 dc.SetPen( m_dottedPen );
1231 m_lineHeight = (int)(dc.GetCharHeight() + 4);
1232
1233 int y = m_lineHeight / 2 + 2;
1234 PaintLevel( m_anchor, dc, 0, y );
1235 }
1236
1237 void wxTreeCtrl::OnSetFocus( wxFocusEvent &WXUNUSED(event) )
1238 {
1239 m_hasFocus = TRUE;
1240
1241 if (m_current) RefreshLine( m_current );
1242 }
1243
1244 void wxTreeCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
1245 {
1246 m_hasFocus = FALSE;
1247
1248 if (m_current) RefreshLine( m_current );
1249 }
1250
1251 void wxTreeCtrl::OnChar( wxKeyEvent &event )
1252 {
1253 wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() );
1254 te.m_code = event.KeyCode();
1255 te.SetEventObject( this );
1256 GetEventHandler()->ProcessEvent( te );
1257
1258 if (m_current == 0)
1259 {
1260 event.Skip();
1261 return;
1262 }
1263
1264 switch (event.KeyCode())
1265 {
1266 case '+':
1267 case WXK_ADD:
1268 if (m_current->HasPlus() && !IsExpanded(m_current))
1269 {
1270 Expand(m_current);
1271 }
1272 break;
1273
1274 case '-':
1275 case WXK_SUBTRACT:
1276 if (IsExpanded(m_current))
1277 {
1278 Collapse(m_current);
1279 }
1280 break;
1281
1282 case '*':
1283 case WXK_MULTIPLY:
1284 Toggle(m_current);
1285 break;
1286
1287 case ' ':
1288 case WXK_RETURN:
1289 {
1290 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
1291 event.m_item = m_current;
1292 event.m_code = 0;
1293 event.SetEventObject( this );
1294 GetEventHandler()->ProcessEvent( event );
1295 }
1296 break;
1297
1298 // up goes to the previous sibling or to the last of its children if
1299 // it's expanded
1300 case WXK_UP:
1301 {
1302 wxTreeItemId prev = GetPrevSibling( m_current );
1303 if (!prev)
1304 {
1305 prev = GetParent( m_current );
1306 long cockie = 0;
1307 wxTreeItemId current = m_current;
1308 if (current == GetFirstChild( prev, cockie ))
1309 {
1310 // otherwise we return to where we came from
1311 SelectItem( prev );
1312 EnsureVisible( prev );
1313 break;
1314 }
1315 }
1316 if (prev)
1317 {
1318 while ( IsExpanded(prev) && HasChildren(prev) )
1319 {
1320 wxTreeItemId child = GetLastChild(prev);
1321 if ( child )
1322 {
1323 prev = child;
1324 }
1325 }
1326
1327 SelectItem( prev );
1328 EnsureVisible( prev );
1329 }
1330 }
1331 break;
1332
1333 // left arrow goes to the parent
1334 case WXK_LEFT:
1335 {
1336 wxTreeItemId prev = GetParent( m_current );
1337 if (prev)
1338 {
1339 EnsureVisible( prev );
1340 SelectItem( prev );
1341 }
1342 }
1343 break;
1344
1345 case WXK_RIGHT:
1346 // this works the same as the down arrow except that we also expand the
1347 // item if it wasn't expanded yet
1348 Expand(m_current);
1349 // fall through
1350
1351 case WXK_DOWN:
1352 {
1353 if (IsExpanded(m_current) && HasChildren(m_current))
1354 {
1355 long cookie = 0;
1356 wxTreeItemId child = GetFirstChild( m_current, cookie );
1357 SelectItem( child );
1358 EnsureVisible( child );
1359 }
1360 else
1361 {
1362 wxTreeItemId next = GetNextSibling( m_current );
1363 if (next == 0)
1364 {
1365 wxTreeItemId current = m_current;
1366 while (current && !next)
1367 {
1368 current = GetParent( current );
1369 if (current) next = GetNextSibling( current );
1370 }
1371 }
1372 if (next != 0)
1373 {
1374 SelectItem( next );
1375 EnsureVisible( next );
1376 }
1377 }
1378 }
1379 break;
1380
1381 // <End> selects the last visible tree item
1382 case WXK_END:
1383 {
1384 wxTreeItemId last = GetRootItem();
1385
1386 while ( last.IsOk() && IsExpanded(last) )
1387 {
1388 wxTreeItemId lastChild = GetLastChild(last);
1389
1390 // it may happen if the item was expanded but then all of
1391 // its children have been deleted - so IsExpanded() returned
1392 // TRUE, but GetLastChild() returned invalid item
1393 if ( !lastChild )
1394 break;
1395
1396 last = lastChild;
1397 }
1398
1399 if ( last.IsOk() )
1400 {
1401 EnsureVisible( last );
1402 SelectItem( last );
1403 }
1404 }
1405 break;
1406
1407 // <Home> selects the root item
1408 case WXK_HOME:
1409 {
1410 wxTreeItemId prev = GetRootItem();
1411 if (prev)
1412 {
1413 EnsureVisible( prev );
1414 SelectItem( prev );
1415 }
1416 }
1417 break;
1418
1419 default:
1420 event.Skip();
1421 }
1422 }
1423
1424 wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& WXUNUSED(flags))
1425 {
1426 bool onButton = FALSE;
1427 return m_anchor->HitTest( point, onButton );
1428 }
1429
1430 void wxTreeCtrl::OnMouse( wxMouseEvent &event )
1431 {
1432 if (!event.LeftIsDown()) m_dragCount = 0;
1433
1434 if ( !(event.LeftDown() || event.LeftDClick() || event.Dragging()) ) return;
1435
1436 if ( !m_anchor ) return;
1437
1438 wxClientDC dc(this);
1439 PrepareDC(dc);
1440 long x = dc.DeviceToLogicalX( (long)event.GetX() );
1441 long y = dc.DeviceToLogicalY( (long)event.GetY() );
1442
1443 bool onButton = FALSE;
1444 wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), onButton );
1445
1446 if (item == NULL) return; /* we hit the blank area */
1447
1448 if (event.Dragging())
1449 {
1450 if (m_dragCount == 2) /* small drag latency (3?) */
1451 {
1452 m_dragCount = 0;
1453
1454 wxTreeEvent nevent(wxEVT_COMMAND_TREE_BEGIN_DRAG, GetId());
1455 nevent.m_item = m_current;
1456 nevent.SetEventObject(this);
1457 GetEventHandler()->ProcessEvent(nevent);
1458 }
1459 else
1460 {
1461 m_dragCount++;
1462 }
1463 return;
1464 }
1465
1466 if (!IsSelected(item))
1467 SelectItem(item); /* we dont support multiple selections, BTW */
1468
1469 if (event.LeftDClick())
1470 {
1471 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
1472 event.m_item = item;
1473 event.m_code = 0;
1474 event.SetEventObject( this );
1475 GetEventHandler()->ProcessEvent( event );
1476 }
1477
1478 if (onButton)
1479 {
1480 Toggle( item );
1481 }
1482 }
1483
1484 void wxTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) )
1485 {
1486 /* after all changes have been done to the tree control,
1487 * we actually redraw the tree when everything is over */
1488
1489 if (!m_dirty)
1490 return;
1491
1492 m_dirty = FALSE;
1493
1494 CalculatePositions();
1495
1496 AdjustMyScrollbars();
1497 }
1498
1499 // -----------------------------------------------------------------------------
1500
1501 void wxTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
1502 {
1503 int horizX = level*m_indent;
1504
1505 item->SetX( horizX+33 );
1506 item->SetY( y-m_lineHeight/3-2 );
1507 item->SetHeight( m_lineHeight );
1508
1509 if ( !item->IsExpanded() )
1510 {
1511 // we dont need to calculate collapsed branches
1512 return;
1513 }
1514
1515 wxArrayTreeItems& children = item->GetChildren();
1516 size_t count = children.Count();
1517 for ( size_t n = 0; n < count; n++ )
1518 {
1519 y += m_lineHeight;
1520 CalculateLevel( children[n], dc, level+1, y ); // recurse
1521 }
1522 }
1523
1524 void wxTreeCtrl::CalculatePositions()
1525 {
1526 if ( !m_anchor ) return;
1527
1528 wxClientDC dc(this);
1529 PrepareDC( dc );
1530
1531 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ) );
1532
1533 dc.SetPen( m_dottedPen );
1534 m_lineHeight = (int)(dc.GetCharHeight() + 4);
1535
1536 int y = m_lineHeight / 2 + 2;
1537 CalculateLevel( m_anchor, dc, 0, y ); // start recursion
1538 }
1539
1540 void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
1541 {
1542 wxClientDC dc(this);
1543 PrepareDC(dc);
1544
1545 int cw = 0;
1546 int ch = 0;
1547 GetClientSize( &cw, &ch );
1548
1549 wxRect rect;
1550 rect.x = dc.LogicalToDeviceX( 0 );
1551 rect.width = cw;
1552 rect.y = dc.LogicalToDeviceY( item->GetY() );
1553 rect.height = ch;
1554
1555 Refresh( TRUE, &rect );
1556
1557 AdjustMyScrollbars();
1558 }
1559
1560 void wxTreeCtrl::RefreshLine( wxGenericTreeItem *item )
1561 {
1562 wxClientDC dc(this);
1563 PrepareDC( dc );
1564
1565 wxRect rect;
1566 rect.x = dc.LogicalToDeviceX( item->GetX() - 2 );
1567 rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
1568 rect.width = 1000;
1569 rect.height = dc.GetCharHeight() + 6;
1570
1571 Refresh( TRUE, &rect );
1572 }
1573