]> git.saurik.com Git - wxWidgets.git/blob - src/generic/treebkg.cpp
Corrected GetFontAttributes
[wxWidgets.git] / src / generic / treebkg.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/generic/treebkg.cpp
3 // Purpose:     generic implementation of wxTreebook
4 // Author:      Evgeniy Tarassov, Vadim Zeitlin
5 // Modified by:
6 // Created:     2005-09-15
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2005 Vadim Zeitlin <vadim@wxwidgets.org>
9 // Licence:     wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24     #pragma hdrstop
25 #endif
26
27 #if wxUSE_TREEBOOK
28
29 #include "wx/treebook.h"
30
31 #ifndef WX_PRECOMP
32     #include "wx/settings.h"
33 #endif
34
35 #include "wx/imaglist.h"
36
37 // ----------------------------------------------------------------------------
38 // various wxWidgets macros
39 // ----------------------------------------------------------------------------
40
41 // check that the page index is valid
42 #define IS_VALID_PAGE(nPage) ((nPage) < DoInternalGetPageCount())
43
44 // ----------------------------------------------------------------------------
45 // event table
46 // ----------------------------------------------------------------------------
47
48 IMPLEMENT_DYNAMIC_CLASS(wxTreebook, wxBookCtrlBase)
49 IMPLEMENT_DYNAMIC_CLASS(wxTreebookEvent, wxNotifyEvent)
50
51 const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING = wxNewEventType();
52 const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED = wxNewEventType();
53 const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED = wxNewEventType();
54 const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED = wxNewEventType();
55
56 BEGIN_EVENT_TABLE(wxTreebook, wxBookCtrlBase)
57     EVT_TREE_SEL_CHANGED   (wxID_ANY, wxTreebook::OnTreeSelectionChange)
58     EVT_TREE_ITEM_EXPANDED (wxID_ANY, wxTreebook::OnTreeNodeExpandedCollapsed)
59     EVT_TREE_ITEM_COLLAPSED(wxID_ANY, wxTreebook::OnTreeNodeExpandedCollapsed)
60 END_EVENT_TABLE()
61
62 // ============================================================================
63 // wxTreebook implementation
64 // ============================================================================
65
66 // ----------------------------------------------------------------------------
67 // wxTreebook creation
68 // ----------------------------------------------------------------------------
69
70 void wxTreebook::Init()
71 {
72     m_selection =
73     m_actualSelection = wxNOT_FOUND;
74 }
75
76 bool
77 wxTreebook::Create(wxWindow *parent,
78                    wxWindowID id,
79                    const wxPoint& pos,
80                    const wxSize& size,
81                    long style,
82                    const wxString& name)
83 {
84     // Check the style flag to have either wxTBK_RIGHT or wxTBK_LEFT
85     if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT )
86     {
87         style |= wxBK_LEFT;
88     }
89     style |= wxTAB_TRAVERSAL;
90
91     // no border for this control, it doesn't look nice together with the tree
92     style &= ~wxBORDER_MASK;
93     style |= wxBORDER_NONE;
94
95     if ( !wxControl::Create(parent, id, pos, size,
96                             style, wxDefaultValidator, name) )
97         return false;
98
99     m_bookctrl = new wxTreeCtrl
100                  (
101                     this,
102                     wxID_ANY,
103                     wxDefaultPosition,
104                     wxDefaultSize,
105 #ifndef __WXMSW__
106                     wxBORDER_SIMPLE | // On wxMSW this produces a black border which is wrong
107 #endif
108                     wxTR_DEFAULT_STYLE |
109                     wxTR_HIDE_ROOT |
110                     wxTR_SINGLE
111                  );
112     GetTreeCtrl()->SetQuickBestSize(false); // do full size calculation
113     GetTreeCtrl()->AddRoot(wxEmptyString); // label doesn't matter, it's hidden
114
115 #ifdef __WXMSW__
116     // We need to add dummy size event to force possible scrollbar hiding
117     wxSizeEvent evt;
118     GetEventHandler()->AddPendingEvent(evt);
119 #endif
120
121     return true;
122 }
123
124
125 // insert a new page just before the pagePos
126 bool wxTreebook::InsertPage(size_t pagePos,
127                             wxWindow *page,
128                             const wxString& text,
129                             bool bSelect,
130                             int imageId)
131 {
132     return DoInsertPage(pagePos, page, text, bSelect, imageId);
133 }
134
135 bool wxTreebook::InsertSubPage(size_t pagePos,
136                                wxWindow *page,
137                                const wxString& text,
138                                bool bSelect,
139                                int imageId)
140 {
141     return DoInsertSubPage(pagePos, page, text, bSelect, imageId);
142 }
143
144 bool wxTreebook::AddPage(wxWindow *page, const wxString& text, bool bSelect,
145                          int imageId)
146 {
147     return DoInsertPage(m_treeIds.GetCount(), page, text, bSelect, imageId);
148 }
149
150 // insertion time is linear to the number of top-pages
151 bool wxTreebook::AddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId)
152 {
153     return DoAddSubPage(page, text, bSelect, imageId);
154 }
155
156
157 bool wxTreebook::DoInsertPage(size_t pagePos,
158                               wxWindow *page,
159                               const wxString& text,
160                               bool bSelect,
161                               int imageId)
162 {
163     wxCHECK_MSG( pagePos <= DoInternalGetPageCount(), false,
164                         wxT("Invalid treebook page position") );
165
166     if ( !wxBookCtrlBase::InsertPage(pagePos, page, text, bSelect, imageId) )
167         return false;
168
169     wxTreeCtrl *tree = GetTreeCtrl();
170     wxTreeItemId newId;
171     if ( pagePos == DoInternalGetPageCount() )
172     {
173         // append the page to the end
174         wxTreeItemId rootId = tree->GetRootItem();
175
176         newId = tree->AppendItem(rootId, text, imageId);
177     }
178     else // insert the new page before the given one
179     {
180         wxTreeItemId nodeId = m_treeIds[pagePos];
181
182         wxTreeItemId previousId = tree->GetPrevSibling(nodeId);
183         wxTreeItemId parentId = tree->GetItemParent(nodeId);
184
185         if ( previousId.IsOk() )
186         {
187             // insert before the sibling - previousId
188             newId = tree->InsertItem(parentId, previousId, text, imageId);
189         }
190         else // no prev siblings -- insert as a first child
191         {
192             wxASSERT_MSG( parentId.IsOk(), wxT( "Tree has no root node?" ) );
193
194             newId = tree->PrependItem(parentId, text, imageId);
195         }
196     }
197
198     if ( !newId.IsOk() )
199     {
200         //something wrong -> cleaning and returning with false
201         (void)wxBookCtrlBase::DoRemovePage(pagePos);
202
203         wxFAIL_MSG( wxT("Failed to insert treebook page") );
204         return false;
205     }
206
207     DoInternalAddPage(pagePos, page, newId);
208
209     DoUpdateSelection(bSelect, pagePos);
210
211     return true;
212 }
213
214 bool wxTreebook::DoAddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId)
215 {
216     wxTreeCtrl *tree = GetTreeCtrl();
217
218     wxTreeItemId rootId = tree->GetRootItem();
219
220     wxTreeItemId lastNodeId = tree->GetLastChild(rootId);
221
222     wxCHECK_MSG( lastNodeId.IsOk(), false,
223                         _T("Can't insert sub page when there are no pages") );
224
225     // now calculate its position (should we save/update it too?)
226     size_t newPos = tree->GetCount() -
227                         (tree->GetChildrenCount(lastNodeId, true) + 1);
228
229     return DoInsertSubPage(newPos, page, text, bSelect, imageId);
230 }
231
232 bool wxTreebook::DoInsertSubPage(size_t pagePos,
233                                  wxTreebookPage *page,
234                                  const wxString& text,
235                                  bool bSelect,
236                                  int imageId)
237 {
238     wxTreeItemId parentId = DoInternalGetPage(pagePos);
239     wxCHECK_MSG( parentId.IsOk(), false, wxT("invalid tree item") );
240
241     wxTreeCtrl *tree = GetTreeCtrl();
242
243     size_t newPos = pagePos + tree->GetChildrenCount(parentId, true) + 1;
244     wxASSERT_MSG( newPos <= DoInternalGetPageCount(),
245                     wxT("Internal error in tree insert point calculation") );
246
247     if ( !wxBookCtrlBase::InsertPage(newPos, page, text, bSelect, imageId) )
248         return false;
249
250     wxTreeItemId newId = tree->AppendItem(parentId, text, imageId);
251
252     if ( !newId.IsOk() )
253     {
254         (void)wxBookCtrlBase::DoRemovePage(newPos);
255
256         wxFAIL_MSG( wxT("Failed to insert treebook page") );
257         return false;
258     }
259
260     DoInternalAddPage(newPos, page, newId);
261
262     DoUpdateSelection(bSelect, newPos);
263
264     return true;
265 }
266
267 bool wxTreebook::DeletePage(size_t pagePos)
268 {
269     wxCHECK_MSG( IS_VALID_PAGE(pagePos), false, wxT("Invalid tree index") );
270
271     wxTreebookPage *oldPage = DoRemovePage(pagePos);
272     if ( !oldPage )
273         return false;
274
275     delete oldPage;
276
277     return true;
278 }
279
280 wxTreebookPage *wxTreebook::DoRemovePage(size_t pagePos)
281 {
282     wxTreeItemId pageId = DoInternalGetPage(pagePos);
283     wxCHECK_MSG( pageId.IsOk(), NULL, wxT("Invalid tree index") );
284
285     wxTreebookPage * oldPage = GetPage(pagePos);
286     wxTreeCtrl *tree = GetTreeCtrl();
287
288     size_t subCount = tree->GetChildrenCount(pageId, true);
289     wxASSERT_MSG ( IS_VALID_PAGE(pagePos + subCount),
290                         wxT("Internal error in wxTreebook::DoRemovePage") );
291
292     // here we are going to delete ALL the pages in the range
293     // [pagePos, pagePos + subCount] -- the page and its children
294
295     // deleting all the pages from the base class
296     for ( size_t i = 0; i <= subCount; ++i )
297     {
298         wxTreebookPage *page = wxBookCtrlBase::DoRemovePage(pagePos);
299
300         // don't delete the page itself though -- it will be deleted in
301         // DeletePage() when we return
302         if ( i )
303         {
304             delete page;
305         }
306     }
307
308     DoInternalRemovePageRange(pagePos, subCount);
309
310     tree->DeleteChildren( pageId );
311     tree->Delete( pageId );
312
313     return oldPage;
314 }
315
316 bool wxTreebook::DeleteAllPages()
317 {
318     wxBookCtrlBase::DeleteAllPages();
319     m_treeIds.Clear();
320     m_selection =
321     m_actualSelection = wxNOT_FOUND;
322
323     wxTreeCtrl *tree = GetTreeCtrl();
324     tree->DeleteChildren(tree->GetRootItem());
325
326     return true;
327 }
328
329 void wxTreebook::DoInternalAddPage(size_t newPos,
330                                    wxTreebookPage *page,
331                                    wxTreeItemId pageId)
332 {
333     wxASSERT_MSG( newPos <= m_treeIds.GetCount(), wxT("Ivalid index passed to wxTreebook::DoInternalAddPage") );
334
335     // hide newly inserted page initially (it will be shown when selected)
336     if ( page )
337         page->Hide();
338
339     if ( newPos == m_treeIds.GetCount() )
340     {
341         // append
342         m_treeIds.Add(pageId);
343     }
344     else // insert
345     {
346         m_treeIds.Insert(pageId, newPos);
347
348         if ( m_selection != wxNOT_FOUND && newPos <= (size_t)m_selection )
349         {
350             // selection has been moved one unit toward the end
351             ++m_selection;
352             if ( m_actualSelection != wxNOT_FOUND )
353                 ++m_actualSelection;
354         }
355         else if ( m_actualSelection != wxNOT_FOUND &&
356                     newPos <= (size_t)m_actualSelection )
357         {
358             DoSetSelection(m_selection);
359         }
360     }
361 }
362
363 void wxTreebook::DoInternalRemovePageRange(size_t pagePos, size_t subCount)
364 {
365     // Attention: this function is only for a situation when we delete a node
366     // with all its children so pagePos is the node's index and subCount is the
367     // node children count
368     wxASSERT_MSG( pagePos + subCount < m_treeIds.GetCount(),
369                     wxT("Ivalid page index") );
370
371     wxTreeItemId pageId = m_treeIds[pagePos];
372
373     m_treeIds.RemoveAt(pagePos, subCount + 1);
374
375     if ( m_selection != wxNOT_FOUND )
376     {
377         if ( (size_t)m_selection > pagePos + subCount)
378         {
379             // selection is far after the deleted page, so just update the index and move on
380             m_selection -= 1 + subCount;
381             if ( m_actualSelection != wxNOT_FOUND)
382             {
383                 m_actualSelection -= subCount + 1;
384             }
385         }
386         else if ( (size_t)m_selection >= pagePos )
387         {
388             wxTreeCtrl *tree = GetTreeCtrl();
389
390             // as selected page is going to be deleted, try to select the next
391             // sibling if exists, if not then the parent
392             wxTreeItemId nodeId = tree->GetNextSibling(pageId);
393
394             m_selection = wxNOT_FOUND;
395             m_actualSelection = wxNOT_FOUND;
396
397             if ( nodeId.IsOk() )
398             {
399                 // selecting next siblings
400                 tree->SelectItem(nodeId);
401             }
402             else // no next sibling, select the parent
403             {
404                 wxTreeItemId parentId = tree->GetItemParent(pageId);
405
406                 if ( parentId.IsOk() && parentId != tree->GetRootItem() )
407                 {
408                     tree->SelectItem(parentId);
409                 }
410                 else // parent is root
411                 {
412                     // we can't select it as it's hidden
413                     DoUpdateSelection(false, wxNOT_FOUND);
414                 }
415             }
416         }
417         else if ( m_actualSelection != wxNOT_FOUND &&
418                     (size_t)m_actualSelection >= pagePos )
419         {
420             // nothing to do -- selection is before the deleted node, but
421             // actually shown page (the first (sub)child with page != NULL) is
422             // already deleted
423             m_actualSelection = m_selection;
424
425             // send event as documented
426             DoSetSelection(m_selection, SetSelection_SendEvent);
427         }
428         //else: nothing to do -- selection is before the deleted node
429     }
430     else
431     {
432         DoUpdateSelection(false, wxNOT_FOUND);
433     }
434 }
435
436
437 void wxTreebook::DoUpdateSelection(bool bSelect, int newPos)
438 {
439     int newSelPos;
440     if ( bSelect )
441     {
442         newSelPos = newPos;
443     }
444     else if ( m_selection == wxNOT_FOUND && DoInternalGetPageCount() > 0 )
445     {
446         newSelPos = 0;
447     }
448     else
449     {
450         newSelPos = wxNOT_FOUND;
451     }
452
453     if ( newSelPos != wxNOT_FOUND )
454     {
455         SetSelection((size_t)newSelPos);
456     }
457 }
458
459 wxTreeItemId wxTreebook::DoInternalGetPage(size_t pagePos) const
460 {
461     if ( pagePos >= m_treeIds.GetCount() )
462     {
463         // invalid position but ok here, in this internal function, don't assert
464         // (the caller will do it)
465         return wxTreeItemId();
466     }
467
468     return m_treeIds[pagePos];
469 }
470
471 int wxTreebook::DoInternalFindPageById(wxTreeItemId pageId) const
472 {
473     const size_t count = m_treeIds.GetCount();
474     for ( size_t i = 0; i < count; ++i )
475     {
476         if ( m_treeIds[i] == pageId )
477             return i;
478     }
479
480     return wxNOT_FOUND;
481 }
482
483 bool wxTreebook::IsNodeExpanded(size_t pagePos) const
484 {
485     wxTreeItemId pageId = DoInternalGetPage(pagePos);
486
487     wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
488
489     return GetTreeCtrl()->IsExpanded(pageId);
490 }
491
492 bool wxTreebook::ExpandNode(size_t pagePos, bool expand)
493 {
494     wxTreeItemId pageId = DoInternalGetPage(pagePos);
495
496     wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
497
498     if ( expand )
499     {
500         GetTreeCtrl()->Expand( pageId );
501     }
502     else // collapse
503     {
504         GetTreeCtrl()->Collapse( pageId );
505
506         // rely on the events generated by wxTreeCtrl to update selection
507     }
508
509     return true;
510 }
511
512 int wxTreebook::GetPageParent(size_t pagePos) const
513 {
514     wxTreeItemId nodeId = DoInternalGetPage( pagePos );
515     wxCHECK_MSG( nodeId.IsOk(), wxNOT_FOUND, wxT("Invalid page index spacified!") );
516
517     const wxTreeItemId parent = GetTreeCtrl()->GetItemParent( nodeId );
518
519     return parent.IsOk() ? DoInternalFindPageById(parent) : wxNOT_FOUND;
520 }
521
522 bool wxTreebook::SetPageText(size_t n, const wxString& strText)
523 {
524     wxTreeItemId pageId = DoInternalGetPage(n);
525
526     wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
527
528     GetTreeCtrl()->SetItemText(pageId, strText);
529
530     return true;
531 }
532
533 wxString wxTreebook::GetPageText(size_t n) const
534 {
535     wxTreeItemId pageId = DoInternalGetPage(n);
536
537     wxCHECK_MSG( pageId.IsOk(), wxString(), wxT("invalid tree item") );
538
539     return GetTreeCtrl()->GetItemText(pageId);
540 }
541
542 int wxTreebook::GetPageImage(size_t n) const
543 {
544     wxTreeItemId pageId = DoInternalGetPage(n);
545
546     wxCHECK_MSG( pageId.IsOk(), wxNOT_FOUND, wxT("invalid tree item") );
547
548     return GetTreeCtrl()->GetItemImage(pageId);
549 }
550
551 bool wxTreebook::SetPageImage(size_t n, int imageId)
552 {
553     wxTreeItemId pageId = DoInternalGetPage(n);
554
555     wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
556
557     GetTreeCtrl()->SetItemImage(pageId, imageId);
558
559     return true;
560 }
561
562 wxSize wxTreebook::CalcSizeFromPage(const wxSize& sizePage) const
563 {
564     const wxSize sizeTree = GetControllerSize();
565
566     wxSize size = sizePage;
567     size.x += sizeTree.x;
568
569     return size;
570 }
571
572 int wxTreebook::GetSelection() const
573 {
574    return m_selection;
575 }
576
577 int wxTreebook::DoSetSelection(size_t pagePos, int flags)
578 {
579     wxCHECK_MSG( IS_VALID_PAGE(pagePos), wxNOT_FOUND,
580                  wxT("invalid page index in wxListbook::DoSetSelection()") );
581     wxASSERT_MSG( GetPageCount() == DoInternalGetPageCount(),
582                   wxT("wxTreebook logic error: m_treeIds and m_pages not in sync!"));
583
584     wxTreebookEvent event(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING, m_windowId);
585     const int oldSel = m_selection;
586     wxTreeCtrl *tree = GetTreeCtrl();
587     bool allowed = false;
588
589     if (flags & SetSelection_SendEvent)
590     {
591         event.SetEventObject(this);
592         event.SetSelection(pagePos);
593         event.SetOldSelection(m_selection);
594
595         // don't send the event if the old and new pages are the same; do send it
596         // otherwise and be prepared for it to be vetoed
597         allowed = (int)pagePos == m_selection ||
598                   !GetEventHandler()->ProcessEvent(event) ||
599                   event.IsAllowed();
600     }
601
602     if ( !(flags & SetSelection_SendEvent) || allowed )
603     {
604         // hide the previously shown page
605         wxTreebookPage * const oldPage = DoGetCurrentPage();
606         if ( oldPage )
607             oldPage->Hide();
608
609         // then show the new one
610         m_selection = pagePos;
611         wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection);
612         if ( !page )
613         {
614             // find the next page suitable to be shown: the first (grand)child
615             // of this one with a non-NULL associated page
616             wxTreeItemId childId = m_treeIds[pagePos];
617             int actualPagePos = pagePos;
618             while ( !page && childId.IsOk() )
619             {
620                 wxTreeItemIdValue cookie;
621                 childId = tree->GetFirstChild( childId, cookie );
622                 if ( childId.IsOk() )
623                 {
624                     page = wxBookCtrlBase::GetPage(++actualPagePos);
625                 }
626             }
627
628             m_actualSelection = page ? actualPagePos : m_selection;
629         }
630
631         if ( page )
632             page->Show();
633
634         tree->SelectItem(DoInternalGetPage(pagePos));
635
636         if (flags & SetSelection_SendEvent)
637         {
638             // notify about the (now completed) page change
639             event.SetEventType(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED);
640             (void)GetEventHandler()->ProcessEvent(event);
641         }
642     }
643     else if ( (flags & SetSelection_SendEvent) && !allowed) // page change vetoed
644     {
645         // tree selection might have already had changed
646         if ( oldSel != wxNOT_FOUND )
647             tree->SelectItem(DoInternalGetPage(oldSel));
648     }
649
650     return oldSel;
651 }
652
653 wxTreebookPage *wxTreebook::DoGetCurrentPage() const
654 {
655     if ( m_selection == wxNOT_FOUND )
656         return NULL;
657
658     wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection);
659     if ( !page && m_actualSelection != wxNOT_FOUND )
660     {
661         page = wxBookCtrlBase::GetPage(m_actualSelection);
662     }
663
664     return page;
665 }
666
667 void wxTreebook::SetImageList(wxImageList *imageList)
668 {
669     wxBookCtrlBase::SetImageList(imageList);
670     GetTreeCtrl()->SetImageList(imageList);
671 }
672
673 void wxTreebook::AssignImageList(wxImageList *imageList)
674 {
675     wxBookCtrlBase::AssignImageList(imageList);
676     GetTreeCtrl()->SetImageList(imageList);
677 }
678
679 // ----------------------------------------------------------------------------
680 // event handlers
681 // ----------------------------------------------------------------------------
682
683 void wxTreebook::OnTreeSelectionChange(wxTreeEvent& event)
684 {
685     if ( event.GetEventObject() != m_bookctrl )
686     {
687         event.Skip();
688         return;
689     }
690
691     wxTreeItemId newId = event.GetItem();
692
693     if ( (m_selection == wxNOT_FOUND &&
694                 (!newId.IsOk() || newId == GetTreeCtrl()->GetRootItem())) ||
695             (m_selection != wxNOT_FOUND && newId == m_treeIds[m_selection]) )
696     {
697         // this event can only come when we modify the tree selection ourselves
698         // so we should simply ignore it
699         return;
700     }
701
702     int newPos = DoInternalFindPageById(newId);
703
704     if ( newPos != wxNOT_FOUND )
705         SetSelection( newPos );
706 }
707
708 void wxTreebook::OnTreeNodeExpandedCollapsed(wxTreeEvent & event)
709 {
710     if ( event.GetEventObject() != m_bookctrl )
711     {
712         event.Skip();
713         return;
714     }
715
716     wxTreeItemId nodeId = event.GetItem();
717     if ( !nodeId.IsOk() || nodeId == GetTreeCtrl()->GetRootItem() )
718         return;
719     int pagePos = DoInternalFindPageById(nodeId);
720     wxCHECK_RET( pagePos != wxNOT_FOUND, wxT("Internal problem in wxTreebook!..") );
721
722     wxTreebookEvent ev(GetTreeCtrl()->IsExpanded(nodeId)
723             ? wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED
724             : wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED,
725         m_windowId);
726
727     ev.SetSelection(pagePos);
728     ev.SetOldSelection(pagePos);
729     ev.SetEventObject(this);
730
731     GetEventHandler()->ProcessEvent(ev);
732 }
733
734 // ----------------------------------------------------------------------------
735 // wxTreebook geometry management
736 // ----------------------------------------------------------------------------
737
738 int wxTreebook::HitTest(wxPoint const & pt, long * flags) const
739 {
740     int pagePos = wxNOT_FOUND;
741
742     if ( flags )
743         *flags = wxBK_HITTEST_NOWHERE;
744
745     // convert from wxTreebook coorindates to wxTreeCtrl ones
746     const wxTreeCtrl * const tree = GetTreeCtrl();
747     const wxPoint treePt = tree->ScreenToClient(ClientToScreen(pt));
748
749     // is it over the tree?
750     if ( wxRect(tree->GetSize()).Contains(treePt) )
751     {
752         int flagsTree;
753         wxTreeItemId id = tree->HitTest(treePt, flagsTree);
754
755         if ( id.IsOk() && (flagsTree & wxTREE_HITTEST_ONITEM) )
756         {
757             pagePos = DoInternalFindPageById(id);
758         }
759
760         if ( flags )
761         {
762             if ( pagePos != wxNOT_FOUND )
763                 *flags = 0;
764
765             if ( flagsTree & (wxTREE_HITTEST_ONITEMBUTTON |
766                               wxTREE_HITTEST_ONITEMICON |
767                               wxTREE_HITTEST_ONITEMSTATEICON) )
768                 *flags |= wxBK_HITTEST_ONICON;
769
770             if ( flagsTree & wxTREE_HITTEST_ONITEMLABEL )
771                 *flags |= wxBK_HITTEST_ONLABEL;
772         }
773     }
774     else // not over the tree
775     {
776         if ( flags && GetPageRect().Contains( pt ) )
777             *flags |= wxBK_HITTEST_ONPAGE;
778     }
779
780     return pagePos;
781 }
782
783 #endif // wxUSE_TREEBOOK