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.
This commit is contained in:
Vadim Zeitlin 2020-09-21 18:01:47 +02:00
parent bcb016613e
commit 09060ed262
3 changed files with 106 additions and 129 deletions

View File

@ -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<const wxRadioButton*>(this));
}
wxRadioButton* GetLastInGroup() const
{
return wxPrivate::wxGetLastButtonInGroup(static_cast<const wxRadioButton*>(this));
}
wxRadioButton* GetPreviousInGroup() const
{
return wxPrivate::wxGetPreviousButtonInGroup(static_cast<const wxRadioButton*>(this));
}
wxRadioButton* GetNextInGroup() const
{
return wxPrivate::wxGetNextButtonInGroup(static_cast<const wxRadioButton*>(this));
}
wxRadioButton* GetFirstInGroup() const;
wxRadioButton* GetLastInGroup() const;
wxRadioButton* GetPreviousInGroup() const;
wxRadioButton* GetNextInGroup() const;
private:
wxDECLARE_NO_COPY_CLASS(wxRadioButtonBase);

View File

@ -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<wxRadioButton*>(btn);
btn = prevBtn;
}
}
wxRadioButton* wxGetLastButtonInGroup(const wxRadioButton *btn)
{
while (true)
{
wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn);
if (!nextBtn)
return const_cast<wxRadioButton*>(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<wxRadioButton*>(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();
}
}

View File

@ -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<wxRadioButton*>(const_cast<wxRadioButtonBase*>(this));
while (true)
{
wxRadioButton* prevBtn = btn->GetPreviousInGroup();
if (!prevBtn)
return btn;
btn = prevBtn;
}
}
wxRadioButton* wxRadioButtonBase::GetLastInGroup() const
{
wxRadioButton*
btn = static_cast<wxRadioButton*>(const_cast<wxRadioButtonBase*>(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