diff --git a/include/wx/gtk/radiobut.h b/include/wx/gtk/radiobut.h index cf6492a623..8a19a022dd 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() { } @@ -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/gtk1/radiobut.h b/include/wx/gtk1/radiobut.h index d958079729..d467f7100c 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..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 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..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 wxMSWOwnerDrawnButton +class WXDLLIMPEXP_CORE wxRadioButton : public wxMSWOwnerDrawnButton { public: // ctors and creation functions @@ -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 e968d80acd..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 wxControl +class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase { wxDECLARE_DYNAMIC_CLASS(wxRadioButton); @@ -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 5a1ab5ad14..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 wxControl +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase { public: wxRadioButton(); @@ -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 11f466cdbe..f4cf3b1a09 100644 --- a/include/wx/radiobut.h +++ b/include/wx/radiobut.h @@ -15,23 +15,42 @@ #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; + +// 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: + 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; + wxRadioButton* GetLastInGroup() const; + wxRadioButton* GetPreviousInGroup() const; + wxRadioButton* GetNextInGroup() const; + +private: + wxDECLARE_NO_COPY_CLASS(wxRadioButtonBase); +}; + 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..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 wxCheckBox +class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase { public: // constructors @@ -46,6 +44,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; diff --git a/interface/wx/radiobut.h b/interface/wx/radiobut.h index d037412e55..0a42c1c0f9 100644 --- a/interface/wx/radiobut.h +++ b/interface/wx/radiobut.h @@ -12,18 +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. + 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} @@ -119,5 +129,64 @@ public: @true to check, @false to uncheck. */ virtual void SetValue(bool value); + + /** + Returns the first button of the radio button group this button belongs + to. + + 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() + + @since 3.1.5 + */ + wxRadioButton* GetFirstInGroup() const; + + /** + Returns the last button of the radio button group this button belongs + to. + + 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. + + The returned value is never @NULL. + + @see GetPreviousInGroup(), GetNextInGroup() + + @since 3.1.5 + */ + wxRadioButton* GetLastInGroup() const; + + /** + Returns the previous radio button in the same group. + + The return value is @NULL if there is no predecessor or if this button + has @c wxRB_SINGLE style. + + @see GetFirstInGroup(), GetNextInGroup(), GetLastInGroup() + + @since 3.1.5 + */ + wxRadioButton* GetPreviousInGroup() const; + + /** + Returns the next radio button in the same group. + + The return value is @NULL if there is no successor or if this button + has @c wxRB_SINGLE style. + + @see GetFirstInGroup(), GetPreviousInGroup(), GetLastInGroup() + + @since 3.1.5 + */ + wxRadioButton* GetNextInGroup() const; }; diff --git a/src/common/containr.cpp b/src/common/containr.cpp index b418a3b8c2..cf5f630665 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -234,101 +234,19 @@ void wxControlContainer::SetLastFocus(wxWindow *win) } // -------------------------------------------------------------------- -// The following four functions are used to find other radio buttons -// within the same group. Used by wxSetFocusToChild +// The following functions is used by wxSetFocusToChild() // -------------------------------------------------------------------- -#if wxUSE_RADIOBTN +#if defined(USE_RADIOBTN_NAV) -wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn) +namespace { - 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(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(wxRadioButton *btn) -{ - while (true) - { - wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn); - if (!prevBtn) - return btn; - - btn = prevBtn; - } -} - -wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn) -{ - while (true) - { - wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn); - if (!nextBtn) - return 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; @@ -336,19 +254,21 @@ wxRadioButton* wxGetSelectedButtonInGroup(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; } -#endif // wxUSE_RADIOBTN +} // anonymous namespace + +#endif // USE_RADIOBTN_NAV // ---------------------------------------------------------------------------- // Keyboard handling - this is the place where the TAB traversal logic is @@ -468,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 ); @@ -586,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 diff --git a/tests/controls/radiobuttontest.cpp b/tests/controls/radiobuttontest.cpp index a81d6aec61..cdcc144972 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,87 +66,115 @@ 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(); // 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.2")); 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); - wxDELETE(g2radio0); - wxDELETE(g2radio1); - wxDELETE(g2radio2); - wxDELETE(text); + + // 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); } -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(), @@ -197,9 +204,15 @@ void RadioButtonTestCase::Single() 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("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. 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 {