1 //---------------------------------------------------------------------------
2 // $RCSfile: wxTreeMultiCtrl.cpp,v $
3 // $Source: /cvs/creatis/bbtk/kernel/src/ThirdParty/wx/treemultictrl/wxTreeMultiCtrl.cpp,v $
5 // $Date: 2009/10/05 22:44:50 $
6 //---------------------------------------------------------------------------
7 // Author: Jorgen Bodde
8 // Copyright: (c) Jorgen Bodde
9 // License: wxWidgets License
10 //---------------------------------------------------------------------------
13 #pragma implementation "wxTreeMultiCtrl.h"
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
18 #include "wx/treebase.h"
24 #include "wx/arrimpl.cpp"
26 #include "wx/treemultictrl/wxTreeMultiCtrl.h"
27 #include "wx/treemultictrl/wxTreeMultiEvent.h"
28 #include "tmcimages.h"
32 //----------------------------------------------------------------------------
34 //----------------------------------------------------------------------------
36 WX_DEFINE_OBJARRAY(wxArrayTreeMultiItem);
38 //----------------------------------------------------------------------------
40 //----------------------------------------------------------------------------
42 IMPLEMENT_DYNAMIC_CLASS(wxTreeMultiCtrl, wxScrolledWindow)
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)
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 )
58 wxScrolledWindow::Create( parent, id, pos, size, style | wxTAB_TRAVERSAL, name);
60 _create_called = true;
68 void wxTreeMultiCtrl::Init()
83 _checkboxView = false;
86 _gutterWidth = WXTMC_GUTTER_DEFAULT;
91 _spacingY = WXTMC_YSPACING_DEFAULT;
94 // create two bitmap nodes for drawing
96 _expandBmp = new wxBitmap(expand_xpm);
97 _collBmp = new wxBitmap(collapse_xpm);
99 // calculate average font height for bitmap centering
101 _iconWidth = _expandBmp->GetWidth();
102 _iconHeight = _expandBmp->GetHeight();
105 // create bitmaps for checkboxes
106 _checkBmp = new wxBitmap(checked_icon);
107 _uncheckBmp = new wxBitmap(unchecked_icon);
108 _tristateBmp = new wxBitmap(tristate_icon);
110 // adjust the height if the checkboxes are higher
111 // so that everything is alligned properly
112 _checkHeight = _checkBmp->GetHeight();
113 _checkWidth = _checkBmp->GetWidth();
116 // remember the highest of the two bitmaps so there is
117 // always enough room
118 _maxHeight = _iconHeight;
121 if(_maxHeight < _checkHeight)
122 _maxHeight = _checkHeight;
125 // set standard highlighting brush
126 this->m_HilightBrush = new wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT),wxSOLID);
128 // set standard DC font
129 _captionFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
131 // adjust bitmap icon y position so they are centered
134 // set virtual size to this window size
135 if (_create_called) {
136 wxSize wndsize = GetSize();
137 SetVirtualSize(wndsize.GetWidth(), wndsize.GetWidth());
141 void wxTreeMultiCtrl::SetCaptionFont(const wxFont &font)
145 // adjust the icons so that they are in the middle
151 void wxTreeMultiCtrl::AdjustIconsDeltaY()
155 if(_captionFont.Ok())
156 GetTextExtent(wxT("jG"), &x, &y, 0, 0, &_captionFont);
159 if(_maxHeight < _captionHeight)
160 _maxHeight = _captionHeight;
162 // determine the center pos for the [+]
163 _iconDeltaY = abs(_maxHeight - _iconHeight) / 2 + 1;
168 // determine the center pos for the checkbox
169 _checkDeltaY = abs(_maxHeight - _checkHeight) / 2 + 1;
175 wxTreeMultiCtrl::~wxTreeMultiCtrl()
177 // delete the bitmap resources
188 wxTreeMultiItem wxTreeMultiCtrl::AddRoot(const wxString &caption, const wxString &name)
190 wxTreeMultiItem result((TreeMultiItemBase *)&_root);
191 result = AppendNode(result, caption, name);
196 wxTreeMultiItem wxTreeMultiCtrl::AppendWindow(const wxTreeMultiItem &ParentItem, wxWindow *window, const wxString &name, const wxTreeMultiWindowInfo &info, int flags)
198 // add window only if the parent item is valid and...
199 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
201 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
204 wxCHECK(parent != NULL, wxTreeMultiItem(0));
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;
214 wxTreeMultiItem wxTreeMultiCtrl::InsertWindow(wxTreeMultiItem const& ParentItem, size_t Position, wxWindow *window, wxString const& name, wxTreeMultiWindowInfo const& info, int flags)
216 // add window only if the parent item is valid and...
217 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
219 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
222 wxCHECK(parent != NULL, wxTreeMultiItem(0));
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) */
232 wxTreeMultiItem wxTreeMultiCtrl::PrependWindow(wxTreeMultiItem const& ParentItem, wxWindow *window, const wxString &name, wxTreeMultiWindowInfo const& info, int flags)
234 // add window only if the parent item is valid and...
235 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
237 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
240 wxCHECK(parent != NULL, wxTreeMultiItem(0));
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) */
250 wxTreeMultiItem wxTreeMultiCtrl::AppendNode(wxTreeMultiItem const& ParentItem, const wxString &caption, const wxString &name)
252 // add window only if the parent item is valid and...
253 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
255 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
258 wxCHECK(parent != NULL, wxTreeMultiItem(0));
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:
266 } /* wxTreeMultiCtrl::AppendNode(wxTreeMultiItem const&, const wxString &, const wxString&) */
268 wxTreeMultiItem wxTreeMultiCtrl::InsertNode(wxTreeMultiItem const& ParentItem, size_t Position, wxString const& caption, wxString const& name)
270 // add window only if the parent item is valid and...
271 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
273 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
276 wxCHECK(parent != NULL, wxTreeMultiItem(0));
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:
284 } /* wxTreeMultiCtrl::InsertNode(wxTreeMultiItem const&, size_t, wxString const&, wxString const&) */
286 wxTreeMultiItem wxTreeMultiCtrl::PrependNode(wxTreeMultiItem const& ParentItem, wxString const& caption, wxString const& name)
288 // add window only if the parent item is valid and...
289 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
291 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
294 wxCHECK(parent != NULL, wxTreeMultiItem(0));
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:
302 } /* wxTreeMultiCtrl::PrependNode(wxTreeMultiItem const&, wxString const&, wxString const&) */
304 bool wxTreeMultiCtrl::Delete(wxTreeMultiItem &item)
307 wxCHECK(item.IsOk(), false);
309 wxTreeMultiItem nullItem(0);
312 // if item has been selected, remove it from the selected list:
313 size_t ItemIndex(this->GetSelectedItemIndex(item));
315 if (ItemIndex != this->GetSelectedItemCount())
316 this->m_SelectedItems.RemoveAt(ItemIndex);
318 // get parent, to delete item from
319 TreeMultiItemNode *p = item.GetItem()->GetParent();
321 // first check if it was visible, if so from the parent off
322 // it needs redrawing
323 redraw = item.GetItem()->IsVisible();
325 p->DeleteNode(item.GetItem());
327 _root.DeleteNode(item.GetItem());
331 // do redraw when node was visible
338 void wxTreeMultiCtrl::DeleteChildren(const wxTreeMultiItem &item)
340 if(item.IsNodeItem())
342 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
344 // remove all children from the selected item list:
345 if (n->GetNodeCount() > 0)
347 // variable definitions and initializations:
349 wxTreeMultiItem FirstItemIterator(this->GetFirstChild(item,Cookie)), LastItemIterator(this->GetLastChild(item));
353 size_t ItemIndex(this->GetSelectedItemIndex(item)); // variable definition and initialization
355 if (ItemIndex != this->GetSelectedItemCount())
356 this->m_SelectedItems.RemoveAt(ItemIndex);
357 if (FirstItemIterator == LastItemIterator)
358 break; // all children checked
360 FirstItemIterator = this->GetNext(FirstItemIterator);
370 void wxTreeMultiCtrl::Expand(const wxTreeMultiItem &item, bool recursive)
374 TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();
376 n = item.GetItem()->GetParent();
377 DoFold(n, true, recursive);
378 RedrawFromNode(item.GetItem()->IsTreeMultiItemNode());
382 void wxTreeMultiCtrl::Collapse(const wxTreeMultiItem &item, bool recursive)
386 TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();
388 n = item.GetItem()->GetParent();
389 DoFold(n, false, recursive);
390 RedrawFromNode(item.GetItem()->IsTreeMultiItemNode());
395 void wxTreeMultiCtrl::ExpandNodes(bool recursive)
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);
403 void wxTreeMultiCtrl::CollapseNodes(bool recursive)
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);
411 void wxTreeMultiCtrl::CollapseAndReset(const wxTreeMultiItem &item)
413 if(item.IsNodeItem())
415 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
419 Collapse(item, false);
423 // Selection manipulation
424 wxTreeMultiItem wxTreeMultiCtrl::GetFirstSelectedItem(void) const
426 if (this->GetSelectedItemCount() > 0)
427 return this->m_SelectedItems[0];
429 return wxTreeMultiItem();
430 } /* wxTreeMultiCtrl::GetFirstSelectedItem(void) const */
432 wxTreeMultiItem wxTreeMultiCtrl::GetLastSelectedItem(void) const
434 if (this->GetSelectedItemCount() > 0)
435 return this->m_SelectedItems[this->GetSelectedItemCount()-1];
437 return wxTreeMultiItem();
438 } /* wxTreeMultiCtrl::GetLastSelectedItem(void) const */
440 wxTreeMultiItem wxTreeMultiCtrl::GetSelectedItem(size_t Index) const
442 if (Index < this->GetSelectedItemCount())
443 return this->m_SelectedItems[Index];
445 return wxTreeMultiItem();
446 } /* wxTreeMultiCtrl::GetSelectedItem(size_t Index) const */
448 size_t wxTreeMultiCtrl::GetSelectedItemIndex(wxTreeMultiItem const& Item) const
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();
457 while ((Index < NoOfSelectedItems) && (this->m_SelectedItems[Index] != Item))
460 } /* wxTreeMultiCtrl::GetSelectedItemIndex(wxTreeMultiItem const&) const */
462 void wxTreeMultiCtrl::SelectItem(wxTreeMultiItem const& Item, bool UnselectOthers, bool ExpandSelection)
464 TreeMultiItemNode* NodePtr(Item.GetItem()->IsTreeMultiItemNode());
467 // only nodes can be selected and they can only be selected if they are not already selected:
468 if ((NodePtr == NULL) || NodePtr->IsSelected())
471 // inform that we are about to change:
472 wxTreeMultiEvent Event(wxEVT_COMMAND_TREE_MULTI_SEL_CHANGING,Item); // variable definition and initialization
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()))
480 // make sure that the to be selected item can be seen:
483 // variable definition and initialization:
484 wxTreeMultiItem ExcludedParent(this->GetExcludedParent(Item));
486 while (ExcludedParent.IsOk())
488 this->Include(ExcludedParent);
489 ExcludedParent = this->GetExcludedParent(Item);
492 // unselect items if necessary:
495 // expand selection if necessary:
498 // variable definition:
499 wxTreeMultiItem FirstItemIterator, LastItemIterator;
500 wxTreeMultiItem LastSelectedItem;
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();
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())
510 FirstItemIterator = LastSelectedItem;
511 LastItemIterator = Item;
515 FirstItemIterator = Item;
516 LastItemIterator = LastSelectedItem;
518 // select all items that are a node and are placed between the two limiting iterators (included the limits):
521 if (!(FirstItemIterator.IsSelected()) && FirstItemIterator.IsNodeItem())
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()));
528 if (FirstItemIterator == LastItemIterator)
530 // continue iterating:
531 FirstItemIterator = this->GetNext(FirstItemIterator);
534 else // select passed item only
537 this->m_SelectedItems.Add(NodePtr);
538 this->RefreshRect(wxRect(NodePtr->GetX(),NodePtr->GetY(),NodePtr->GetWidth(),NodePtr->GetHeight()));
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) */
546 void wxTreeMultiCtrl::UnselectAll(void)
548 const size_t NoOfSelectedItems = this->m_SelectedItems.GetCount();
551 for (size_t i=0; i<NoOfSelectedItems; ++i)
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();
557 this->m_SelectedItems.Clear();
558 } /* wxTreeMultiCtrl::UnselectAll(void) */
560 void wxTreeMultiCtrl::Unselect(wxTreeMultiItem const& Item)
562 size_t ItemIndex(this->GetSelectedItemIndex(Item));
565 if (ItemIndex != this->GetSelectedItemCount())
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()));
571 } /* wxTreeMultiCtrl::Unselect(wxTreeMultiItem const&) */
573 void wxTreeMultiCtrl::DoFold(TreeMultiItemBase *item, bool expand, bool recursive)
576 // go through all node objects on this level, and expand or
582 // if this is a node, use it to go through all the subnodes (if needed)
583 // if not, then just exit.
585 TreeMultiItemNode *node = item->IsTreeMultiItemNode();
593 TreeMultiItemNode *p;
594 for(int i = 0; i < node->GetNodeCount(); i++)
596 // get node, and if a real node, then call fold
597 p = node->GetNode(i)->IsTreeMultiItemNode();
601 // go recursive for every node
602 DoFold(p, expand, recursive);
608 void wxTreeMultiCtrl::Exclude(const wxTreeMultiItem &item)
610 wxCHECK2(item.IsOk(), return);
612 // exclude the item, and refresh
613 // if already excluded, skip
615 if(!item.GetItem()->IsExcluded())
617 item.GetItem()->SetExcluded(true);
618 RedrawFromParentNode(item.GetItem());
622 void wxTreeMultiCtrl::Include(const wxTreeMultiItem &item)
624 wxCHECK2(item.IsOk(), return);
626 // include the item, and refresh. If not
627 // excluded, do nothing
629 if(item.GetItem()->IsExcluded())
631 item.GetItem()->SetExcluded(false);
632 RedrawFromParentNode(item.GetItem());
636 wxTreeMultiItem wxTreeMultiCtrl::GetExcludedParent(const wxTreeMultiItem &item)
638 wxCHECK(item.IsOk(), wxTreeMultiItem(0));
640 // go find the parent (including this one) that
641 // can be the excluded one
643 TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();
644 if(n && n->IsExcluded())
645 return wxTreeMultiItem(n);
647 n = item.GetItem()->GetParent();
651 return wxTreeMultiItem(n);
656 return wxTreeMultiItem(0);
659 void wxTreeMultiCtrl::OnSize(wxSizeEvent &WXUNUSED(event))
661 RecalculateSpanSizes();
664 void wxTreeMultiCtrl::OnPaint(wxPaintEvent& WXUNUSED(event) )
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);
676 void wxTreeMultiCtrl::DrawNode(TreeMultiItemBase *b, wxDC &dc)
678 // go through this item .. if it is a node, draw
679 // the caption, else reposition the window.
684 // forget it if this node is not visible
687 int bmpOffsetX = b->GetX() - (_gutterWidth + _iconWidth);
690 // now draw the checkbox if there is any, in the proper state
695 // adjust the bmpOffset because we also have a checkbox
696 bmpOffsetX -= _checkWidth;
700 if(b->IsTreeMultiItemNode())
702 // draw the node icon and the caption
703 TreeMultiItemNode *n = (TreeMultiItemNode *)b;
705 // set background of caption item
708 dc.SetBrush(*(this->m_HilightBrush));
709 dc.SetPen(wxPen(this->m_HilightBrush->GetColour(),1,wxSOLID));
713 dc.SetBrush(wxBrush(*wxWHITE,wxSOLID));
714 dc.SetPen(wxPen(*wxWHITE,1,wxSOLID));
716 dc.DrawRectangle(n->GetX(),n->GetY(),n->GetWidth(),n->GetHeight());
718 dc.DrawText(n->GetCaption(), n->GetX(), n->GetY());
720 // draw the bitmap for the state
722 dc.DrawBitmap(*_expandBmp, bmpOffsetX, n->GetY() + _iconDeltaY, true);
724 dc.DrawBitmap(*_collBmp, bmpOffsetX, n->GetY() + _iconDeltaY, true);
726 // now go through all the subnodes
727 for(int i = 0; i < n->GetNodeCount(); i++)
728 DrawNode(n->GetNode(i), dc);
736 void wxTreeMultiCtrl::DrawCheckbox(TreeMultiItemBase *b, wxDC &dc, bool convertScrolled)
741 int bmpOffsetX = b->GetX() - (_gutterWidth + _iconWidth);
743 switch(b->GetCheckboxState())
758 if(b->IsTreeMultiItemWindow())
760 xx = x = bmpOffsetX - ((TreeMultiItemWindow *)b)->GetFrontSpacing() + _checkWidth;
761 yy = y = b->GetY() + _checkDeltaY;
766 yy = y = b->GetY() + _checkDeltaY;
770 CalcScrolledPosition(x, y, &xx, &yy);
772 dc.DrawBitmap(*bmp, xx, yy, true);
775 #endif // #if(CHECKBOXVIEW)
777 void wxTreeMultiCtrl::OnKey(wxKeyEvent &event)
779 // check if we need to traverse to upper or lower
780 // control in the list
781 if(event.GetKeyCode() == WXK_TAB)
783 wxTreeMultiItem item = GetFocus();
786 // traverse down direction
787 if(!event.ShiftDown())
788 item = FindNextVisibleWindowItem(item.GetItem());
789 //else // traverse in up direction
790 // item = FindPreviousVisibleWindowItem(item);
794 TreeMultiItemWindow *w = item.GetItem()->IsTreeMultiItemWindow();
797 wxWindow *wnd = w->GetWindow();
807 void wxTreeMultiCtrl::OnMouseClick( wxMouseEvent &event )
809 // react on double click and left mouse down
810 if(event.LeftDown() || event.LeftDClick())
812 // get translation point
813 wxPoint pt( event.GetPosition() );
816 CalcUnscrolledPosition( pt.x, pt.y, &x, &y );
818 // go check if we clicked a treenode
821 wxTreeMultiItem id = HitTest(p, flags);
824 if(flags == wxTMC_HITTEST_CHECKBOX)
826 // toggle the checkbox, and redraw
829 TreeMultiItemBase *b = id.GetItem();
830 b->SetCheckboxState((b->GetCheckboxState()+1) & 0x1);
832 TreeMultiItemWindow *w = b->IsTreeMultiItemWindow();
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();
841 // draw the checkbox in the state needed
843 DrawCheckbox(b, dc, true);
845 // TODO: determine if the upper parents should be
848 ScanTristateCheckstates(b);
851 else if(b->IsTreeMultiItemNode())
853 // descend to all the children and set the state of the parent
854 SetRecursiveCheckState((TreeMultiItemNode *)b, b->GetCheckboxState() == 1);
855 RedrawFromNode((TreeMultiItemNode *)b);
860 #endif // #if(CHECKBOXVIEW)
862 // react on left mouse button, to fold and on
863 // right for caption doubleclick
866 // adjust behaviour for Linux (single click = always fold)
868 if(event.LeftDClick())
869 area = wxTMC_HITTEST_CAPTION;
871 area = wxTMC_HITTEST_GUTTER;
876 // Linux (single or double click -> always fold
880 // we have a valid item, if it is a node, then fold
881 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode();
884 this->SelectItem(id);
885 Fold(n, !n->IsExpanded());
888 if (event.LeftDown())
889 if (flags == wxTMC_HITTEST_GUTTER)
891 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode(); // for some reasons also windows may have set the flag
894 Fold(n, !n->IsExpanded());
896 else if (flags == wxTMC_HITTEST_CAPTION)
898 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode(); // for some reasons also windows may have set the flag
902 this->SelectItem(id);
903 this->RedrawFromNode(n);
914 void wxTreeMultiCtrl::OnRightMouseClick(wxMouseEvent& Event)
916 if (Event.RightDown())
917 if (Event.Dragging())
921 // variable definitions:
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
930 if (Item.IsOk() && (Flags == wxTMC_HITTEST_CAPTION))
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
942 } /* wxTreeMultiCtrl::OnRightMouseClick(wxMouseEvent&) */
944 wxTreeMultiItem wxTreeMultiCtrl::HitTest(wxPoint const& pt, int &flags)
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);
955 return wxTreeMultiItem(0);
959 return wxTreeMultiItem(b);
962 TreeMultiItemBase *wxTreeMultiCtrl::FindNodeByPoint(TreeMultiItemBase *b, wxPoint const& pt, int &area)
966 // if this layer is not visible, return with nothing.
972 // now see if our y is matching the mouse
973 if(pt.y >= b->GetY() && pt.y < (b->GetY() + b->GetHeight()))
976 // if we are checkboxed, calculate the checkbox position
979 int extraSpacing = 0, extraWidth = 0;
981 // now for a windows item, this is minus the gutter. For a normal node it is X minus checkbox
982 if(b->IsTreeMultiItemWindow())
984 extraWidth = _checkWidth;
985 extraSpacing = ((TreeMultiItemWindow *)b)->GetFrontSpacing();
990 if(pt.x > (b->GetX() - extraSpacing - _checkWidth) && pt.x < (b->GetX() - extraSpacing + extraWidth))
992 area = wxTMC_HITTEST_CHECKBOX;
998 // allrighty we have something, now where and what is it (look with x)
1000 area = wxTMC_HITTEST_GUTTER;
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.
1008 // inside area, return proper flag
1009 if(b->IsTreeMultiItemNode())
1010 area = wxTMC_HITTEST_CAPTION;
1012 area = wxTMC_HITTEST_WINDOW;
1019 // not found, let's try our children if we have some
1020 TreeMultiItemNode *n = b->IsTreeMultiItemNode();
1023 TreeMultiItemBase *bb = 0;
1024 for(int i = 0; i < n->GetNodeCount() && !bb; i++)
1025 bb = FindNodeByPoint(n->GetNode(i), pt, area);
1027 // keep returning result to caller
1035 wxTreeMultiItem wxTreeMultiCtrl::GetFocus()
1037 wxWindow *wnd = wxWindow::FindFocus();
1039 // now find window that holds this item. if not
1040 // visible it cannot have focus (should not have)
1042 wxTreeMultiItem item = FindWindowNode(wnd);
1043 if(item.IsOk() && item.GetItem()->IsVisible())
1046 return wxTreeMultiItem(0);
1051 void wxTreeMultiCtrl::SetRecursiveCheckState(TreeMultiItemNode *n, bool check)
1057 // go check all kids on this level
1058 for(int i = 0; i < n->GetNodeCount(); i++)
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);
1067 void wxTreeMultiCtrl::ScanTristateCheckstates(TreeMultiItemBase *b)
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();
1073 if(p && p->GetCheckbox())
1075 bool foundcheck = false, foundclear = false;
1076 for(size_t i = 0; i < (size_t)p->GetNodeCount(); ++i)
1078 // only evaluate when checkboxed
1079 if(p->GetNode(i)->IsTreeMultiItemWindow() && p->GetNode(i)->GetCheckbox())
1081 // record instance of a cleared checkbox
1082 if(!p->GetNode(i)->GetCheckboxState())
1084 // record instance of checked checkbox
1085 if(p->GetNode(i)->GetCheckboxState() == 1)
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);
1100 //DrawCheckbox(p, dc, false);
1105 #endif // #if(CHECKBOXVIEW)
1107 wxTreeMultiItem wxTreeMultiCtrl::InsertNode(TreeMultiItemNode* ParentPtr, size_t Position, wxString const& Caption, wxString const& Name)
1111 TreeMultiItemNode* NodePtr(new TreeMultiItemNode(ParentPtr,Caption,Name)); // generate new node pointer
1114 // continue with initializing the new node:
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);
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);
1129 ParentPtr->AddNode(NodePtr);
1130 // return the newly created node:
1131 return wxTreeMultiItem(NodePtr);
1132 } /* wxTreeMultiCtrl::InsertNode(TreeMultiItemNode*, size_t, wxString const&, wxString const&) */
1134 wxTreeMultiItem wxTreeMultiCtrl::InsertWindow(TreeMultiItemNode* ParentPtr, size_t Position, wxWindow* WindowPtr, wxString const& Name, wxTreeMultiWindowInfo const& Info, int Flags)
1138 TreeMultiItemWindow* NewWindowPtr = new TreeMultiItemWindow(ParentPtr,Name); // generate new window pointer
1141 // get flags from passed variable "Flags"; in case this variable does not contain any flags use the window's information flags:
1143 WindowFlags = Flags;
1145 WindowFlags = Info.GetFlags();
1147 // continue with initializing the new window:
1149 // if checkbox view is desired, tag this item as a checkbox
1150 // and set the state as 'false'
1151 NewWindowPtr->SetCheckbox(_checkboxView);
1153 // if style wants us to change background, set it to our background
1154 if (WindowFlags & wxTMC_BG_ADJUST_ALL)
1156 // go through all children of this window, and set the
1157 // background of it (recursively)
1158 this->SetWindowBackgroundColour(WindowPtr,this->GetBackgroundColour(),WindowFlags);
1162 NewWindowPtr->SetTopSpacing(Info.GetTopSpacing());
1164 // make sure that the checkboxes are at least indented enough
1165 if (this->_checkboxView)
1166 NewWindowPtr->SetFrontSpacing(Info.GetFrontSpacing() + this->_checkWidth);
1169 NewWindowPtr->SetFrontSpacing(Info.GetFrontSpacing());
1170 // assign finally the window:
1171 NewWindowPtr->AssignWindow(WindowPtr);
1174 // set the checkbox state after the window is assigned
1175 NewWindowPtr->SetCheckboxState(Info.GetDefaultCheckState());
1178 // if the window is not visible, set hide flag
1179 this->ShowTreeMultiWindow(NewWindowPtr,NewWindowPtr->IsVisible());
1181 // finally, insert the newly constructed window:
1182 if (Position < (size_t)ParentPtr->GetNodeCount())
1183 ParentPtr->InsertNode(NewWindowPtr,Position);
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) */
1190 void wxTreeMultiCtrl::RedrawFromParentNode(TreeMultiItemBase *n)
1192 TreeMultiItemNode *p = 0;
1199 void wxTreeMultiCtrl::RedrawFromNode(TreeMultiItemNode *n)
1201 static int recalcMutex = 0;
1202 bool visible = true;
1209 // when node is not visible or excluded
1210 // then don't redraw.
1213 visible = n->IsVisible();
1218 GetVirtualSize(&w, &h);
1220 UpdateAllWindowVisibility();
1221 RecalculateNodePositions();
1222 RecalculateVirtualSize();
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);
1233 // only refresh the part from x,y down
1237 CalcScrolledPosition(n->GetX(), n->GetY(), &x, &y);
1240 wxRect rect(0, y, w, h - y);
1247 Refresh(); // do a full refresh
1253 void wxTreeMultiCtrl::RecalculateNodePositions()
1255 int currentY = _spacingY;
1256 // go recursive on every node, and store the information in the node
1258 for(int i = 0; i < _root.GetNodeCount(); i++)
1259 currentY += CalculateNodeDimensions(_root.GetNode(i), currentY, 0);
1262 int wxTreeMultiCtrl::CalculateNodeDimensions(TreeMultiItemBase *b, int currentY, int level)
1264 int gutter = (_gutterWidth * 2) + _iconWidth;
1265 int y = 0, topSpacing = 0;
1267 // return same if no proper object
1271 if(b->GetCheckbox())
1272 gutter += _checkWidth;
1275 // if we are not visible, skip recalculation and descending
1280 // if level is 0, calculate with front gutter, else without
1281 y = currentY + b->GetHeight();
1282 if(b->IsTreeMultiItemNode())
1284 TreeMultiItemNode *n = (TreeMultiItemNode *)b;
1289 b->SetX(gutter + (level * (_gutterWidth + _iconWidth)));
1291 // now do children of this node
1293 for(int i = 0; i < n->GetNodeCount(); i++)
1294 y += CalculateNodeDimensions(n->GetNode(i), y + _spacingY, level+1);
1296 else if(b->IsTreeMultiItemWindow())
1298 TreeMultiItemWindow *w = (TreeMultiItemWindow *)b;
1301 b->SetX(gutter + w->GetFrontSpacing());
1303 b->SetX(_gutterWidth + (level * (_gutterWidth + _iconWidth)) + w->GetFrontSpacing());
1305 topSpacing = w->GetTopSpacing();
1307 // reposition the window
1309 wxWindow *wnd = w->GetWindow();
1313 CalcScrolledPosition(w->GetX(), w->GetY(), &x, &y);
1314 wnd->SetSize(x, y, w->GetWidth(), w->GetHeight());
1319 return (y - currentY) + _spacingY + topSpacing; // return delta
1324 return 0; // not visible, thus we skip calculations
1327 void wxTreeMultiCtrl::RecalculateSpanSizes()
1329 for(int i = 0; i < _root.GetNodeCount(); i++)
1330 CalculateNodeSpanning(_root.GetNode(i));
1333 void wxTreeMultiCtrl::CalculateNodeSpanning(TreeMultiItemBase *b)
1335 // return same if no proper object
1336 wxCHECK2(b, return);
1338 if(b->IsTreeMultiItemNode())
1340 TreeMultiItemNode *n = (TreeMultiItemNode *)b;
1342 // now do children of this node
1344 for(int i = 0; i < n->GetNodeCount(); i++)
1345 CalculateNodeSpanning(n->GetNode(i));
1347 else if(b->IsTreeMultiItemWindow())
1349 TreeMultiItemWindow *w = (TreeMultiItemWindow *)b;
1350 wxWindow *wnd = w->GetWindow();
1353 // if the window is spanning, we adjust the width to the max width of the control
1354 if(w->GetHorizontalSpan())
1356 wxSize tmcsize = GetClientSize();
1357 int maxwidth = tmcsize.GetWidth() - w->GetX() - 8; // extract 3 for border
1359 wxSizer *sz = wnd->GetSizer();
1362 if(maxwidth < sz->GetMinSize().GetWidth())
1363 maxwidth = sz->GetMinSize().GetWidth();
1366 // prevent a size of 0
1371 w->SetWidth(maxwidth);
1372 wnd->SetSize(w->GetWidth(), w->GetHeight());
1374 // layout by sizer (not sure if this is needed)
1376 wnd->GetSizer()->Layout();
1382 void wxTreeMultiCtrl::RecalculateVirtualSize()
1384 // go through all the nodes, and store the largest x and largest y
1387 RecalculateVirtualSizeFromNode(&_root, x, y);
1389 // now adjust virtual size
1390 SetVirtualSize(x, y);
1391 AdjustScrollbars(x, y);
1394 void wxTreeMultiCtrl::AdjustScrollbars(int x, int y)
1396 // adjust scrollbars
1397 // courtesy of treectrlg.cpp
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 );
1407 void wxTreeMultiCtrl::RecalculateVirtualSizeFromNode(const TreeMultiItemNode *node, int &x, int &y)
1409 if(node->IsExcluded())
1412 // if calulate this node's dimensions
1413 if(x < (node->GetWidth() + node->GetX()))
1414 x = node->GetWidth() + node->GetX();
1416 y = node->GetY() + node->GetHeight();
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())
1422 TreeMultiItemBase *b;
1423 for(int i = 0; i < node->GetNodeCount(); i++)
1425 b = node->GetNode(i);
1427 // calculate x and y
1428 if(x < (b->GetWidth() + b->GetX()))
1429 x = b->GetWidth() + b->GetX();
1431 y = b->GetY() + b->GetHeight();
1433 if(b->IsTreeMultiItemNode())
1434 RecalculateVirtualSizeFromNode((TreeMultiItemNode *)b, x, y);
1439 void wxTreeMultiCtrl::SetWindowBackgroundColour(wxWindow *wnd, const wxColour &col, int flags)
1443 // if we cannot change a button, make sure all button
1444 // classes are not changed
1446 wxButton *btn = wxDynamicCast(wnd, wxButton);
1447 if(!btn || ((flags & wxTMC_BG_ADJUST_BTN) != 0))
1448 wnd->SetBackgroundColour(col);
1450 // get every window, and make the background equal to the given one
1451 wxWindowListNode *node = wnd->GetChildren().GetFirst();
1454 SetWindowBackgroundColour(node->GetData(), col, flags);
1455 node = node->GetNext();
1460 void wxTreeMultiCtrl::ShowTreeMultiWindow(TreeMultiItemWindow *window, bool show)
1462 // show or hide window
1463 if(window && window->GetWindow())
1464 window->GetWindow()->Show(show);
1467 void wxTreeMultiCtrl::UpdateAllWindowVisibility()
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);
1474 void wxTreeMultiCtrl::UpdateTreeMultiWindowVisibility(TreeMultiItemBase *b, bool show)
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)
1484 showMe = b->IsVisible();
1486 if(b->IsTreeMultiItemWindow())
1488 // if this level must be hidden, hide
1489 ShowTreeMultiWindow((TreeMultiItemWindow*)b, showMe);
1491 else if(b->IsTreeMultiItemNode())
1493 TreeMultiItemNode *node = (TreeMultiItemNode *)b;
1495 // if hidden, descend and hide all windows
1496 for(int i = 0; i < node->GetNodeCount(); i++)
1497 UpdateTreeMultiWindowVisibility(node->GetNode(i), showMe);
1502 wxTreeMultiItem wxTreeMultiCtrl::FindItem(const wxTreeMultiItem &item, const wxString &name, bool ignoreCase, bool skipFirst)
1506 TreeMultiItemBase *b = item.GetItem();
1508 // check this item first (or not)
1512 if(b->GetName().IsSameAs(name, !ignoreCase))
1513 return wxTreeMultiItem(b);
1516 if(b->IsTreeMultiItemNode())
1518 // now check whether we are a node, then go check children
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);
1529 return wxTreeMultiItem(0);
1532 wxTreeMultiItem wxTreeMultiCtrl::FindWindowNode(wxWindow *wnd, TreeMultiItemNode *n)
1534 wxCHECK(wnd, wxTreeMultiItem(0));
1536 // take root node if not assigned one
1539 n = (TreeMultiItemNode *)&_root;
1541 // check on this level for the wxWindow pointer
1543 TreeMultiItemWindow *w;
1544 wxTreeMultiItem result(0);
1545 for(int i = 0; i < n->GetNodeCount() && !result.IsOk(); i++)
1548 w = n->GetNode(i)->IsTreeMultiItemWindow();
1549 if(w && w->GetWindow() == wnd)
1550 return wxTreeMultiItem(n);
1552 // if node, go deeper
1553 if(n->GetNode(i)->IsTreeMultiItemNode())
1554 result = FindWindowNode(wnd, (TreeMultiItemNode*)n->GetNode(i));
1560 TreeMultiItemWindow *wxTreeMultiCtrl::FindNextVisibleWindowItem(TreeMultiItemBase *b, int index)
1564 // check on this level, go deeper with every node we got. When a node is not
1565 // visible anymore, skip the node.
1567 TreeMultiItemWindow *value = 0;
1570 // if we are already searching on a node with an index
1572 TreeMultiItemBase *bn = 0;
1573 TreeMultiItemNode *n = b->IsTreeMultiItemNode();
1576 for(int i = index + 1; i < n->GetNodeCount() && !value; i++)
1579 value = bn->IsTreeMultiItemWindow();
1581 // assume a node, root when not a a window
1583 value = FindNextVisibleWindowItem(bn, -1);
1589 if(b->IsTreeMultiItemWindow())
1591 // get parent first, and locate child as ptr
1592 TreeMultiItemNode *p = b->GetParent();
1595 // go scan the parent from the given index, if
1596 // the index is valid else there is no child with that index
1598 int idx = p->Index(b);
1599 wxCHECK(idx >= 0, 0);
1601 value = FindNextVisibleWindowItem(p, idx);
1610 bool wxTreeMultiCtrl::GetBooleanValue(int wndId)
1612 wxWindow *wnd = wxWindow::FindWindow(wndId);
1613 wxCHECK(wnd, false);
1615 // try a radio button
1616 wxRadioButton *b = wxDynamicCast(wnd, wxRadioButton);
1618 return b->GetValue();
1621 wxCheckBox *c = wxDynamicCast(wnd, wxCheckBox);
1623 return c->GetValue();
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
1631 // generate assert or just return with false
1635 void wxTreeMultiCtrl::SetBooleanValue(int wndId, bool value)
1637 wxWindow *wnd = wxWindow::FindWindow(wndId);
1638 wxCHECK2(wnd, return);
1640 // try a radio button
1641 wxRadioButton *b = wxDynamicCast(wnd, wxRadioButton);
1649 wxCheckBox *c = wxDynamicCast(wnd, wxCheckBox);
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
1663 wxCHECK2(0, return);
1666 void wxTreeMultiCtrl::SetTextValue(int wndId, const wxString &value)
1668 wxWindow *wnd = wxWindow::FindWindow(wndId);
1669 wxCHECK2(wnd, return);
1671 // try a radio button
1672 wxTextCtrl *t = wxDynamicCast(wnd, wxTextCtrl);
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
1686 wxCHECK2(0, return);
1689 wxString wxTreeMultiCtrl::GetTextValue(int wndId)
1691 wxWindow *wnd = wxWindow::FindWindow(wndId);
1692 wxCHECK(wnd, wxEmptyString);
1694 // try a radio button
1695 wxTextCtrl *t = wxDynamicCast(wnd, wxTextCtrl);
1697 return t->GetValue();
1700 wxChoice *c1 = wxDynamicCast(wnd, wxChoice);
1702 return c1->GetStringSelection();
1705 wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);
1707 return c2->GetStringSelection();
1710 wxListBox *l = wxDynamicCast(wnd, wxListBox);
1712 return l->GetStringSelection();
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
1720 // generate assert or just return with string
1721 wxCHECK(0, wxEmptyString);
1724 int wxTreeMultiCtrl::GetSelectionValue(int wndId)
1726 wxWindow *wnd = wxWindow::FindWindow(wndId);
1730 wxChoice *c1 = wxDynamicCast(wnd, wxChoice);
1732 return c1->GetSelection();
1735 wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);
1737 return c2->GetSelection();
1740 wxListBox *l = wxDynamicCast(wnd, wxListBox);
1742 return l->GetSelection();
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
1750 // generate assert or just return with string
1754 void wxTreeMultiCtrl::GetSelectionValues(int wndId, wxArrayInt &sels)
1758 wxWindow *wnd = wxWindow::FindWindow(wndId);
1759 wxCHECK2(wnd, return);
1762 wxListBox *l = wxDynamicCast(wnd, wxListBox);
1765 l->GetSelections(sels);
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
1775 // generate assert or just return with string
1776 wxCHECK2(0, return);
1779 void wxTreeMultiCtrl::SetSelectionValue(int wndId, int sel)
1781 wxWindow *wnd = wxWindow::FindWindow(wndId);
1782 wxCHECK2(wnd, return);
1785 wxChoice *c1 = wxDynamicCast(wnd, wxChoice);
1788 c1->SetSelection(sel);
1793 wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);
1796 c2->SetSelection(sel);
1801 wxListBox *l = wxDynamicCast(wnd, wxListBox);
1804 l->SetSelection(sel);
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
1814 // generate assert or just return with string
1815 wxCHECK2(0, return);
1819 wxTreeMultiItem wxTreeMultiCtrl::GetParent(wxTreeMultiItem const& item) const
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();
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 */
1829 wxTreeMultiItem wxTreeMultiCtrl::GetFirstChild(const wxTreeMultiItem &item, int &cookie) const
1831 if(item.IsNodeItem())
1833 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
1835 if(n->GetNodeCount() > 0)
1838 return wxTreeMultiItem(n->GetNode(0));
1842 // no children or no valid node
1844 return wxTreeMultiItem(0);
1847 wxTreeMultiItem wxTreeMultiCtrl::GetNextChild(const wxTreeMultiItem &item, int &cookie) const
1849 if(item.IsNodeItem())
1851 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
1853 if(cookie >= 0 && cookie < (n->GetNodeCount()-1))
1855 // increment cookie, return node
1857 return wxTreeMultiItem(n->GetNode(cookie));
1861 // end of query, or no valid node
1863 return wxTreeMultiItem(0);
1866 wxTreeMultiItem wxTreeMultiCtrl::GetLastChild(const wxTreeMultiItem &item) const
1868 if(item.IsNodeItem())
1870 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
1872 if(n->GetNodeCount() > 0)
1873 return wxTreeMultiItem(n->GetNode(n->GetNodeCount()-1));
1876 return wxTreeMultiItem(0);
1879 wxTreeMultiItem wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const& item) const
1881 // check if a valid item has been passed:
1883 return wxTreeMultiItem();
1885 TreeMultiItemNode* ParentPtr(item.GetItem()->GetParent());
1888 if (ParentPtr != NULL) // the parent pointer is only null if the passed item is the root
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
1893 if (NextItemIndex < ParentPtr->GetNodeCount())
1894 return ParentPtr->GetNode(NextItemIndex);
1896 return wxTreeMultiItem();
1899 return wxTreeMultiItem();
1900 } /* wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const&) const */
1902 wxTreeMultiItem wxTreeMultiCtrl::GetPrevSibling(wxTreeMultiItem const& item) const
1904 // check if a valid item has been passed:
1906 return wxTreeMultiItem();
1908 TreeMultiItemNode* ParentPtr(item.GetItem()->GetParent());
1911 if (ParentPtr != NULL)
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
1916 if (PrevItemIndex >= 0)
1917 return ParentPtr->GetNode(PrevItemIndex);
1919 return wxTreeMultiItem();
1922 return wxTreeMultiItem();
1923 } /* wxTreeMultiCtrl::GetPrevSibling(wxTreeMultiItem const&) const */
1925 wxTreeMultiItem wxTreeMultiCtrl::GetNext(wxTreeMultiItem const& item) const
1927 // check if a valid item has been passed:
1929 return wxTreeMultiItem();
1931 TreeMultiItemNode* NodePtr(item.GetItem()->IsTreeMultiItemNode()); // variable definition and initialization
1933 if ((NodePtr != NULL) && (NodePtr->GetNodeCount() > 0))
1934 return wxTreeMultiItem(NodePtr->First());
1937 // variable definitions and initializations:
1938 wxTreeMultiItem Parent(item);
1939 wxTreeMultiItem Sibling;
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
1949 } /* wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const&) const */
1951 wxTreeMultiItem wxTreeMultiCtrl::GetPrevious(wxTreeMultiItem const& item) const
1953 // check if a valid item has been passed:
1955 return wxTreeMultiItem();
1957 TreeMultiItemNode* NodePtr(item.GetItem()->IsTreeMultiItemNode()); // variable definition and initialization
1959 if ((NodePtr != NULL) && (NodePtr->GetNodeCount() > 0))
1960 return wxTreeMultiItem(NodePtr->Last());
1963 // variable definitions and initializations:
1964 wxTreeMultiItem Parent(item);
1965 wxTreeMultiItem Sibling;
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
1975 } /* wxTreeMultiCtrl::GetPrevious(wxTreeMultiItem const&) const */
1977 // WDR: handler implementations for wxTreeMultiCtrl
1979 void wxTreeMultiCtrl::OnDraw(wxDC& dc)
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);