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