X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/b6b4695492baff990f5cb4c50522fd6a72c2773d..2e14066008229145e2da7b9f05a478ce38631f83:/src/common/bookctrl.cpp diff --git a/src/common/bookctrl.cpp b/src/common/bookctrl.cpp index 16e4cf3e9a..5392388681 100644 --- a/src/common/bookctrl.cpp +++ b/src/common/bookctrl.cpp @@ -53,6 +53,7 @@ END_EVENT_TABLE() void wxBookCtrlBase::Init() { + m_selection = wxNOT_FOUND; m_bookctrl = NULL; m_imageList = NULL; m_ownsImageList = false; @@ -125,6 +126,40 @@ void wxBookCtrlBase::AssignImageList(wxImageList* imageList) // geometry // ---------------------------------------------------------------------------- +void wxBookCtrlBase::DoInvalidateBestSize() +{ + // notice that it is not necessary to invalidate our own best size + // explicitly if we have m_bookctrl as it will already invalidate the best + // size of its parent when its own size is invalidated and its parent is + // this control + if ( m_bookctrl ) + m_bookctrl->InvalidateBestSize(); + else + wxControl::InvalidateBestSize(); +} + +wxSize wxBookCtrlBase::CalcSizeFromPage(const wxSize& sizePage) const +{ + // we need to add the size of the choice control and the border between + const wxSize sizeController = GetControllerSize(); + + wxSize size = sizePage; + if ( IsVertical() ) + { + if ( sizeController.x > sizePage.x ) + size.x = sizeController.x; + size.y += sizeController.y + GetInternalBorder(); + } + else // left/right aligned + { + size.x += sizeController.x + GetInternalBorder(); + if ( sizeController.y > sizePage.y ) + size.y = sizeController.y; + } + + return size; +} + void wxBookCtrlBase::SetPageSize(const wxSize& size) { SetClientSize(CalcSizeFromPage(size)); @@ -161,116 +196,6 @@ wxSize wxBookCtrlBase::DoGetBestSize() const return best; } -#if wxUSE_HELP -void wxBookCtrlBase::OnHelp(wxHelpEvent& event) -{ - // ignore the events not coming from the book control itself, otherwise we - // could attempt to redirect a help event generated by one of our pages - // back to the same page resulting in an infinite loop - if ( event.GetEventObject() != this ) - { - event.Skip(); - return; - } - - // find the corresponding page - wxWindow *page = NULL; - - if ( event.GetOrigin() == wxHelpEvent::Origin_HelpButton ) - { - // show help for the page under the mouse - const int pagePos = HitTest(ScreenToClient(event.GetPosition())); - - if ( pagePos != wxNOT_FOUND) - { - page = GetPage((size_t)pagePos); - } - } - - if ( !page ) - { - page = GetCurrentPage(); - } - - if ( !page || !page->GetEventHandler()->ProcessEvent(event) ) - { - event.Skip(); - } -} -#endif // wxUSE_HELP - -// ---------------------------------------------------------------------------- -// pages management -// ---------------------------------------------------------------------------- - -bool -wxBookCtrlBase::InsertPage(size_t nPage, - wxWindow *page, - const wxString& WXUNUSED(text), - bool WXUNUSED(bSelect), - int WXUNUSED(imageId)) -{ - wxCHECK_MSG( page || AllowNullPage(), false, - _T("NULL page in wxBookCtrlBase::InsertPage()") ); - wxCHECK_MSG( nPage <= m_pages.size(), false, - _T("invalid page index in wxBookCtrlBase::InsertPage()") ); - - m_pages.Insert(page, nPage); - if ( page ) - page->SetSize(GetPageRect()); - - InvalidateBestSize(); - - return true; -} - -bool wxBookCtrlBase::DeletePage(size_t nPage) -{ - wxWindow *page = DoRemovePage(nPage); - if ( !(page || AllowNullPage()) ) - return false; - - // delete NULL is harmless - delete page; - - return true; -} - -wxWindow *wxBookCtrlBase::DoRemovePage(size_t nPage) -{ - wxCHECK_MSG( nPage < m_pages.size(), NULL, - _T("invalid page index in wxBookCtrlBase::DoRemovePage()") ); - - wxWindow *pageRemoved = m_pages[nPage]; - m_pages.RemoveAt(nPage); - InvalidateBestSize(); - - return pageRemoved; -} - -int wxBookCtrlBase::GetNextPage(bool forward) const -{ - int nPage; - - int nMax = GetPageCount(); - if ( nMax-- ) // decrement it to get the last valid index - { - int nSel = GetSelection(); - - // change selection wrapping if it becomes invalid - nPage = forward ? nSel == nMax ? 0 - : nSel + 1 - : nSel == 0 ? nMax - : nSel - 1; - } - else // notebook is empty, no next page - { - nPage = wxNOT_FOUND; - } - - return nPage; -} - wxRect wxBookCtrlBase::GetPageRect() const { const wxSize size = GetControllerSize(); @@ -281,7 +206,7 @@ wxRect wxBookCtrlBase::GetPageRect() const switch ( GetWindowStyle() & wxBK_ALIGN_MASK ) { default: - wxFAIL_MSG( _T("unexpected alignment") ); + wxFAIL_MSG( wxT("unexpected alignment") ); // fall through case wxBK_TOP: @@ -290,6 +215,8 @@ wxRect wxBookCtrlBase::GetPageRect() const case wxBK_BOTTOM: rectPage.height -= size.y + GetInternalBorder(); + if (rectPage.height < 0) + rectPage.height = 0; break; case wxBK_LEFT: @@ -298,6 +225,8 @@ wxRect wxBookCtrlBase::GetPageRect() const case wxBK_RIGHT: rectPage.width -= size.x + GetInternalBorder(); + if (rectPage.width < 0) + rectPage.width = 0; break; } @@ -323,13 +252,20 @@ void wxBookCtrlBase::DoSize() sizeCtrl( GetControllerSize() ); m_bookctrl->SetClientSize( sizeCtrl.x - sizeBorder.x, sizeCtrl.y - sizeBorder.y ); + // if this changes the visibility of the scrollbars the best size changes, relayout in this case + wxSize sizeCtrl2 = GetControllerSize(); + if ( sizeCtrl != sizeCtrl2 ) + { + wxSize sizeBorder2 = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(); + m_bookctrl->SetClientSize( sizeCtrl2.x - sizeBorder2.x, sizeCtrl2.y - sizeBorder2.y ); + } const wxSize sizeNew = m_bookctrl->GetSize(); wxPoint posCtrl; switch ( GetWindowStyle() & wxBK_ALIGN_MASK ) { default: - wxFAIL_MSG( _T("unexpected alignment") ); + wxFAIL_MSG( wxT("unexpected alignment") ); // fall through case wxBK_TOP: @@ -352,14 +288,14 @@ void wxBookCtrlBase::DoSize() // resize all pages to fit the new control size const wxRect pageRect = GetPageRect(); - const unsigned pagesCount = m_pages.Count(); + const unsigned pagesCount = m_pages.GetCount(); for ( unsigned int i = 0; i < pagesCount; ++i ) { wxWindow * const page = m_pages[i]; if ( !page ) { wxASSERT_MSG( AllowNullPage(), - _T("Null page in a control that does not allow null pages?") ); + wxT("Null page in a control that does not allow null pages?") ); continue; } @@ -376,12 +312,14 @@ void wxBookCtrlBase::OnSize(wxSizeEvent& event) wxSize wxBookCtrlBase::GetControllerSize() const { - if(!m_bookctrl) - return wxSize(0,0); + // For at least some book controls (e.g. wxChoicebook) it may make sense to + // (temporarily?) hide the controller and we shouldn't leave extra space + // for the hidden control in this case. + if ( !m_bookctrl || !m_bookctrl->IsShown() ) + return wxSize(0, 0); const wxSize sizeClient = GetClientSize(), - sizeBorder = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(), - sizeCtrl = m_bookctrl->GetBestSize() + sizeBorder; + sizeCtrl = m_bookctrl->GetBestSize(); wxSize size; @@ -399,4 +337,200 @@ wxSize wxBookCtrlBase::GetControllerSize() const return size; } +// ---------------------------------------------------------------------------- +// miscellaneous stuff +// ---------------------------------------------------------------------------- + +#if wxUSE_HELP + +void wxBookCtrlBase::OnHelp(wxHelpEvent& event) +{ + // determine where does this even originate from to avoid redirecting it + // back to the page which generated it (resulting in an infinite loop) + + // notice that we have to check in the hard(er) way instead of just testing + // if the event object == this because the book control can have other + // subcontrols inside it (e.g. wxSpinButton in case of a notebook in wxUniv) + wxWindow *source = wxStaticCast(event.GetEventObject(), wxWindow); + while ( source && source != this && source->GetParent() != this ) + { + source = source->GetParent(); + } + + if ( source && m_pages.Index(source) == wxNOT_FOUND ) + { + // this event is for the book control itself, redirect it to the + // corresponding page + wxWindow *page = NULL; + + if ( event.GetOrigin() == wxHelpEvent::Origin_HelpButton ) + { + // show help for the page under the mouse + const int pagePos = HitTest(ScreenToClient(event.GetPosition())); + + if ( pagePos != wxNOT_FOUND) + { + page = GetPage((size_t)pagePos); + } + } + else // event from keyboard or unknown source + { + // otherwise show the current page help + page = GetCurrentPage(); + } + + if ( page ) + { + // change event object to the page to avoid infinite recursion if + // we get this event ourselves if the page doesn't handle it + event.SetEventObject(page); + + if ( page->GetEventHandler()->ProcessEvent(event) ) + { + // don't call event.Skip() + return; + } + } + } + //else: event coming from one of our pages already + + event.Skip(); +} + +#endif // wxUSE_HELP + +// ---------------------------------------------------------------------------- +// pages management +// ---------------------------------------------------------------------------- + +bool +wxBookCtrlBase::InsertPage(size_t nPage, + wxWindow *page, + const wxString& WXUNUSED(text), + bool WXUNUSED(bSelect), + int WXUNUSED(imageId)) +{ + wxCHECK_MSG( page || AllowNullPage(), false, + wxT("NULL page in wxBookCtrlBase::InsertPage()") ); + wxCHECK_MSG( nPage <= m_pages.size(), false, + wxT("invalid page index in wxBookCtrlBase::InsertPage()") ); + + m_pages.Insert(page, nPage); + if ( page ) + page->SetSize(GetPageRect()); + + DoInvalidateBestSize(); + + return true; +} + +bool wxBookCtrlBase::DeletePage(size_t nPage) +{ + wxWindow *page = DoRemovePage(nPage); + if ( !(page || AllowNullPage()) ) + return false; + + // delete NULL is harmless + delete page; + + return true; +} + +wxWindow *wxBookCtrlBase::DoRemovePage(size_t nPage) +{ + wxCHECK_MSG( nPage < m_pages.size(), NULL, + wxT("invalid page index in wxBookCtrlBase::DoRemovePage()") ); + + wxWindow *pageRemoved = m_pages[nPage]; + m_pages.RemoveAt(nPage); + DoInvalidateBestSize(); + + return pageRemoved; +} + +int wxBookCtrlBase::GetNextPage(bool forward) const +{ + int nPage; + + int nMax = GetPageCount(); + if ( nMax-- ) // decrement it to get the last valid index + { + int nSel = GetSelection(); + + // change selection wrapping if it becomes invalid + nPage = forward ? nSel == nMax ? 0 + : nSel + 1 + : nSel == 0 ? nMax + : nSel - 1; + } + else // notebook is empty, no next page + { + nPage = wxNOT_FOUND; + } + + return nPage; +} + +bool wxBookCtrlBase::DoSetSelectionAfterInsertion(size_t n, bool bSelect) +{ + if ( bSelect ) + SetSelection(n); + else if ( m_selection == wxNOT_FOUND ) + ChangeSelection(0); + else // We're not going to select this page. + return false; + + // Return true to indicate that we selected this page. + return true; +} + +int wxBookCtrlBase::DoSetSelection(size_t n, int flags) +{ + wxCHECK_MSG( n < GetPageCount(), wxNOT_FOUND, + wxT("invalid page index in wxBookCtrlBase::DoSetSelection()") ); + + const int oldSel = GetSelection(); + + if ( n != (size_t)oldSel ) + { + wxBookCtrlEvent *event = CreatePageChangingEvent(); + bool allowed = false; + + if ( flags & SetSelection_SendEvent ) + { + event->SetSelection(n); + event->SetOldSelection(oldSel); + event->SetEventObject(this); + + allowed = !GetEventHandler()->ProcessEvent(*event) || event->IsAllowed(); + } + + if ( !(flags & SetSelection_SendEvent) || allowed) + { + if ( oldSel != wxNOT_FOUND ) + m_pages[oldSel]->Hide(); + + wxWindow *page = m_pages[n]; + page->SetSize(GetPageRect()); + page->Show(); + + // change selection now to ignore the selection change event + UpdateSelectedPage(n); + + if ( flags & SetSelection_SendEvent ) + { + // program allows the page change + MakeChangedEvent(*event); + (void)GetEventHandler()->ProcessEvent(*event); + } + } + + delete event; + } + + return oldSel; +} + +IMPLEMENT_DYNAMIC_CLASS(wxBookCtrlEvent, wxNotifyEvent) + #endif // wxUSE_BOOKCTRL