]> git.saurik.com Git - wxWidgets.git/blob - src/generic/treectrl.cpp
final (?) changes to the generic tree ctrl -- seems to work ok
[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 #include "wx/treectrl.h"
25 #include "wx/settings.h"
26 #include "wx/log.h"
27 #include "wx/intl.h"
28 #include "wx/dynarray.h"
29 #include "wx/dcclient.h"
30
31 // -----------------------------------------------------------------------------
32 // array types
33 // -----------------------------------------------------------------------------
34
35 WX_DEFINE_ARRAY(wxGenericTreeItem *, wxArrayTreeItems);
36
37 // -----------------------------------------------------------------------------
38 // private classes
39 // -----------------------------------------------------------------------------
40
41 // a tree item
42 class WXDLLEXPORT wxGenericTreeItem
43 {
44 public:
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; }
79
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
108 private:
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 // -----------------------------------------------------------------------------
135 // wxTreeEvent
136 // -----------------------------------------------------------------------------
137
138 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxCommandEvent)
139
140 wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
141 : wxCommandEvent( commandType, id )
142 {
143 m_code = 0;
144 m_itemOld = (wxGenericTreeItem *)NULL;
145 }
146
147 // -----------------------------------------------------------------------------
148 // wxGenericTreeItem
149 // -----------------------------------------------------------------------------
150
151 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent,
152 const wxString& text,
153 wxDC& dc,
154 int image, int selImage,
155 wxTreeItemData *data)
156 : m_text(text)
157 {
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;
167 m_hasHilight = FALSE;
168
169 m_parent = parent;
170
171 dc.GetTextExtent( m_text, &m_width, &m_height );
172 }
173
174 wxGenericTreeItem::~wxGenericTreeItem()
175 {
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];
181 }
182
183 void wxGenericTreeItem::SetText( const wxString &text, wxDC& dc )
184 {
185 m_text = text;
186
187 dc.GetTextExtent( m_text, &m_width, &m_height );
188 }
189
190 void wxGenericTreeItem::Reset()
191 {
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 =
199 m_yCross = 0;
200
201 m_level = 0;
202
203 m_children.Empty();
204 m_isCollapsed = TRUE;
205
206 m_parent = (wxGenericTreeItem *)NULL;
207 }
208
209 size_t wxGenericTreeItem::GetTotalNumberOfChildren() const
210 {
211 size_t count = m_children.Count();
212 size_t total = count;
213 for ( size_t n = 0; n < count; n++ )
214 {
215 total += m_children[n]->GetTotalNumberOfChildren();
216 }
217
218 return total;
219 }
220
221 void wxGenericTreeItem::SetCross( int x, int y )
222 {
223 m_xCross = x;
224 m_yCross = y;
225 }
226
227 void wxGenericTreeItem::GetSize( int &x, int &y )
228 {
229 // FIXME what does this all mean??
230 if ( y < m_y + 10 ) y = m_y +10;
231 int width = m_x + m_width;
232 if (width > x) x = width;
233
234 size_t count = m_children.Count();
235 for ( size_t n = 0; n < count; n++ )
236 {
237 m_children[n]->GetSize( x, y );
238 }
239 }
240
241 wxGenericTreeItem *wxGenericTreeItem::HitTest( const wxPoint& point,
242 bool &onButton )
243 {
244 if ((point.y > m_y) && (point.y < m_y + m_height))
245 {
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) &&
249 HasChildren())
250 {
251 onButton = TRUE;
252 return this;
253 }
254
255 if ((point.x > m_x) && (point.x < m_x+m_width))
256 {
257 onButton = FALSE;
258 return this;
259 }
260 }
261 else
262 {
263 if (!m_isCollapsed)
264 {
265 size_t count = m_children.Count();
266 for ( size_t n = 0; n < count; n++ )
267 {
268 wxGenericTreeItem *res = m_children[n]->HitTest( point, onButton );
269 if ( res != NULL )
270 return res;
271 }
272 }
273 }
274
275 return NULL;
276 }
277
278 // -----------------------------------------------------------------------------
279 // wxTreeCtrl implementation
280 // -----------------------------------------------------------------------------
281
282 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxScrolledWindow)
283
284 BEGIN_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)
290 END_EVENT_TABLE()
291
292 // -----------------------------------------------------------------------------
293 // construction/destruction
294 // -----------------------------------------------------------------------------
295 void wxTreeCtrl::Init()
296 {
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;
314 }
315
316 bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id,
317 const wxPoint& pos, const wxSize& size,
318 long style, const wxString& name )
319 {
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;
328 }
329
330 wxTreeCtrl::~wxTreeCtrl()
331 {
332 wxDELETE( m_hilightBrush );
333 wxDELETE( m_anchor );
334 }
335
336 // -----------------------------------------------------------------------------
337 // accessors
338 // -----------------------------------------------------------------------------
339
340 size_t wxTreeCtrl::GetCount() const
341 {
342 return m_anchor == NULL ? 0u : m_anchor->GetTotalNumberOfChildren();
343 }
344
345 void wxTreeCtrl::SetIndent(unsigned int indent)
346 {
347 m_indent = indent;
348 Refresh();
349 }
350
351 // -----------------------------------------------------------------------------
352 // functions to work with tree items
353 // -----------------------------------------------------------------------------
354
355 wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
356 {
357 return item.m_pItem->GetText();
358 }
359
360 int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
361 {
362 return item.m_pItem->GetImage();
363 }
364
365 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
366 {
367 return item.m_pItem->GetSelectedImage();
368 }
369
370 wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
371 {
372 return item.m_pItem->GetData();
373 }
374
375 void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
376 {
377 wxClientDC dc(this);
378 return item.m_pItem->SetText(text, dc);
379 }
380
381 void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
382 {
383 return item.m_pItem->SetImage(image);
384 }
385
386 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
387 {
388 return item.m_pItem->SetSelectedImage(image);
389 }
390
391 void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
392 {
393 return item.m_pItem->SetData(data);
394 }
395
396 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
397 {
398 item.m_pItem->SetHasPlus(has);
399 }
400
401 // -----------------------------------------------------------------------------
402 // item status inquiries
403 // -----------------------------------------------------------------------------
404
405 bool wxTreeCtrl::IsVisible(const wxTreeItemId& item) const
406 {
407 wxFAIL_MSG("not implemented");
408
409 return TRUE;
410 }
411
412 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
413 {
414 return !item.m_pItem->GetChildren().IsEmpty();
415 }
416
417 bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
418 {
419 return item.m_pItem->IsExpanded();
420 }
421
422 bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
423 {
424 return item.m_pItem->HasHilight();
425 }
426
427 // -----------------------------------------------------------------------------
428 // navigation
429 // -----------------------------------------------------------------------------
430
431 wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
432 {
433 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
434
435 return item.m_pItem->GetParent();
436 }
437
438 wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item, long& cookie) const
439 {
440 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
441
442 cookie = 0;
443 return GetNextChild(item, cookie);
444 }
445
446 wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& item, long& cookie) const
447 {
448 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
449
450 return item.m_pItem->GetChildren().Item(cookie++);
451 }
452
453 wxTreeItemId 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;
463 }
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?
468
469 size_t n = (size_t)(index + 1);
470 return n == siblings.Count() ? NULL : siblings[n];
471 }
472
473 wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
474 {
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 )
480 {
481 // root item doesn't have any siblings
482 return NULL;
483 }
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?
488
489 return index == 0 ? NULL : siblings[(size_t)(index - 1)];
490 }
491
492 wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
493 {
494 wxFAIL_MSG("not implemented");
495
496 return NULL;
497 }
498
499 wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
500 {
501 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
502
503 wxFAIL_MSG("not implemented");
504
505 return NULL;
506 }
507
508 wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
509 {
510 wxCHECK_MSG( item.IsOk(), NULL, "invalid tree item" );
511
512 wxFAIL_MSG("not implemented");
513
514 return NULL;
515 }
516
517 // -----------------------------------------------------------------------------
518 // operations
519 // -----------------------------------------------------------------------------
520
521 wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
522 size_t previous,
523 const wxString& text,
524 int image, int selImage,
525 wxTreeItemData *data)
526 {
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);
539
540 if ( data != NULL )
541 {
542 data->m_pItem = item;
543 }
544
545 parent->Insert( item, previous );
546
547 CalculatePositions();
548
549 int cw, ch;
550 GetClientSize( &cw, &ch );
551
552 PrepareDC( dc );
553
554 wxRectangle rect;
555 rect.x = dc.LogicalToDeviceX( 0 );
556 rect.y = 0;
557 rect.width = 10000; // @@@ not very elegant...
558 rect.height = ch;
559
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 }
568
569 AdjustMyScrollbars();
570
571 if ( rect.height > 0 )
572 Refresh( FALSE, &rect );
573
574 return item;
575 }
576
577 wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
578 int image, int selImage,
579 wxTreeItemData *data)
580 {
581 wxCHECK_MSG( !m_anchor, NULL, "tree can have only one root" );
582
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 }
590
591 AdjustMyScrollbars();
592 Refresh();
593
594 return m_anchor;
595 }
596
597 wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
598 const wxString& text,
599 int image, int selImage,
600 wxTreeItemData *data)
601 {
602 return DoInsertItem(parent, 0u, text, image, selImage, data);
603 }
604
605 wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parentId,
606 const wxTreeItemId& idPrevious,
607 const wxString& text,
608 int image, int selImage,
609 wxTreeItemData *data)
610 {
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 }
617
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);
622 }
623
624 wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parentId,
625 const wxString& text,
626 int image, int selImage,
627 wxTreeItemData *data)
628 {
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);
638 }
639
640 void wxTreeCtrl::Delete(const wxTreeItemId& itemId)
641 {
642 wxGenericTreeItem *item = itemId.m_pItem;
643
644 delete item;
645
646 Refresh();
647 }
648
649 void wxTreeCtrl::DeleteAllItems()
650 {
651 if ( m_anchor )
652 {
653 delete m_anchor;
654 m_anchor = NULL;
655
656 Refresh();
657 }
658 }
659
660 void wxTreeCtrl::Expand(const wxTreeItemId& itemId)
661 {
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 );
682 }
683
684 void wxTreeCtrl::Collapse(const wxTreeItemId& itemId)
685 {
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 )
695 {
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]);
707 }
708
709 CalculatePositions();
710
711 RefreshSubtree(item);
712
713 event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
714 ProcessEvent( event );
715 }
716
717 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
718 {
719 Collapse(item);
720 Delete(item);
721 }
722
723 void wxTreeCtrl::Toggle(const wxTreeItemId& itemId)
724 {
725 wxGenericTreeItem *item = itemId.m_pItem;
726
727 if ( item->IsExpanded() )
728 Collapse(itemId);
729 else
730 Expand(itemId);
731 }
732
733 void wxTreeCtrl::Unselect()
734 {
735 if ( m_current )
736 {
737 m_current->SetHilight( FALSE );
738 RefreshLine( m_current );
739 }
740 }
741
742 void wxTreeCtrl::SelectItem(const wxTreeItemId& itemId)
743 {
744 wxGenericTreeItem *item = itemId.m_pItem;
745
746 if ( m_current != item )
747 {
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 )
756 {
757 m_current->SetHilight( FALSE );
758 RefreshLine( m_current );
759 }
760
761 m_current = item;
762 m_current->SetHilight( TRUE );
763 RefreshLine( m_current );
764
765 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
766 ProcessEvent( event );
767 }
768 }
769
770 void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
771 {
772 wxFAIL_MSG("not implemented");
773 }
774
775 void wxTreeCtrl::ScrollTo(const wxTreeItemId& item)
776 {
777 wxFAIL_MSG("not implemented");
778 }
779
780 wxTextCtrl *wxTreeCtrl::EditLabel(const wxTreeItemId& item,
781 wxClassInfo* textCtrlClass)
782 {
783 wxFAIL_MSG("not implemented");
784
785 return NULL;
786 }
787
788 wxTextCtrl *wxTreeCtrl::GetEditControl() const
789 {
790 wxFAIL_MSG("not implemented");
791
792 return NULL;
793 }
794
795 void wxTreeCtrl::EndEditLabel(const wxTreeItemId& item, bool discardChanges)
796 {
797 wxFAIL_MSG("not implemented");
798 }
799
800 void wxTreeCtrl::SortChildren(const wxTreeItemId& item,
801 wxTreeItemCmpFunc *cmpFunction)
802 {
803 wxFAIL_MSG("not implemented");
804 }
805
806 // -----------------------------------------------------------------------------
807 // images are not currently supported, but we still provide stubs for these
808 // functions
809 // -----------------------------------------------------------------------------
810 wxImageList *wxTreeCtrl::GetImageList() const
811 {
812 return m_imageListNormal;
813 }
814
815 wxImageList *wxTreeCtrl::GetStateImageList() const
816 {
817 return m_imageListState;
818 }
819
820 void wxTreeCtrl::SetImageList(wxImageList *imageList)
821 {
822 m_imageListNormal = imageList;
823 }
824
825 void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
826 {
827 m_imageListState = imageList;
828 }
829
830 // -----------------------------------------------------------------------------
831 // helpers
832 // -----------------------------------------------------------------------------
833 void wxTreeCtrl::AdjustMyScrollbars()
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 );
848 }
849 }
850
851 void wxTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level, int &y )
852 {
853 int horizX = level*m_indent;
854
855 item->SetX( horizX+33 );
856 item->SetY( y-m_lineHeight/3 );
857 item->SetHeight( m_lineHeight );
858
859 item->SetCross( horizX+15, y );
860
861 int oldY = y;
862
863 int exposed_x = dc.LogicalToDeviceX( 0 );
864 int exposed_y = dc.LogicalToDeviceY( item->GetY()-2 );
865
866 if (IsExposed( exposed_x, exposed_y, 1000, m_lineHeight+4 ))
867 {
868 int startX = horizX;
869 int endX = horizX + 10;
870
871 if (!item->HasChildren()) endX += 20;
872
873 dc.DrawLine( startX, y, endX, y );
874
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 }
886
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)
894 {
895 dc.SetPen( *wxBLACK_PEN );
896 dc.DrawRectangle( item->GetX()-2, item->GetY()-2, tw+4, th+4 );
897 }
898 else
899 {
900 dc.SetPen( *wxTRANSPARENT_PEN );
901 dc.DrawRectangle( item->GetX()-2, item->GetY()-2, tw+4, th+4 );
902 }
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 }
919 }
920
921 if ( !item->IsExpanded() )
922 return;
923
924 int semiOldY = y;
925
926 wxArrayTreeItems& children = item->GetChildren();
927 size_t count = children.Count();
928 for ( size_t n = 0; n < count; n++ )
929 {
930 y += m_lineHeight;
931 semiOldY = y;
932
933 PaintLevel( children[n], dc, level+1, y );
934 }
935
936 dc.DrawLine( horizX+15, oldY+5, horizX+15, semiOldY );
937 }
938
939 // -----------------------------------------------------------------------------
940 // wxWindows callbacks
941 // -----------------------------------------------------------------------------
942
943 void wxTreeCtrl::OnPaint( const wxPaintEvent &WXUNUSED(event) )
944 {
945 if ( !m_anchor )
946 return;
947
948 wxPaintDC dc(this);
949 PrepareDC( dc );
950
951 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_SYSTEM_FONT ) );
952
953 dc.SetPen( m_dottedPen );
954 m_lineHeight = (int)(dc.GetCharHeight() + 4);
955
956 int y = m_lineHeight / 2 + 2;
957 PaintLevel( m_anchor, dc, 0, y );
958 }
959
960 void wxTreeCtrl::OnSetFocus( const wxFocusEvent &WXUNUSED(event) )
961 {
962 m_hasFocus = TRUE;
963 if ( m_current )
964 RefreshLine( m_current );
965 }
966
967 void wxTreeCtrl::OnKillFocus( const wxFocusEvent &WXUNUSED(event) )
968 {
969 m_hasFocus = FALSE;
970 if ( m_current )
971 RefreshLine( m_current );
972 }
973
974 void wxTreeCtrl::OnChar( wxKeyEvent &event )
975 {
976 // TODO process '+', '-' (expand/collapse branch) and cursor keys
977 event.Skip();
978 }
979
980 void wxTreeCtrl::OnMouse( const wxMouseEvent &event )
981 {
982 if ( !(event.LeftDown() || event.LeftDClick()) )
983 return;
984
985 if ( !m_anchor )
986 return;
987
988 wxClientDC dc(this);
989 PrepareDC(dc);
990 long x = dc.DeviceToLogicalX( (long)event.GetX() );
991 long y = dc.DeviceToLogicalY( (long)event.GetY() );
992
993 bool onButton = FALSE;
994 wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y), onButton );
995 if ( item == NULL )
996 return;
997
998 SelectItem(item);
999
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 }
1008
1009 if ( onButton )
1010 {
1011 Toggle( item );
1012 }
1013 }
1014
1015 // -----------------------------------------------------------------------------
1016 // -----------------------------------------------------------------------------
1017 void wxTreeCtrl::CalculateLevel( wxGenericTreeItem *item,
1018 wxDC &dc,
1019 int level,
1020 int &y )
1021 {
1022 int horizX = level*m_indent;
1023
1024 item->SetX( horizX+33 );
1025 item->SetY( y-m_lineHeight/3-2 );
1026 item->SetHeight( m_lineHeight );
1027
1028 if ( item->IsExpanded() )
1029 return;
1030
1031 wxArrayTreeItems& children = item->GetChildren();
1032 size_t count = children.Count();
1033 for ( size_t n = 0; n < count; n++ )
1034 {
1035 y += m_lineHeight;
1036 CalculateLevel( children[n], dc, level+1, y );
1037 }
1038 }
1039
1040 void wxTreeCtrl::CalculatePositions()
1041 {
1042 if ( !m_anchor )
1043 return;
1044
1045 wxClientDC dc(this);
1046 PrepareDC( dc );
1047
1048 dc.SetFont( wxSystemSettings::GetSystemFont( wxSYS_SYSTEM_FONT ) );
1049
1050 dc.SetPen( m_dottedPen );
1051 m_lineHeight = (int)(dc.GetCharHeight() + 4);
1052
1053 int y = m_lineHeight / 2 + 2;
1054 CalculateLevel( m_anchor, dc, 0, y );
1055 }
1056
1057 void wxTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
1058 {
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();
1075 }
1076
1077 void wxTreeCtrl::RefreshLine( wxGenericTreeItem *item )
1078 {
1079 wxClientDC dc(this);
1080 PrepareDC( dc );
1081
1082 wxRect rect;
1083 rect.x = dc.LogicalToDeviceX( item->GetX() - 2 );
1084 rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
1085 rect.width = 1000;
1086 rect.height = dc.GetCharHeight() + 6;
1087
1088 Refresh( TRUE, &rect );
1089 }
1090