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