]> Creatis software - bbtk.git/blob - kernel/src/ThirdParty/wx/treemultictrl/wxTreeMultiCtrl.cpp
Works with visual studio 2009
[bbtk.git] / kernel / src / ThirdParty / wx / treemultictrl / wxTreeMultiCtrl.cpp
1 //---------------------------------------------------------------------------
2 // $RCSfile: wxTreeMultiCtrl.cpp,v $
3 // $Source: /cvs/creatis/bbtk/kernel/src/ThirdParty/wx/treemultictrl/wxTreeMultiCtrl.cpp,v $
4 // $Revision: 1.2 $
5 // $Date: 2009/10/05 22:44:50 $
6 //---------------------------------------------------------------------------
7 // Author:      Jorgen Bodde
8 // Copyright:   (c) Jorgen Bodde
9 // License:     wxWidgets License
10 //---------------------------------------------------------------------------
11
12 #ifdef __GNUG__
13     #pragma implementation "wxTreeMultiCtrl.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
18 #include "wx/treebase.h"
19
20 #ifdef __BORLANDC__
21     #pragma hdrstop
22 #endif
23
24 #include "wx/arrimpl.cpp"
25
26 #include "wx/treemultictrl/wxTreeMultiCtrl.h"
27 #include "wx/treemultictrl/wxTreeMultiEvent.h"
28 #include "tmcimages.h"
29
30
31
32 //----------------------------------------------------------------------------
33 // wxTreeMultiItem
34 //----------------------------------------------------------------------------
35
36 WX_DEFINE_OBJARRAY(wxArrayTreeMultiItem);
37
38 //----------------------------------------------------------------------------
39 // wxTreeMultiCtrl
40 //----------------------------------------------------------------------------
41
42 IMPLEMENT_DYNAMIC_CLASS(wxTreeMultiCtrl, wxScrolledWindow)
43
44 // WDR: event table for wxTreeMultiCtrl
45 BEGIN_EVENT_TABLE(wxTreeMultiCtrl, wxScrolledWindow)
46   EVT_LEFT_DOWN  (wxTreeMultiCtrl::OnMouseClick)
47   EVT_LEFT_DCLICK(wxTreeMultiCtrl::OnMouseClick)
48   EVT_RIGHT_DOWN (wxTreeMultiCtrl::OnRightMouseClick)
49   EVT_PAINT(wxTreeMultiCtrl::OnPaint)
50   EVT_SIZE(wxTreeMultiCtrl::OnSize)
51 //  EVT_KEY_UP(wxTreeMultiCtrl::OnKey)
52 END_EVENT_TABLE()
53
54 bool wxTreeMultiCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos,
55                                const wxSize& size, long style, const wxValidator & WXUNUSED(validator),
56                                const wxString& name )
57 {
58     wxScrolledWindow::Create( parent, id, pos, size, style | wxTAB_TRAVERSAL, name);
59
60         _create_called = true;
61
62         // do the init
63         Init();
64
65     return TRUE;
66 }
67
68 void wxTreeMultiCtrl::Init()
69 {
70         _root.Clear();
71
72         _expandBmp = 0;
73         _collBmp = 0;
74
75 #if(CHECKBOXVIEW)
76         _checkBmp = 0;
77         _uncheckBmp = 0;
78         _tristateBmp = 0;
79
80         _checkHeight = 11;
81         _checkWidth = 11;
82
83         _checkboxView = false;
84 #endif
85
86         _gutterWidth = WXTMC_GUTTER_DEFAULT;
87         _iconWidth = 11;
88         _iconHeight = 11;
89         _maxHeight = 1;;
90         _iconDeltaY = 2;
91         _spacingY = WXTMC_YSPACING_DEFAULT;
92         _captionHeight = 13;
93
94         // create two bitmap nodes for drawing
95
96         _expandBmp = new wxBitmap(expand_xpm);
97         _collBmp = new wxBitmap(collapse_xpm);
98
99         // calculate average font height for bitmap centering
100
101         _iconWidth = _expandBmp->GetWidth();
102         _iconHeight = _expandBmp->GetHeight();
103
104 #if(CHECKBOXVIEW)
105         // create bitmaps for checkboxes
106         _checkBmp = new wxBitmap(checked_icon);
107         _uncheckBmp = new wxBitmap(unchecked_icon);
108         _tristateBmp = new wxBitmap(tristate_icon);
109
110         // adjust the height if the checkboxes are higher
111         // so that everything is alligned properly
112         _checkHeight = _checkBmp->GetHeight();
113         _checkWidth = _checkBmp->GetWidth();
114 #endif
115
116         // remember the highest of the two bitmaps so there is
117         // always enough room
118         _maxHeight = _iconHeight;
119
120 #if(CHECKBOXVIEW)
121         if(_maxHeight < _checkHeight)
122                 _maxHeight = _checkHeight;
123 #endif
124
125  // set standard highlighting brush
126   this->m_HilightBrush = new wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT),wxSOLID);
127
128         // set standard DC font
129     _captionFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
130
131         // adjust bitmap icon y position so they are centered
132         AdjustIconsDeltaY();
133
134         // set virtual size to this window size
135         if (_create_called) {
136                 wxSize wndsize = GetSize();
137                 SetVirtualSize(wndsize.GetWidth(), wndsize.GetWidth());
138         }
139 }
140
141 void wxTreeMultiCtrl::SetCaptionFont(const wxFont &font)
142 {
143         _captionFont = font;
144
145         // adjust the icons so that they are in the middle
146         AdjustIconsDeltaY();
147
148         RedrawFromNode(0);
149 };
150
151 void wxTreeMultiCtrl::AdjustIconsDeltaY()
152 {
153         int x = 0, y = 0;
154
155         if(_captionFont.Ok())
156       GetTextExtent(wxT("jG"), &x, &y, 0, 0, &_captionFont);
157         _captionHeight = y;
158
159         if(_maxHeight < _captionHeight)
160                 _maxHeight = _captionHeight;
161
162         // determine the center pos for the [+]
163         _iconDeltaY = abs(_maxHeight - _iconHeight) / 2 + 1;
164         if(_iconDeltaY < 1)
165                 _iconDeltaY = 1;
166
167 #if(CHECKBOXVIEW)
168         // determine the center pos for the checkbox
169         _checkDeltaY = abs(_maxHeight - _checkHeight) / 2 + 1;
170         if(_checkDeltaY < 1)
171                 _checkDeltaY = 1;
172 #endif
173 }
174
175 wxTreeMultiCtrl::~wxTreeMultiCtrl()
176 {
177         // delete the bitmap resources
178         delete _expandBmp;
179         delete _collBmp;
180
181 #if(CHECKBOXVIEW)
182         delete _checkBmp;
183         delete _uncheckBmp;
184         delete _tristateBmp;
185 #endif
186 }
187
188 wxTreeMultiItem wxTreeMultiCtrl::AddRoot(const wxString &caption, const wxString &name)
189 {
190         wxTreeMultiItem result((TreeMultiItemBase *)&_root);
191         result = AppendNode(result, caption, name);
192
193         return result;
194 }
195
196 wxTreeMultiItem wxTreeMultiCtrl::AppendWindow(const wxTreeMultiItem &ParentItem, wxWindow *window, const wxString &name, const wxTreeMultiWindowInfo &info, int flags)
197 {
198  // add window only if the parent item is valid and...
199         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
200
201         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
202
203  // ... is a node
204   wxCHECK(parent != NULL, wxTreeMultiItem(0));
205
206  // now, append node to the tree control:
207   wxTreeMultiItem NewWindowItem(this->InsertWindow(parent,wx_static_cast(size_t,parent->GetNodeCount()),window,name,info,flags));
208  // redraw the stucture:
209         this->RedrawFromNode(parent);
210  // return the new window
211         return NewWindowItem;
212 }
213
214 wxTreeMultiItem wxTreeMultiCtrl::InsertWindow(wxTreeMultiItem const& ParentItem, size_t Position, wxWindow *window, wxString const& name, wxTreeMultiWindowInfo const& info, int flags)
215 {
216  // add window only if the parent item is valid and...
217         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
218
219         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
220
221  // ... is a node
222   wxCHECK(parent != NULL, wxTreeMultiItem(0));
223
224  // now, append node to the tree control:
225   wxTreeMultiItem NewWindowItem(this->InsertWindow(parent,Position,window,name,info,flags));
226  // redraw the stucture:
227         this->RedrawFromNode(parent);
228  // return the new window
229         return NewWindowItem;
230 } /* wxTreeMultiCtrl::InsertWindow(wxTreeMultiItem const&, size_t, wxWindow*, wxString const&, wxTreeMultiWindowInfo const&, int) */
231
232 wxTreeMultiItem wxTreeMultiCtrl::PrependWindow(wxTreeMultiItem const& ParentItem, wxWindow *window, const wxString &name, wxTreeMultiWindowInfo const& info, int flags)
233 {
234  // add window only if the parent item is valid and...
235         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
236
237         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
238
239  // ... is a node
240   wxCHECK(parent != NULL, wxTreeMultiItem(0));
241
242  // now, append node to the tree control:
243   wxTreeMultiItem NewWindowItem(this->InsertWindow(parent,0,window,name,info,flags));
244  // redraw the stucture:
245         this->RedrawFromNode(parent);
246  // return the new window
247         return NewWindowItem;
248 } /* wxTreeMultiCtrl::PrependWindow(wxTreeMultiItem const&, wxWindow*, const wxString &, wxTreeMultiWindowInfo const&, int) */
249
250 wxTreeMultiItem wxTreeMultiCtrl::AppendNode(wxTreeMultiItem const& ParentItem, const wxString &caption, const wxString &name)
251 {
252  // add window only if the parent item is valid and...
253         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
254
255         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
256
257  // ... is a node
258   wxCHECK(parent != NULL, wxTreeMultiItem(0));
259
260  // now, append node to the tree control:
261   wxTreeMultiItem NewNodeItem(this->InsertNode(parent,wx_static_cast(size_t,parent->GetNodeCount()),caption,name));
262  // redraw the structure:
263         this->RedrawFromNode(parent);
264  // return the new node:
265         return NewNodeItem;
266 } /* wxTreeMultiCtrl::AppendNode(wxTreeMultiItem const&, const wxString &, const wxString&) */
267
268 wxTreeMultiItem wxTreeMultiCtrl::InsertNode(wxTreeMultiItem const& ParentItem, size_t Position, wxString const& caption, wxString const& name)
269 {
270  // add window only if the parent item is valid and...
271         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
272
273         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
274
275  // ... is a node
276   wxCHECK(parent != NULL, wxTreeMultiItem(0));
277
278  // now, append node to the tree control:
279   wxTreeMultiItem NewNodeItem(this->InsertNode(parent,Position,caption,name));
280  // redraw the structure:
281         this->RedrawFromNode(parent);
282  // return the new node:
283         return NewNodeItem;
284 } /* wxTreeMultiCtrl::InsertNode(wxTreeMultiItem const&, size_t, wxString const&, wxString const&) */
285
286 wxTreeMultiItem wxTreeMultiCtrl::PrependNode(wxTreeMultiItem const& ParentItem, wxString const& caption, wxString const& name)
287 {
288  // add window only if the parent item is valid and...
289         wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
290
291         TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
292
293  // ... is a node
294   wxCHECK(parent != NULL, wxTreeMultiItem(0));
295
296  // now, append node to the tree control:
297   wxTreeMultiItem NewNodeItem(this->InsertNode(parent,0,caption,name));
298  // redraw the structure:
299         this->RedrawFromNode(parent);
300  // return the new node:
301         return NewNodeItem;
302 } /* wxTreeMultiCtrl::PrependNode(wxTreeMultiItem const&, wxString const&, wxString const&) */
303
304 bool wxTreeMultiCtrl::Delete(wxTreeMultiItem &item)
305 {
306         bool redraw = true;
307         wxCHECK(item.IsOk(), false);
308
309         wxTreeMultiItem nullItem(0);
310
311
312  // if item has been selected, remove it from the selected list:
313   size_t ItemIndex(this->GetSelectedItemIndex(item));
314
315   if (ItemIndex != this->GetSelectedItemCount())
316     this->m_SelectedItems.RemoveAt(ItemIndex);
317
318         // get parent, to delete item from
319         TreeMultiItemNode *p = item.GetItem()->GetParent();
320
321         // first check if it was visible, if so from the parent off
322         // it needs redrawing
323         redraw = item.GetItem()->IsVisible();
324         if(p)
325                 p->DeleteNode(item.GetItem());
326         else
327                 _root.DeleteNode(item.GetItem());
328
329         item = nullItem;
330
331         // do redraw when node was visible
332         if(redraw)
333                 RedrawFromNode(p);
334
335         return true;
336 }
337
338 void wxTreeMultiCtrl::DeleteChildren(const wxTreeMultiItem &item)
339 {
340         if(item.IsNodeItem())
341         {
342                 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
343
344    // remove all children from the selected item list:
345           if (n->GetNodeCount() > 0)
346           {
347            // variable definitions and initializations:
348             int Cookie;
349             wxTreeMultiItem FirstItemIterator(this->GetFirstChild(item,Cookie)), LastItemIterator(this->GetLastChild(item));
350
351             for (;;)
352             {
353               size_t ItemIndex(this->GetSelectedItemIndex(item)); // variable definition and initialization
354
355               if (ItemIndex != this->GetSelectedItemCount())
356                 this->m_SelectedItems.RemoveAt(ItemIndex);
357               if (FirstItemIterator == LastItemIterator)
358                 break; // all children checked
359               else
360                 FirstItemIterator = this->GetNext(FirstItemIterator);
361             } /* for */
362           } /* if */
363          // delete children:
364                 n->Clear();
365         // redraw:
366                 RedrawFromNode(n);
367         }
368 }
369
370 void wxTreeMultiCtrl::Expand(const wxTreeMultiItem &item, bool recursive)
371 {
372         if(item.IsOk())
373         {
374         TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();
375                 if(!n)
376                         n = item.GetItem()->GetParent();
377         DoFold(n, true, recursive);
378                 RedrawFromNode(item.GetItem()->IsTreeMultiItemNode());
379         }
380 }
381
382 void wxTreeMultiCtrl::Collapse(const wxTreeMultiItem &item, bool recursive)
383 {
384         if(item.IsOk())
385         {
386         TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();
387                 if(!n)
388                         n = item.GetItem()->GetParent();
389                 DoFold(n, false, recursive);
390                 RedrawFromNode(item.GetItem()->IsTreeMultiItemNode());
391         }
392 }
393
394
395 void wxTreeMultiCtrl::ExpandNodes(bool recursive)
396 {
397         // go through all children and call DoFold recursively
398         for(int i = 0; i < _root.GetNodeCount(); i++)
399                 DoFold(_root.GetNode(i), true, recursive);
400         RedrawFromNode(0);
401 }
402
403 void wxTreeMultiCtrl::CollapseNodes(bool recursive)
404 {
405         // go through all children and call DoFold recursively
406         for(int i = 0; i < _root.GetNodeCount(); i++)
407                 DoFold(_root.GetNode(i), false, recursive);
408         RedrawFromNode(0);
409 }
410
411 void wxTreeMultiCtrl::CollapseAndReset(const wxTreeMultiItem &item)
412 {
413         if(item.IsNodeItem())
414         {
415                  TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
416
417                  // delete all kids
418                  n->Clear();
419                  Collapse(item, false);
420         }
421 }
422
423 // Selection manipulation
424 wxTreeMultiItem wxTreeMultiCtrl::GetFirstSelectedItem(void) const
425 {
426   if (this->GetSelectedItemCount() > 0)
427     return this->m_SelectedItems[0];
428   else
429     return wxTreeMultiItem();
430 } /* wxTreeMultiCtrl::GetFirstSelectedItem(void) const */
431
432 wxTreeMultiItem wxTreeMultiCtrl::GetLastSelectedItem(void) const
433 {
434   if (this->GetSelectedItemCount() > 0)
435     return this->m_SelectedItems[this->GetSelectedItemCount()-1];
436   else
437     return wxTreeMultiItem();
438 } /* wxTreeMultiCtrl::GetLastSelectedItem(void) const */
439
440 wxTreeMultiItem wxTreeMultiCtrl::GetSelectedItem(size_t Index) const
441 {
442   if (Index < this->GetSelectedItemCount())
443     return this->m_SelectedItems[Index];
444   else
445     return wxTreeMultiItem();
446 } /* wxTreeMultiCtrl::GetSelectedItem(size_t Index) const */
447
448 size_t wxTreeMultiCtrl::GetSelectedItemIndex(wxTreeMultiItem const& Item) const
449 {
450  // attention: the function wxArray::Index() can NOT be used in a save manner as it only checks the address of an item
451  //            element but it is not guaranteed that Item may not be a copy of the originally inserted item
452   const size_t NoOfSelectedItems = this->GetSelectedItemCount();
453
454   size_t Index(0);
455
456
457   while ((Index < NoOfSelectedItems) && (this->m_SelectedItems[Index] != Item))
458     ++Index;
459   return Index;
460 } /* wxTreeMultiCtrl::GetSelectedItemIndex(wxTreeMultiItem const&) const */
461
462 void wxTreeMultiCtrl::SelectItem(wxTreeMultiItem const& Item, bool UnselectOthers, bool ExpandSelection)
463 {
464   TreeMultiItemNode* NodePtr(Item.GetItem()->IsTreeMultiItemNode());
465
466
467  // only nodes can be selected and they can only be selected if they are not already selected:
468   if ((NodePtr == NULL) || NodePtr->IsSelected())
469    return;
470
471  // inform that we are about to change:
472   wxTreeMultiEvent Event(wxEVT_COMMAND_TREE_MULTI_SEL_CHANGING,Item); // variable definition and initialization
473
474   if (this->m_SelectedItems.GetCount() > 0) // the last item in the array is always the latest inserted item
475     Event.SetOldItem(this->m_SelectedItems.Last());
476   Event.SetEventObject(this);
477   if (this->GetEventHandler()->ProcessEvent(Event) && !(Event.IsAllowed()))
478       return; // vetoed
479
480  // make sure that the to be selected item can be seen:
481   this->Include(Item);
482
483  // variable definition and initialization:
484   wxTreeMultiItem ExcludedParent(this->GetExcludedParent(Item));
485
486   while (ExcludedParent.IsOk())
487   {
488     this->Include(ExcludedParent);
489     ExcludedParent = this->GetExcludedParent(Item);
490   } /* while */
491
492  // unselect items if necessary:
493   if (UnselectOthers)
494     this->UnselectAll();
495  // expand selection if necessary:
496   if (ExpandSelection)
497   {
498    // variable definition:
499     wxTreeMultiItem FirstItemIterator, LastItemIterator;
500     wxTreeMultiItem LastSelectedItem;
501
502    // determine the last selected item or the first item in case nothing has been selected before:
503     if (this->m_SelectedItems.GetCount() > 0)
504       LastSelectedItem = this->m_SelectedItems.Last();
505     else
506       LastSelectedItem = this->GetFirstRoot();
507    // determine the item from which to start and the one with which to end the selection:
508     if (Item.GetItem()->GetY() > LastSelectedItem.GetItem()->GetY())
509     {
510       FirstItemIterator = LastSelectedItem;
511       LastItemIterator  = Item;
512     } /* if */
513     else
514     {
515       FirstItemIterator = Item;
516       LastItemIterator  = LastSelectedItem;
517     } /* if */
518    // select all items that are a node and are placed between the two limiting iterators (included the limits):
519     for (;;)
520     {
521       if (!(FirstItemIterator.IsSelected()) && FirstItemIterator.IsNodeItem())
522       {
523         FirstItemIterator.GetItem()->Select();
524         this->m_SelectedItems.Add(FirstItemIterator);
525         this->RefreshRect(wxRect(FirstItemIterator.GetItem()->GetX(),    FirstItemIterator.GetItem()->GetY(),
526                                  FirstItemIterator.GetItem()->GetWidth(),FirstItemIterator.GetItem()->GetHeight()));
527       } /* if */
528       if (FirstItemIterator == LastItemIterator)
529         break; // done
530      // continue iterating:
531       FirstItemIterator = this->GetNext(FirstItemIterator);
532     } /* for */
533   } /* if */
534   else // select passed item only
535   {
536     NodePtr->Select();
537     this->m_SelectedItems.Add(NodePtr);
538     this->RefreshRect(wxRect(NodePtr->GetX(),NodePtr->GetY(),NodePtr->GetWidth(),NodePtr->GetHeight()));
539   } /* if */
540
541  // inform that we have selected the item:
542   Event.SetEventType(wxEVT_COMMAND_TREE_MULTI_SEL_CHANGED);
543   this->GetEventHandler()->ProcessEvent(Event);
544 } /* wxTreeMultiCtrl::SelectItem(wxTreeMultiItem const&, bool, bool) */
545
546 void wxTreeMultiCtrl::UnselectAll(void)
547 {
548   const size_t NoOfSelectedItems = this->m_SelectedItems.GetCount();
549
550
551   for (size_t i=0; i<NoOfSelectedItems; ++i)
552   {
553     this->RefreshRect(wxRect(this->m_SelectedItems[i].GetItem()->GetX(),    this->m_SelectedItems[i].GetItem()->GetY(),
554                              this->m_SelectedItems[i].GetItem()->GetWidth(),this->m_SelectedItems[i].GetItem()->GetHeight()));
555     this->m_SelectedItems[i].GetItem()->Unselect();
556   } /* for */
557   this->m_SelectedItems.Clear();
558 } /* wxTreeMultiCtrl::UnselectAll(void) */
559
560 void wxTreeMultiCtrl::Unselect(wxTreeMultiItem const& Item)
561 {
562   size_t ItemIndex(this->GetSelectedItemIndex(Item));
563
564
565   if (ItemIndex != this->GetSelectedItemCount())
566   {
567     Item.GetItem()->Unselect();
568     this->m_SelectedItems.RemoveAt(ItemIndex);
569     this->RefreshRect(wxRect(Item.GetItem()->GetX(),Item.GetItem()->GetY(),Item.GetItem()->GetWidth(),Item.GetItem()->GetHeight()));
570   } /* if */
571 } /* wxTreeMultiCtrl::Unselect(wxTreeMultiItem const&) */
572
573 void wxTreeMultiCtrl::DoFold(TreeMultiItemBase *item, bool expand, bool recursive)
574 {
575
576         // go through all node objects on this level, and expand or
577         // collapse them
578
579         if(item == 0)
580                 return;
581
582         // if this is a node, use it to go through all the subnodes (if needed)
583         // if not, then just exit.
584
585         TreeMultiItemNode *node = item->IsTreeMultiItemNode();
586         if(node)
587         {
588                 node->Fold(expand);
589
590                 // go recursive
591                 if(recursive)
592                 {
593                         TreeMultiItemNode *p;
594                         for(int i = 0; i < node->GetNodeCount(); i++)
595                         {
596                                 // get node, and if a real node, then call fold
597                                 p = node->GetNode(i)->IsTreeMultiItemNode();
598                                 if(p)
599                                         p->Fold(expand);
600
601                                 // go recursive for every node
602                                 DoFold(p, expand, recursive);
603                         }
604                 }
605         }
606 }
607
608 void wxTreeMultiCtrl::Exclude(const wxTreeMultiItem &item)
609 {
610         wxCHECK2(item.IsOk(), return);
611
612         // exclude the item, and refresh
613         // if already excluded, skip
614
615         if(!item.GetItem()->IsExcluded())
616         {
617                 item.GetItem()->SetExcluded(true);
618                 RedrawFromParentNode(item.GetItem());
619         }
620 }
621
622 void wxTreeMultiCtrl::Include(const wxTreeMultiItem &item)
623 {
624         wxCHECK2(item.IsOk(), return);
625
626         // include the item, and refresh. If not
627         // excluded, do nothing
628
629         if(item.GetItem()->IsExcluded())
630         {
631                 item.GetItem()->SetExcluded(false);
632                 RedrawFromParentNode(item.GetItem());
633         }
634 }
635
636 wxTreeMultiItem wxTreeMultiCtrl::GetExcludedParent(const wxTreeMultiItem &item)
637 {
638         wxCHECK(item.IsOk(), wxTreeMultiItem(0));
639
640         // go find the parent (including this one) that
641         // can be the excluded one
642
643         TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();
644         if(n && n->IsExcluded())
645                 return wxTreeMultiItem(n);
646
647         n = item.GetItem()->GetParent();
648         while(n)
649         {
650                 if(n->IsExcluded())
651                         return wxTreeMultiItem(n);
652                 else
653                         n = n->GetParent();
654         }
655
656         return wxTreeMultiItem(0);
657 }
658
659 void wxTreeMultiCtrl::OnSize(wxSizeEvent &WXUNUSED(event))
660 {
661         RecalculateSpanSizes();
662 }
663
664 void wxTreeMultiCtrl::OnPaint(wxPaintEvent& WXUNUSED(event) )
665 {
666         wxPaintDC dc(this);
667
668         PrepareDC(dc);
669
670         // go recursive and draw the whole visible tree.
671         dc.SetFont(_captionFont);
672         for(int i = 0; i < _root.GetNodeCount(); i++)
673                 DrawNode(_root.GetNode(i), dc);
674 }
675
676 void wxTreeMultiCtrl::DrawNode(TreeMultiItemBase *b, wxDC &dc)
677 {
678         // go through this item .. if it is a node, draw
679         // the caption, else reposition the window.
680
681         if(!b)
682                 return;
683
684         // forget it if this node is not visible
685         if(b->IsVisible())
686         {
687                 int bmpOffsetX = b->GetX() - (_gutterWidth + _iconWidth);
688
689 #if(CHECKBOXVIEW)
690                 // now draw the checkbox if there is any, in the proper state
691                 if(b->GetCheckbox())
692                 {
693                         DrawCheckbox(b, dc);
694
695                         // adjust the bmpOffset because we also have a checkbox
696                         bmpOffsetX -= _checkWidth;
697                 }
698 #endif
699
700                 if(b->IsTreeMultiItemNode())
701                 {
702                         // draw the node icon and the caption
703                         TreeMultiItemNode *n = (TreeMultiItemNode *)b;
704
705                  // set background of caption item
706                   if (n->IsSelected())
707                   {
708                     dc.SetBrush(*(this->m_HilightBrush));
709         dc.SetPen(wxPen(this->m_HilightBrush->GetColour(),1,wxSOLID));
710                   } /* if */
711                   else
712                   {
713                     dc.SetBrush(wxBrush(*wxWHITE,wxSOLID));
714         dc.SetPen(wxPen(*wxWHITE,1,wxSOLID));
715                   } /* if */
716                   dc.DrawRectangle(n->GetX(),n->GetY(),n->GetWidth(),n->GetHeight());
717                  // draw caption
718                         dc.DrawText(n->GetCaption(), n->GetX(), n->GetY());
719
720                         // draw the bitmap for the state
721                         if(n->IsExpanded())
722                                 dc.DrawBitmap(*_expandBmp, bmpOffsetX, n->GetY() + _iconDeltaY, true);
723                         else
724                                 dc.DrawBitmap(*_collBmp, bmpOffsetX, n->GetY() + _iconDeltaY, true);
725
726                         // now go through all the subnodes
727                         for(int i = 0; i < n->GetNodeCount(); i++)
728                                 DrawNode(n->GetNode(i), dc);
729
730                 }
731         }
732 }
733
734 #if(CHECKBOXVIEW)
735
736 void wxTreeMultiCtrl::DrawCheckbox(TreeMultiItemBase *b, wxDC &dc, bool convertScrolled)
737 {
738         wxCHECK2(b, return);
739
740         wxBitmap *bmp;
741         int bmpOffsetX = b->GetX() - (_gutterWidth + _iconWidth);
742
743         switch(b->GetCheckboxState())
744         {
745         case 0:
746                 bmp = _uncheckBmp;
747                 break;
748         case 1:
749                 bmp = _checkBmp;
750                 break;
751         default:
752                 bmp = _tristateBmp;
753                 break;
754         }
755
756         int x, xx, y, yy;
757
758         if(b->IsTreeMultiItemWindow())
759         {
760                 xx = x = bmpOffsetX - ((TreeMultiItemWindow *)b)->GetFrontSpacing() + _checkWidth;
761                 yy = y = b->GetY() + _checkDeltaY;
762         }
763         else
764         {
765                 xx = x = bmpOffsetX;
766                 yy = y = b->GetY() + _checkDeltaY;
767         }
768
769         if(convertScrolled)
770                 CalcScrolledPosition(x, y, &xx, &yy);
771
772         dc.DrawBitmap(*bmp, xx, yy, true);
773 }
774
775 #endif // #if(CHECKBOXVIEW)
776
777 void wxTreeMultiCtrl::OnKey(wxKeyEvent &event)
778 {
779         // check if we need to traverse to upper or lower
780         // control in the list
781         if(event.GetKeyCode() == WXK_TAB)
782         {
783                 wxTreeMultiItem item = GetFocus();
784                 if(item.IsOk())
785                 {
786                         // traverse down direction
787                         if(!event.ShiftDown())
788                                 item = FindNextVisibleWindowItem(item.GetItem());
789                         //else // traverse in up direction
790                         //      item = FindPreviousVisibleWindowItem(item);
791
792                         if(item.IsOk())
793                         {
794                                 TreeMultiItemWindow *w = item.GetItem()->IsTreeMultiItemWindow();
795                                 if(w)
796                                 {
797                                         wxWindow *wnd = w->GetWindow();
798                                         wnd->SetFocus();
799                                 }
800                         }
801                 }
802         }
803         else
804                 event.Skip();
805 }
806
807 void wxTreeMultiCtrl::OnMouseClick( wxMouseEvent &event )
808 {
809         // react on double click and left mouse down
810         if(event.LeftDown() || event.LeftDClick())
811         {
812                 // get translation point
813                 wxPoint pt( event.GetPosition() );
814
815                 int x = 0, y = 0;
816                 CalcUnscrolledPosition( pt.x, pt.y, &x, &y );
817
818                 // go check if we clicked a treenode
819                 int flags;
820                 wxPoint p(x,y);
821                 wxTreeMultiItem id = HitTest(p, flags);
822
823 #if(CHECKBOXVIEW)
824                 if(flags == wxTMC_HITTEST_CHECKBOX)
825                 {
826                         // toggle the checkbox, and redraw
827                         if(id.IsOk())
828                         {
829                                 TreeMultiItemBase *b = id.GetItem();
830                                 b->SetCheckboxState((b->GetCheckboxState()+1) & 0x1);
831
832                                 TreeMultiItemWindow *w = b->IsTreeMultiItemWindow();
833                                 if(w)
834                                 {
835                                         // try to force a focus on the window. This could
836                                         // be extended by searching for the first edit control
837                                         // class but for now, just a focus is tried.
838                                         w->GetWindow()->Enable(b->GetCheckboxState() == 1);
839                                         w->GetWindow()->SetFocus();
840
841                                         // draw the checkbox in the state needed
842                                         wxClientDC dc(this);
843                                         DrawCheckbox(b, dc, true);
844
845                                         // TODO: determine if the upper parents should be
846                                         // tristated or not
847
848                                         ScanTristateCheckstates(b);
849
850                                 }
851                                 else if(b->IsTreeMultiItemNode())
852                                 {
853                                         // descend to all the children and set the state of the parent
854                                         SetRecursiveCheckState((TreeMultiItemNode *)b, b->GetCheckboxState() == 1);
855                                         RedrawFromNode((TreeMultiItemNode *)b);
856                                 }
857                         }
858                 }
859                 else
860 #endif // #if(CHECKBOXVIEW)
861                 {
862                         // react on left mouse button, to fold and on
863                         // right for caption doubleclick
864                         int area = -1;
865
866 // adjust behaviour for Linux (single click = always fold)
867 #ifndef LINUX
868                         if(event.LeftDClick())
869                                 area = wxTMC_HITTEST_CAPTION;
870                         else
871                                 area = wxTMC_HITTEST_GUTTER;
872 #else
873                         area = flags;
874 #endif
875
876 // Linux (single or double click -> always fold
877       if (id.IsOk())
878       {
879 #ifdef LINUX
880                                 // we have a valid item, if it is a node, then fold
881                                 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode();
882                                 if(n)
883                                 {
884                                   this->SelectItem(id);
885                                         Fold(n, !n->IsExpanded());
886                                 } /* if */
887 #else
888         if (event.LeftDown())
889           if (flags == wxTMC_HITTEST_GUTTER)
890           {
891                                 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode(); // for some reasons also windows may have set the flag
892
893             if (n != NULL)
894                                         Fold(n, !n->IsExpanded());
895           } /* if */
896           else if (flags == wxTMC_HITTEST_CAPTION)
897           {
898                                 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode(); // for some reasons also windows may have set the flag
899
900                                 if (n != NULL)
901                                 {
902                                   this->SelectItem(id);
903                                 this->RedrawFromNode(n);
904                                 } /* if */
905           } /* if */
906 #endif
907       } /* if */
908       else
909         this->UnselectAll();
910                 }
911         }
912 }
913
914 void wxTreeMultiCtrl::OnRightMouseClick(wxMouseEvent& Event)
915 {
916   if (Event.RightDown())
917     if (Event.Dragging())
918       this->UnselectAll();
919     else
920     {
921      // variable definitions:
922         int Flags;
923         wxPoint Point;
924
925      // translate mouse coordinates:
926         CalcUnscrolledPosition(Event.GetPosition().x,Event.GetPosition().y,&(Point.x),&(Point.y));
927      // check if the mouse is above the caption of an item:
928       wxTreeMultiItem Item(this->HitTest(Point,Flags)); // variable definition and initialization
929
930       if (Item.IsOk() && (Flags == wxTMC_HITTEST_CAPTION))
931       {
932         this->SelectItem(Item);
933                                 this->RedrawFromNode(Item.GetItem()->IsTreeMultiItemNode());
934           Event.Skip(); // window will convert right mouse click to a context menu event or proceed with
935                         // a right mouse click event if the context menu event cannot be processed
936       } /* if */
937       else
938         this->UnselectAll();
939     } /* if */
940   else
941     this->UnselectAll();
942 } /* wxTreeMultiCtrl::OnRightMouseClick(wxMouseEvent&) */
943
944 wxTreeMultiItem wxTreeMultiCtrl::HitTest(wxPoint const& pt, int &flags)
945 {
946         // scan all nodes to see which one matches
947         TreeMultiItemBase *b = 0;
948         for(int i = 0; i < _root.GetNodeCount() && !b; i++)
949                 b = FindNodeByPoint(_root.GetNode(i), pt, flags);
950
951         if(!b)
952         {
953                 // none found, reset
954                 flags = 0;
955                 return wxTreeMultiItem(0);
956         }
957
958         // return an item
959         return wxTreeMultiItem(b);
960 }
961
962 TreeMultiItemBase *wxTreeMultiCtrl::FindNodeByPoint(TreeMultiItemBase *b, wxPoint const& pt, int &area)
963 {
964         wxCHECK(b, 0);
965
966         // if this layer is not visible, return with nothing.
967         if(!b->IsVisible())
968                 return 0;
969
970         area = 0;
971
972         // now see if our y is matching the mouse
973         if(pt.y >= b->GetY() && pt.y < (b->GetY() + b->GetHeight()))
974         {
975 #if(CHECKBOXVIEW)
976                 // if we are checkboxed, calculate the checkbox position
977                 if(b->GetCheckbox())
978                 {
979                         int extraSpacing = 0, extraWidth = 0;
980
981                         // now for a windows item, this is minus the gutter. For a normal node it is X minus checkbox
982                         if(b->IsTreeMultiItemWindow())
983                         {
984                             extraWidth = _checkWidth;
985                                 extraSpacing = ((TreeMultiItemWindow *)b)->GetFrontSpacing();
986                         }
987                         else
988                                 extraSpacing = 4;
989
990                         if(pt.x > (b->GetX() - extraSpacing - _checkWidth) && pt.x < (b->GetX() - extraSpacing + extraWidth))
991                         {
992                                 area = wxTMC_HITTEST_CHECKBOX;
993                                 return b;
994                         }
995                 }
996 #endif
997
998                 // allrighty we have something, now where and what is it (look with x)
999                 if(pt.x < b->GetX())
1000                         area = wxTMC_HITTEST_GUTTER;
1001
1002                 /** \todo Match only the real part of the caption, window (we assume x > GetX() which is the rest)
1003                         HOWEVER the window probably doesn't propagate the click event back to the parent, so we might
1004                         leave it like this so the use can click behind a window so it will be selected.
1005                 */
1006                 else
1007                 {
1008                         // inside area, return proper flag
1009                         if(b->IsTreeMultiItemNode())
1010                                 area = wxTMC_HITTEST_CAPTION;
1011                         else
1012                                 area = wxTMC_HITTEST_WINDOW;
1013                 }
1014
1015                 return b;
1016         }
1017         else
1018         {
1019                 // not found, let's try our children if we have some
1020                 TreeMultiItemNode *n = b->IsTreeMultiItemNode();
1021                 if(n)
1022                 {
1023                         TreeMultiItemBase *bb = 0;
1024                         for(int i = 0; i < n->GetNodeCount() && !bb; i++)
1025                                 bb = FindNodeByPoint(n->GetNode(i), pt, area);
1026
1027                         // keep returning result to caller
1028                         return bb;
1029                 }
1030         }
1031
1032         return 0;
1033 }
1034
1035 wxTreeMultiItem wxTreeMultiCtrl::GetFocus()
1036 {
1037         wxWindow *wnd = wxWindow::FindFocus();
1038
1039         // now find window that holds this item. if not
1040         // visible it cannot have focus (should not have)
1041
1042         wxTreeMultiItem item = FindWindowNode(wnd);
1043         if(item.IsOk() && item.GetItem()->IsVisible())
1044                 return item;
1045
1046         return wxTreeMultiItem(0);
1047 }
1048
1049 #if(CHECKBOXVIEW)
1050
1051 void wxTreeMultiCtrl::SetRecursiveCheckState(TreeMultiItemNode *n, bool check)
1052 {
1053         int state = 0;
1054         if(check)
1055                 state++;
1056
1057         // go check all kids on this level
1058         for(int i = 0; i < n->GetNodeCount(); i++)
1059         {
1060                 // check all the nodes, and go deeper
1061                 n->GetNode(i)->SetCheckboxState(state);
1062                 if(n->GetNode(i)->IsTreeMultiItemNode())
1063                         SetRecursiveCheckState((TreeMultiItemNode *)n->GetNode(i), check);
1064         }
1065 }
1066
1067 void wxTreeMultiCtrl::ScanTristateCheckstates(TreeMultiItemBase *b)
1068 {
1069         // check from the parent on, all node entries and see if they are
1070         // checked or cleared or scattered
1071         TreeMultiItemNode *p = b->GetParent();
1072
1073         if(p && p->GetCheckbox())
1074         {
1075                 bool foundcheck = false, foundclear = false;
1076                 for(size_t i = 0; i < (size_t)p->GetNodeCount(); ++i)
1077                 {
1078                         // only evaluate when checkboxed
1079                         if(p->GetNode(i)->IsTreeMultiItemWindow() && p->GetNode(i)->GetCheckbox())
1080                         {
1081                                 // record instance of a cleared checkbox
1082                                 if(!p->GetNode(i)->GetCheckboxState())
1083                                         foundclear = true;
1084                                 // record instance of checked checkbox
1085                                 if(p->GetNode(i)->GetCheckboxState() == 1)
1086                                         foundcheck = true;
1087                         }
1088                 }
1089
1090                 // if we have both check and clear, go tristate
1091                 // if all clear, clear parent and if all set, then set parent
1092                 if(foundclear && !foundcheck)
1093                         p->SetCheckboxState(0);
1094                 else if(!foundclear && foundcheck)
1095                         p->SetCheckboxState(1);
1096                 else if(foundclear && foundcheck)
1097                         p->SetCheckboxState(2);
1098
1099                 //wxClientDC dc;
1100                 //DrawCheckbox(p, dc, false);
1101                 RedrawFromNode(p);
1102         }
1103 }
1104
1105 #endif // #if(CHECKBOXVIEW)
1106
1107 wxTreeMultiItem wxTreeMultiCtrl::InsertNode(TreeMultiItemNode* ParentPtr, size_t Position, wxString const& Caption, wxString const& Name)
1108 {
1109         int extX, extY;
1110
1111   TreeMultiItemNode* NodePtr(new TreeMultiItemNode(ParentPtr,Caption,Name)); // generate new node pointer
1112
1113
1114  // continue with initializing the new node:
1115 #if(CHECKBOXVIEW)
1116  // if checkbox view is desired, tag this item as a checkbox
1117  // and set the state as 'false'
1118         NodePtr->SetCheckbox(_checkboxView);
1119         NodePtr->SetCheckboxState(0);
1120 #endif
1121  // calculate the height and width
1122         this->GetTextExtent(Caption,&extX,&extY,0,0,&(this->_captionFont));
1123         NodePtr->SetHeight(extY);
1124         NodePtr->SetWidth(extX);
1125  // finally, insert node:
1126   if (Position < (size_t)ParentPtr->GetNodeCount())
1127     ParentPtr->InsertNode(NodePtr,Position);
1128   else
1129     ParentPtr->AddNode(NodePtr);
1130  // return the newly created node:
1131   return wxTreeMultiItem(NodePtr);
1132 } /* wxTreeMultiCtrl::InsertNode(TreeMultiItemNode*, size_t, wxString const&, wxString const&) */
1133
1134 wxTreeMultiItem wxTreeMultiCtrl::InsertWindow(TreeMultiItemNode* ParentPtr, size_t Position, wxWindow* WindowPtr, wxString const& Name, wxTreeMultiWindowInfo const& Info, int Flags)
1135 {
1136   int WindowFlags;
1137
1138         TreeMultiItemWindow* NewWindowPtr = new TreeMultiItemWindow(ParentPtr,Name); // generate new window pointer
1139
1140
1141  // get flags from passed variable "Flags"; in case this variable does not contain any flags use the window's information flags:
1142   if (Flags != 0)
1143     WindowFlags = Flags;
1144   else
1145     WindowFlags = Info.GetFlags();
1146
1147  // continue with initializing the new window:
1148 #if(CHECKBOXVIEW)
1149         // if checkbox view is desired, tag this item as a checkbox
1150         // and set the state as 'false'
1151         NewWindowPtr->SetCheckbox(_checkboxView);
1152 #endif
1153  // if style wants us to change background, set it to our background
1154         if (WindowFlags & wxTMC_BG_ADJUST_ALL)
1155         {
1156                 // go through all children of this window, and set the
1157                 // background of it (recursively)
1158                 this->SetWindowBackgroundColour(WindowPtr,this->GetBackgroundColour(),WindowFlags);
1159         } /* if */
1160
1161  // set the spacing:
1162         NewWindowPtr->SetTopSpacing(Info.GetTopSpacing());
1163 #if(CHECKBOXVIEW)
1164         // make sure that the checkboxes are at least indented enough
1165         if (this->_checkboxView)
1166                 NewWindowPtr->SetFrontSpacing(Info.GetFrontSpacing() + this->_checkWidth);
1167         else
1168 #endif
1169                 NewWindowPtr->SetFrontSpacing(Info.GetFrontSpacing());
1170  // assign finally the window:
1171         NewWindowPtr->AssignWindow(WindowPtr);
1172
1173 #if(CHECKBOXVIEW)
1174  // set the checkbox state after the window is assigned
1175         NewWindowPtr->SetCheckboxState(Info.GetDefaultCheckState());
1176 #endif
1177
1178  // if the window is not visible, set hide flag
1179         this->ShowTreeMultiWindow(NewWindowPtr,NewWindowPtr->IsVisible());
1180
1181  // finally, insert the newly constructed window:
1182   if (Position < (size_t)ParentPtr->GetNodeCount())
1183     ParentPtr->InsertNode(NewWindowPtr,Position);
1184   else
1185     ParentPtr->AddNode(NewWindowPtr);
1186  // return the newly created window:
1187         return wxTreeMultiItem(NewWindowPtr);
1188 } /* wxTreeMultiCtrl::InsertWindow(TreeMultiItemNode*, size_t, wxWindow*, wxString const&, wxTreeMultiWindowInfo const&, int) */
1189
1190 void wxTreeMultiCtrl::RedrawFromParentNode(TreeMultiItemBase *n)
1191 {
1192         TreeMultiItemNode *p = 0;
1193         if(n)
1194                 p = n->GetParent();
1195
1196         RedrawFromNode(p);
1197 }
1198
1199 void wxTreeMultiCtrl::RedrawFromNode(TreeMultiItemNode *n)
1200 {
1201         static int recalcMutex = 0;
1202         bool visible = true;
1203
1204         if(recalcMutex > 0)
1205                 return;
1206
1207         recalcMutex ++;
1208
1209         // when node is not visible or excluded
1210         // then don't redraw.
1211
1212         if(n)
1213                 visible = n->IsVisible();
1214
1215         if(visible)
1216         {
1217                 int h, h1,w, w1;
1218                 GetVirtualSize(&w, &h);
1219
1220                 UpdateAllWindowVisibility();
1221                 RecalculateNodePositions();
1222                 RecalculateVirtualSize();
1223
1224                 // why is this needed? Because folding or collapsing can change
1225                 // the state. When the virtual area gets smaller, we need to keep
1226                 // the largest one and the other way atound. And since we do not
1227                 // know here we are folding or collapsing, we remember the biggest
1228                 GetVirtualSize(&w1, &h1);
1229
1230                 if(h1 > h)
1231                         h = h1;
1232
1233                 // only refresh the part from x,y down
1234                 if(n)
1235                 {
1236                         int x, y;
1237                         CalcScrolledPosition(n->GetX(), n->GetY(), &x, &y);
1238                         if(h - y > 0)
1239                         {
1240                                 wxRect rect(0, y, w, h - y);
1241                                 RefreshRect(rect);
1242                         }
1243                         else
1244                                 Refresh();
1245                 }
1246                 else
1247                         Refresh();      // do a full refresh
1248         }
1249
1250         recalcMutex --;
1251 }
1252
1253 void wxTreeMultiCtrl::RecalculateNodePositions()
1254 {
1255         int currentY = _spacingY;
1256         // go recursive on every node, and store the information in the node
1257
1258         for(int i = 0; i < _root.GetNodeCount(); i++)
1259         currentY += CalculateNodeDimensions(_root.GetNode(i), currentY, 0);
1260 }
1261
1262 int wxTreeMultiCtrl::CalculateNodeDimensions(TreeMultiItemBase *b, int currentY, int level)
1263 {
1264         int gutter = (_gutterWidth * 2) + _iconWidth;
1265         int y = 0, topSpacing = 0;
1266
1267         // return same if no proper object
1268         wxCHECK(b, 0);
1269
1270 #if(CHECKBOXVIEW)
1271         if(b->GetCheckbox())
1272                 gutter += _checkWidth;
1273 #endif
1274
1275         // if we are not visible, skip recalculation and descending
1276         if(b->IsVisible())
1277         {
1278                 b->SetY(currentY);
1279
1280                 // if level is 0, calculate with front gutter, else without
1281                 y = currentY + b->GetHeight();
1282                 if(b->IsTreeMultiItemNode())
1283                 {
1284                         TreeMultiItemNode *n = (TreeMultiItemNode *)b;
1285
1286                         if(level == 0)
1287                                 b->SetX(gutter);
1288                         else
1289                                 b->SetX(gutter + (level * (_gutterWidth + _iconWidth)));
1290
1291                         // now do children of this node
1292
1293                         for(int i = 0; i < n->GetNodeCount(); i++)
1294                                 y += CalculateNodeDimensions(n->GetNode(i), y + _spacingY, level+1);
1295                 }
1296                 else if(b->IsTreeMultiItemWindow())
1297                 {
1298                         TreeMultiItemWindow *w = (TreeMultiItemWindow *)b;
1299
1300                         if(level == 0)
1301                                 b->SetX(gutter + w->GetFrontSpacing());
1302                         else
1303                                 b->SetX(_gutterWidth + (level * (_gutterWidth + _iconWidth)) + w->GetFrontSpacing());
1304
1305                         topSpacing = w->GetTopSpacing();
1306
1307                         // reposition the window
1308
1309                         wxWindow *wnd = w->GetWindow();
1310                         if(wnd)
1311                         {
1312                                 int x = 0, y = 0;
1313                                 CalcScrolledPosition(w->GetX(), w->GetY(), &x, &y);
1314                                 wnd->SetSize(x, y, w->GetWidth(), w->GetHeight());
1315                         }
1316                 }
1317
1318                 if(y > 0)
1319                         return (y - currentY) + _spacingY + topSpacing; // return delta
1320                 else
1321                         return 0;
1322         }
1323
1324         return 0;       // not visible, thus we skip calculations
1325 }
1326
1327 void wxTreeMultiCtrl::RecalculateSpanSizes()
1328 {
1329         for(int i = 0; i < _root.GetNodeCount(); i++)
1330         CalculateNodeSpanning(_root.GetNode(i));
1331 }
1332
1333 void wxTreeMultiCtrl::CalculateNodeSpanning(TreeMultiItemBase *b)
1334 {
1335         // return same if no proper object
1336         wxCHECK2(b, return);
1337
1338         if(b->IsTreeMultiItemNode())
1339         {
1340                 TreeMultiItemNode *n = (TreeMultiItemNode *)b;
1341
1342                 // now do children of this node
1343
1344                 for(int i = 0; i < n->GetNodeCount(); i++)
1345                         CalculateNodeSpanning(n->GetNode(i));
1346         }
1347         else if(b->IsTreeMultiItemWindow())
1348         {
1349                 TreeMultiItemWindow *w = (TreeMultiItemWindow *)b;
1350                 wxWindow *wnd = w->GetWindow();
1351                 if(wnd)
1352                 {
1353                         // if the window is spanning, we adjust the width to the max width of the control
1354                         if(w->GetHorizontalSpan())
1355                         {
1356                                 wxSize tmcsize = GetClientSize();
1357                                 int maxwidth = tmcsize.GetWidth() - w->GetX() - 8; // extract 3 for border
1358
1359                                 wxSizer *sz = wnd->GetSizer();
1360                                 if(sz)
1361                                 {
1362                                         if(maxwidth < sz->GetMinSize().GetWidth())
1363                                                 maxwidth = sz->GetMinSize().GetWidth();
1364                                 }
1365
1366                                 // prevent a size of 0
1367                                 if(maxwidth < 1)
1368                                         maxwidth = 1;
1369
1370                                 // set the size
1371                                 w->SetWidth(maxwidth);
1372                                 wnd->SetSize(w->GetWidth(), w->GetHeight());
1373
1374                                 // layout by sizer (not sure if this is needed)
1375                                 if(wnd->GetSizer())
1376                                         wnd->GetSizer()->Layout();
1377                         }
1378                 }
1379         }
1380 }
1381
1382 void wxTreeMultiCtrl::RecalculateVirtualSize()
1383 {
1384         // go through all the nodes, and store the largest x and largest y
1385
1386         int x = 0, y = 0;
1387         RecalculateVirtualSizeFromNode(&_root, x, y);
1388
1389         // now adjust virtual size
1390         SetVirtualSize(x, y);
1391         AdjustScrollbars(x, y);
1392 }
1393
1394 void wxTreeMultiCtrl::AdjustScrollbars(int x, int y)
1395 {
1396         // adjust scrollbars
1397         // courtesy of treectrlg.cpp
1398
1399         y += WXTMC_PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
1400     x += WXTMC_PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
1401     int x_pos = GetScrollPos( wxHORIZONTAL );
1402     int y_pos = GetScrollPos( wxVERTICAL );
1403     SetScrollbars( WXTMC_PIXELS_PER_UNIT, WXTMC_PIXELS_PER_UNIT, x/WXTMC_PIXELS_PER_UNIT,
1404                            y/WXTMC_PIXELS_PER_UNIT, x_pos, y_pos, true );
1405 }
1406
1407 void wxTreeMultiCtrl::RecalculateVirtualSizeFromNode(const TreeMultiItemNode *node, int &x, int &y)
1408 {
1409         if(node->IsExcluded())
1410                 return;
1411
1412         // if calulate this node's dimensions
1413         if(x < (node->GetWidth() + node->GetX()))
1414                 x = node->GetWidth() + node->GetX();
1415
1416         y = node->GetY() + node->GetHeight();
1417
1418         // if this node is collapsed, no subnodes are visible, else
1419         // go through all subnodes as well, node needs to be included as well
1420         if(node->IsExpanded())
1421         {
1422                 TreeMultiItemBase *b;
1423                 for(int i = 0; i < node->GetNodeCount(); i++)
1424                 {
1425                         b = node->GetNode(i);
1426
1427                         // calculate x and y
1428                         if(x < (b->GetWidth() + b->GetX()))
1429                                 x = b->GetWidth() + b->GetX();
1430
1431                         y = b->GetY() + b->GetHeight();
1432
1433                         if(b->IsTreeMultiItemNode())
1434                                 RecalculateVirtualSizeFromNode((TreeMultiItemNode *)b, x, y);
1435                 }
1436         }
1437 }
1438
1439 void wxTreeMultiCtrl::SetWindowBackgroundColour(wxWindow *wnd, const wxColour &col, int flags)
1440 {
1441         if(wnd)
1442         {
1443                 // if we cannot change a button, make sure all button
1444                 // classes are not changed
1445
1446                 wxButton *btn = wxDynamicCast(wnd, wxButton);
1447                 if(!btn || ((flags & wxTMC_BG_ADJUST_BTN) != 0))
1448                         wnd->SetBackgroundColour(col);
1449
1450                 // get every window, and make the background equal to the given one
1451                 wxWindowListNode *node = wnd->GetChildren().GetFirst();
1452                 while (node)
1453                 {
1454                         SetWindowBackgroundColour(node->GetData(), col, flags);
1455                         node = node->GetNext();
1456                 }
1457         }
1458 }
1459
1460 void wxTreeMultiCtrl::ShowTreeMultiWindow(TreeMultiItemWindow *window, bool show)
1461 {
1462         // show or hide window
1463         if(window && window->GetWindow())
1464                 window->GetWindow()->Show(show);
1465 }
1466
1467 void wxTreeMultiCtrl::UpdateAllWindowVisibility()
1468 {
1469         // all roots are visible, but what lies beneath ... who knows
1470         for(int i = 0; i < _root.GetNodeCount(); i++)
1471                 UpdateTreeMultiWindowVisibility(_root.GetNode(i), true);
1472 }
1473
1474 void wxTreeMultiCtrl::UpdateTreeMultiWindowVisibility(TreeMultiItemBase *b, bool show)
1475 {
1476         if(b)
1477         {
1478                 // this is done for performance issues. IsVisible can go all
1479                 // the way up the tree to check. However if show is already
1480                 // false, there is no need to check (some higher one is collapsed)
1481                 bool showMe = show;
1482
1483                 if(showMe)
1484                         showMe = b->IsVisible();
1485
1486                 if(b->IsTreeMultiItemWindow())
1487                 {
1488                         // if this level must be hidden, hide
1489                         ShowTreeMultiWindow((TreeMultiItemWindow*)b, showMe);
1490                 }
1491                 else if(b->IsTreeMultiItemNode())
1492                 {
1493                         TreeMultiItemNode *node = (TreeMultiItemNode *)b;
1494
1495                         // if hidden, descend and hide all windows
1496                         for(int i = 0; i < node->GetNodeCount(); i++)
1497                                 UpdateTreeMultiWindowVisibility(node->GetNode(i), showMe);
1498                 }
1499         }
1500 }
1501
1502 wxTreeMultiItem wxTreeMultiCtrl::FindItem(const wxTreeMultiItem &item, const wxString &name, bool ignoreCase, bool skipFirst)
1503 {
1504         if(item.IsOk())
1505         {
1506                 TreeMultiItemBase *b = item.GetItem();
1507
1508                 // check this item first (or not)
1509
1510                 if(!skipFirst)
1511                 {
1512                         if(b->GetName().IsSameAs(name, !ignoreCase))
1513                                 return wxTreeMultiItem(b);
1514                 }
1515
1516                 if(b->IsTreeMultiItemNode())
1517                 {
1518                         // now check whether we are a node, then go check children
1519
1520                         TreeMultiItemNode *n = (TreeMultiItemNode *)b;
1521                         wxTreeMultiItem result(0);
1522                         for(int i = 0; i < n->GetNodeCount() && !result.IsOk(); i++)
1523                                 result = FindItem(wxTreeMultiItem(n->GetNode(i)), name, ignoreCase, false);
1524
1525                         return result;
1526                 }
1527         }
1528
1529         return wxTreeMultiItem(0);
1530 }
1531
1532 wxTreeMultiItem wxTreeMultiCtrl::FindWindowNode(wxWindow *wnd, TreeMultiItemNode *n)
1533 {
1534         wxCHECK(wnd, wxTreeMultiItem(0));
1535
1536         // take root node if not assigned one
1537
1538         if(!n)
1539                 n = (TreeMultiItemNode *)&_root;
1540
1541         // check on this level for the wxWindow pointer
1542
1543         TreeMultiItemWindow *w;
1544         wxTreeMultiItem result(0);
1545         for(int i = 0; i < n->GetNodeCount() && !result.IsOk(); i++)
1546         {
1547                 // if window node
1548                 w = n->GetNode(i)->IsTreeMultiItemWindow();
1549                 if(w && w->GetWindow() == wnd)
1550                         return wxTreeMultiItem(n);
1551
1552                 // if node, go deeper
1553                 if(n->GetNode(i)->IsTreeMultiItemNode())
1554                         result = FindWindowNode(wnd, (TreeMultiItemNode*)n->GetNode(i));
1555         }
1556
1557         return result;
1558 }
1559
1560 TreeMultiItemWindow *wxTreeMultiCtrl::FindNextVisibleWindowItem(TreeMultiItemBase *b, int index)
1561 {
1562         wxCHECK(b, 0);
1563
1564         // check on this level, go deeper with every node we got. When a node is not
1565         // visible anymore, skip the node.
1566
1567         TreeMultiItemWindow *value = 0;
1568         if(b->IsVisible())
1569         {
1570                 // if we are already searching on a node with an index
1571
1572                 TreeMultiItemBase *bn = 0;
1573                 TreeMultiItemNode *n = b->IsTreeMultiItemNode();
1574                 if(n)
1575                 {
1576                         for(int i = index + 1; i < n->GetNodeCount() && !value; i++)
1577                         {
1578                                 bn = n->GetNode(i);
1579                                 value = bn->IsTreeMultiItemWindow();
1580
1581                                 // assume a node, root when not a a window
1582                                 if(!value)
1583                                         value = FindNextVisibleWindowItem(bn, -1);
1584                         }
1585
1586                 }
1587                 else
1588                 {
1589                         if(b->IsTreeMultiItemWindow())
1590                         {
1591                                 // get parent first, and locate child as ptr
1592                                 TreeMultiItemNode *p = b->GetParent();
1593                                 wxCHECK(p, 0);
1594
1595                                 // go scan the parent from the given index, if
1596                                 // the index is valid else there is no child with that index
1597
1598                                 int idx = p->Index(b);
1599                                 wxCHECK(idx >= 0, 0);
1600
1601                                 value = FindNextVisibleWindowItem(p, idx);
1602                         }
1603                 }
1604         }
1605
1606         return value;
1607
1608 }
1609
1610 bool wxTreeMultiCtrl::GetBooleanValue(int wndId)
1611 {
1612         wxWindow *wnd = wxWindow::FindWindow(wndId);
1613         wxCHECK(wnd, false);
1614
1615         // try a radio button
1616         wxRadioButton *b = wxDynamicCast(wnd, wxRadioButton);
1617         if(b)
1618                 return b->GetValue();
1619
1620         // try a check box
1621         wxCheckBox *c = wxDynamicCast(wnd, wxCheckBox);
1622         if(c)
1623                 return c->GetValue();
1624
1625         /** \todo For custom controls we should put something in wxMultiTreeItemData class
1626             which can be overridden to retrieve the boolean value. It will also be passed
1627             the pointer to the window, so the derived class can figure out how to get a boolean
1628             value.
1629         */
1630
1631         // generate assert or just return with false
1632         wxCHECK(0, false);
1633 }
1634
1635 void wxTreeMultiCtrl::SetBooleanValue(int wndId, bool value)
1636 {
1637         wxWindow *wnd = wxWindow::FindWindow(wndId);
1638         wxCHECK2(wnd, return);
1639
1640         // try a radio button
1641         wxRadioButton *b = wxDynamicCast(wnd, wxRadioButton);
1642         if(b)
1643         {
1644                 b->SetValue(value);
1645                 return;
1646         }
1647
1648         // try a check box
1649         wxCheckBox *c = wxDynamicCast(wnd, wxCheckBox);
1650         if(c)
1651         {
1652                 c->SetValue(value);
1653                 return;
1654         }
1655
1656         /** \todo For custom controls we should put something in wxMultiTreeItemData class
1657                     which can be overridden to retrieve the boolean value. It will also be passed
1658                     the pointer to the window, so the derived class can figure out how to get a boolean
1659                     value.
1660         */
1661
1662         // generate assert
1663         wxCHECK2(0, return);
1664 }
1665
1666 void wxTreeMultiCtrl::SetTextValue(int wndId, const wxString &value)
1667 {
1668         wxWindow *wnd = wxWindow::FindWindow(wndId);
1669         wxCHECK2(wnd, return);
1670
1671         // try a radio button
1672         wxTextCtrl *t = wxDynamicCast(wnd, wxTextCtrl);
1673         if(t)
1674         {
1675                 t->SetValue(value);
1676                 return;
1677         }
1678
1679         /** \todo For custom controls we should put something in wxMultiTreeItemData class
1680                     which can be overridden to retrieve the boolean value. It will also be passed
1681                     the pointer to the window, so the derived class can figure out how to get a boolean
1682                     value.
1683         */
1684
1685         // generate assert
1686         wxCHECK2(0, return);
1687 }
1688
1689 wxString wxTreeMultiCtrl::GetTextValue(int wndId)
1690 {
1691         wxWindow *wnd = wxWindow::FindWindow(wndId);
1692         wxCHECK(wnd, wxEmptyString);
1693
1694         // try a radio button
1695         wxTextCtrl *t = wxDynamicCast(wnd, wxTextCtrl);
1696         if(t)
1697                 return t->GetValue();
1698
1699         // try a choice box
1700         wxChoice *c1 = wxDynamicCast(wnd, wxChoice);
1701         if(c1)
1702                 return c1->GetStringSelection();
1703
1704         // try a combo box
1705         wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);
1706         if(c2)
1707                 return c2->GetStringSelection();
1708
1709         // try a listbox
1710         wxListBox *l = wxDynamicCast(wnd, wxListBox);
1711         if(l)
1712                 return l->GetStringSelection();
1713
1714         /** \todo For custom controls we should put something in wxMultiTreeItemData class
1715             which can be overridden to retrieve the boolean value. It will also be passed
1716             the pointer to the window, so the derived class can figure out how to get a boolean
1717             value.
1718         */
1719
1720         // generate assert or just return with string
1721         wxCHECK(0, wxEmptyString);
1722 }
1723
1724 int wxTreeMultiCtrl::GetSelectionValue(int wndId)
1725 {
1726         wxWindow *wnd = wxWindow::FindWindow(wndId);
1727         wxCHECK(wnd, -1);
1728
1729         // try a choice box
1730         wxChoice *c1 = wxDynamicCast(wnd, wxChoice);
1731         if(c1)
1732                 return c1->GetSelection();
1733
1734         // try a combo box
1735         wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);
1736         if(c2)
1737                 return c2->GetSelection();
1738
1739         // try a listbox
1740         wxListBox *l = wxDynamicCast(wnd, wxListBox);
1741         if(l)
1742                 return l->GetSelection();
1743
1744         /** \todo For custom controls we should put something in wxMultiTreeItemData class
1745             which can be overridden to retrieve the boolean value. It will also be passed
1746             the pointer to the window, so the derived class can figure out how to get a boolean
1747             value.
1748         */
1749
1750         // generate assert or just return with string
1751         wxCHECK(0, -1);
1752 }
1753
1754 void wxTreeMultiCtrl::GetSelectionValues(int wndId, wxArrayInt &sels)
1755 {
1756         sels.Clear();
1757
1758         wxWindow *wnd = wxWindow::FindWindow(wndId);
1759         wxCHECK2(wnd, return);
1760
1761         // try a listbox
1762         wxListBox *l = wxDynamicCast(wnd, wxListBox);
1763         if(l)
1764         {
1765                 l->GetSelections(sels);
1766                 return;
1767         }
1768
1769         /** \todo For custom controls we should put something in wxMultiTreeItemData class
1770             which can be overridden to retrieve the boolean value. It will also be passed
1771             the pointer to the window, so the derived class can figure out how to get a boolean
1772             value.
1773         */
1774
1775         // generate assert or just return with string
1776         wxCHECK2(0, return);
1777 }
1778
1779 void wxTreeMultiCtrl::SetSelectionValue(int wndId, int sel)
1780 {
1781         wxWindow *wnd = wxWindow::FindWindow(wndId);
1782         wxCHECK2(wnd, return);
1783
1784         // try a choice box
1785         wxChoice *c1 = wxDynamicCast(wnd, wxChoice);
1786         if(c1)
1787         {
1788                 c1->SetSelection(sel);
1789                 return;
1790         }
1791
1792         // try a combo box
1793         wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);
1794         if(c2)
1795         {
1796                 c2->SetSelection(sel);
1797                 return;
1798         }
1799
1800         // try a listbox
1801         wxListBox *l = wxDynamicCast(wnd, wxListBox);
1802         if(l)
1803         {
1804                 l->SetSelection(sel);
1805                 return;
1806         }
1807
1808         /** \todo For custom controls we should put something in wxMultiTreeItemData class
1809             which can be overridden to retrieve the boolean value. It will also be passed
1810             the pointer to the window, so the derived class can figure out how to get a boolean
1811             value.
1812         */
1813
1814         // generate assert or just return with string
1815         wxCHECK2(0, return);
1816 }
1817
1818
1819 wxTreeMultiItem wxTreeMultiCtrl::GetParent(wxTreeMultiItem const& item) const
1820 {
1821  // check if valid or root item has been passed, both do not have parents:
1822   if (!(item.IsOk()) || item.GetItem()->IsTreeMultiItemRoot())
1823     return wxTreeMultiItem();
1824   else
1825     return wxTreeMultiItem(item.GetItem()->GetParent()); // GetParent() returns a valid pointer in case of a root item!!
1826                                                          // therefore, the check if the passed item is a root item is necessary
1827 } /* wxTreeMultiCtrl::GetParent(wxTreeMultiItem const& item) const */
1828
1829 wxTreeMultiItem wxTreeMultiCtrl::GetFirstChild(const wxTreeMultiItem &item, int &cookie) const
1830 {
1831         if(item.IsNodeItem())
1832         {
1833                 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
1834
1835                 if(n->GetNodeCount() > 0)
1836                 {
1837                         cookie = 0;
1838                         return wxTreeMultiItem(n->GetNode(0));
1839                 }
1840         }
1841
1842         // no children or no valid node
1843         cookie = -1;
1844         return wxTreeMultiItem(0);
1845 }
1846
1847 wxTreeMultiItem wxTreeMultiCtrl::GetNextChild(const wxTreeMultiItem &item, int &cookie) const
1848 {
1849         if(item.IsNodeItem())
1850         {
1851                 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
1852
1853                 if(cookie >= 0 && cookie < (n->GetNodeCount()-1))
1854                 {
1855                         // increment cookie, return node
1856                         cookie ++;
1857                         return wxTreeMultiItem(n->GetNode(cookie));
1858                 }
1859         }
1860
1861         // end of query, or no valid node
1862         cookie = -1;
1863         return wxTreeMultiItem(0);
1864 }
1865
1866 wxTreeMultiItem wxTreeMultiCtrl::GetLastChild(const wxTreeMultiItem &item) const
1867 {
1868         if(item.IsNodeItem())
1869         {
1870                 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
1871
1872                 if(n->GetNodeCount() > 0)
1873                         return wxTreeMultiItem(n->GetNode(n->GetNodeCount()-1));
1874         }
1875
1876         return wxTreeMultiItem(0);
1877 }
1878
1879 wxTreeMultiItem wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const& item) const
1880 {
1881  // check if a valid item has been passed:
1882   if (!(item.IsOk()))
1883     return wxTreeMultiItem();
1884
1885   TreeMultiItemNode* ParentPtr(item.GetItem()->GetParent());
1886
1887
1888   if (ParentPtr != NULL) // the parent pointer is only null if the passed item is the root
1889   {
1890    // find the current item in the parent's list; the next sibling has an index that is one higher than the one of the current item:
1891     int NextItemIndex(ParentPtr->Index(item.GetItem())+1); // variable definition and initialization
1892
1893     if (NextItemIndex < ParentPtr->GetNodeCount())
1894       return ParentPtr->GetNode(NextItemIndex);
1895     else
1896       return wxTreeMultiItem();
1897   } /* if */
1898   else
1899     return wxTreeMultiItem();
1900 } /* wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const&) const */
1901
1902 wxTreeMultiItem wxTreeMultiCtrl::GetPrevSibling(wxTreeMultiItem const& item) const
1903 {
1904  // check if a valid item has been passed:
1905   if (!(item.IsOk()))
1906     return wxTreeMultiItem();
1907
1908   TreeMultiItemNode* ParentPtr(item.GetItem()->GetParent());
1909
1910
1911   if (ParentPtr != NULL)
1912   {
1913    // find the current item in the parent's list; the next sibling has an index that is one higher than the one of the current item:
1914     int PrevItemIndex(ParentPtr->Index(item.GetItem())-1); // variable definition and initialization
1915
1916     if (PrevItemIndex >= 0)
1917       return ParentPtr->GetNode(PrevItemIndex);
1918     else
1919       return wxTreeMultiItem();
1920   } /* if */
1921   else
1922     return wxTreeMultiItem();
1923 } /* wxTreeMultiCtrl::GetPrevSibling(wxTreeMultiItem const&) const */
1924
1925 wxTreeMultiItem wxTreeMultiCtrl::GetNext(wxTreeMultiItem const& item) const
1926 {
1927  // check if a valid item has been passed:
1928   if (!(item.IsOk()))
1929     return wxTreeMultiItem();
1930
1931   TreeMultiItemNode* NodePtr(item.GetItem()->IsTreeMultiItemNode()); // variable definition and initialization
1932
1933   if ((NodePtr != NULL) && (NodePtr->GetNodeCount() > 0))
1934     return wxTreeMultiItem(NodePtr->First());
1935   else
1936   {
1937    // variable definitions and initializations:
1938     wxTreeMultiItem Parent(item);
1939     wxTreeMultiItem Sibling;
1940
1941     do
1942     {
1943       Sibling = this->GetNextSibling(Parent); // try to find next sibling
1944       Parent = this->GetParent(Parent);       // get next ancestor
1945     } while (!(Sibling.IsOk()) && Parent.IsOk());
1946    // in case the loop ended with Sibling.IsOk() "Sibling" contains a valid sibling otherwise an invalid
1947     return Sibling;
1948   } /* if */
1949 } /* wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const&) const */
1950
1951 wxTreeMultiItem wxTreeMultiCtrl::GetPrevious(wxTreeMultiItem const& item) const
1952 {
1953  // check if a valid item has been passed:
1954   if (!(item.IsOk()))
1955     return wxTreeMultiItem();
1956
1957   TreeMultiItemNode* NodePtr(item.GetItem()->IsTreeMultiItemNode()); // variable definition and initialization
1958
1959   if ((NodePtr != NULL) && (NodePtr->GetNodeCount() > 0))
1960     return wxTreeMultiItem(NodePtr->Last());
1961   else
1962   {
1963    // variable definitions and initializations:
1964     wxTreeMultiItem Parent(item);
1965     wxTreeMultiItem Sibling;
1966
1967     do
1968     {
1969       Sibling = this->GetPrevSibling(Parent); // try to find next sibling
1970       Parent = this->GetParent(Parent);       // get next ancestor
1971     } while (!(Sibling.IsOk()) && Parent.IsOk());
1972    // in case the loop ended with Sibling.IsOk() "Sibling" contains a valid sibling otherwise an invalid
1973     return Sibling;
1974   } /* if */
1975 } /* wxTreeMultiCtrl::GetPrevious(wxTreeMultiItem const&) const */
1976
1977 // WDR: handler implementations for wxTreeMultiCtrl
1978
1979 void wxTreeMultiCtrl::OnDraw(wxDC& dc)
1980 {
1981         // go recursive and draw the whole visible tree.
1982         dc.SetFont(_captionFont);
1983         for(int i = 0; i < _root.GetNodeCount(); i++)
1984                 DrawNode(_root.GetNode(i), dc);
1985 } /*  */