From 92ea83f00b4f444112cc59bd873c7b17724fa85d Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Thu, 17 Sep 2020 22:35:22 +0200 Subject: [PATCH 01/21] First implementation --- include/wx/gtk/radiobut.h | 2 +- include/wx/gtk1/radiobut.h | 2 +- include/wx/motif/radiobut.h | 2 +- include/wx/msw/radiobut.h | 2 +- include/wx/osx/radiobut.h | 2 +- include/wx/qt/radiobut.h | 2 +- include/wx/radiobut.h | 39 +++++++++++++++++++++++++++++++++++++ include/wx/univ/radiobut.h | 2 +- 8 files changed, 46 insertions(+), 7 deletions(-) diff --git a/include/wx/gtk/radiobut.h b/include/wx/gtk/radiobut.h index cf6492a623..b85f8ea723 100644 --- a/include/wx/gtk/radiobut.h +++ b/include/wx/gtk/radiobut.h @@ -13,7 +13,7 @@ // wxRadioButton //----------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton: public wxControl +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { public: wxRadioButton() { } diff --git a/include/wx/gtk1/radiobut.h b/include/wx/gtk1/radiobut.h index d958079729..662b681d74 100644 --- a/include/wx/gtk1/radiobut.h +++ b/include/wx/gtk1/radiobut.h @@ -13,7 +13,7 @@ // wxRadioButton //----------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton: public wxControl +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { public: wxRadioButton() { } diff --git a/include/wx/motif/radiobut.h b/include/wx/motif/radiobut.h index 43414438a7..5759f01162 100644 --- a/include/wx/motif/radiobut.h +++ b/include/wx/motif/radiobut.h @@ -11,7 +11,7 @@ #ifndef _WX_RADIOBUT_H_ #define _WX_RADIOBUT_H_ -class WXDLLIMPEXP_CORE wxRadioButton: public wxControl +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { wxDECLARE_DYNAMIC_CLASS(wxRadioButton); public: diff --git a/include/wx/msw/radiobut.h b/include/wx/msw/radiobut.h index a568316edf..0554881601 100644 --- a/include/wx/msw/radiobut.h +++ b/include/wx/msw/radiobut.h @@ -13,7 +13,7 @@ #include "wx/msw/ownerdrawnbutton.h" -class WXDLLIMPEXP_CORE wxRadioButton : public wxMSWOwnerDrawnButton +class WXDLLIMPEXP_CORE wxRadioButton : public public wxRadioButtonBase> { public: // ctors and creation functions diff --git a/include/wx/osx/radiobut.h b/include/wx/osx/radiobut.h index e968d80acd..cf74f14d89 100644 --- a/include/wx/osx/radiobut.h +++ b/include/wx/osx/radiobut.h @@ -11,7 +11,7 @@ #ifndef _WX_RADIOBUT_H_ #define _WX_RADIOBUT_H_ -class WXDLLIMPEXP_CORE wxRadioButton: public wxControl +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { wxDECLARE_DYNAMIC_CLASS(wxRadioButton); diff --git a/include/wx/qt/radiobut.h b/include/wx/qt/radiobut.h index 5a1ab5ad14..1502173105 100644 --- a/include/wx/qt/radiobut.h +++ b/include/wx/qt/radiobut.h @@ -10,7 +10,7 @@ class QRadioButton; -class WXDLLIMPEXP_CORE wxRadioButton : public wxControl +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase { public: wxRadioButton(); diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index 11f466cdbe..dec331af73 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -32,6 +32,45 @@ #include "wx/control.h" +class WXDLLIMPEXP_FWD_CORE wxRadioButton; + +wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn); +wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn); +wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn); +wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn); + +template +class WXDLLIMPEXP_CORE wxRadioButtonBase : public W +{ +public: + typedef W BaseWindowClass; + + wxRadioButtonBase() { } + + wxRadioButton* GetFirstInGroup() const + { + return wxGetFirstButtonInGroup( static_cast(this)); + } + + wxRadioButton* GetLastInGroup() const + { + return wxGetLastButtonInGroup( static_cast(this)); + } + + wxRadioButton* GetPreviousInGroup() const + { + return wxGetPreviousButtonInGroup( static_cast(this)); + } + + wxRadioButton* GetNextInGroup() const + { + return wxGetNextButtonInGroup( static_cast(this)); + } + +private: + wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxRadioButtonBase, W); +}; + extern WXDLLIMPEXP_DATA_CORE(const char) wxRadioButtonNameStr[]; #if defined(__WXUNIVERSAL__) diff --git a/include/wx/univ/radiobut.h b/include/wx/univ/radiobut.h index ae16aa25ce..0b6580a2ab 100644 --- a/include/wx/univ/radiobut.h +++ b/include/wx/univ/radiobut.h @@ -17,7 +17,7 @@ // wxRadioButton // ---------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton : public wxCheckBox +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase { public: // constructors From 552dbbe26eae729f77a05799e9b7a926373c8754 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Thu, 17 Sep 2020 22:46:18 +0200 Subject: [PATCH 02/21] Removing const for first version --- include/wx/radiobut.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index dec331af73..02dadc5ff9 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -47,22 +47,22 @@ public: wxRadioButtonBase() { } - wxRadioButton* GetFirstInGroup() const + wxRadioButton* GetFirstInGroup() { return wxGetFirstButtonInGroup( static_cast(this)); } - wxRadioButton* GetLastInGroup() const + wxRadioButton* GetLastInGroup() { return wxGetLastButtonInGroup( static_cast(this)); } - wxRadioButton* GetPreviousInGroup() const + wxRadioButton* GetPreviousInGroup() { return wxGetPreviousButtonInGroup( static_cast(this)); } - wxRadioButton* GetNextInGroup() const + wxRadioButton* GetNextInGroup() { return wxGetNextButtonInGroup( static_cast(this)); } From 200c1af6978af783899e2dfcc7361de187451461 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Thu, 17 Sep 2020 23:13:44 +0200 Subject: [PATCH 03/21] Going private with the implementations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Although they’re still exported of course … --- include/wx/radiobut.h | 19 +++++++++++-------- src/common/containr.cpp | 19 ++++++++++++------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index 02dadc5ff9..182ae9c8c5 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -34,10 +34,13 @@ class WXDLLIMPEXP_FWD_CORE wxRadioButton; -wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn); -wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn); -wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn); -wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn); +namespace wxPrivate +{ + WXDLLIMPEXP_CORE wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn); +} // namespace wxPrivate template class WXDLLIMPEXP_CORE wxRadioButtonBase : public W @@ -49,22 +52,22 @@ public: wxRadioButton* GetFirstInGroup() { - return wxGetFirstButtonInGroup( static_cast(this)); + return wxPrivate::wxGetFirstButtonInGroup( static_cast(this)); } wxRadioButton* GetLastInGroup() { - return wxGetLastButtonInGroup( static_cast(this)); + return wxPrivate::wxGetLastButtonInGroup( static_cast(this)); } wxRadioButton* GetPreviousInGroup() { - return wxGetPreviousButtonInGroup( static_cast(this)); + return wxPrivate::wxGetPreviousButtonInGroup( static_cast(this)); } wxRadioButton* GetNextInGroup() { - return wxGetNextButtonInGroup( static_cast(this)); + return wxPrivate::wxGetNextButtonInGroup( static_cast(this)); } private: diff --git a/src/common/containr.cpp b/src/common/containr.cpp index b418a3b8c2..9bcdbab781 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -240,6 +240,9 @@ void wxControlContainer::SetLastFocus(wxWindow *win) #if wxUSE_RADIOBTN +namespace wxPrivate +{ + wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn) { if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) @@ -348,6 +351,8 @@ wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn) return NULL; } +} // namespace wxPrivate + #endif // wxUSE_RADIOBTN // ---------------------------------------------------------------------------- @@ -468,7 +473,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // If we are in a radio button group, start from the first item in the // group if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) ) - winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus); + winFocus = wxPrivate::wxGetFirstButtonInGroup((wxRadioButton*)winFocus); #endif // USE_RADIOBTN_NAV // ok, we found the focus - now is it our child? start_node = children.Find( winFocus ); @@ -564,7 +569,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) if ( child->HasFlag(wxRB_GROUP) ) { // need to tab into the active button within a group - wxRadioButton *rb = wxGetSelectedButtonInGroup((wxRadioButton*)child); + wxRadioButton *rb = wxPrivate::wxGetSelectedButtonInGroup((wxRadioButton*)child); if ( rb ) child = rb; } @@ -586,20 +591,20 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // find the correct radio button to focus if ( forward ) { - child = wxGetNextButtonInGroup(lastBtn); + child = wxPrivate::wxGetNextButtonInGroup(lastBtn); if ( !child ) { // no next button in group, set it to the first button - child = wxGetFirstButtonInGroup(lastBtn); + child = wxPrivate::wxGetFirstButtonInGroup(lastBtn); } } else { - child = wxGetPreviousButtonInGroup(lastBtn); + child = wxPrivate::wxGetPreviousButtonInGroup(lastBtn); if ( !child ) { // no previous button in group, set it to the last button - child = wxGetLastButtonInGroup(lastBtn); + child = wxPrivate::wxGetLastButtonInGroup(lastBtn); } } @@ -764,7 +769,7 @@ bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused) wxRadioButton* btn = wxDynamicCast(child, wxRadioButton); if (btn) { - wxRadioButton* selected = wxGetSelectedButtonInGroup(btn); + wxRadioButton* selected = wxPrivate::wxGetSelectedButtonInGroup(btn); if (selected) child = selected; } From 593e6a9ca680d35bd0734ba6ab62e3db52f80e1f Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Sun, 20 Sep 2020 18:35:51 +0200 Subject: [PATCH 04/21] Update include/wx/msw/radiobut.h Co-authored-by: VZ --- include/wx/msw/radiobut.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wx/msw/radiobut.h b/include/wx/msw/radiobut.h index 0554881601..fc6d2a8949 100644 --- a/include/wx/msw/radiobut.h +++ b/include/wx/msw/radiobut.h @@ -13,7 +13,7 @@ #include "wx/msw/ownerdrawnbutton.h" -class WXDLLIMPEXP_CORE wxRadioButton : public public wxRadioButtonBase> +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase< wxMSWOwnerDrawnButton > { public: // ctors and creation functions From 02b3b9d745cc434419b5f94c96820b8dc3bca64a Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Sun, 20 Sep 2020 19:44:16 +0200 Subject: [PATCH 05/21] Adding docs --- interface/wx/radiobut.h | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index d037412e55..0257bc31ce 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -14,7 +14,9 @@ You can create a group of mutually-exclusive radio buttons by specifying @c wxRB_GROUP for the first in the group. The group ends when another - radio button group is created, or there are no more radio buttons. + radio button group is created, or there are no more radio buttons. You can navigate + among the items in a group with @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() + @beginStyleTable @style{wxRB_GROUP} @@ -119,5 +121,33 @@ public: @true to check, @false to uncheck. */ virtual void SetValue(bool value); + + /** + Returns the first radio button of the @c wxRB_GROUP this instance is in. + + @see GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() + */ + wxRadioButton* GetFirstInGroup(); + + /** + Returns the last radio button of the @c wxRB_GROUP this instance is in. + + @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup() + */ + wxRadioButton* GetLastInGroup(); + + /** + Returns the previous radio button of the @c wxRB_GROUP this instance is in. + + @see GetFirstInGroup(), GetNextInGroup(), GetLastInGroup() + */ + wxRadioButton* GetPreviousInGroup(); + + /** + Returns the next radio button of the @c wxRB_GROUP this instance is in. + + @see GetFirstInGroup(), GetPreviousInGroup(), GetLastInGroup() + */ + wxRadioButton* GetNextInGroup(); }; From 7bf00e1161e5bf8f7a09892e10489fa85e56d699 Mon Sep 17 00:00:00 2001 From: Stefan Csomor Date: Mon, 21 Sep 2020 09:02:06 +0200 Subject: [PATCH 06/21] Added info about wxRB_SINGLE --- interface/wx/radiobut.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index 0257bc31ce..3ae7778152 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -125,6 +125,8 @@ public: /** Returns the first radio button of the @c wxRB_GROUP this instance is in. + The return value is NULL if this button has the style @c wxRB_SINGLE. + @see GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() */ wxRadioButton* GetFirstInGroup(); @@ -132,6 +134,8 @@ public: /** Returns the last radio button of the @c wxRB_GROUP this instance is in. + The return value is NULL if this button has the style @c wxRB_SINGLE. + @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup() */ wxRadioButton* GetLastInGroup(); @@ -139,6 +143,9 @@ public: /** Returns the previous radio button of the @c wxRB_GROUP this instance is in. + The return value is NULL if there is no predecessor or this button has + the style @c wxRB_SINGLE. + @see GetFirstInGroup(), GetNextInGroup(), GetLastInGroup() */ wxRadioButton* GetPreviousInGroup(); @@ -146,6 +153,9 @@ public: /** Returns the next radio button of the @c wxRB_GROUP this instance is in. + The return value is NULL if there is no successor or this button has + the style @c wxRB_SINGLE. + @see GetFirstInGroup(), GetPreviousInGroup(), GetLastInGroup() */ wxRadioButton* GetNextInGroup(); From dfd1638f39cd759697df4e28704b146a47dfe8fb Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:02:47 +0200 Subject: [PATCH 07/21] Improve radio button groups documentation Explain the role of wxRB_SINGLE better, it's useful not only for avoiding wxMSW bugs (which, besides, shouldn't exist any more). --- interface/wx/radiobut.h | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index 3ae7778152..98407b1f38 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -12,20 +12,28 @@ mutually exclusive options. It has a text label next to a (usually) round button. - You can create a group of mutually-exclusive radio buttons by specifying - @c wxRB_GROUP for the first in the group. The group ends when another - radio button group is created, or there are no more radio buttons. You can navigate - among the items in a group with @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() + Radio buttons are typically used in groups of mutually-exclusive buttons, + i.e. exactly one of the buttons in the group is checked, and the other ones + are unchecked automatically. Such groups are created implicitly, but can + also be started explicitly by using @c wxRB_GROUP style: a button with this + style starts a new group and will become the initial selection in this + group. Alternatively, a radio button may be excluded from the group that it + would otherwise belong to by using @c wxRB_SINGLE style. + + To find the other elements of the same radio button group, you can use + GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup() and + GetLastInGroup() functions. @beginStyleTable @style{wxRB_GROUP} Marks the beginning of a new group of radio buttons. @style{wxRB_SINGLE} - In some circumstances, radio buttons that are not consecutive - siblings trigger a hang bug in Windows (only). If this happens, add - this style to mark the button as not belonging to a group, and - implement the mutually-exclusive group behaviour yourself. + Creates a radio button which is not part of any radio button group. + When this style is used, no other radio buttons will be turned off + automatically when this button is turned on and such behaviour will + need to be implemented manually, in the event handler for this + button. @endStyleTable @beginEventEmissionTable{wxCommandEvent} From 3ccbee2e1c577ee75d0a2c74b7b926380dad7055 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:05:35 +0200 Subject: [PATCH 08/21] Mark radio button group navigation functions as new in 3.1.5 Just add the missing "@since" lines. --- interface/wx/radiobut.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index 98407b1f38..2bf6b22261 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -136,6 +136,8 @@ public: The return value is NULL if this button has the style @c wxRB_SINGLE. @see GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() + + @since 3.1.5 */ wxRadioButton* GetFirstInGroup(); @@ -145,6 +147,8 @@ public: The return value is NULL if this button has the style @c wxRB_SINGLE. @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup() + + @since 3.1.5 */ wxRadioButton* GetLastInGroup(); @@ -155,6 +159,8 @@ public: the style @c wxRB_SINGLE. @see GetFirstInGroup(), GetNextInGroup(), GetLastInGroup() + + @since 3.1.5 */ wxRadioButton* GetPreviousInGroup(); @@ -165,6 +171,8 @@ public: the style @c wxRB_SINGLE. @see GetFirstInGroup(), GetPreviousInGroup(), GetLastInGroup() + + @since 3.1.5 */ wxRadioButton* GetNextInGroup(); }; From 0edc9d7eda49e3bedd3af2e489a4998077b836a3 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:09:38 +0200 Subject: [PATCH 09/21] Just use wxPrivate namespace Writing "wxPrivate::wxFoo()" is a bit ugly, so just add a using directive for the namespace, it's not a problem to do it in this file. --- src/common/containr.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/common/containr.cpp b/src/common/containr.cpp index 9bcdbab781..0ab07916f1 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -353,6 +353,8 @@ wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn) } // namespace wxPrivate +using namespace wxPrivate; + #endif // wxUSE_RADIOBTN // ---------------------------------------------------------------------------- @@ -473,7 +475,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // If we are in a radio button group, start from the first item in the // group if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) ) - winFocus = wxPrivate::wxGetFirstButtonInGroup((wxRadioButton*)winFocus); + winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus); #endif // USE_RADIOBTN_NAV // ok, we found the focus - now is it our child? start_node = children.Find( winFocus ); @@ -569,7 +571,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) if ( child->HasFlag(wxRB_GROUP) ) { // need to tab into the active button within a group - wxRadioButton *rb = wxPrivate::wxGetSelectedButtonInGroup((wxRadioButton*)child); + wxRadioButton *rb = wxGetSelectedButtonInGroup((wxRadioButton*)child); if ( rb ) child = rb; } @@ -591,20 +593,20 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // find the correct radio button to focus if ( forward ) { - child = wxPrivate::wxGetNextButtonInGroup(lastBtn); + child = wxGetNextButtonInGroup(lastBtn); if ( !child ) { // no next button in group, set it to the first button - child = wxPrivate::wxGetFirstButtonInGroup(lastBtn); + child = wxGetFirstButtonInGroup(lastBtn); } } else { - child = wxPrivate::wxGetPreviousButtonInGroup(lastBtn); + child = wxGetPreviousButtonInGroup(lastBtn); if ( !child ) { // no previous button in group, set it to the last button - child = wxPrivate::wxGetLastButtonInGroup(lastBtn); + child = wxGetLastButtonInGroup(lastBtn); } } @@ -769,7 +771,7 @@ bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused) wxRadioButton* btn = wxDynamicCast(child, wxRadioButton); if (btn) { - wxRadioButton* selected = wxPrivate::wxGetSelectedButtonInGroup(btn); + wxRadioButton* selected = wxGetSelectedButtonInGroup(btn); if (selected) child = selected; } From fceaa907a80dc31e7b6ea107a844e0fd40a3d39b Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:14:40 +0200 Subject: [PATCH 10/21] Remove CppUnit boilerplate from wxRadioButton unit test Replace CppUnit test case class with a simple fixture and use CHECK() instead of CPPUNIT_ASSERT_XXX(). No real changes. --- tests/controls/radiobuttontest.cpp | 83 +++++++++++------------------- 1 file changed, 31 insertions(+), 52 deletions(-) diff --git a/tests/controls/radiobuttontest.cpp b/tests/controls/radiobuttontest.cpp index a81d6aec61..ea0f2a93c8 100644 --- a/tests/controls/radiobuttontest.cpp +++ b/tests/controls/radiobuttontest.cpp @@ -27,40 +27,19 @@ #include "testableframe.h" #include "testwindow.h" -class RadioButtonTestCase : public CppUnit::TestCase +class RadioButtonTestCase { public: - RadioButtonTestCase() { } - - void setUp() wxOVERRIDE; - void tearDown() wxOVERRIDE; - -private: - CPPUNIT_TEST_SUITE( RadioButtonTestCase ); - WXUISIM_TEST( Click ); - CPPUNIT_TEST( Value ); - CPPUNIT_TEST( Group ); - CPPUNIT_TEST( Single ); - CPPUNIT_TEST_SUITE_END(); - - void Click(); - void Value(); - void Group(); - void Single(); + RadioButtonTestCase(); + ~RadioButtonTestCase(); +protected: wxRadioButton* m_radio; wxDECLARE_NO_COPY_CLASS(RadioButtonTestCase); }; -// register in the unnamed registry so that these tests are run by default -CPPUNIT_TEST_SUITE_REGISTRATION( RadioButtonTestCase ); - -// also include in its own registry so that these tests can be run alone -CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( RadioButtonTestCase, - "RadioButtonTestCase" ); - -void RadioButtonTestCase::setUp() +RadioButtonTestCase::RadioButtonTestCase() { m_radio = new wxRadioButton(wxTheApp->GetTopWindow(), wxID_ANY, "wxRadioButton"); @@ -68,12 +47,12 @@ void RadioButtonTestCase::setUp() m_radio->Refresh(); } -void RadioButtonTestCase::tearDown() +RadioButtonTestCase::~RadioButtonTestCase() { - wxDELETE(m_radio); + delete m_radio; } -void RadioButtonTestCase::Click() +TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Click", "[radiobutton]") { // OS X doesn't support selecting a single radio button #if wxUSE_UIACTIONSIMULATOR && !defined(__WXOSX__) @@ -87,28 +66,28 @@ void RadioButtonTestCase::Click() wxYield(); - CPPUNIT_ASSERT_EQUAL( 1, selected.GetCount() ); + CHECK(selected.GetCount() == 1); #endif } -void RadioButtonTestCase::Value() +TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Value", "[radiobutton]") { #ifndef __WXGTK__ EventCounter selected(m_radio, wxEVT_RADIOBUTTON); m_radio->SetValue(true); - CPPUNIT_ASSERT(m_radio->GetValue()); + CHECK(m_radio->GetValue()); m_radio->SetValue(false); - CPPUNIT_ASSERT(!m_radio->GetValue()); + CHECK(!m_radio->GetValue()); - CPPUNIT_ASSERT_EQUAL(0, selected.GetCount()); + CHECK(selected.GetCount() == 0); #endif } -void RadioButtonTestCase::Group() +TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]") { wxWindow* const parent = wxTheApp->GetTopWindow(); @@ -133,31 +112,31 @@ void RadioButtonTestCase::Group() g1radio0->SetValue(true); g2radio0->SetValue(true); - CPPUNIT_ASSERT(g1radio0->GetValue()); - CPPUNIT_ASSERT(!g1radio1->GetValue()); - CPPUNIT_ASSERT(g2radio0->GetValue()); - CPPUNIT_ASSERT(!g2radio1->GetValue()); + CHECK(g1radio0->GetValue()); + CHECK(!g1radio1->GetValue()); + CHECK(g2radio0->GetValue()); + CHECK(!g2radio1->GetValue()); g1radio1->SetValue(true); g2radio1->SetValue(true); - CPPUNIT_ASSERT(!g1radio0->GetValue()); - CPPUNIT_ASSERT(g1radio1->GetValue()); - CPPUNIT_ASSERT(!g2radio0->GetValue()); - CPPUNIT_ASSERT(g2radio1->GetValue()); + CHECK(!g1radio0->GetValue()); + CHECK(g1radio1->GetValue()); + CHECK(!g2radio0->GetValue()); + CHECK(g2radio1->GetValue()); g2radio2->SetValue(true); - CPPUNIT_ASSERT(!g2radio0->GetValue()); - CPPUNIT_ASSERT(!g2radio1->GetValue()); - CPPUNIT_ASSERT(g2radio2->GetValue()); + CHECK(!g2radio0->GetValue()); + CHECK(!g2radio1->GetValue()); + CHECK(g2radio2->GetValue()); g1radio0->SetValue(true); g2radio0->SetValue(true); - CPPUNIT_ASSERT(g1radio0->GetValue()); - CPPUNIT_ASSERT(!g1radio1->GetValue()); - CPPUNIT_ASSERT(g2radio0->GetValue()); - CPPUNIT_ASSERT(!g2radio1->GetValue()); + CHECK(g1radio0->GetValue()); + CHECK(!g1radio1->GetValue()); + CHECK(g2radio0->GetValue()); + CHECK(!g2radio1->GetValue()); wxDELETE(g1radio0); wxDELETE(g1radio1); @@ -167,7 +146,7 @@ void RadioButtonTestCase::Group() wxDELETE(text); } -void RadioButtonTestCase::Single() +TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Single", "[radiobutton]") { //Create a group of 2 buttons, having second button selected wxScopedPtr gradio0(new wxRadioButton(wxTheApp->GetTopWindow(), @@ -199,7 +178,7 @@ void RadioButtonTestCase::Single() CHECK(ngradio->GetValue()); } -TEST_CASE("wxRadioButton::Focus", "[radiobutton][focus]") +TEST_CASE("RadioButton::Focus", "[radiobutton][focus]") { // Create a container panel just to be able to destroy all the windows // created here at once by simply destroying it. From 46a21e5abaa2d858a38e8fddbec442568806bb4f Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:18:22 +0200 Subject: [PATCH 11/21] Use wxScopedPtr<> instead of manual delete in wxRadioButton test Make the test code safer and ensure that no controls created here remain alive after the test end. --- tests/controls/radiobuttontest.cpp | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/tests/controls/radiobuttontest.cpp b/tests/controls/radiobuttontest.cpp index ea0f2a93c8..583a9b64c4 100644 --- a/tests/controls/radiobuttontest.cpp +++ b/tests/controls/radiobuttontest.cpp @@ -23,6 +23,7 @@ #include "wx/stattext.h" #endif // WX_PRECOMP +#include "wx/scopedptr.h" #include "wx/uiaction.h" #include "testableframe.h" #include "testwindow.h" @@ -92,22 +93,22 @@ TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]") wxWindow* const parent = wxTheApp->GetTopWindow(); // Create two different radio groups. - wxRadioButton* g1radio0 = new wxRadioButton(parent, wxID_ANY, "radio 1.0", + wxScopedPtr g1radio0(new wxRadioButton(parent, wxID_ANY, "radio 1.0", wxDefaultPosition, wxDefaultSize, - wxRB_GROUP); + wxRB_GROUP)); - wxRadioButton* g1radio1 = new wxRadioButton(parent, wxID_ANY, "radio 1.1"); + wxScopedPtr g1radio1(new wxRadioButton(parent, wxID_ANY, "radio 1.1")); - wxRadioButton* g2radio0 = new wxRadioButton(parent, wxID_ANY, "radio 2.0", + wxScopedPtr g2radio0(new wxRadioButton(parent, wxID_ANY, "radio 2.0", wxDefaultPosition, wxDefaultSize, - wxRB_GROUP); + wxRB_GROUP)); - wxRadioButton* g2radio1 = new wxRadioButton(parent, wxID_ANY, "radio 2.1"); + wxScopedPtr g2radio1(new wxRadioButton(parent, wxID_ANY, "radio 2.1")); // Check that having another control between radio buttons doesn't break // grouping. - wxStaticText* text = new wxStaticText(parent, wxID_ANY, "Label"); - wxRadioButton* g2radio2 = new wxRadioButton(parent, wxID_ANY, "radio 2.1"); + wxScopedPtr text(new wxStaticText(parent, wxID_ANY, "Label")); + wxScopedPtr g2radio2(new wxRadioButton(parent, wxID_ANY, "radio 2.1")); g1radio0->SetValue(true); g2radio0->SetValue(true); @@ -137,13 +138,6 @@ TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]") CHECK(!g1radio1->GetValue()); CHECK(g2radio0->GetValue()); CHECK(!g2radio1->GetValue()); - - wxDELETE(g1radio0); - wxDELETE(g1radio1); - wxDELETE(g2radio0); - wxDELETE(g2radio1); - wxDELETE(g2radio2); - wxDELETE(text); } TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Single", "[radiobutton]") From 24cc6c541e06a6462bbbc482180950a545a33632 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:28:06 +0200 Subject: [PATCH 12/21] Don't DLL-export wxRadioButtonBase template class This is unnecessary, this class only has inline functions. --- include/wx/radiobut.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index 182ae9c8c5..d68ac4a665 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -43,7 +43,7 @@ namespace wxPrivate } // namespace wxPrivate template -class WXDLLIMPEXP_CORE wxRadioButtonBase : public W +class wxRadioButtonBase : public W { public: typedef W BaseWindowClass; From b5fb9bd8d63b96e97903118154ccc34c882827e4 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:34:55 +0200 Subject: [PATCH 13/21] Compile radio button group navigation functions on all platforms Previously they were only used, and compiled, on the platforms without wxHAS_NATIVE_TAB_TRAVERSAL, i.e. were not compiled at all in wxGTK, but we now need them everywhere as they're used to implement public API. --- src/common/containr.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/common/containr.cpp b/src/common/containr.cpp index 0ab07916f1..93245b674d 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -233,9 +233,12 @@ void wxControlContainer::SetLastFocus(wxWindow *win) } } +#endif // !wxHAS_NATIVE_TAB_TRAVERSAL + // -------------------------------------------------------------------- // The following four functions are used to find other radio buttons -// within the same group. Used by wxSetFocusToChild +// within the same group. Used by wxSetFocusToChild() and to implement +// wxRadioButtonBase public API. // -------------------------------------------------------------------- #if wxUSE_RADIOBTN @@ -357,6 +360,8 @@ using namespace wxPrivate; #endif // wxUSE_RADIOBTN +#ifndef wxHAS_NATIVE_TAB_TRAVERSAL + // ---------------------------------------------------------------------------- // Keyboard handling - this is the place where the TAB traversal logic is // implemented. As this code is common to all ports, this ensures consistent From 1a4f628e405661c042dcaa5f62c076a9c328719e Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:36:41 +0200 Subject: [PATCH 14/21] Make radio button navigation functions const This requires adding a couple of const_cast<>s in their implementation in order to still allow them returning non-const wxRadioButton pointers, but this seems preferable to not being able to call them on a const wxRadioButton in the first place. --- include/wx/radiobut.h | 24 ++++++++++++------------ interface/wx/radiobut.h | 8 ++++---- src/common/containr.cpp | 16 ++++++++-------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index d68ac4a665..d999800efb 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -36,10 +36,10 @@ class WXDLLIMPEXP_FWD_CORE wxRadioButton; namespace wxPrivate { - WXDLLIMPEXP_CORE wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetNextButtonInGroup(const wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetPreviousButtonInGroup(const wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetFirstButtonInGroup(const wxRadioButton *btn); + WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn); } // namespace wxPrivate template @@ -50,24 +50,24 @@ public: wxRadioButtonBase() { } - wxRadioButton* GetFirstInGroup() + wxRadioButton* GetFirstInGroup() const { - return wxPrivate::wxGetFirstButtonInGroup( static_cast(this)); + return wxPrivate::wxGetFirstButtonInGroup(static_cast(this)); } - wxRadioButton* GetLastInGroup() + wxRadioButton* GetLastInGroup() const { - return wxPrivate::wxGetLastButtonInGroup( static_cast(this)); + return wxPrivate::wxGetLastButtonInGroup(static_cast(this)); } - wxRadioButton* GetPreviousInGroup() + wxRadioButton* GetPreviousInGroup() const { - return wxPrivate::wxGetPreviousButtonInGroup( static_cast(this)); + return wxPrivate::wxGetPreviousButtonInGroup(static_cast(this)); } - wxRadioButton* GetNextInGroup() + wxRadioButton* GetNextInGroup() const { - return wxPrivate::wxGetNextButtonInGroup( static_cast(this)); + return wxPrivate::wxGetNextButtonInGroup(static_cast(this)); } private: diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index 2bf6b22261..9094b23fde 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -139,7 +139,7 @@ public: @since 3.1.5 */ - wxRadioButton* GetFirstInGroup(); + wxRadioButton* GetFirstInGroup() const; /** Returns the last radio button of the @c wxRB_GROUP this instance is in. @@ -150,7 +150,7 @@ public: @since 3.1.5 */ - wxRadioButton* GetLastInGroup(); + wxRadioButton* GetLastInGroup() const; /** Returns the previous radio button of the @c wxRB_GROUP this instance is in. @@ -162,7 +162,7 @@ public: @since 3.1.5 */ - wxRadioButton* GetPreviousInGroup(); + wxRadioButton* GetPreviousInGroup() const; /** Returns the next radio button of the @c wxRB_GROUP this instance is in. @@ -174,6 +174,6 @@ public: @since 3.1.5 */ - wxRadioButton* GetNextInGroup(); + wxRadioButton* GetNextInGroup() const; }; diff --git a/src/common/containr.cpp b/src/common/containr.cpp index 93245b674d..52b808a29f 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -246,7 +246,7 @@ void wxControlContainer::SetLastFocus(wxWindow *win) namespace wxPrivate { -wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn) +wxRadioButton* wxGetPreviousButtonInGroup(const wxRadioButton *btn) { if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) return NULL; @@ -276,7 +276,7 @@ wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn) return prevBtn; } -wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn) +wxRadioButton* wxGetNextButtonInGroup(const wxRadioButton *btn) { if (btn->HasFlag(wxRB_SINGLE)) return NULL; @@ -306,35 +306,35 @@ wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn) return nextBtn; } -wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn) +wxRadioButton* wxGetFirstButtonInGroup(const wxRadioButton *btn) { while (true) { wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn); if (!prevBtn) - return btn; + return const_cast(btn); btn = prevBtn; } } -wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn) +wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn) { while (true) { wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn); if (!nextBtn) - return btn; + return const_cast(btn); btn = nextBtn; } } -wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn) +wxRadioButton* wxGetSelectedButtonInGroup(const wxRadioButton *btn) { // Find currently selected button if (btn->GetValue()) - return btn; + return const_cast(btn); if (btn->HasFlag(wxRB_SINGLE)) return NULL; From ee55427c286e6c54306d2417a90321b1931c9404 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:52:40 +0200 Subject: [PATCH 15/21] Make it simpler to write useful tests comparing windows Allow creating wxWindowPtr from wxScopedPtr<> too, to avoid having to use .get() in the test code, and add CHECK_SAME_WINDOW() macro which gives more useful information about the windows in case of failure. --- tests/testwindow.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/testwindow.h b/tests/testwindow.h index 64b455b261..00f8003ec5 100644 --- a/tests/testwindow.h +++ b/tests/testwindow.h @@ -9,6 +9,7 @@ #ifndef _WX_TESTS_TESTWINDOW_H_ #define _WX_TESTS_TESTWINDOW_H_ +#include "wx/scopedptr.h" #include "wx/window.h" // We need to wrap wxWindow* in a class as specializing StringMaker for @@ -17,6 +18,8 @@ class wxWindowPtr { public: explicit wxWindowPtr(wxWindow* win) : m_win(win) {} + template + explicit wxWindowPtr(const wxScopedPtr& win) : m_win(win.get()) {} wxString Dump() const { @@ -44,7 +47,9 @@ private: // Macro providing more information about the current focus if comparison // fails. -#define CHECK_FOCUS_IS(w) CHECK(wxWindowPtr(wxWindow::FindFocus()) == wxWindowPtr(w)) +#define CHECK_SAME_WINDOW(w1, w2) CHECK(wxWindowPtr(w1) == wxWindowPtr(w2)) + +#define CHECK_FOCUS_IS(w) CHECK_SAME_WINDOW(wxWindow::FindFocus(), w) namespace Catch { From b84bc8e26a84eb84cf8e13728560857e662f8348 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 15:44:59 +0200 Subject: [PATCH 16/21] Add unit tests for radio button group navigation functions Extend the existing "group" and "single" tests to check these functions too. This at least verifies that these functions can be used. --- tests/controls/radiobuttontest.cpp | 44 ++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/tests/controls/radiobuttontest.cpp b/tests/controls/radiobuttontest.cpp index 583a9b64c4..cdcc144972 100644 --- a/tests/controls/radiobuttontest.cpp +++ b/tests/controls/radiobuttontest.cpp @@ -23,7 +23,6 @@ #include "wx/stattext.h" #endif // WX_PRECOMP -#include "wx/scopedptr.h" #include "wx/uiaction.h" #include "testableframe.h" #include "testwindow.h" @@ -108,7 +107,7 @@ TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]") // Check that having another control between radio buttons doesn't break // grouping. wxScopedPtr text(new wxStaticText(parent, wxID_ANY, "Label")); - wxScopedPtr g2radio2(new wxRadioButton(parent, wxID_ANY, "radio 2.1")); + wxScopedPtr g2radio2(new wxRadioButton(parent, wxID_ANY, "radio 2.2")); g1radio0->SetValue(true); g2radio0->SetValue(true); @@ -138,6 +137,41 @@ TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]") CHECK(!g1radio1->GetValue()); CHECK(g2radio0->GetValue()); CHECK(!g2radio1->GetValue()); + + + // Check that group navigation functions behave as expected. + + // GetFirstInGroup() + CHECK_SAME_WINDOW(g1radio0->GetFirstInGroup(), g1radio0); + CHECK_SAME_WINDOW(g1radio1->GetFirstInGroup(), g1radio0); + + CHECK_SAME_WINDOW(g2radio0->GetFirstInGroup(), g2radio0); + CHECK_SAME_WINDOW(g2radio1->GetFirstInGroup(), g2radio0); + CHECK_SAME_WINDOW(g2radio2->GetFirstInGroup(), g2radio0); + + // GetLastInGroup() + CHECK_SAME_WINDOW(g1radio0->GetLastInGroup(), g1radio1); + CHECK_SAME_WINDOW(g1radio1->GetLastInGroup(), g1radio1); + + CHECK_SAME_WINDOW(g2radio0->GetLastInGroup(), g2radio2); + CHECK_SAME_WINDOW(g2radio1->GetLastInGroup(), g2radio2); + CHECK_SAME_WINDOW(g2radio2->GetLastInGroup(), g2radio2); + + // GetNextInGroup() + CHECK_SAME_WINDOW(g1radio0->GetNextInGroup(), g1radio1); + CHECK_SAME_WINDOW(g1radio1->GetNextInGroup(), NULL); + + CHECK_SAME_WINDOW(g2radio0->GetNextInGroup(), g2radio1); + CHECK_SAME_WINDOW(g2radio1->GetNextInGroup(), g2radio2); + CHECK_SAME_WINDOW(g2radio2->GetNextInGroup(), NULL); + + // GetPreviousInGroup() + CHECK_SAME_WINDOW(g1radio0->GetPreviousInGroup(), NULL); + CHECK_SAME_WINDOW(g1radio1->GetPreviousInGroup(), g1radio0); + + CHECK_SAME_WINDOW(g2radio0->GetPreviousInGroup(), NULL); + CHECK_SAME_WINDOW(g2radio1->GetPreviousInGroup(), g2radio0); + CHECK_SAME_WINDOW(g2radio2->GetPreviousInGroup(), g2radio1); } TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Single", "[radiobutton]") @@ -170,6 +204,12 @@ TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Single", "[radiobutton]") CHECK(gradio1->GetValue()); CHECK(ngradio->GetValue()); + + // Also check that navigation works as expected with "single" buttons. + CHECK_SAME_WINDOW(sradio->GetFirstInGroup(), sradio); + CHECK_SAME_WINDOW(sradio->GetLastInGroup(), sradio); + CHECK_SAME_WINDOW(sradio->GetPreviousInGroup(), NULL); + CHECK_SAME_WINDOW(sradio->GetNextInGroup(), NULL); } TEST_CASE("RadioButton::Focus", "[radiobutton][focus]") From 9e51389676f389427d6fd73ad15c502fe64cc485 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 16:02:40 +0200 Subject: [PATCH 17/21] Improve radio button navigation functions documentation Correct the previously wrong described behaviour for wxRB_SINGLE buttons and also mention that Get{First,Last}InGroup() never return NULL. --- interface/wx/radiobut.h | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index 9094b23fde..0a42c1c0f9 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -131,9 +131,16 @@ public: virtual void SetValue(bool value); /** - Returns the first radio button of the @c wxRB_GROUP this instance is in. + Returns the first button of the radio button group this button belongs + to. - The return value is NULL if this button has the style @c wxRB_SINGLE. + For a radio button with @c wxRB_SINGLE style, this function returns this + button itself, as it is the only member of its group. Otherwise, the + function returns the closest previous radio button with @c wxRB_GROUP + style (which could still be this button itself) or the first radio + button in the same window. + + The returned value is never @NULL. @see GetPreviousInGroup(), GetNextInGroup(), GetLastInGroup() @@ -142,21 +149,27 @@ public: wxRadioButton* GetFirstInGroup() const; /** - Returns the last radio button of the @c wxRB_GROUP this instance is in. + Returns the last button of the radio button group this button belongs + to. - The return value is NULL if this button has the style @c wxRB_SINGLE. + Similarly to GetFirstInGroup(), this function returns this button + itself if it has @c wxRB_SINGLE style. Otherwise, the function returns + the last button before the next button with @c wxRB_GROUP style or the + last radio button in the same window. - @see GetFirstInGroup(), GetPreviousInGroup(), GetNextInGroup() + The returned value is never @NULL. + + @see GetPreviousInGroup(), GetNextInGroup() @since 3.1.5 */ wxRadioButton* GetLastInGroup() const; /** - Returns the previous radio button of the @c wxRB_GROUP this instance is in. + Returns the previous radio button in the same group. - The return value is NULL if there is no predecessor or this button has - the style @c wxRB_SINGLE. + The return value is @NULL if there is no predecessor or if this button + has @c wxRB_SINGLE style. @see GetFirstInGroup(), GetNextInGroup(), GetLastInGroup() @@ -165,10 +178,10 @@ public: wxRadioButton* GetPreviousInGroup() const; /** - Returns the next radio button of the @c wxRB_GROUP this instance is in. + Returns the next radio button in the same group. - The return value is NULL if there is no successor or this button has - the style @c wxRB_SINGLE. + The return value is @NULL if there is no successor or if this button + has @c wxRB_SINGLE style. @see GetFirstInGroup(), GetPreviousInGroup(), GetLastInGroup() From 3d72c009be9c062a4e828a1f50ed8240bab295fa Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 16:08:16 +0200 Subject: [PATCH 18/21] Add wxRadioButtonBase::{Set,Get}Value() Now that we do have wxRadioButtonBase class, declare wxRadioButton API methods as pure virtual in it, to force the derived classes to implement them. Also remove the outdated comment saying that there is no base class for wxRadioButtons in different ports, this is not true any longer. --- include/wx/gtk/radiobut.h | 4 ++-- include/wx/msw/radiobut.h | 4 ++-- include/wx/osx/radiobut.h | 4 ++-- include/wx/qt/radiobut.h | 4 ++-- include/wx/radiobut.h | 23 ++++++++--------------- include/wx/univ/radiobut.h | 4 ++++ 6 files changed, 20 insertions(+), 23 deletions(-) diff --git a/include/wx/gtk/radiobut.h b/include/wx/gtk/radiobut.h index b85f8ea723..785530a98e 100644 --- a/include/wx/gtk/radiobut.h +++ b/include/wx/gtk/radiobut.h @@ -39,8 +39,8 @@ public: const wxString& name = wxASCII_STR(wxRadioButtonNameStr) ); virtual void SetLabel(const wxString& label) wxOVERRIDE; - virtual void SetValue(bool val); - virtual bool GetValue() const; + virtual void SetValue(bool val) wxOVERRIDE; + virtual bool GetValue() const wxOVERRIDE; static wxVisualAttributes GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL); diff --git a/include/wx/msw/radiobut.h b/include/wx/msw/radiobut.h index fc6d2a8949..41103ed3b9 100644 --- a/include/wx/msw/radiobut.h +++ b/include/wx/msw/radiobut.h @@ -43,8 +43,8 @@ public: const wxString& name = wxASCII_STR(wxRadioButtonNameStr)); // implement the radio button interface - virtual void SetValue(bool value); - virtual bool GetValue() const; + virtual void SetValue(bool value) wxOVERRIDE; + virtual bool GetValue() const wxOVERRIDE; // implementation only from now on virtual bool MSWCommand(WXUINT param, WXWORD id) wxOVERRIDE; diff --git a/include/wx/osx/radiobut.h b/include/wx/osx/radiobut.h index cf74f14d89..b6bcb8ada3 100644 --- a/include/wx/osx/radiobut.h +++ b/include/wx/osx/radiobut.h @@ -35,8 +35,8 @@ public: const wxValidator& validator = wxDefaultValidator, const wxString& name = wxASCII_STR(wxRadioButtonNameStr)); - virtual void SetValue(bool val); - virtual bool GetValue() const ; + virtual void SetValue(bool val) wxOVERRIDE; + virtual bool GetValue() const wxOVERRIDE; // implementation diff --git a/include/wx/qt/radiobut.h b/include/wx/qt/radiobut.h index 1502173105..da00d190cf 100644 --- a/include/wx/qt/radiobut.h +++ b/include/wx/qt/radiobut.h @@ -32,8 +32,8 @@ public: const wxValidator& validator = wxDefaultValidator, const wxString& name = wxASCII_STR(wxRadioButtonNameStr) ); - virtual void SetValue(bool value); - virtual bool GetValue() const; + virtual void SetValue(bool value) wxOVERRIDE; + virtual bool GetValue() const wxOVERRIDE; virtual QWidget *GetHandle() const wxOVERRIDE; diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index d999800efb..a4d78656bc 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -15,21 +15,6 @@ #if wxUSE_RADIOBTN -/* - There is no wxRadioButtonBase class as wxRadioButton interface is the same - as wxCheckBox(Base), but under some platforms wxRadioButton really - derives from wxCheckBox and on the others it doesn't. - - The pseudo-declaration of wxRadioButtonBase would look like this: - - class wxRadioButtonBase : public ... - { - public: - virtual void SetValue(bool value); - virtual bool GetValue() const; - }; - */ - #include "wx/control.h" class WXDLLIMPEXP_FWD_CORE wxRadioButton; @@ -42,6 +27,8 @@ namespace wxPrivate WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn); } // namespace wxPrivate +// Unlike most of the other wxXXXBase classes, this one needs to be a template +// as wxRadioButton derives from different classes in different ports. template class wxRadioButtonBase : public W { @@ -50,6 +37,12 @@ public: wxRadioButtonBase() { } + // Methods to be implemented by the derived classes: + virtual void SetValue(bool value) = 0; + virtual bool GetValue() const = 0; + + + // Methods implemented by this class itself. wxRadioButton* GetFirstInGroup() const { return wxPrivate::wxGetFirstButtonInGroup(static_cast(this)); diff --git a/include/wx/univ/radiobut.h b/include/wx/univ/radiobut.h index 0b6580a2ab..ab81a71c5a 100644 --- a/include/wx/univ/radiobut.h +++ b/include/wx/univ/radiobut.h @@ -46,6 +46,10 @@ public: const wxValidator& validator = wxDefaultValidator, const wxString& name = wxASCII_STR(wxRadioButtonNameStr)); + // (re)implement pure virtuals from wxRadioButtonBase + virtual void SetValue(bool value) wxOVERRIDE { return wxCheckBox::SetValue(value); } + virtual bool GetValue() const wxOVERRIDE { return wxCheckBox::GetValue(); } + // override some base class methods virtual void ChangeValue(bool value) wxOVERRIDE; From bcb016613e508aedde906a9f57cf2ac0cc8b25ba Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 17:59:22 +0200 Subject: [PATCH 19/21] Make wxRadioButtonBase a plain class, not template Use a dirty hack to accommodate wxUniv by deriving wxRadioButtonBase from wxCheckBox, rather than wxControl, there. This is not pretty, but should be addressed by refactoring wxUniv code and in the meanwhile all the other ports don't have to bother with using a template class unnecessarily. --- include/wx/gtk/radiobut.h | 2 +- include/wx/gtk1/radiobut.h | 2 +- include/wx/motif/radiobut.h | 2 +- include/wx/msw/radiobut.h | 2 +- include/wx/osx/radiobut.h | 2 +- include/wx/qt/radiobut.h | 2 +- include/wx/radiobut.h | 21 ++++++++++++++------- include/wx/univ/radiobut.h | 4 +--- 8 files changed, 21 insertions(+), 16 deletions(-) diff --git a/include/wx/gtk/radiobut.h b/include/wx/gtk/radiobut.h index 785530a98e..8a19a022dd 100644 --- a/include/wx/gtk/radiobut.h +++ b/include/wx/gtk/radiobut.h @@ -13,7 +13,7 @@ // wxRadioButton //----------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { public: wxRadioButton() { } diff --git a/include/wx/gtk1/radiobut.h b/include/wx/gtk1/radiobut.h index 662b681d74..d467f7100c 100644 --- a/include/wx/gtk1/radiobut.h +++ b/include/wx/gtk1/radiobut.h @@ -13,7 +13,7 @@ // wxRadioButton //----------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { public: wxRadioButton() { } diff --git a/include/wx/motif/radiobut.h b/include/wx/motif/radiobut.h index 5759f01162..0233364946 100644 --- a/include/wx/motif/radiobut.h +++ b/include/wx/motif/radiobut.h @@ -11,7 +11,7 @@ #ifndef _WX_RADIOBUT_H_ #define _WX_RADIOBUT_H_ -class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { wxDECLARE_DYNAMIC_CLASS(wxRadioButton); public: diff --git a/include/wx/msw/radiobut.h b/include/wx/msw/radiobut.h index 41103ed3b9..765f6bcc8f 100644 --- a/include/wx/msw/radiobut.h +++ b/include/wx/msw/radiobut.h @@ -13,7 +13,7 @@ #include "wx/msw/ownerdrawnbutton.h" -class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase< wxMSWOwnerDrawnButton > +class WXDLLIMPEXP_CORE wxRadioButton : public wxMSWOwnerDrawnButton { public: // ctors and creation functions diff --git a/include/wx/osx/radiobut.h b/include/wx/osx/radiobut.h index b6bcb8ada3..3934f839f8 100644 --- a/include/wx/osx/radiobut.h +++ b/include/wx/osx/radiobut.h @@ -11,7 +11,7 @@ #ifndef _WX_RADIOBUT_H_ #define _WX_RADIOBUT_H_ -class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { wxDECLARE_DYNAMIC_CLASS(wxRadioButton); diff --git a/include/wx/qt/radiobut.h b/include/wx/qt/radiobut.h index da00d190cf..145b97a4ea 100644 --- a/include/wx/qt/radiobut.h +++ b/include/wx/qt/radiobut.h @@ -10,7 +10,7 @@ class QRadioButton; -class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase { public: wxRadioButton(); diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index a4d78656bc..90217847a5 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -27,14 +27,21 @@ namespace wxPrivate WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn); } // namespace wxPrivate -// Unlike most of the other wxXXXBase classes, this one needs to be a template -// as wxRadioButton derives from different classes in different ports. -template -class wxRadioButtonBase : public W +// TODO: In wxUniv, wxRadioButton must derive from wxCheckBox as it reuses +// much of its code. This should be fixed by refactoring wxCheckBox to allow +// this class to reuse its functionality without inheriting from it, but for +// now use this hack to allow the existing code to compile. +#ifdef __WXUNIVERSAL__ + #include "wx/checkbox.h" + + typedef wxCheckBox wxRadioButtonBaseBase; +#else + typedef wxControl wxRadioButtonBaseBase; +#endif + +class WXDLLIMPEXP_CORE wxRadioButtonBase : public wxRadioButtonBaseBase { public: - typedef W BaseWindowClass; - wxRadioButtonBase() { } // Methods to be implemented by the derived classes: @@ -64,7 +71,7 @@ public: } private: - wxDECLARE_NO_COPY_TEMPLATE_CLASS(wxRadioButtonBase, W); + wxDECLARE_NO_COPY_CLASS(wxRadioButtonBase); }; extern WXDLLIMPEXP_DATA_CORE(const char) wxRadioButtonNameStr[]; diff --git a/include/wx/univ/radiobut.h b/include/wx/univ/radiobut.h index ab81a71c5a..711e0a676c 100644 --- a/include/wx/univ/radiobut.h +++ b/include/wx/univ/radiobut.h @@ -11,13 +11,11 @@ #ifndef _WX_UNIV_RADIOBUT_H_ #define _WX_UNIV_RADIOBUT_H_ -#include "wx/checkbox.h" - // ---------------------------------------------------------------------------- // wxRadioButton // ---------------------------------------------------------------------------- -class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase { public: // constructors From 09060ed262ed283d2bd932625eb6a5a879f3cf92 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 18:01:47 +0200 Subject: [PATCH 20/21] Move radio group navigation functions to wxRadioButtonBase Now that this class is not a template any longer, we can have the code for radio button group navigation directly in it, without making it inline, so move the existing functions bodies into the new methods and remove the old functions entirely. No real changes, this is just a refactoring. --- include/wx/radiobut.h | 31 ++-------- src/common/containr.cpp | 112 ++++--------------------------------- src/common/radiobtncmn.cpp | 92 ++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 129 deletions(-) diff --git a/include/wx/radiobut.h b/include/wx/radiobut.h index 90217847a5..f4cf3b1a09 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -19,14 +19,6 @@ class WXDLLIMPEXP_FWD_CORE wxRadioButton; -namespace wxPrivate -{ - WXDLLIMPEXP_CORE wxRadioButton* wxGetNextButtonInGroup(const wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetPreviousButtonInGroup(const wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetFirstButtonInGroup(const wxRadioButton *btn); - WXDLLIMPEXP_CORE wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn); -} // namespace wxPrivate - // TODO: In wxUniv, wxRadioButton must derive from wxCheckBox as it reuses // much of its code. This should be fixed by refactoring wxCheckBox to allow // this class to reuse its functionality without inheriting from it, but for @@ -50,25 +42,10 @@ public: // Methods implemented by this class itself. - wxRadioButton* GetFirstInGroup() const - { - return wxPrivate::wxGetFirstButtonInGroup(static_cast(this)); - } - - wxRadioButton* GetLastInGroup() const - { - return wxPrivate::wxGetLastButtonInGroup(static_cast(this)); - } - - wxRadioButton* GetPreviousInGroup() const - { - return wxPrivate::wxGetPreviousButtonInGroup(static_cast(this)); - } - - wxRadioButton* GetNextInGroup() const - { - return wxPrivate::wxGetNextButtonInGroup(static_cast(this)); - } + wxRadioButton* GetFirstInGroup() const; + wxRadioButton* GetLastInGroup() const; + wxRadioButton* GetPreviousInGroup() const; + wxRadioButton* GetNextInGroup() const; private: wxDECLARE_NO_COPY_CLASS(wxRadioButtonBase); diff --git a/src/common/containr.cpp b/src/common/containr.cpp index 52b808a29f..d20098f869 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -233,103 +233,15 @@ void wxControlContainer::SetLastFocus(wxWindow *win) } } -#endif // !wxHAS_NATIVE_TAB_TRAVERSAL - // -------------------------------------------------------------------- -// The following four functions are used to find other radio buttons -// within the same group. Used by wxSetFocusToChild() and to implement -// wxRadioButtonBase public API. +// The following functions is used by wxSetFocusToChild() // -------------------------------------------------------------------- #if wxUSE_RADIOBTN -namespace wxPrivate +namespace { -wxRadioButton* wxGetPreviousButtonInGroup(const wxRadioButton *btn) -{ - if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) - return NULL; - - const wxWindowList& siblings = btn->GetParent()->GetChildren(); - wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); - wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") ); - - // Iterate over all previous siblings until we find the next radio button - wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious(); - wxRadioButton *prevBtn = 0; - while (nodeBefore) - { - prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton); - if (prevBtn) - break; - - nodeBefore = nodeBefore->GetPrevious(); - } - - if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE)) - { - // no more buttons in group - return NULL; - } - - return prevBtn; -} - -wxRadioButton* wxGetNextButtonInGroup(const wxRadioButton *btn) -{ - if (btn->HasFlag(wxRB_SINGLE)) - return NULL; - - const wxWindowList& siblings = btn->GetParent()->GetChildren(); - wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); - wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") ); - - // Iterate over all previous siblings until we find the next radio button - wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext(); - wxRadioButton *nextBtn = 0; - while (nodeNext) - { - nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton); - if (nextBtn) - break; - - nodeNext = nodeNext->GetNext(); - } - - if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) ) - { - // no more buttons or the first button of the next group - return NULL; - } - - return nextBtn; -} - -wxRadioButton* wxGetFirstButtonInGroup(const wxRadioButton *btn) -{ - while (true) - { - wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn); - if (!prevBtn) - return const_cast(btn); - - btn = prevBtn; - } -} - -wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn) -{ - while (true) - { - wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn); - if (!nextBtn) - return const_cast(btn); - - btn = nextBtn; - } -} - wxRadioButton* wxGetSelectedButtonInGroup(const wxRadioButton *btn) { // Find currently selected button @@ -342,26 +254,22 @@ wxRadioButton* wxGetSelectedButtonInGroup(const wxRadioButton *btn) wxRadioButton *selBtn; // First check all previous buttons - for (selBtn = wxGetPreviousButtonInGroup(btn); selBtn; selBtn = wxGetPreviousButtonInGroup(selBtn)) + for (selBtn = btn->GetPreviousInGroup(); selBtn; selBtn = selBtn->GetPreviousInGroup()) if (selBtn->GetValue()) return selBtn; // Now all following buttons - for (selBtn = wxGetNextButtonInGroup(btn); selBtn; selBtn = wxGetNextButtonInGroup(selBtn)) + for (selBtn = btn->GetNextInGroup(); selBtn; selBtn = selBtn->GetNextInGroup()) if (selBtn->GetValue()) return selBtn; return NULL; } -} // namespace wxPrivate - -using namespace wxPrivate; +} // anonymous namespace #endif // wxUSE_RADIOBTN -#ifndef wxHAS_NATIVE_TAB_TRAVERSAL - // ---------------------------------------------------------------------------- // Keyboard handling - this is the place where the TAB traversal logic is // implemented. As this code is common to all ports, this ensures consistent @@ -480,7 +388,7 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // If we are in a radio button group, start from the first item in the // group if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) ) - winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus); + winFocus = static_cast(winFocus)->GetFirstInGroup(); #endif // USE_RADIOBTN_NAV // ok, we found the focus - now is it our child? start_node = children.Find( winFocus ); @@ -598,20 +506,20 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) // find the correct radio button to focus if ( forward ) { - child = wxGetNextButtonInGroup(lastBtn); + child = lastBtn->GetNextInGroup(); if ( !child ) { // no next button in group, set it to the first button - child = wxGetFirstButtonInGroup(lastBtn); + child = lastBtn->GetFirstInGroup(); } } else { - child = wxGetPreviousButtonInGroup(lastBtn); + child = lastBtn->GetPreviousInGroup(); if ( !child ) { // no previous button in group, set it to the last button - child = wxGetLastButtonInGroup(lastBtn); + child = lastBtn->GetLastInGroup(); } } diff --git a/src/common/radiobtncmn.cpp b/src/common/radiobtncmn.cpp index dc2bd09240..5e847c7ab9 100644 --- a/src/common/radiobtncmn.cpp +++ b/src/common/radiobtncmn.cpp @@ -92,4 +92,96 @@ wxCONSTRUCTOR_6( wxRadioButton, wxWindow*, Parent, wxWindowID, Id, \ wxString, Label, wxPoint, Position, wxSize, Size, long, WindowStyle ) +// ---------------------------------------------------------------------------- +// wxRadioButton group navigation +// ---------------------------------------------------------------------------- + +wxRadioButton* wxRadioButtonBase::GetFirstInGroup() const +{ + wxRadioButton* + btn = static_cast(const_cast(this)); + while (true) + { + wxRadioButton* prevBtn = btn->GetPreviousInGroup(); + if (!prevBtn) + return btn; + + btn = prevBtn; + } +} + +wxRadioButton* wxRadioButtonBase::GetLastInGroup() const +{ + wxRadioButton* + btn = static_cast(const_cast(this)); + while (true) + { + wxRadioButton* nextBtn = btn->GetNextInGroup(); + if (!nextBtn) + return btn; + + btn = nextBtn; + } +} + +wxRadioButton* wxRadioButtonBase::GetPreviousInGroup() const +{ + if ( HasFlag(wxRB_GROUP) || HasFlag(wxRB_SINGLE) ) + return NULL; + + const wxWindowList& siblings = GetParent()->GetChildren(); + wxWindowList::compatibility_iterator nodeThis = siblings.Find(this); + wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") ); + + // Iterate over all previous siblings until we find the next radio button + wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious(); + wxRadioButton *prevBtn = 0; + while (nodeBefore) + { + prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton); + if (prevBtn) + break; + + nodeBefore = nodeBefore->GetPrevious(); + } + + if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE)) + { + // no more buttons in group + return NULL; + } + + return prevBtn; +} + +wxRadioButton* wxRadioButtonBase::GetNextInGroup() const +{ + if ( HasFlag(wxRB_SINGLE) ) + return NULL; + + const wxWindowList& siblings = GetParent()->GetChildren(); + wxWindowList::compatibility_iterator nodeThis = siblings.Find(this); + wxCHECK_MSG( nodeThis, NULL, wxT("radio button not a child of its parent?") ); + + // Iterate over all previous siblings until we find the next radio button + wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext(); + wxRadioButton *nextBtn = 0; + while (nodeNext) + { + nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton); + if (nextBtn) + break; + + nodeNext = nodeNext->GetNext(); + } + + if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) ) + { + // no more buttons or the first button of the next group + return NULL; + } + + return nextBtn; +} + #endif // wxUSE_RADIOBTN From 808ff104dcfb8319e4a38f73923620f05c1415e4 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 21 Sep 2020 20:37:37 +0200 Subject: [PATCH 21/21] Don't compile wxGetSelectedButtonInGroup() if it's unused Now that this function is static, not using it results in warnings when building the ports not using it (e.g. wxX11). --- src/common/containr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/common/containr.cpp b/src/common/containr.cpp index d20098f869..cf5f630665 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -237,7 +237,7 @@ void wxControlContainer::SetLastFocus(wxWindow *win) // The following functions is used by wxSetFocusToChild() // -------------------------------------------------------------------- -#if wxUSE_RADIOBTN +#if defined(USE_RADIOBTN_NAV) namespace { @@ -268,7 +268,7 @@ wxRadioButton* wxGetSelectedButtonInGroup(const wxRadioButton *btn) } // anonymous namespace -#endif // wxUSE_RADIOBTN +#endif // USE_RADIOBTN_NAV // ---------------------------------------------------------------------------- // Keyboard handling - this is the place where the TAB traversal logic is