1 //---------------------------------------------------------------------------
\r
2 // $RCSfile: wxTreeMultiCtrl.cpp,v $
\r
3 // $Source: /cvs/creatis/bbtk/kernel/src/ThirdParty/wx/treemultictrl/wxTreeMultiCtrl.cpp,v $
\r
5 // $Date: 2008/03/28 13:42:19 $
\r
6 //---------------------------------------------------------------------------
\r
7 // Author: Jorgen Bodde
\r
8 // Copyright: (c) Jorgen Bodde
\r
9 // License: wxWidgets License
\r
10 //---------------------------------------------------------------------------
\r
13 #pragma implementation "wxTreeMultiCtrl.h"
\r
16 // For compilers that support precompilation, includes "wx/wx.h".
\r
17 #include "wx/wxprec.h"
\r
18 #include "wx/treebase.h"
\r
24 #include "wx/arrimpl.cpp"
\r
26 #include "wx/treemultictrl/wxTreeMultiCtrl.h"
\r
27 #include "wx/treemultictrl/wxTreeMultiEvent.h"
\r
28 #include "tmcimages.h"
\r
32 //----------------------------------------------------------------------------
\r
34 //----------------------------------------------------------------------------
\r
36 WX_DEFINE_OBJARRAY(wxArrayTreeMultiItem);
\r
38 //----------------------------------------------------------------------------
\r
40 //----------------------------------------------------------------------------
\r
42 IMPLEMENT_DYNAMIC_CLASS(wxTreeMultiCtrl, wxScrolledWindow)
\r
44 // WDR: event table for wxTreeMultiCtrl
\r
45 BEGIN_EVENT_TABLE(wxTreeMultiCtrl, wxScrolledWindow)
\r
46 EVT_LEFT_DOWN (wxTreeMultiCtrl::OnMouseClick)
\r
47 EVT_LEFT_DCLICK(wxTreeMultiCtrl::OnMouseClick)
\r
48 EVT_RIGHT_DOWN (wxTreeMultiCtrl::OnRightMouseClick)
\r
49 EVT_PAINT(wxTreeMultiCtrl::OnPaint)
\r
50 EVT_SIZE(wxTreeMultiCtrl::OnSize)
\r
51 // EVT_KEY_UP(wxTreeMultiCtrl::OnKey)
\r
54 bool wxTreeMultiCtrl::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos,
\r
55 const wxSize& size, long style, const wxValidator & WXUNUSED(validator),
\r
56 const wxString& name )
\r
58 wxScrolledWindow::Create( parent, id, pos, size, style | wxTAB_TRAVERSAL, name);
\r
60 _create_called = true;
\r
68 void wxTreeMultiCtrl::Init()
\r
83 _checkboxView = false;
\r
86 _gutterWidth = WXTMC_GUTTER_DEFAULT;
\r
91 _spacingY = WXTMC_YSPACING_DEFAULT;
\r
92 _captionHeight = 13;
\r
94 // create two bitmap nodes for drawing
\r
96 _expandBmp = new wxBitmap(expand_xpm);
\r
97 _collBmp = new wxBitmap(collapse_xpm);
\r
99 // calculate average font height for bitmap centering
\r
101 _iconWidth = _expandBmp->GetWidth();
\r
102 _iconHeight = _expandBmp->GetHeight();
\r
105 // create bitmaps for checkboxes
\r
106 _checkBmp = new wxBitmap(checked_icon);
\r
107 _uncheckBmp = new wxBitmap(unchecked_icon);
\r
108 _tristateBmp = new wxBitmap(tristate_icon);
\r
110 // adjust the height if the checkboxes are higher
\r
111 // so that everything is alligned properly
\r
112 _checkHeight = _checkBmp->GetHeight();
\r
113 _checkWidth = _checkBmp->GetWidth();
\r
116 // remember the highest of the two bitmaps so there is
\r
117 // always enough room
\r
118 _maxHeight = _iconHeight;
\r
121 if(_maxHeight < _checkHeight)
\r
122 _maxHeight = _checkHeight;
\r
125 // set standard highlighting brush
\r
126 this->m_HilightBrush = new wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT),wxSOLID);
\r
128 // set standard DC font
\r
129 _captionFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
\r
131 // adjust bitmap icon y position so they are centered
\r
132 AdjustIconsDeltaY();
\r
134 // set virtual size to this window size
\r
135 if (_create_called) {
\r
136 wxSize wndsize = GetSize();
\r
137 SetVirtualSize(wndsize.GetWidth(), wndsize.GetWidth());
\r
141 void wxTreeMultiCtrl::SetCaptionFont(const wxFont &font)
\r
143 _captionFont = font;
\r
145 // adjust the icons so that they are in the middle
\r
146 AdjustIconsDeltaY();
\r
151 void wxTreeMultiCtrl::AdjustIconsDeltaY()
\r
155 if(_captionFont.Ok())
\r
156 GetTextExtent(wxT("jG"), &x, &y, 0, 0, &_captionFont);
\r
157 _captionHeight = y;
\r
159 if(_maxHeight < _captionHeight)
\r
160 _maxHeight = _captionHeight;
\r
162 // determine the center pos for the [+]
\r
163 _iconDeltaY = abs(_maxHeight - _iconHeight) / 2 + 1;
\r
164 if(_iconDeltaY < 1)
\r
168 // determine the center pos for the checkbox
\r
169 _checkDeltaY = abs(_maxHeight - _checkHeight) / 2 + 1;
\r
170 if(_checkDeltaY < 1)
\r
175 wxTreeMultiCtrl::~wxTreeMultiCtrl()
\r
177 // delete the bitmap resources
\r
183 delete _uncheckBmp;
\r
184 delete _tristateBmp;
\r
188 wxTreeMultiItem wxTreeMultiCtrl::AddRoot(const wxString &caption, const wxString &name)
\r
190 wxTreeMultiItem result((TreeMultiItemBase *)&_root);
\r
191 result = AppendNode(result, caption, name);
\r
196 wxTreeMultiItem wxTreeMultiCtrl::AppendWindow(const wxTreeMultiItem &ParentItem, wxWindow *window, const wxString &name, const wxTreeMultiWindowInfo &info, int flags)
\r
198 // add window only if the parent item is valid and...
\r
199 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
\r
201 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
\r
204 wxCHECK(parent != NULL, wxTreeMultiItem(0));
\r
206 // now, append node to the tree control:
\r
207 wxTreeMultiItem NewWindowItem(this->InsertWindow(parent,wx_static_cast(size_t,parent->GetNodeCount()),window,name,info,flags));
\r
208 // redraw the stucture:
\r
209 this->RedrawFromNode(parent);
\r
210 // return the new window
\r
211 return NewWindowItem;
\r
214 wxTreeMultiItem wxTreeMultiCtrl::InsertWindow(wxTreeMultiItem const& ParentItem, size_t Position, wxWindow *window, wxString const& name, wxTreeMultiWindowInfo const& info, int flags)
\r
216 // add window only if the parent item is valid and...
\r
217 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
\r
219 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
\r
222 wxCHECK(parent != NULL, wxTreeMultiItem(0));
\r
224 // now, append node to the tree control:
\r
225 wxTreeMultiItem NewWindowItem(this->InsertWindow(parent,Position,window,name,info,flags));
\r
226 // redraw the stucture:
\r
227 this->RedrawFromNode(parent);
\r
228 // return the new window
\r
229 return NewWindowItem;
\r
230 } /* wxTreeMultiCtrl::InsertWindow(wxTreeMultiItem const&, size_t, wxWindow*, wxString const&, wxTreeMultiWindowInfo const&, int) */
\r
232 wxTreeMultiItem wxTreeMultiCtrl::PrependWindow(wxTreeMultiItem const& ParentItem, wxWindow *window, const wxString &name, wxTreeMultiWindowInfo const& info, int flags)
\r
234 // add window only if the parent item is valid and...
\r
235 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
\r
237 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
\r
240 wxCHECK(parent != NULL, wxTreeMultiItem(0));
\r
242 // now, append node to the tree control:
\r
243 wxTreeMultiItem NewWindowItem(this->InsertWindow(parent,0,window,name,info,flags));
\r
244 // redraw the stucture:
\r
245 this->RedrawFromNode(parent);
\r
246 // return the new window
\r
247 return NewWindowItem;
\r
248 } /* wxTreeMultiCtrl::PrependWindow(wxTreeMultiItem const&, wxWindow*, const wxString &, wxTreeMultiWindowInfo const&, int) */
\r
250 wxTreeMultiItem wxTreeMultiCtrl::AppendNode(wxTreeMultiItem const& ParentItem, const wxString &caption, const wxString &name)
\r
252 // add window only if the parent item is valid and...
\r
253 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
\r
255 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
\r
258 wxCHECK(parent != NULL, wxTreeMultiItem(0));
\r
260 // now, append node to the tree control:
\r
261 wxTreeMultiItem NewNodeItem(this->InsertNode(parent,wx_static_cast(size_t,parent->GetNodeCount()),caption,name));
\r
262 // redraw the structure:
\r
263 this->RedrawFromNode(parent);
\r
264 // return the new node:
\r
265 return NewNodeItem;
\r
266 } /* wxTreeMultiCtrl::AppendNode(wxTreeMultiItem const&, const wxString &, const wxString&) */
\r
268 wxTreeMultiItem wxTreeMultiCtrl::InsertNode(wxTreeMultiItem const& ParentItem, size_t Position, wxString const& caption, wxString const& name)
\r
270 // add window only if the parent item is valid and...
\r
271 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
\r
273 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
\r
276 wxCHECK(parent != NULL, wxTreeMultiItem(0));
\r
278 // now, append node to the tree control:
\r
279 wxTreeMultiItem NewNodeItem(this->InsertNode(parent,Position,caption,name));
\r
280 // redraw the structure:
\r
281 this->RedrawFromNode(parent);
\r
282 // return the new node:
\r
283 return NewNodeItem;
\r
284 } /* wxTreeMultiCtrl::InsertNode(wxTreeMultiItem const&, size_t, wxString const&, wxString const&) */
\r
286 wxTreeMultiItem wxTreeMultiCtrl::PrependNode(wxTreeMultiItem const& ParentItem, wxString const& caption, wxString const& name)
\r
288 // add window only if the parent item is valid and...
\r
289 wxCHECK(ParentItem.IsOk(), wxTreeMultiItem(0));
\r
291 TreeMultiItemNode* parent = ParentItem.GetItem()->IsTreeMultiItemNode(); // also roots are nodes
\r
294 wxCHECK(parent != NULL, wxTreeMultiItem(0));
\r
296 // now, append node to the tree control:
\r
297 wxTreeMultiItem NewNodeItem(this->InsertNode(parent,0,caption,name));
\r
298 // redraw the structure:
\r
299 this->RedrawFromNode(parent);
\r
300 // return the new node:
\r
301 return NewNodeItem;
\r
302 } /* wxTreeMultiCtrl::PrependNode(wxTreeMultiItem const&, wxString const&, wxString const&) */
\r
304 bool wxTreeMultiCtrl::Delete(wxTreeMultiItem &item)
\r
306 bool redraw = true;
\r
307 wxCHECK(item.IsOk(), false);
\r
309 wxTreeMultiItem nullItem(0);
\r
312 // if item has been selected, remove it from the selected list:
\r
313 size_t ItemIndex(this->GetSelectedItemIndex(item));
\r
315 if (ItemIndex != this->GetSelectedItemCount())
\r
316 this->m_SelectedItems.RemoveAt(ItemIndex);
\r
318 // get parent, to delete item from
\r
319 TreeMultiItemNode *p = item.GetItem()->GetParent();
\r
321 // first check if it was visible, if so from the parent off
\r
322 // it needs redrawing
\r
323 redraw = item.GetItem()->IsVisible();
\r
325 p->DeleteNode(item.GetItem());
\r
327 _root.DeleteNode(item.GetItem());
\r
331 // do redraw when node was visible
\r
338 void wxTreeMultiCtrl::DeleteChildren(const wxTreeMultiItem &item)
\r
340 if(item.IsNodeItem())
\r
342 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
\r
344 // remove all children from the selected item list:
\r
345 if (n->GetNodeCount() > 0)
\r
347 // variable definitions and initializations:
\r
349 wxTreeMultiItem FirstItemIterator(this->GetFirstChild(item,Cookie)), LastItemIterator(this->GetLastChild(item));
\r
353 size_t ItemIndex(this->GetSelectedItemIndex(item)); // variable definition and initialization
\r
355 if (ItemIndex != this->GetSelectedItemCount())
\r
356 this->m_SelectedItems.RemoveAt(ItemIndex);
\r
357 if (FirstItemIterator == LastItemIterator)
\r
358 break; // all children checked
\r
360 FirstItemIterator = this->GetNext(FirstItemIterator);
\r
363 // delete children:
\r
370 void wxTreeMultiCtrl::Expand(const wxTreeMultiItem &item, bool recursive)
\r
374 TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();
\r
376 n = item.GetItem()->GetParent();
\r
377 DoFold(n, true, recursive);
\r
378 RedrawFromNode(item.GetItem()->IsTreeMultiItemNode());
\r
382 void wxTreeMultiCtrl::Collapse(const wxTreeMultiItem &item, bool recursive)
\r
386 TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();
\r
388 n = item.GetItem()->GetParent();
\r
389 DoFold(n, false, recursive);
\r
390 RedrawFromNode(item.GetItem()->IsTreeMultiItemNode());
\r
395 void wxTreeMultiCtrl::ExpandNodes(bool recursive)
\r
397 // go through all children and call DoFold recursively
\r
398 for(int i = 0; i < _root.GetNodeCount(); i++)
\r
399 DoFold(_root.GetNode(i), true, recursive);
\r
403 void wxTreeMultiCtrl::CollapseNodes(bool recursive)
\r
405 // go through all children and call DoFold recursively
\r
406 for(int i = 0; i < _root.GetNodeCount(); i++)
\r
407 DoFold(_root.GetNode(i), false, recursive);
\r
411 void wxTreeMultiCtrl::CollapseAndReset(const wxTreeMultiItem &item)
\r
413 if(item.IsNodeItem())
\r
415 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
\r
419 Collapse(item, false);
\r
423 // Selection manipulation
\r
424 wxTreeMultiItem wxTreeMultiCtrl::GetFirstSelectedItem(void) const
\r
426 if (this->GetSelectedItemCount() > 0)
\r
427 return this->m_SelectedItems[0];
\r
429 return wxTreeMultiItem();
\r
430 } /* wxTreeMultiCtrl::GetFirstSelectedItem(void) const */
\r
432 wxTreeMultiItem wxTreeMultiCtrl::GetLastSelectedItem(void) const
\r
434 if (this->GetSelectedItemCount() > 0)
\r
435 return this->m_SelectedItems[this->GetSelectedItemCount()-1];
\r
437 return wxTreeMultiItem();
\r
438 } /* wxTreeMultiCtrl::GetLastSelectedItem(void) const */
\r
440 wxTreeMultiItem wxTreeMultiCtrl::GetSelectedItem(size_t Index) const
\r
442 if (Index < this->GetSelectedItemCount())
\r
443 return this->m_SelectedItems[Index];
\r
445 return wxTreeMultiItem();
\r
446 } /* wxTreeMultiCtrl::GetSelectedItem(size_t Index) const */
\r
448 size_t wxTreeMultiCtrl::GetSelectedItemIndex(wxTreeMultiItem const& Item) const
\r
450 // attention: the function wxArray::Index() can NOT be used in a save manner as it only checks the address of an item
\r
451 // element but it is not guaranteed that Item may not be a copy of the originally inserted item
\r
452 const size_t NoOfSelectedItems = this->GetSelectedItemCount();
\r
457 while ((Index < NoOfSelectedItems) && (this->m_SelectedItems[Index] != Item))
\r
460 } /* wxTreeMultiCtrl::GetSelectedItemIndex(wxTreeMultiItem const&) const */
\r
462 void wxTreeMultiCtrl::SelectItem(wxTreeMultiItem const& Item, bool UnselectOthers, bool ExpandSelection)
\r
464 TreeMultiItemNode* NodePtr(Item.GetItem()->IsTreeMultiItemNode());
\r
467 // only nodes can be selected and they can only be selected if they are not already selected:
\r
468 if ((NodePtr == NULL) || NodePtr->IsSelected())
\r
471 // inform that we are about to change:
\r
472 wxTreeMultiEvent Event(wxEVT_COMMAND_TREE_MULTI_SEL_CHANGING,Item); // variable definition and initialization
\r
474 if (this->m_SelectedItems.GetCount() > 0) // the last item in the array is always the latest inserted item
\r
475 Event.SetOldItem(this->m_SelectedItems.Last());
\r
476 Event.SetEventObject(this);
\r
477 if (this->GetEventHandler()->ProcessEvent(Event) && !(Event.IsAllowed()))
\r
480 // make sure that the to be selected item can be seen:
\r
481 this->Include(Item);
\r
483 // variable definition and initialization:
\r
484 wxTreeMultiItem ExcludedParent(this->GetExcludedParent(Item));
\r
486 while (ExcludedParent.IsOk())
\r
488 this->Include(ExcludedParent);
\r
489 ExcludedParent = this->GetExcludedParent(Item);
\r
492 // unselect items if necessary:
\r
493 if (UnselectOthers)
\r
494 this->UnselectAll();
\r
495 // expand selection if necessary:
\r
496 if (ExpandSelection)
\r
498 // variable definition:
\r
499 wxTreeMultiItem FirstItemIterator, LastItemIterator;
\r
500 wxTreeMultiItem LastSelectedItem;
\r
502 // determine the last selected item or the first item in case nothing has been selected before:
\r
503 if (this->m_SelectedItems.GetCount() > 0)
\r
504 LastSelectedItem = this->m_SelectedItems.Last();
\r
506 LastSelectedItem = this->GetFirstRoot();
\r
507 // determine the item from which to start and the one with which to end the selection:
\r
508 if (Item.GetItem()->GetY() > LastSelectedItem.GetItem()->GetY())
\r
510 FirstItemIterator = LastSelectedItem;
\r
511 LastItemIterator = Item;
\r
515 FirstItemIterator = Item;
\r
516 LastItemIterator = LastSelectedItem;
\r
518 // select all items that are a node and are placed between the two limiting iterators (included the limits):
\r
521 if (!(FirstItemIterator.IsSelected()) && FirstItemIterator.IsNodeItem())
\r
523 FirstItemIterator.GetItem()->Select();
\r
524 this->m_SelectedItems.Add(FirstItemIterator);
\r
525 this->RefreshRect(wxRect(FirstItemIterator.GetItem()->GetX(), FirstItemIterator.GetItem()->GetY(),
\r
526 FirstItemIterator.GetItem()->GetWidth(),FirstItemIterator.GetItem()->GetHeight()));
\r
528 if (FirstItemIterator == LastItemIterator)
\r
530 // continue iterating:
\r
531 FirstItemIterator = this->GetNext(FirstItemIterator);
\r
534 else // select passed item only
\r
537 this->m_SelectedItems.Add(NodePtr);
\r
538 this->RefreshRect(wxRect(NodePtr->GetX(),NodePtr->GetY(),NodePtr->GetWidth(),NodePtr->GetHeight()));
\r
541 // inform that we have selected the item:
\r
542 Event.SetEventType(wxEVT_COMMAND_TREE_MULTI_SEL_CHANGED);
\r
543 this->GetEventHandler()->ProcessEvent(Event);
\r
544 } /* wxTreeMultiCtrl::SelectItem(wxTreeMultiItem const&, bool, bool) */
\r
546 void wxTreeMultiCtrl::UnselectAll(void)
\r
548 const size_t NoOfSelectedItems = this->m_SelectedItems.GetCount();
\r
551 for (size_t i=0; i<NoOfSelectedItems; ++i)
\r
553 this->RefreshRect(wxRect(this->m_SelectedItems[i].GetItem()->GetX(), this->m_SelectedItems[i].GetItem()->GetY(),
\r
554 this->m_SelectedItems[i].GetItem()->GetWidth(),this->m_SelectedItems[i].GetItem()->GetHeight()));
\r
555 this->m_SelectedItems[i].GetItem()->Unselect();
\r
557 this->m_SelectedItems.Clear();
\r
558 } /* wxTreeMultiCtrl::UnselectAll(void) */
\r
560 void wxTreeMultiCtrl::Unselect(wxTreeMultiItem const& Item)
\r
562 size_t ItemIndex(this->GetSelectedItemIndex(Item));
\r
565 if (ItemIndex != this->GetSelectedItemCount())
\r
567 Item.GetItem()->Unselect();
\r
568 this->m_SelectedItems.RemoveAt(ItemIndex);
\r
569 this->RefreshRect(wxRect(Item.GetItem()->GetX(),Item.GetItem()->GetY(),Item.GetItem()->GetWidth(),Item.GetItem()->GetHeight()));
\r
571 } /* wxTreeMultiCtrl::Unselect(wxTreeMultiItem const&) */
\r
573 void wxTreeMultiCtrl::DoFold(TreeMultiItemBase *item, bool expand, bool recursive)
\r
576 // go through all node objects on this level, and expand or
\r
582 // if this is a node, use it to go through all the subnodes (if needed)
\r
583 // if not, then just exit.
\r
585 TreeMultiItemNode *node = item->IsTreeMultiItemNode();
\r
588 node->Fold(expand);
\r
593 TreeMultiItemNode *p;
\r
594 for(int i = 0; i < node->GetNodeCount(); i++)
\r
596 // get node, and if a real node, then call fold
\r
597 p = node->GetNode(i)->IsTreeMultiItemNode();
\r
601 // go recursive for every node
\r
602 DoFold(p, expand, recursive);
\r
608 void wxTreeMultiCtrl::Exclude(const wxTreeMultiItem &item)
\r
610 wxCHECK2(item.IsOk(), return);
\r
612 // exclude the item, and refresh
\r
613 // if already excluded, skip
\r
615 if(!item.GetItem()->IsExcluded())
\r
617 item.GetItem()->SetExcluded(true);
\r
618 RedrawFromParentNode(item.GetItem());
\r
622 void wxTreeMultiCtrl::Include(const wxTreeMultiItem &item)
\r
624 wxCHECK2(item.IsOk(), return);
\r
626 // include the item, and refresh. If not
\r
627 // excluded, do nothing
\r
629 if(item.GetItem()->IsExcluded())
\r
631 item.GetItem()->SetExcluded(false);
\r
632 RedrawFromParentNode(item.GetItem());
\r
636 wxTreeMultiItem wxTreeMultiCtrl::GetExcludedParent(const wxTreeMultiItem &item)
\r
638 wxCHECK(item.IsOk(), wxTreeMultiItem(0));
\r
640 // go find the parent (including this one) that
\r
641 // can be the excluded one
\r
643 TreeMultiItemNode *n = item.GetItem()->IsTreeMultiItemNode();
\r
644 if(n && n->IsExcluded())
\r
645 return wxTreeMultiItem(n);
\r
647 n = item.GetItem()->GetParent();
\r
650 if(n->IsExcluded())
\r
651 return wxTreeMultiItem(n);
\r
653 n = n->GetParent();
\r
656 return wxTreeMultiItem(0);
\r
659 void wxTreeMultiCtrl::OnSize(wxSizeEvent &WXUNUSED(event))
\r
661 RecalculateSpanSizes();
\r
664 void wxTreeMultiCtrl::OnPaint(wxPaintEvent& WXUNUSED(event) )
\r
666 wxPaintDC dc(this);
\r
670 // go recursive and draw the whole visible tree.
\r
671 dc.SetFont(_captionFont);
\r
672 for(int i = 0; i < _root.GetNodeCount(); i++)
\r
673 DrawNode(_root.GetNode(i), dc);
\r
676 void wxTreeMultiCtrl::DrawNode(TreeMultiItemBase *b, wxDC &dc)
\r
678 // go through this item .. if it is a node, draw
\r
679 // the caption, else reposition the window.
\r
684 // forget it if this node is not visible
\r
687 int bmpOffsetX = b->GetX() - (_gutterWidth + _iconWidth);
\r
690 // now draw the checkbox if there is any, in the proper state
\r
691 if(b->GetCheckbox())
\r
693 DrawCheckbox(b, dc);
\r
695 // adjust the bmpOffset because we also have a checkbox
\r
696 bmpOffsetX -= _checkWidth;
\r
700 if(b->IsTreeMultiItemNode())
\r
702 // draw the node icon and the caption
\r
703 TreeMultiItemNode *n = (TreeMultiItemNode *)b;
\r
705 // set background of caption item
\r
706 if (n->IsSelected())
\r
708 dc.SetBrush(*(this->m_HilightBrush));
\r
709 dc.SetPen(wxPen(this->m_HilightBrush->GetColour(),1,wxSOLID));
\r
713 dc.SetBrush(wxBrush(*wxWHITE,wxSOLID));
\r
714 dc.SetPen(wxPen(*wxWHITE,1,wxSOLID));
\r
716 dc.DrawRectangle(n->GetX(),n->GetY(),n->GetWidth(),n->GetHeight());
\r
718 dc.DrawText(n->GetCaption(), n->GetX(), n->GetY());
\r
720 // draw the bitmap for the state
\r
721 if(n->IsExpanded())
\r
722 dc.DrawBitmap(*_expandBmp, bmpOffsetX, n->GetY() + _iconDeltaY, true);
\r
724 dc.DrawBitmap(*_collBmp, bmpOffsetX, n->GetY() + _iconDeltaY, true);
\r
726 // now go through all the subnodes
\r
727 for(int i = 0; i < n->GetNodeCount(); i++)
\r
728 DrawNode(n->GetNode(i), dc);
\r
736 void wxTreeMultiCtrl::DrawCheckbox(TreeMultiItemBase *b, wxDC &dc, bool convertScrolled)
\r
738 wxCHECK2(b, return);
\r
741 int bmpOffsetX = b->GetX() - (_gutterWidth + _iconWidth);
\r
743 switch(b->GetCheckboxState())
\r
752 bmp = _tristateBmp;
\r
758 if(b->IsTreeMultiItemWindow())
\r
760 xx = x = bmpOffsetX - ((TreeMultiItemWindow *)b)->GetFrontSpacing() + _checkWidth;
\r
761 yy = y = b->GetY() + _checkDeltaY;
\r
765 xx = x = bmpOffsetX;
\r
766 yy = y = b->GetY() + _checkDeltaY;
\r
769 if(convertScrolled)
\r
770 CalcScrolledPosition(x, y, &xx, &yy);
\r
772 dc.DrawBitmap(*bmp, xx, yy, true);
\r
775 #endif // #if(CHECKBOXVIEW)
\r
777 void wxTreeMultiCtrl::OnKey(wxKeyEvent &event)
\r
779 // check if we need to traverse to upper or lower
\r
780 // control in the list
\r
781 if(event.GetKeyCode() == WXK_TAB)
\r
783 wxTreeMultiItem item = GetFocus();
\r
786 // traverse down direction
\r
787 if(!event.ShiftDown())
\r
788 item = FindNextVisibleWindowItem(item.GetItem());
\r
789 //else // traverse in up direction
\r
790 // item = FindPreviousVisibleWindowItem(item);
\r
794 TreeMultiItemWindow *w = item.GetItem()->IsTreeMultiItemWindow();
\r
797 wxWindow *wnd = w->GetWindow();
\r
807 void wxTreeMultiCtrl::OnMouseClick( wxMouseEvent &event )
\r
809 // react on double click and left mouse down
\r
810 if(event.LeftDown() || event.LeftDClick())
\r
812 // get translation point
\r
813 wxPoint pt( event.GetPosition() );
\r
816 CalcUnscrolledPosition( pt.x, pt.y, &x, &y );
\r
818 // go check if we clicked a treenode
\r
821 wxTreeMultiItem id = HitTest(p, flags);
\r
824 if(flags == wxTMC_HITTEST_CHECKBOX)
\r
826 // toggle the checkbox, and redraw
\r
829 TreeMultiItemBase *b = id.GetItem();
\r
830 b->SetCheckboxState((b->GetCheckboxState()+1) & 0x1);
\r
832 TreeMultiItemWindow *w = b->IsTreeMultiItemWindow();
\r
835 // try to force a focus on the window. This could
\r
836 // be extended by searching for the first edit control
\r
837 // class but for now, just a focus is tried.
\r
838 w->GetWindow()->Enable(b->GetCheckboxState() == 1);
\r
839 w->GetWindow()->SetFocus();
\r
841 // draw the checkbox in the state needed
\r
842 wxClientDC dc(this);
\r
843 DrawCheckbox(b, dc, true);
\r
845 // TODO: determine if the upper parents should be
\r
846 // tristated or not
\r
848 ScanTristateCheckstates(b);
\r
851 else if(b->IsTreeMultiItemNode())
\r
853 // descend to all the children and set the state of the parent
\r
854 SetRecursiveCheckState((TreeMultiItemNode *)b, b->GetCheckboxState() == 1);
\r
855 RedrawFromNode((TreeMultiItemNode *)b);
\r
860 #endif // #if(CHECKBOXVIEW)
\r
862 // react on left mouse button, to fold and on
\r
863 // right for caption doubleclick
\r
866 // adjust behaviour for Linux (single click = always fold)
\r
868 if(event.LeftDClick())
\r
869 area = wxTMC_HITTEST_CAPTION;
\r
871 area = wxTMC_HITTEST_GUTTER;
\r
876 // Linux (single or double click -> always fold
\r
880 // we have a valid item, if it is a node, then fold
\r
881 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode();
\r
884 this->SelectItem(id);
\r
885 Fold(n, !n->IsExpanded());
\r
888 if (event.LeftDown())
\r
889 if (flags == wxTMC_HITTEST_GUTTER)
\r
891 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode(); // for some reasons also windows may have set the flag
\r
894 Fold(n, !n->IsExpanded());
\r
896 else if (flags == wxTMC_HITTEST_CAPTION)
\r
898 TreeMultiItemNode *n = id.GetItem()->IsTreeMultiItemNode(); // for some reasons also windows may have set the flag
\r
902 this->SelectItem(id);
\r
903 this->RedrawFromNode(n);
\r
909 this->UnselectAll();
\r
914 void wxTreeMultiCtrl::OnRightMouseClick(wxMouseEvent& Event)
\r
916 if (Event.RightDown())
\r
917 if (Event.Dragging())
\r
918 this->UnselectAll();
\r
921 // variable definitions:
\r
925 // translate mouse coordinates:
\r
926 CalcUnscrolledPosition(Event.GetPosition().x,Event.GetPosition().y,&(Point.x),&(Point.y));
\r
927 // check if the mouse is above the caption of an item:
\r
928 wxTreeMultiItem Item(this->HitTest(Point,Flags)); // variable definition and initialization
\r
930 if (Item.IsOk() && (Flags == wxTMC_HITTEST_CAPTION))
\r
932 this->SelectItem(Item);
\r
933 this->RedrawFromNode(Item.GetItem()->IsTreeMultiItemNode());
\r
934 Event.Skip(); // window will convert right mouse click to a context menu event or proceed with
\r
935 // a right mouse click event if the context menu event cannot be processed
\r
938 this->UnselectAll();
\r
941 this->UnselectAll();
\r
942 } /* wxTreeMultiCtrl::OnRightMouseClick(wxMouseEvent&) */
\r
944 wxTreeMultiItem wxTreeMultiCtrl::HitTest(wxPoint const& pt, int &flags)
\r
946 // scan all nodes to see which one matches
\r
947 TreeMultiItemBase *b = 0;
\r
948 for(int i = 0; i < _root.GetNodeCount() && !b; i++)
\r
949 b = FindNodeByPoint(_root.GetNode(i), pt, flags);
\r
953 // none found, reset
\r
955 return wxTreeMultiItem(0);
\r
959 return wxTreeMultiItem(b);
\r
962 TreeMultiItemBase *wxTreeMultiCtrl::FindNodeByPoint(TreeMultiItemBase *b, wxPoint const& pt, int &area)
\r
966 // if this layer is not visible, return with nothing.
\r
967 if(!b->IsVisible())
\r
972 // now see if our y is matching the mouse
\r
973 if(pt.y >= b->GetY() && pt.y < (b->GetY() + b->GetHeight()))
\r
976 // if we are checkboxed, calculate the checkbox position
\r
977 if(b->GetCheckbox())
\r
979 int extraSpacing = 0, extraWidth = 0;
\r
981 // now for a windows item, this is minus the gutter. For a normal node it is X minus checkbox
\r
982 if(b->IsTreeMultiItemWindow())
\r
984 extraWidth = _checkWidth;
\r
985 extraSpacing = ((TreeMultiItemWindow *)b)->GetFrontSpacing();
\r
990 if(pt.x > (b->GetX() - extraSpacing - _checkWidth) && pt.x < (b->GetX() - extraSpacing + extraWidth))
\r
992 area = wxTMC_HITTEST_CHECKBOX;
\r
998 // allrighty we have something, now where and what is it (look with x)
\r
999 if(pt.x < b->GetX())
\r
1000 area = wxTMC_HITTEST_GUTTER;
\r
1002 /** \todo Match only the real part of the caption, window (we assume x > GetX() which is the rest)
\r
1003 HOWEVER the window probably doesn't propagate the click event back to the parent, so we might
\r
1004 leave it like this so the use can click behind a window so it will be selected.
\r
1008 // inside area, return proper flag
\r
1009 if(b->IsTreeMultiItemNode())
\r
1010 area = wxTMC_HITTEST_CAPTION;
\r
1012 area = wxTMC_HITTEST_WINDOW;
\r
1019 // not found, let's try our children if we have some
\r
1020 TreeMultiItemNode *n = b->IsTreeMultiItemNode();
\r
1023 TreeMultiItemBase *bb = 0;
\r
1024 for(int i = 0; i < n->GetNodeCount() && !bb; i++)
\r
1025 bb = FindNodeByPoint(n->GetNode(i), pt, area);
\r
1027 // keep returning result to caller
\r
1035 wxTreeMultiItem wxTreeMultiCtrl::GetFocus()
\r
1037 wxWindow *wnd = wxWindow::FindFocus();
\r
1039 // now find window that holds this item. if not
\r
1040 // visible it cannot have focus (should not have)
\r
1042 wxTreeMultiItem item = FindWindowNode(wnd);
\r
1043 if(item.IsOk() && item.GetItem()->IsVisible())
\r
1046 return wxTreeMultiItem(0);
\r
1051 void wxTreeMultiCtrl::SetRecursiveCheckState(TreeMultiItemNode *n, bool check)
\r
1057 // go check all kids on this level
\r
1058 for(int i = 0; i < n->GetNodeCount(); i++)
\r
1060 // check all the nodes, and go deeper
\r
1061 n->GetNode(i)->SetCheckboxState(state);
\r
1062 if(n->GetNode(i)->IsTreeMultiItemNode())
\r
1063 SetRecursiveCheckState((TreeMultiItemNode *)n->GetNode(i), check);
\r
1067 void wxTreeMultiCtrl::ScanTristateCheckstates(TreeMultiItemBase *b)
\r
1069 // check from the parent on, all node entries and see if they are
\r
1070 // checked or cleared or scattered
\r
1071 TreeMultiItemNode *p = b->GetParent();
\r
1073 if(p && p->GetCheckbox())
\r
1075 bool foundcheck = false, foundclear = false;
\r
1076 for(size_t i = 0; i < (size_t)p->GetNodeCount(); ++i)
\r
1078 // only evaluate when checkboxed
\r
1079 if(p->GetNode(i)->IsTreeMultiItemWindow() && p->GetNode(i)->GetCheckbox())
\r
1081 // record instance of a cleared checkbox
\r
1082 if(!p->GetNode(i)->GetCheckboxState())
\r
1083 foundclear = true;
\r
1084 // record instance of checked checkbox
\r
1085 if(p->GetNode(i)->GetCheckboxState() == 1)
\r
1086 foundcheck = true;
\r
1090 // if we have both check and clear, go tristate
\r
1091 // if all clear, clear parent and if all set, then set parent
\r
1092 if(foundclear && !foundcheck)
\r
1093 p->SetCheckboxState(0);
\r
1094 else if(!foundclear && foundcheck)
\r
1095 p->SetCheckboxState(1);
\r
1096 else if(foundclear && foundcheck)
\r
1097 p->SetCheckboxState(2);
\r
1100 //DrawCheckbox(p, dc, false);
\r
1101 RedrawFromNode(p);
\r
1105 #endif // #if(CHECKBOXVIEW)
\r
1107 wxTreeMultiItem wxTreeMultiCtrl::InsertNode(TreeMultiItemNode* ParentPtr, size_t Position, wxString const& Caption, wxString const& Name)
\r
1111 TreeMultiItemNode* NodePtr(new TreeMultiItemNode(ParentPtr,Caption,Name)); // generate new node pointer
\r
1114 // continue with initializing the new node:
\r
1116 // if checkbox view is desired, tag this item as a checkbox
\r
1117 // and set the state as 'false'
\r
1118 NodePtr->SetCheckbox(_checkboxView);
\r
1119 NodePtr->SetCheckboxState(0);
\r
1121 // calculate the height and width
\r
1122 this->GetTextExtent(Caption,&extX,&extY,0,0,&(this->_captionFont));
\r
1123 NodePtr->SetHeight(extY);
\r
1124 NodePtr->SetWidth(extX);
\r
1125 // finally, insert node:
\r
1126 if (Position < (size_t)ParentPtr->GetNodeCount())
\r
1127 ParentPtr->InsertNode(NodePtr,Position);
\r
1129 ParentPtr->AddNode(NodePtr);
\r
1130 // return the newly created node:
\r
1131 return wxTreeMultiItem(NodePtr);
\r
1132 } /* wxTreeMultiCtrl::InsertNode(TreeMultiItemNode*, size_t, wxString const&, wxString const&) */
\r
1134 wxTreeMultiItem wxTreeMultiCtrl::InsertWindow(TreeMultiItemNode* ParentPtr, size_t Position, wxWindow* WindowPtr, wxString const& Name, wxTreeMultiWindowInfo const& Info, int Flags)
\r
1138 TreeMultiItemWindow* NewWindowPtr = new TreeMultiItemWindow(ParentPtr,Name); // generate new window pointer
\r
1141 // get flags from passed variable "Flags"; in case this variable does not contain any flags use the window's information flags:
\r
1143 WindowFlags = Flags;
\r
1145 WindowFlags = Info.GetFlags();
\r
1147 // continue with initializing the new window:
\r
1149 // if checkbox view is desired, tag this item as a checkbox
\r
1150 // and set the state as 'false'
\r
1151 NewWindowPtr->SetCheckbox(_checkboxView);
\r
1153 // if style wants us to change background, set it to our background
\r
1154 if (WindowFlags & wxTMC_BG_ADJUST_ALL)
\r
1156 // go through all children of this window, and set the
\r
1157 // background of it (recursively)
\r
1158 this->SetWindowBackgroundColour(WindowPtr,this->GetBackgroundColour(),WindowFlags);
\r
1161 // set the spacing:
\r
1162 NewWindowPtr->SetTopSpacing(Info.GetTopSpacing());
\r
1164 // make sure that the checkboxes are at least indented enough
\r
1165 if (this->_checkboxView)
\r
1166 NewWindowPtr->SetFrontSpacing(Info.GetFrontSpacing() + this->_checkWidth);
\r
1169 NewWindowPtr->SetFrontSpacing(Info.GetFrontSpacing());
\r
1170 // assign finally the window:
\r
1171 NewWindowPtr->AssignWindow(WindowPtr);
\r
1174 // set the checkbox state after the window is assigned
\r
1175 NewWindowPtr->SetCheckboxState(Info.GetDefaultCheckState());
\r
1178 // if the window is not visible, set hide flag
\r
1179 this->ShowTreeMultiWindow(NewWindowPtr,NewWindowPtr->IsVisible());
\r
1181 // finally, insert the newly constructed window:
\r
1182 if (Position < (size_t)ParentPtr->GetNodeCount())
\r
1183 ParentPtr->InsertNode(NewWindowPtr,Position);
\r
1185 ParentPtr->AddNode(NewWindowPtr);
\r
1186 // return the newly created window:
\r
1187 return wxTreeMultiItem(NewWindowPtr);
\r
1188 } /* wxTreeMultiCtrl::InsertWindow(TreeMultiItemNode*, size_t, wxWindow*, wxString const&, wxTreeMultiWindowInfo const&, int) */
\r
1190 void wxTreeMultiCtrl::RedrawFromParentNode(TreeMultiItemBase *n)
\r
1192 TreeMultiItemNode *p = 0;
\r
1194 p = n->GetParent();
\r
1196 RedrawFromNode(p);
\r
1199 void wxTreeMultiCtrl::RedrawFromNode(TreeMultiItemNode *n)
\r
1201 static int recalcMutex = 0;
\r
1202 bool visible = true;
\r
1204 if(recalcMutex > 0)
\r
1209 // when node is not visible or excluded
\r
1210 // then don't redraw.
\r
1213 visible = n->IsVisible();
\r
1218 GetVirtualSize(&w, &h);
\r
1220 UpdateAllWindowVisibility();
\r
1221 RecalculateNodePositions();
\r
1222 RecalculateVirtualSize();
\r
1224 // why is this needed? Because folding or collapsing can change
\r
1225 // the state. When the virtual area gets smaller, we need to keep
\r
1226 // the largest one and the other way atound. And since we do not
\r
1227 // know here we are folding or collapsing, we remember the biggest
\r
1228 GetVirtualSize(&w1, &h1);
\r
1233 // only refresh the part from x,y down
\r
1237 CalcScrolledPosition(n->GetX(), n->GetY(), &x, &y);
\r
1240 wxRect rect(0, y, w, h - y);
\r
1241 RefreshRect(rect);
\r
1247 Refresh(); // do a full refresh
\r
1253 void wxTreeMultiCtrl::RecalculateNodePositions()
\r
1255 int currentY = _spacingY;
\r
1256 // go recursive on every node, and store the information in the node
\r
1258 for(int i = 0; i < _root.GetNodeCount(); i++)
\r
1259 currentY += CalculateNodeDimensions(_root.GetNode(i), currentY, 0);
\r
1262 int wxTreeMultiCtrl::CalculateNodeDimensions(TreeMultiItemBase *b, int currentY, int level)
\r
1264 int gutter = (_gutterWidth * 2) + _iconWidth;
\r
1265 int y = 0, topSpacing = 0;
\r
1267 // return same if no proper object
\r
1271 if(b->GetCheckbox())
\r
1272 gutter += _checkWidth;
\r
1275 // if we are not visible, skip recalculation and descending
\r
1276 if(b->IsVisible())
\r
1278 b->SetY(currentY);
\r
1280 // if level is 0, calculate with front gutter, else without
\r
1281 y = currentY + b->GetHeight();
\r
1282 if(b->IsTreeMultiItemNode())
\r
1284 TreeMultiItemNode *n = (TreeMultiItemNode *)b;
\r
1289 b->SetX(gutter + (level * (_gutterWidth + _iconWidth)));
\r
1291 // now do children of this node
\r
1293 for(int i = 0; i < n->GetNodeCount(); i++)
\r
1294 y += CalculateNodeDimensions(n->GetNode(i), y + _spacingY, level+1);
\r
1296 else if(b->IsTreeMultiItemWindow())
\r
1298 TreeMultiItemWindow *w = (TreeMultiItemWindow *)b;
\r
1301 b->SetX(gutter + w->GetFrontSpacing());
\r
1303 b->SetX(_gutterWidth + (level * (_gutterWidth + _iconWidth)) + w->GetFrontSpacing());
\r
1305 topSpacing = w->GetTopSpacing();
\r
1307 // reposition the window
\r
1309 wxWindow *wnd = w->GetWindow();
\r
1313 CalcScrolledPosition(w->GetX(), w->GetY(), &x, &y);
\r
1314 wnd->SetSize(x, y, w->GetWidth(), w->GetHeight());
\r
1319 return (y - currentY) + _spacingY + topSpacing; // return delta
\r
1324 return 0; // not visible, thus we skip calculations
\r
1327 void wxTreeMultiCtrl::RecalculateSpanSizes()
\r
1329 for(int i = 0; i < _root.GetNodeCount(); i++)
\r
1330 CalculateNodeSpanning(_root.GetNode(i));
\r
1333 void wxTreeMultiCtrl::CalculateNodeSpanning(TreeMultiItemBase *b)
\r
1335 // return same if no proper object
\r
1336 wxCHECK2(b, return);
\r
1338 if(b->IsTreeMultiItemNode())
\r
1340 TreeMultiItemNode *n = (TreeMultiItemNode *)b;
\r
1342 // now do children of this node
\r
1344 for(int i = 0; i < n->GetNodeCount(); i++)
\r
1345 CalculateNodeSpanning(n->GetNode(i));
\r
1347 else if(b->IsTreeMultiItemWindow())
\r
1349 TreeMultiItemWindow *w = (TreeMultiItemWindow *)b;
\r
1350 wxWindow *wnd = w->GetWindow();
\r
1353 // if the window is spanning, we adjust the width to the max width of the control
\r
1354 if(w->GetHorizontalSpan())
\r
1356 wxSize tmcsize = GetClientSize();
\r
1357 int maxwidth = tmcsize.GetWidth() - w->GetX() - 8; // extract 3 for border
\r
1359 wxSizer *sz = wnd->GetSizer();
\r
1362 if(maxwidth < sz->GetMinSize().GetWidth())
\r
1363 maxwidth = sz->GetMinSize().GetWidth();
\r
1366 // prevent a size of 0
\r
1371 w->SetWidth(maxwidth);
\r
1372 wnd->SetSize(w->GetWidth(), w->GetHeight());
\r
1374 // layout by sizer (not sure if this is needed)
\r
1375 if(wnd->GetSizer())
\r
1376 wnd->GetSizer()->Layout();
\r
1382 void wxTreeMultiCtrl::RecalculateVirtualSize()
\r
1384 // go through all the nodes, and store the largest x and largest y
\r
1387 RecalculateVirtualSizeFromNode(&_root, x, y);
\r
1389 // now adjust virtual size
\r
1390 SetVirtualSize(x, y);
\r
1391 AdjustScrollbars(x, y);
\r
1394 void wxTreeMultiCtrl::AdjustScrollbars(int x, int y)
\r
1396 // adjust scrollbars
\r
1397 // courtesy of treectrlg.cpp
\r
1399 y += WXTMC_PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
\r
1400 x += WXTMC_PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
\r
1401 int x_pos = GetScrollPos( wxHORIZONTAL );
\r
1402 int y_pos = GetScrollPos( wxVERTICAL );
\r
1403 SetScrollbars( WXTMC_PIXELS_PER_UNIT, WXTMC_PIXELS_PER_UNIT, x/WXTMC_PIXELS_PER_UNIT,
\r
1404 y/WXTMC_PIXELS_PER_UNIT, x_pos, y_pos, true );
\r
1407 void wxTreeMultiCtrl::RecalculateVirtualSizeFromNode(const TreeMultiItemNode *node, int &x, int &y)
\r
1409 if(node->IsExcluded())
\r
1412 // if calulate this node's dimensions
\r
1413 if(x < (node->GetWidth() + node->GetX()))
\r
1414 x = node->GetWidth() + node->GetX();
\r
1416 y = node->GetY() + node->GetHeight();
\r
1418 // if this node is collapsed, no subnodes are visible, else
\r
1419 // go through all subnodes as well, node needs to be included as well
\r
1420 if(node->IsExpanded())
\r
1422 TreeMultiItemBase *b;
\r
1423 for(int i = 0; i < node->GetNodeCount(); i++)
\r
1425 b = node->GetNode(i);
\r
1427 // calculate x and y
\r
1428 if(x < (b->GetWidth() + b->GetX()))
\r
1429 x = b->GetWidth() + b->GetX();
\r
1431 y = b->GetY() + b->GetHeight();
\r
1433 if(b->IsTreeMultiItemNode())
\r
1434 RecalculateVirtualSizeFromNode((TreeMultiItemNode *)b, x, y);
\r
1439 void wxTreeMultiCtrl::SetWindowBackgroundColour(wxWindow *wnd, const wxColour &col, int flags)
\r
1443 // if we cannot change a button, make sure all button
\r
1444 // classes are not changed
\r
1446 wxButton *btn = wxDynamicCast(wnd, wxButton);
\r
1447 if(!btn || ((flags & wxTMC_BG_ADJUST_BTN) != 0))
\r
1448 wnd->SetBackgroundColour(col);
\r
1450 // get every window, and make the background equal to the given one
\r
1451 wxWindowListNode *node = wnd->GetChildren().GetFirst();
\r
1454 SetWindowBackgroundColour(node->GetData(), col, flags);
\r
1455 node = node->GetNext();
\r
1460 void wxTreeMultiCtrl::ShowTreeMultiWindow(TreeMultiItemWindow *window, bool show)
\r
1462 // show or hide window
\r
1463 if(window && window->GetWindow())
\r
1464 window->GetWindow()->Show(show);
\r
1467 void wxTreeMultiCtrl::UpdateAllWindowVisibility()
\r
1469 // all roots are visible, but what lies beneath ... who knows
\r
1470 for(int i = 0; i < _root.GetNodeCount(); i++)
\r
1471 UpdateTreeMultiWindowVisibility(_root.GetNode(i), true);
\r
1474 void wxTreeMultiCtrl::UpdateTreeMultiWindowVisibility(TreeMultiItemBase *b, bool show)
\r
1478 // this is done for performance issues. IsVisible can go all
\r
1479 // the way up the tree to check. However if show is already
\r
1480 // false, there is no need to check (some higher one is collapsed)
\r
1481 bool showMe = show;
\r
1484 showMe = b->IsVisible();
\r
1486 if(b->IsTreeMultiItemWindow())
\r
1488 // if this level must be hidden, hide
\r
1489 ShowTreeMultiWindow((TreeMultiItemWindow*)b, showMe);
\r
1491 else if(b->IsTreeMultiItemNode())
\r
1493 TreeMultiItemNode *node = (TreeMultiItemNode *)b;
\r
1495 // if hidden, descend and hide all windows
\r
1496 for(int i = 0; i < node->GetNodeCount(); i++)
\r
1497 UpdateTreeMultiWindowVisibility(node->GetNode(i), showMe);
\r
1502 wxTreeMultiItem wxTreeMultiCtrl::FindItem(const wxTreeMultiItem &item, const wxString &name, bool ignoreCase, bool skipFirst)
\r
1506 TreeMultiItemBase *b = item.GetItem();
\r
1508 // check this item first (or not)
\r
1512 if(b->GetName().IsSameAs(name, !ignoreCase))
\r
1513 return wxTreeMultiItem(b);
\r
1516 if(b->IsTreeMultiItemNode())
\r
1518 // now check whether we are a node, then go check children
\r
1520 TreeMultiItemNode *n = (TreeMultiItemNode *)b;
\r
1521 wxTreeMultiItem result(0);
\r
1522 for(int i = 0; i < n->GetNodeCount() && !result.IsOk(); i++)
\r
1523 result = FindItem(wxTreeMultiItem(n->GetNode(i)), name, ignoreCase, false);
\r
1529 return wxTreeMultiItem(0);
\r
1532 wxTreeMultiItem wxTreeMultiCtrl::FindWindowNode(wxWindow *wnd, TreeMultiItemNode *n)
\r
1534 wxCHECK(wnd, wxTreeMultiItem(0));
\r
1536 // take root node if not assigned one
\r
1539 n = (TreeMultiItemNode *)&_root;
\r
1541 // check on this level for the wxWindow pointer
\r
1543 TreeMultiItemWindow *w;
\r
1544 wxTreeMultiItem result(0);
\r
1545 for(int i = 0; i < n->GetNodeCount() && !result.IsOk(); i++)
\r
1548 w = n->GetNode(i)->IsTreeMultiItemWindow();
\r
1549 if(w && w->GetWindow() == wnd)
\r
1550 return wxTreeMultiItem(n);
\r
1552 // if node, go deeper
\r
1553 if(n->GetNode(i)->IsTreeMultiItemNode())
\r
1554 result = FindWindowNode(wnd, (TreeMultiItemNode*)n->GetNode(i));
\r
1560 TreeMultiItemWindow *wxTreeMultiCtrl::FindNextVisibleWindowItem(TreeMultiItemBase *b, int index)
\r
1564 // check on this level, go deeper with every node we got. When a node is not
\r
1565 // visible anymore, skip the node.
\r
1567 TreeMultiItemWindow *value = 0;
\r
1568 if(b->IsVisible())
\r
1570 // if we are already searching on a node with an index
\r
1572 TreeMultiItemBase *bn = 0;
\r
1573 TreeMultiItemNode *n = b->IsTreeMultiItemNode();
\r
1576 for(int i = index + 1; i < n->GetNodeCount() && !value; i++)
\r
1578 bn = n->GetNode(i);
\r
1579 value = bn->IsTreeMultiItemWindow();
\r
1581 // assume a node, root when not a a window
\r
1583 value = FindNextVisibleWindowItem(bn, -1);
\r
1589 if(b->IsTreeMultiItemWindow())
\r
1591 // get parent first, and locate child as ptr
\r
1592 TreeMultiItemNode *p = b->GetParent();
\r
1595 // go scan the parent from the given index, if
\r
1596 // the index is valid else there is no child with that index
\r
1598 int idx = p->Index(b);
\r
1599 wxCHECK(idx >= 0, 0);
\r
1601 value = FindNextVisibleWindowItem(p, idx);
\r
1610 bool wxTreeMultiCtrl::GetBooleanValue(int wndId)
\r
1612 wxWindow *wnd = wxWindow::FindWindow(wndId);
\r
1613 wxCHECK(wnd, false);
\r
1615 // try a radio button
\r
1616 wxRadioButton *b = wxDynamicCast(wnd, wxRadioButton);
\r
1618 return b->GetValue();
\r
1620 // try a check box
\r
1621 wxCheckBox *c = wxDynamicCast(wnd, wxCheckBox);
\r
1623 return c->GetValue();
\r
1625 /** \todo For custom controls we should put something in wxMultiTreeItemData class
\r
1626 which can be overridden to retrieve the boolean value. It will also be passed
\r
1627 the pointer to the window, so the derived class can figure out how to get a boolean
\r
1631 // generate assert or just return with false
\r
1632 wxCHECK(0, false);
\r
1635 void wxTreeMultiCtrl::SetBooleanValue(int wndId, bool value)
\r
1637 wxWindow *wnd = wxWindow::FindWindow(wndId);
\r
1638 wxCHECK2(wnd, return);
\r
1640 // try a radio button
\r
1641 wxRadioButton *b = wxDynamicCast(wnd, wxRadioButton);
\r
1644 b->SetValue(value);
\r
1648 // try a check box
\r
1649 wxCheckBox *c = wxDynamicCast(wnd, wxCheckBox);
\r
1652 c->SetValue(value);
\r
1656 /** \todo For custom controls we should put something in wxMultiTreeItemData class
\r
1657 which can be overridden to retrieve the boolean value. It will also be passed
\r
1658 the pointer to the window, so the derived class can figure out how to get a boolean
\r
1662 // generate assert
\r
1663 wxCHECK2(0, return);
\r
1666 void wxTreeMultiCtrl::SetTextValue(int wndId, const wxString &value)
\r
1668 wxWindow *wnd = wxWindow::FindWindow(wndId);
\r
1669 wxCHECK2(wnd, return);
\r
1671 // try a radio button
\r
1672 wxTextCtrl *t = wxDynamicCast(wnd, wxTextCtrl);
\r
1675 t->SetValue(value);
\r
1679 /** \todo For custom controls we should put something in wxMultiTreeItemData class
\r
1680 which can be overridden to retrieve the boolean value. It will also be passed
\r
1681 the pointer to the window, so the derived class can figure out how to get a boolean
\r
1685 // generate assert
\r
1686 wxCHECK2(0, return);
\r
1689 wxString wxTreeMultiCtrl::GetTextValue(int wndId)
\r
1691 wxWindow *wnd = wxWindow::FindWindow(wndId);
\r
1692 wxCHECK(wnd, wxEmptyString);
\r
1694 // try a radio button
\r
1695 wxTextCtrl *t = wxDynamicCast(wnd, wxTextCtrl);
\r
1697 return t->GetValue();
\r
1699 // try a choice box
\r
1700 wxChoice *c1 = wxDynamicCast(wnd, wxChoice);
\r
1702 return c1->GetStringSelection();
\r
1704 // try a combo box
\r
1705 wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);
\r
1707 return c2->GetStringSelection();
\r
1710 wxListBox *l = wxDynamicCast(wnd, wxListBox);
\r
1712 return l->GetStringSelection();
\r
1714 /** \todo For custom controls we should put something in wxMultiTreeItemData class
\r
1715 which can be overridden to retrieve the boolean value. It will also be passed
\r
1716 the pointer to the window, so the derived class can figure out how to get a boolean
\r
1720 // generate assert or just return with string
\r
1721 wxCHECK(0, wxEmptyString);
\r
1724 int wxTreeMultiCtrl::GetSelectionValue(int wndId)
\r
1726 wxWindow *wnd = wxWindow::FindWindow(wndId);
\r
1729 // try a choice box
\r
1730 wxChoice *c1 = wxDynamicCast(wnd, wxChoice);
\r
1732 return c1->GetSelection();
\r
1734 // try a combo box
\r
1735 wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);
\r
1737 return c2->GetSelection();
\r
1740 wxListBox *l = wxDynamicCast(wnd, wxListBox);
\r
1742 return l->GetSelection();
\r
1744 /** \todo For custom controls we should put something in wxMultiTreeItemData class
\r
1745 which can be overridden to retrieve the boolean value. It will also be passed
\r
1746 the pointer to the window, so the derived class can figure out how to get a boolean
\r
1750 // generate assert or just return with string
\r
1754 void wxTreeMultiCtrl::GetSelectionValues(int wndId, wxArrayInt &sels)
\r
1758 wxWindow *wnd = wxWindow::FindWindow(wndId);
\r
1759 wxCHECK2(wnd, return);
\r
1762 wxListBox *l = wxDynamicCast(wnd, wxListBox);
\r
1765 l->GetSelections(sels);
\r
1769 /** \todo For custom controls we should put something in wxMultiTreeItemData class
\r
1770 which can be overridden to retrieve the boolean value. It will also be passed
\r
1771 the pointer to the window, so the derived class can figure out how to get a boolean
\r
1775 // generate assert or just return with string
\r
1776 wxCHECK2(0, return);
\r
1779 void wxTreeMultiCtrl::SetSelectionValue(int wndId, int sel)
\r
1781 wxWindow *wnd = wxWindow::FindWindow(wndId);
\r
1782 wxCHECK2(wnd, return);
\r
1784 // try a choice box
\r
1785 wxChoice *c1 = wxDynamicCast(wnd, wxChoice);
\r
1788 c1->SetSelection(sel);
\r
1792 // try a combo box
\r
1793 wxComboBox *c2 = wxDynamicCast(wnd, wxComboBox);
\r
1796 c2->SetSelection(sel);
\r
1801 wxListBox *l = wxDynamicCast(wnd, wxListBox);
\r
1804 l->SetSelection(sel);
\r
1808 /** \todo For custom controls we should put something in wxMultiTreeItemData class
\r
1809 which can be overridden to retrieve the boolean value. It will also be passed
\r
1810 the pointer to the window, so the derived class can figure out how to get a boolean
\r
1814 // generate assert or just return with string
\r
1815 wxCHECK2(0, return);
\r
1819 wxTreeMultiItem wxTreeMultiCtrl::GetParent(wxTreeMultiItem const& item) const
\r
1821 // check if valid or root item has been passed, both do not have parents:
\r
1822 if (!(item.IsOk()) || item.GetItem()->IsTreeMultiItemRoot())
\r
1823 return wxTreeMultiItem();
\r
1825 return wxTreeMultiItem(item.GetItem()->GetParent()); // GetParent() returns a valid pointer in case of a root item!!
\r
1826 // therefore, the check if the passed item is a root item is necessary
\r
1827 } /* wxTreeMultiCtrl::GetParent(wxTreeMultiItem const& item) const */
\r
1829 wxTreeMultiItem wxTreeMultiCtrl::GetFirstChild(const wxTreeMultiItem &item, int &cookie) const
\r
1831 if(item.IsNodeItem())
\r
1833 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
\r
1835 if(n->GetNodeCount() > 0)
\r
1838 return wxTreeMultiItem(n->GetNode(0));
\r
1842 // no children or no valid node
\r
1844 return wxTreeMultiItem(0);
\r
1847 wxTreeMultiItem wxTreeMultiCtrl::GetNextChild(const wxTreeMultiItem &item, int &cookie) const
\r
1849 if(item.IsNodeItem())
\r
1851 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
\r
1853 if(cookie >= 0 && cookie < (n->GetNodeCount()-1))
\r
1855 // increment cookie, return node
\r
1857 return wxTreeMultiItem(n->GetNode(cookie));
\r
1861 // end of query, or no valid node
\r
1863 return wxTreeMultiItem(0);
\r
1866 wxTreeMultiItem wxTreeMultiCtrl::GetLastChild(const wxTreeMultiItem &item) const
\r
1868 if(item.IsNodeItem())
\r
1870 TreeMultiItemNode *n = (TreeMultiItemNode *)item.GetItem();
\r
1872 if(n->GetNodeCount() > 0)
\r
1873 return wxTreeMultiItem(n->GetNode(n->GetNodeCount()-1));
\r
1876 return wxTreeMultiItem(0);
\r
1879 wxTreeMultiItem wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const& item) const
\r
1881 // check if a valid item has been passed:
\r
1882 if (!(item.IsOk()))
\r
1883 return wxTreeMultiItem();
\r
1885 TreeMultiItemNode* ParentPtr(item.GetItem()->GetParent());
\r
1888 if (ParentPtr != NULL) // the parent pointer is only null if the passed item is the root
\r
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:
\r
1891 int NextItemIndex(ParentPtr->Index(item.GetItem())+1); // variable definition and initialization
\r
1893 if (NextItemIndex < ParentPtr->GetNodeCount())
\r
1894 return ParentPtr->GetNode(NextItemIndex);
\r
1896 return wxTreeMultiItem();
\r
1899 return wxTreeMultiItem();
\r
1900 } /* wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const&) const */
\r
1902 wxTreeMultiItem wxTreeMultiCtrl::GetPrevSibling(wxTreeMultiItem const& item) const
\r
1904 // check if a valid item has been passed:
\r
1905 if (!(item.IsOk()))
\r
1906 return wxTreeMultiItem();
\r
1908 TreeMultiItemNode* ParentPtr(item.GetItem()->GetParent());
\r
1911 if (ParentPtr != NULL)
\r
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:
\r
1914 int PrevItemIndex(ParentPtr->Index(item.GetItem())-1); // variable definition and initialization
\r
1916 if (PrevItemIndex >= 0)
\r
1917 return ParentPtr->GetNode(PrevItemIndex);
\r
1919 return wxTreeMultiItem();
\r
1922 return wxTreeMultiItem();
\r
1923 } /* wxTreeMultiCtrl::GetPrevSibling(wxTreeMultiItem const&) const */
\r
1925 wxTreeMultiItem wxTreeMultiCtrl::GetNext(wxTreeMultiItem const& item) const
\r
1927 // check if a valid item has been passed:
\r
1928 if (!(item.IsOk()))
\r
1929 return wxTreeMultiItem();
\r
1931 TreeMultiItemNode* NodePtr(item.GetItem()->IsTreeMultiItemNode()); // variable definition and initialization
\r
1933 if ((NodePtr != NULL) && (NodePtr->GetNodeCount() > 0))
\r
1934 return wxTreeMultiItem(NodePtr->First());
\r
1937 // variable definitions and initializations:
\r
1938 wxTreeMultiItem Parent(item);
\r
1939 wxTreeMultiItem Sibling;
\r
1943 Sibling = this->GetNextSibling(Parent); // try to find next sibling
\r
1944 Parent = this->GetParent(Parent); // get next ancestor
\r
1945 } while (!(Sibling.IsOk()) && Parent.IsOk());
\r
1946 // in case the loop ended with Sibling.IsOk() "Sibling" contains a valid sibling otherwise an invalid
\r
1949 } /* wxTreeMultiCtrl::GetNextSibling(wxTreeMultiItem const&) const */
\r
1951 wxTreeMultiItem wxTreeMultiCtrl::GetPrevious(wxTreeMultiItem const& item) const
\r
1953 // check if a valid item has been passed:
\r
1954 if (!(item.IsOk()))
\r
1955 return wxTreeMultiItem();
\r
1957 TreeMultiItemNode* NodePtr(item.GetItem()->IsTreeMultiItemNode()); // variable definition and initialization
\r
1959 if ((NodePtr != NULL) && (NodePtr->GetNodeCount() > 0))
\r
1960 return wxTreeMultiItem(NodePtr->Last());
\r
1963 // variable definitions and initializations:
\r
1964 wxTreeMultiItem Parent(item);
\r
1965 wxTreeMultiItem Sibling;
\r
1969 Sibling = this->GetPrevSibling(Parent); // try to find next sibling
\r
1970 Parent = this->GetParent(Parent); // get next ancestor
\r
1971 } while (!(Sibling.IsOk()) && Parent.IsOk());
\r
1972 // in case the loop ended with Sibling.IsOk() "Sibling" contains a valid sibling otherwise an invalid
\r
1975 } /* wxTreeMultiCtrl::GetPrevious(wxTreeMultiItem const&) const */
\r
1977 // WDR: handler implementations for wxTreeMultiCtrl
\r
1979 void wxTreeMultiCtrl::OnDraw(wxDC& dc)
\r
1981 // go recursive and draw the whole visible tree.
\r
1982 dc.SetFont(_captionFont);
\r
1983 for(int i = 0; i < _root.GetNodeCount(); i++)
\r
1984 DrawNode(_root.GetNode(i), dc);
\r