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:
Vadim Zeitlin
2005-02-19 21:58:48 +00:00
parent 828f093601
commit 7ff1b620e8

View File

@@ -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());