fix (with unknown but apparently beneficial effects) for TAB navigation in radio buttons (patch 1038330)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@32214 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -153,6 +153,111 @@ void wxControlContainer::SetLastFocus(wxWindow *win)
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
// The following four functions are used to find other radio buttons
|
||||
// within the same group. Used by wxSetFocusToChild on wxMSW
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#ifdef __WXMSW__
|
||||
|
||||
wxRadioButton* wxGetPreviousButtonInGroup(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, _T("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;
|
||||
}
|
||||
else
|
||||
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, _T("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;
|
||||
}
|
||||
else
|
||||
return nextBtn;
|
||||
}
|
||||
|
||||
wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn);
|
||||
if (!prevBtn)
|
||||
return btn;
|
||||
|
||||
btn = prevBtn;
|
||||
}
|
||||
}
|
||||
|
||||
wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn)
|
||||
{
|
||||
// Find currently selected button
|
||||
if (btn->GetValue())
|
||||
return btn;
|
||||
|
||||
if (btn->HasFlag(wxRB_SINGLE))
|
||||
return NULL;
|
||||
|
||||
wxRadioButton *selBtn;
|
||||
|
||||
// First check all previous buttons
|
||||
for (selBtn = wxGetPreviousButtonInGroup(btn); selBtn; selBtn = wxGetPreviousButtonInGroup(selBtn))
|
||||
if (selBtn->GetValue())
|
||||
return selBtn;
|
||||
|
||||
// Now all following buttons
|
||||
for (selBtn = wxGetNextButtonInGroup(btn); selBtn; selBtn = wxGetNextButtonInGroup(selBtn))
|
||||
if (selBtn->GetValue())
|
||||
return selBtn;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif __WXMSW__
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Keyboard handling - this is the place where the TAB traversal logic is
|
||||
// implemented. As this code is common to all ports, this ensures consistent
|
||||
@@ -224,6 +329,12 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event )
|
||||
|
||||
if ( winFocus )
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
// 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);
|
||||
#endif
|
||||
// ok, we found the focus - now is it our child?
|
||||
start_node = children.Find( winFocus );
|
||||
}
|
||||
@@ -291,14 +402,40 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event )
|
||||
|
||||
wxWindow *child = node->GetData();
|
||||
|
||||
#if defined(__WXMSW__)
|
||||
bool is_not_msw_rb = !m_winLastFocused ||
|
||||
!wxIsKindOf(m_winLastFocused,wxRadioButton);
|
||||
#ifdef __WXMSW__
|
||||
bool canSelectRadioButton = true;
|
||||
if (!event.IsFromTab())
|
||||
{
|
||||
// If navigating using cursor keys, make sure not to navigate out of a radio button group.
|
||||
if (m_winLastFocused && wxIsKindOf(m_winLastFocused, wxRadioButton))
|
||||
{
|
||||
if (!wxIsKindOf(child, wxRadioButton))
|
||||
{
|
||||
child = forward ?
|
||||
wxGetNextButtonInGroup((wxRadioButton*)m_winLastFocused) :
|
||||
wxGetPreviousButtonInGroup((wxRadioButton*)m_winLastFocused);
|
||||
if (!child)
|
||||
{
|
||||
event.Skip(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If navigating using tabs, skip all but the first radio button in a group.
|
||||
if (wxIsKindOf(child, wxRadioButton))
|
||||
{
|
||||
if (wxGetPreviousButtonInGroup((wxRadioButton*)child))
|
||||
canSelectRadioButton = false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
static const bool is_not_msw_rb = true;
|
||||
static bool canSelectRadioButton = true;
|
||||
#endif
|
||||
|
||||
if ( child->AcceptsFocusFromKeyboard() && is_not_msw_rb )
|
||||
if ( child->AcceptsFocusFromKeyboard() && canSelectRadioButton )
|
||||
{
|
||||
// if we're setting the focus to a child panel we should prevent it
|
||||
// from giving it to the child which had the focus the last time
|
||||
@@ -310,28 +447,11 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event )
|
||||
// we need to hop to the next activated
|
||||
// radio button, not just the next radio
|
||||
// button under MSW
|
||||
if (wxIsKindOf(child,wxRadioButton))
|
||||
if (wxIsKindOf(child, wxRadioButton) && event.IsFromTab())
|
||||
{
|
||||
wxRadioButton *rb = (wxRadioButton*) child;
|
||||
if (!rb->GetValue())
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
wxWindowList::compatibility_iterator node = children.Find( child );
|
||||
if (forward)
|
||||
node = node->GetNext();
|
||||
else
|
||||
node = node->GetPrevious();
|
||||
if (!node)
|
||||
return; // this would probably an error
|
||||
child = node->GetData();
|
||||
if (!wxIsKindOf(child,wxRadioButton))
|
||||
continue;
|
||||
rb = (wxRadioButton*) child;
|
||||
if (rb->GetValue())
|
||||
break;
|
||||
}
|
||||
}
|
||||
wxRadioButton *rb = wxGetSelectedButtonInGroup((wxRadioButton*)child);
|
||||
if (rb)
|
||||
child = rb;
|
||||
}
|
||||
#endif // __WXMSW__
|
||||
|
||||
@@ -475,6 +595,18 @@ bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused)
|
||||
|
||||
if ( child->AcceptsFocusFromKeyboard() && !child->IsTopLevel() )
|
||||
{
|
||||
#ifdef __WXMSW__
|
||||
// If a radiobutton is the first focusable child, search for the
|
||||
// selected radiobutton in the same group
|
||||
wxRadioButton* btn = wxDynamicCast(child, wxRadioButton);
|
||||
if (btn)
|
||||
{
|
||||
wxRadioButton* selected = wxGetSelectedButtonInGroup(btn);
|
||||
if (selected)
|
||||
child = selected;
|
||||
}
|
||||
#endif
|
||||
|
||||
wxLogTrace(_T("focus"),
|
||||
_T("SetFocusToChild() => first child (0x%08lx)."),
|
||||
(unsigned long)child->GetHandle());
|
||||
|
Reference in New Issue
Block a user