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