diff --git a/include/wx/msw/notebook.h b/include/wx/msw/notebook.h index dbe9531e63..6ab3f09947 100644 --- a/include/wx/msw/notebook.h +++ b/include/wx/msw/notebook.h @@ -93,6 +93,9 @@ public: // style. void SetTabSize(const wxSize& sz) override; + // Return the position and size of the tab for the given page + wxRect GetTabRect(size_t page) const override; + // hit test virtual int HitTest(const wxPoint& pt, long *flags = nullptr) const override; diff --git a/include/wx/notebook.h b/include/wx/notebook.h index 76389df640..41175827af 100644 --- a/include/wx/notebook.h +++ b/include/wx/notebook.h @@ -139,6 +139,13 @@ public: // new is wxNOT_FOUND) void SendPageChangedEvent(int nPageOld, int nPageNew = wxNOT_FOUND); + // return wxTOP/wxBOTTOM/wxRIGHT/wxLEFT + wxDirection GetTabOrientation() const; + + // return the rectangle in window coordinates of the page selector. + // For example, for a wxNotebook this would be its tab. + virtual wxRect GetTabRect(size_t page) const; + #if wxUSE_EXTENDED_RTTI // XTI accessors virtual void AddPageInfo( wxNotebookPageInfo* info ); diff --git a/include/wx/univ/notebook.h b/include/wx/univ/notebook.h index cec4332179..3b1c1d2e05 100644 --- a/include/wx/univ/notebook.h +++ b/include/wx/univ/notebook.h @@ -93,9 +93,6 @@ public: // return true if all tabs have the same width bool FixedSizeTabs() const { return HasFlag(wxNB_FIXEDWIDTH); } - // return wxTOP/wxBOTTOM/wxRIGHT/wxLEFT - wxDirection GetTabOrientation() const; - // return true if the notebook has tabs at the sidesand not at the top (or // bottom) as usual bool IsVertical() const; @@ -121,6 +118,9 @@ public: // refresh the currently selected tab void RefreshCurrent(); + // get the tab rect + wxRect GetTabRect(size_t page) const override; + protected: virtual wxNotebookPage *DoRemovePage(size_t nPage) override; @@ -164,9 +164,6 @@ protected: // refresh all tabs void RefreshAllTabs(); - // get the tab rect (inefficient, don't use this in a loop) - wxRect GetTabRect(int page) const; - // get the rectangle containing all tabs wxRect GetAllTabsRect() const; diff --git a/interface/wx/notebook.h b/interface/wx/notebook.h index 845c46a9d4..dd80c0bb98 100644 --- a/interface/wx/notebook.h +++ b/interface/wx/notebook.h @@ -191,6 +191,30 @@ public: */ virtual void SetPadding(const wxSize& padding); + /** + This is a convenience function mapping wxBK_TOP etc styles to one of the + wxDirection enum elements. + + @since 3.3.0 + */ + wxDirection GetTabOrientation() const; + + /** + Return the rectangle of the given page tab in window coordinates. + + This function always returns the rectangle for the specified tab, even + if the tab is currently not visible. + + If @a page is invalid, an assert failure is triggered and an empty + rectangle is returned. + + @note Currently only available in Univ and MSW and always asserts in + the other ports. + + @since 3.3.0 + */ + virtual wxRect GetTabRect(size_t page) const; + // implementations of pure virtuals virtual int GetPageImage(size_t nPage) const; virtual bool SetPageImage(size_t page, int image); diff --git a/src/common/nbkbase.cpp b/src/common/nbkbase.cpp index 2a16b7549d..985d5eadf4 100644 --- a/src/common/nbkbase.cpp +++ b/src/common/nbkbase.cpp @@ -33,6 +33,8 @@ extern WXDLLEXPORT_DATA(const char) wxNotebookNameStr[] = "notebook"; +#define IS_VALID_PAGE(nPage) ((nPage) < GetPageCount()) + wxDEFINE_EVENT( wxEVT_NOTEBOOK_PAGE_CHANGED, wxBookCtrlEvent ); wxDEFINE_EVENT( wxEVT_NOTEBOOK_PAGE_CHANGING, wxBookCtrlEvent ); @@ -197,4 +199,27 @@ void wxNotebookBase::SendPageChangedEvent(int nPageOld, int nPageNew) GetEventHandler()->ProcessEvent(event); } +wxDirection wxNotebookBase::GetTabOrientation() const +{ + long style = GetWindowStyle(); + if ( style & wxBK_BOTTOM ) + return wxBOTTOM; + else if ( style & wxBK_RIGHT ) + return wxRIGHT; + else if ( style & wxBK_LEFT ) + return wxLEFT; + + // wxBK_TOP == 0 so we don't have to test for it + return wxTOP; +} + +wxRect wxNotebookBase::GetTabRect(size_t page) const +{ + wxRect r; + wxCHECK_MSG(IS_VALID_PAGE(page), r, wxT("invalid notebook page")); + wxFAIL_MSG("Not implemented"); + + return r; +} + #endif // wxUSE_NOTEBOOK diff --git a/src/msw/notebook.cpp b/src/msw/notebook.cpp index 029de658bf..473866d8d0 100644 --- a/src/msw/notebook.cpp +++ b/src/msw/notebook.cpp @@ -499,6 +499,21 @@ void wxNotebook::SetTabSize(const wxSize& sz) ::SendMessage(GetHwnd(), TCM_SETITEMSIZE, 0, MAKELPARAM(sz.x, sz.y)); } +wxRect wxNotebook::GetTabRect(size_t page) const +{ + wxRect r; + wxCHECK_MSG(IS_VALID_PAGE(page), r, wxT("invalid notebook page")); + + if (GetPageCount() > 0) + { + RECT rect; + if (TabCtrl_GetItemRect(GetHwnd(), page, &rect)) + r = wxRectFromRECT(rect); + } + + return r; +} + wxSize wxNotebook::CalcSizeFromPage(const wxSize& sizePage) const { // we can't use TabCtrl_AdjustRect here because it only works for wxNB_TOP diff --git a/src/univ/notebook.cpp b/src/univ/notebook.cpp index 77fd3abc25..43adf1748d 100644 --- a/src/univ/notebook.cpp +++ b/src/univ/notebook.cpp @@ -659,21 +659,7 @@ bool wxNotebook::IsVertical() const return dir == wxLEFT || dir == wxRIGHT; } -wxDirection wxNotebook::GetTabOrientation() const -{ - long style = GetWindowStyle(); - if ( style & wxBK_BOTTOM ) - return wxBOTTOM; - else if ( style & wxBK_RIGHT ) - return wxRIGHT; - else if ( style & wxBK_LEFT ) - return wxLEFT; - - // wxBK_TOP == 0 so we don't have to test for it - return wxTOP; -} - -wxRect wxNotebook::GetTabRect(int page) const +wxRect wxNotebook::GetTabRect(size_t page) const { wxRect rect; wxCHECK_MSG( IS_VALID_PAGE(page), rect, wxT("invalid notebook page") ); @@ -688,7 +674,7 @@ wxRect wxNotebook::GetTabRect(int page) const else { widthBefore = 0; - for ( int n = 0; n < page; n++ ) + for ( size_t n = 0; n < page; n++ ) { widthBefore += m_widths[n]; } diff --git a/tests/controls/notebooktest.cpp b/tests/controls/notebooktest.cpp index f293116b36..5a3e41def9 100644 --- a/tests/controls/notebooktest.cpp +++ b/tests/controls/notebooktest.cpp @@ -45,10 +45,12 @@ private: CPPUNIT_TEST( Image ); CPPUNIT_TEST( RowCount ); CPPUNIT_TEST( NoEventsOnDestruction ); + CPPUNIT_TEST( GetTabRect ); CPPUNIT_TEST_SUITE_END(); void RowCount(); void NoEventsOnDestruction(); + void GetTabRect(); void OnPageChanged(wxNotebookEvent&) { m_numPageChanges++; } @@ -163,4 +165,37 @@ TEST_CASE("wxNotebook::AddPageEvents", "[wxNotebook][AddPage][event]") CHECK( countPageChanged.GetCount() == 1 ); } +void NotebookTestCase::GetTabRect() +{ + if (wxIsRunningUnderWine()) + { + // Wine behaves different than Windows. Windows reports the size of a + // tab even if it is not visible while Wine returns an empty rectangle. + WARN("Skipping test known to fail under Wine."); + return; + } + + wxNotebook *notebook = new wxNotebook(wxTheApp->GetTopWindow(), wxID_ANY, + wxDefaultPosition, wxSize(400, 200)); + wxScopedPtr cleanup(notebook); + + notebook->AddPage(new wxPanel(notebook), "First"); + + // This function is only really implemented for wxMSW and wxUniv currently. +#if defined(__WXMSW__) || defined(__WXUNIVERSAL__) + // Create many pages, so that at least some of the are not visible. + for ( size_t i = 0; i < 30; i++ ) + notebook->AddPage(new wxPanel(notebook), "Page"); + + for ( size_t i = 0; i < notebook->GetPageCount(); i++ ) + { + wxRect r = notebook->GetTabRect(i); + CHECK(r.width != 0); + CHECK(r.height != 0); + } +#else // !(__WXMSW__ || __WXUNIVERSAL__) + WX_ASSERT_FAILS_WITH_ASSERT( notebook->GetTabRect(0) ); +#endif // ports +} + #endif //wxUSE_NOTEBOOK