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