Merge branch 'expose-radiogroup'
Add public functions for navigating in radio button groups. Also introduce wxRadioButtonBase defining wxRadioButton API for all ports. See https://github.com/wxWidgets/wxWidgets/pull/2052
This commit is contained in:
@@ -13,7 +13,7 @@
|
|||||||
// wxRadioButton
|
// wxRadioButton
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
class WXDLLIMPEXP_CORE wxRadioButton: public wxControl
|
class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxRadioButton() { }
|
wxRadioButton() { }
|
||||||
@@ -39,8 +39,8 @@ public:
|
|||||||
const wxString& name = wxASCII_STR(wxRadioButtonNameStr) );
|
const wxString& name = wxASCII_STR(wxRadioButtonNameStr) );
|
||||||
|
|
||||||
virtual void SetLabel(const wxString& label) wxOVERRIDE;
|
virtual void SetLabel(const wxString& label) wxOVERRIDE;
|
||||||
virtual void SetValue(bool val);
|
virtual void SetValue(bool val) wxOVERRIDE;
|
||||||
virtual bool GetValue() const;
|
virtual bool GetValue() const wxOVERRIDE;
|
||||||
|
|
||||||
static wxVisualAttributes
|
static wxVisualAttributes
|
||||||
GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);
|
GetClassDefaultAttributes(wxWindowVariant variant = wxWINDOW_VARIANT_NORMAL);
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
// wxRadioButton
|
// wxRadioButton
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
class WXDLLIMPEXP_CORE wxRadioButton: public wxControl
|
class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxRadioButton() { }
|
wxRadioButton() { }
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
#ifndef _WX_RADIOBUT_H_
|
#ifndef _WX_RADIOBUT_H_
|
||||||
#define _WX_RADIOBUT_H_
|
#define _WX_RADIOBUT_H_
|
||||||
|
|
||||||
class WXDLLIMPEXP_CORE wxRadioButton: public wxControl
|
class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase
|
||||||
{
|
{
|
||||||
wxDECLARE_DYNAMIC_CLASS(wxRadioButton);
|
wxDECLARE_DYNAMIC_CLASS(wxRadioButton);
|
||||||
public:
|
public:
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
#include "wx/msw/ownerdrawnbutton.h"
|
#include "wx/msw/ownerdrawnbutton.h"
|
||||||
|
|
||||||
class WXDLLIMPEXP_CORE wxRadioButton : public wxMSWOwnerDrawnButton<wxControl>
|
class WXDLLIMPEXP_CORE wxRadioButton : public wxMSWOwnerDrawnButton<wxRadioButtonBase>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// ctors and creation functions
|
// ctors and creation functions
|
||||||
@@ -43,8 +43,8 @@ public:
|
|||||||
const wxString& name = wxASCII_STR(wxRadioButtonNameStr));
|
const wxString& name = wxASCII_STR(wxRadioButtonNameStr));
|
||||||
|
|
||||||
// implement the radio button interface
|
// implement the radio button interface
|
||||||
virtual void SetValue(bool value);
|
virtual void SetValue(bool value) wxOVERRIDE;
|
||||||
virtual bool GetValue() const;
|
virtual bool GetValue() const wxOVERRIDE;
|
||||||
|
|
||||||
// implementation only from now on
|
// implementation only from now on
|
||||||
virtual bool MSWCommand(WXUINT param, WXWORD id) wxOVERRIDE;
|
virtual bool MSWCommand(WXUINT param, WXWORD id) wxOVERRIDE;
|
||||||
|
@@ -11,7 +11,7 @@
|
|||||||
#ifndef _WX_RADIOBUT_H_
|
#ifndef _WX_RADIOBUT_H_
|
||||||
#define _WX_RADIOBUT_H_
|
#define _WX_RADIOBUT_H_
|
||||||
|
|
||||||
class WXDLLIMPEXP_CORE wxRadioButton: public wxControl
|
class WXDLLIMPEXP_CORE wxRadioButton: public wxRadioButtonBase
|
||||||
{
|
{
|
||||||
wxDECLARE_DYNAMIC_CLASS(wxRadioButton);
|
wxDECLARE_DYNAMIC_CLASS(wxRadioButton);
|
||||||
|
|
||||||
@@ -35,8 +35,8 @@ public:
|
|||||||
const wxValidator& validator = wxDefaultValidator,
|
const wxValidator& validator = wxDefaultValidator,
|
||||||
const wxString& name = wxASCII_STR(wxRadioButtonNameStr));
|
const wxString& name = wxASCII_STR(wxRadioButtonNameStr));
|
||||||
|
|
||||||
virtual void SetValue(bool val);
|
virtual void SetValue(bool val) wxOVERRIDE;
|
||||||
virtual bool GetValue() const ;
|
virtual bool GetValue() const wxOVERRIDE;
|
||||||
|
|
||||||
// implementation
|
// implementation
|
||||||
|
|
||||||
|
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
class QRadioButton;
|
class QRadioButton;
|
||||||
|
|
||||||
class WXDLLIMPEXP_CORE wxRadioButton : public wxControl
|
class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxRadioButton();
|
wxRadioButton();
|
||||||
@@ -32,8 +32,8 @@ public:
|
|||||||
const wxValidator& validator = wxDefaultValidator,
|
const wxValidator& validator = wxDefaultValidator,
|
||||||
const wxString& name = wxASCII_STR(wxRadioButtonNameStr) );
|
const wxString& name = wxASCII_STR(wxRadioButtonNameStr) );
|
||||||
|
|
||||||
virtual void SetValue(bool value);
|
virtual void SetValue(bool value) wxOVERRIDE;
|
||||||
virtual bool GetValue() const;
|
virtual bool GetValue() const wxOVERRIDE;
|
||||||
|
|
||||||
virtual QWidget *GetHandle() const wxOVERRIDE;
|
virtual QWidget *GetHandle() const wxOVERRIDE;
|
||||||
|
|
||||||
|
@@ -15,23 +15,42 @@
|
|||||||
|
|
||||||
#if wxUSE_RADIOBTN
|
#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"
|
#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[];
|
extern WXDLLIMPEXP_DATA_CORE(const char) wxRadioButtonNameStr[];
|
||||||
|
|
||||||
#if defined(__WXUNIVERSAL__)
|
#if defined(__WXUNIVERSAL__)
|
||||||
|
@@ -11,13 +11,11 @@
|
|||||||
#ifndef _WX_UNIV_RADIOBUT_H_
|
#ifndef _WX_UNIV_RADIOBUT_H_
|
||||||
#define _WX_UNIV_RADIOBUT_H_
|
#define _WX_UNIV_RADIOBUT_H_
|
||||||
|
|
||||||
#include "wx/checkbox.h"
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// wxRadioButton
|
// wxRadioButton
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
class WXDLLIMPEXP_CORE wxRadioButton : public wxCheckBox
|
class WXDLLIMPEXP_CORE wxRadioButton : public wxRadioButtonBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// constructors
|
// constructors
|
||||||
@@ -46,6 +44,10 @@ public:
|
|||||||
const wxValidator& validator = wxDefaultValidator,
|
const wxValidator& validator = wxDefaultValidator,
|
||||||
const wxString& name = wxASCII_STR(wxRadioButtonNameStr));
|
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
|
// override some base class methods
|
||||||
virtual void ChangeValue(bool value) wxOVERRIDE;
|
virtual void ChangeValue(bool value) wxOVERRIDE;
|
||||||
|
|
||||||
|
@@ -12,18 +12,28 @@
|
|||||||
mutually exclusive options. It has a text label next to a (usually) round
|
mutually exclusive options. It has a text label next to a (usually) round
|
||||||
button.
|
button.
|
||||||
|
|
||||||
You can create a group of mutually-exclusive radio buttons by specifying
|
Radio buttons are typically used in groups of mutually-exclusive buttons,
|
||||||
@c wxRB_GROUP for the first in the group. The group ends when another
|
i.e. exactly one of the buttons in the group is checked, and the other ones
|
||||||
radio button group is created, or there are no more radio buttons.
|
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
|
@beginStyleTable
|
||||||
@style{wxRB_GROUP}
|
@style{wxRB_GROUP}
|
||||||
Marks the beginning of a new group of radio buttons.
|
Marks the beginning of a new group of radio buttons.
|
||||||
@style{wxRB_SINGLE}
|
@style{wxRB_SINGLE}
|
||||||
In some circumstances, radio buttons that are not consecutive
|
Creates a radio button which is not part of any radio button group.
|
||||||
siblings trigger a hang bug in Windows (only). If this happens, add
|
When this style is used, no other radio buttons will be turned off
|
||||||
this style to mark the button as not belonging to a group, and
|
automatically when this button is turned on and such behaviour will
|
||||||
implement the mutually-exclusive group behaviour yourself.
|
need to be implemented manually, in the event handler for this
|
||||||
|
button.
|
||||||
@endStyleTable
|
@endStyleTable
|
||||||
|
|
||||||
@beginEventEmissionTable{wxCommandEvent}
|
@beginEventEmissionTable{wxCommandEvent}
|
||||||
@@ -119,5 +129,64 @@ public:
|
|||||||
@true to check, @false to uncheck.
|
@true to check, @false to uncheck.
|
||||||
*/
|
*/
|
||||||
virtual void SetValue(bool value);
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -234,101 +234,19 @@ void wxControlContainer::SetLastFocus(wxWindow *win)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------
|
// --------------------------------------------------------------------
|
||||||
// The following four functions are used to find other radio buttons
|
// The following functions is used by wxSetFocusToChild()
|
||||||
// within the same group. 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();
|
wxRadioButton* wxGetSelectedButtonInGroup(const wxRadioButton *btn)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
// Find currently selected button
|
// Find currently selected button
|
||||||
if (btn->GetValue())
|
if (btn->GetValue())
|
||||||
return btn;
|
return const_cast<wxRadioButton*>(btn);
|
||||||
|
|
||||||
if (btn->HasFlag(wxRB_SINGLE))
|
if (btn->HasFlag(wxRB_SINGLE))
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -336,19 +254,21 @@ wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn)
|
|||||||
wxRadioButton *selBtn;
|
wxRadioButton *selBtn;
|
||||||
|
|
||||||
// First check all previous buttons
|
// First check all previous buttons
|
||||||
for (selBtn = wxGetPreviousButtonInGroup(btn); selBtn; selBtn = wxGetPreviousButtonInGroup(selBtn))
|
for (selBtn = btn->GetPreviousInGroup(); selBtn; selBtn = selBtn->GetPreviousInGroup())
|
||||||
if (selBtn->GetValue())
|
if (selBtn->GetValue())
|
||||||
return selBtn;
|
return selBtn;
|
||||||
|
|
||||||
// Now all following buttons
|
// Now all following buttons
|
||||||
for (selBtn = wxGetNextButtonInGroup(btn); selBtn; selBtn = wxGetNextButtonInGroup(selBtn))
|
for (selBtn = btn->GetNextInGroup(); selBtn; selBtn = selBtn->GetNextInGroup())
|
||||||
if (selBtn->GetValue())
|
if (selBtn->GetValue())
|
||||||
return selBtn;
|
return selBtn;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // wxUSE_RADIOBTN
|
} // anonymous namespace
|
||||||
|
|
||||||
|
#endif // USE_RADIOBTN_NAV
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Keyboard handling - this is the place where the TAB traversal logic is
|
// 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
|
// If we are in a radio button group, start from the first item in the
|
||||||
// group
|
// group
|
||||||
if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) )
|
if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) )
|
||||||
winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus);
|
winFocus = static_cast<wxRadioButton*>(winFocus)->GetFirstInGroup();
|
||||||
#endif // USE_RADIOBTN_NAV
|
#endif // USE_RADIOBTN_NAV
|
||||||
// ok, we found the focus - now is it our child?
|
// ok, we found the focus - now is it our child?
|
||||||
start_node = children.Find( winFocus );
|
start_node = children.Find( winFocus );
|
||||||
@@ -586,20 +506,20 @@ void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event )
|
|||||||
// find the correct radio button to focus
|
// find the correct radio button to focus
|
||||||
if ( forward )
|
if ( forward )
|
||||||
{
|
{
|
||||||
child = wxGetNextButtonInGroup(lastBtn);
|
child = lastBtn->GetNextInGroup();
|
||||||
if ( !child )
|
if ( !child )
|
||||||
{
|
{
|
||||||
// no next button in group, set it to the first button
|
// no next button in group, set it to the first button
|
||||||
child = wxGetFirstButtonInGroup(lastBtn);
|
child = lastBtn->GetFirstInGroup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
child = wxGetPreviousButtonInGroup(lastBtn);
|
child = lastBtn->GetPreviousInGroup();
|
||||||
if ( !child )
|
if ( !child )
|
||||||
{
|
{
|
||||||
// no previous button in group, set it to the last button
|
// no previous button in group, set it to the last button
|
||||||
child = wxGetLastButtonInGroup(lastBtn);
|
child = lastBtn->GetLastInGroup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -92,4 +92,96 @@ wxCONSTRUCTOR_6( wxRadioButton, wxWindow*, Parent, wxWindowID, Id, \
|
|||||||
wxString, Label, wxPoint, Position, wxSize, Size, long, WindowStyle )
|
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
|
#endif // wxUSE_RADIOBTN
|
||||||
|
@@ -27,40 +27,19 @@
|
|||||||
#include "testableframe.h"
|
#include "testableframe.h"
|
||||||
#include "testwindow.h"
|
#include "testwindow.h"
|
||||||
|
|
||||||
class RadioButtonTestCase : public CppUnit::TestCase
|
class RadioButtonTestCase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
RadioButtonTestCase() { }
|
RadioButtonTestCase();
|
||||||
|
~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();
|
|
||||||
|
|
||||||
|
protected:
|
||||||
wxRadioButton* m_radio;
|
wxRadioButton* m_radio;
|
||||||
|
|
||||||
wxDECLARE_NO_COPY_CLASS(RadioButtonTestCase);
|
wxDECLARE_NO_COPY_CLASS(RadioButtonTestCase);
|
||||||
};
|
};
|
||||||
|
|
||||||
// register in the unnamed registry so that these tests are run by default
|
RadioButtonTestCase::RadioButtonTestCase()
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
m_radio = new wxRadioButton(wxTheApp->GetTopWindow(), wxID_ANY,
|
m_radio = new wxRadioButton(wxTheApp->GetTopWindow(), wxID_ANY,
|
||||||
"wxRadioButton");
|
"wxRadioButton");
|
||||||
@@ -68,12 +47,12 @@ void RadioButtonTestCase::setUp()
|
|||||||
m_radio->Refresh();
|
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
|
// OS X doesn't support selecting a single radio button
|
||||||
#if wxUSE_UIACTIONSIMULATOR && !defined(__WXOSX__)
|
#if wxUSE_UIACTIONSIMULATOR && !defined(__WXOSX__)
|
||||||
@@ -87,87 +66,115 @@ void RadioButtonTestCase::Click()
|
|||||||
|
|
||||||
wxYield();
|
wxYield();
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL( 1, selected.GetCount() );
|
CHECK(selected.GetCount() == 1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioButtonTestCase::Value()
|
TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Value", "[radiobutton]")
|
||||||
{
|
{
|
||||||
#ifndef __WXGTK__
|
#ifndef __WXGTK__
|
||||||
EventCounter selected(m_radio, wxEVT_RADIOBUTTON);
|
EventCounter selected(m_radio, wxEVT_RADIOBUTTON);
|
||||||
|
|
||||||
m_radio->SetValue(true);
|
m_radio->SetValue(true);
|
||||||
|
|
||||||
CPPUNIT_ASSERT(m_radio->GetValue());
|
CHECK(m_radio->GetValue());
|
||||||
|
|
||||||
m_radio->SetValue(false);
|
m_radio->SetValue(false);
|
||||||
|
|
||||||
CPPUNIT_ASSERT(!m_radio->GetValue());
|
CHECK(!m_radio->GetValue());
|
||||||
|
|
||||||
CPPUNIT_ASSERT_EQUAL(0, selected.GetCount());
|
CHECK(selected.GetCount() == 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void RadioButtonTestCase::Group()
|
TEST_CASE_METHOD(RadioButtonTestCase, "RadioButton::Group", "[radiobutton]")
|
||||||
{
|
{
|
||||||
wxWindow* const parent = wxTheApp->GetTopWindow();
|
wxWindow* const parent = wxTheApp->GetTopWindow();
|
||||||
|
|
||||||
// Create two different radio groups.
|
// Create two different radio groups.
|
||||||
wxRadioButton* g1radio0 = new wxRadioButton(parent, wxID_ANY, "radio 1.0",
|
wxScopedPtr<wxRadioButton> g1radio0(new wxRadioButton(parent, wxID_ANY, "radio 1.0",
|
||||||
wxDefaultPosition, wxDefaultSize,
|
wxDefaultPosition, wxDefaultSize,
|
||||||
wxRB_GROUP);
|
wxRB_GROUP));
|
||||||
|
|
||||||
wxRadioButton* g1radio1 = new wxRadioButton(parent, wxID_ANY, "radio 1.1");
|
wxScopedPtr<wxRadioButton> g1radio1(new wxRadioButton(parent, wxID_ANY, "radio 1.1"));
|
||||||
|
|
||||||
wxRadioButton* g2radio0 = new wxRadioButton(parent, wxID_ANY, "radio 2.0",
|
wxScopedPtr<wxRadioButton> g2radio0(new wxRadioButton(parent, wxID_ANY, "radio 2.0",
|
||||||
wxDefaultPosition, wxDefaultSize,
|
wxDefaultPosition, wxDefaultSize,
|
||||||
wxRB_GROUP);
|
wxRB_GROUP));
|
||||||
|
|
||||||
wxRadioButton* g2radio1 = new wxRadioButton(parent, wxID_ANY, "radio 2.1");
|
wxScopedPtr<wxRadioButton> g2radio1(new wxRadioButton(parent, wxID_ANY, "radio 2.1"));
|
||||||
|
|
||||||
// Check that having another control between radio buttons doesn't break
|
// Check that having another control between radio buttons doesn't break
|
||||||
// grouping.
|
// grouping.
|
||||||
wxStaticText* text = new wxStaticText(parent, wxID_ANY, "Label");
|
wxScopedPtr<wxStaticText> text(new wxStaticText(parent, wxID_ANY, "Label"));
|
||||||
wxRadioButton* g2radio2 = new wxRadioButton(parent, wxID_ANY, "radio 2.1");
|
wxScopedPtr<wxRadioButton> g2radio2(new wxRadioButton(parent, wxID_ANY, "radio 2.2"));
|
||||||
|
|
||||||
g1radio0->SetValue(true);
|
g1radio0->SetValue(true);
|
||||||
g2radio0->SetValue(true);
|
g2radio0->SetValue(true);
|
||||||
|
|
||||||
CPPUNIT_ASSERT(g1radio0->GetValue());
|
CHECK(g1radio0->GetValue());
|
||||||
CPPUNIT_ASSERT(!g1radio1->GetValue());
|
CHECK(!g1radio1->GetValue());
|
||||||
CPPUNIT_ASSERT(g2radio0->GetValue());
|
CHECK(g2radio0->GetValue());
|
||||||
CPPUNIT_ASSERT(!g2radio1->GetValue());
|
CHECK(!g2radio1->GetValue());
|
||||||
|
|
||||||
g1radio1->SetValue(true);
|
g1radio1->SetValue(true);
|
||||||
g2radio1->SetValue(true);
|
g2radio1->SetValue(true);
|
||||||
|
|
||||||
CPPUNIT_ASSERT(!g1radio0->GetValue());
|
CHECK(!g1radio0->GetValue());
|
||||||
CPPUNIT_ASSERT(g1radio1->GetValue());
|
CHECK(g1radio1->GetValue());
|
||||||
CPPUNIT_ASSERT(!g2radio0->GetValue());
|
CHECK(!g2radio0->GetValue());
|
||||||
CPPUNIT_ASSERT(g2radio1->GetValue());
|
CHECK(g2radio1->GetValue());
|
||||||
|
|
||||||
g2radio2->SetValue(true);
|
g2radio2->SetValue(true);
|
||||||
CPPUNIT_ASSERT(!g2radio0->GetValue());
|
CHECK(!g2radio0->GetValue());
|
||||||
CPPUNIT_ASSERT(!g2radio1->GetValue());
|
CHECK(!g2radio1->GetValue());
|
||||||
CPPUNIT_ASSERT(g2radio2->GetValue());
|
CHECK(g2radio2->GetValue());
|
||||||
|
|
||||||
g1radio0->SetValue(true);
|
g1radio0->SetValue(true);
|
||||||
g2radio0->SetValue(true);
|
g2radio0->SetValue(true);
|
||||||
|
|
||||||
CPPUNIT_ASSERT(g1radio0->GetValue());
|
CHECK(g1radio0->GetValue());
|
||||||
CPPUNIT_ASSERT(!g1radio1->GetValue());
|
CHECK(!g1radio1->GetValue());
|
||||||
CPPUNIT_ASSERT(g2radio0->GetValue());
|
CHECK(g2radio0->GetValue());
|
||||||
CPPUNIT_ASSERT(!g2radio1->GetValue());
|
CHECK(!g2radio1->GetValue());
|
||||||
|
|
||||||
wxDELETE(g1radio0);
|
|
||||||
wxDELETE(g1radio1);
|
// Check that group navigation functions behave as expected.
|
||||||
wxDELETE(g2radio0);
|
|
||||||
wxDELETE(g2radio1);
|
// GetFirstInGroup()
|
||||||
wxDELETE(g2radio2);
|
CHECK_SAME_WINDOW(g1radio0->GetFirstInGroup(), g1radio0);
|
||||||
wxDELETE(text);
|
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
|
//Create a group of 2 buttons, having second button selected
|
||||||
wxScopedPtr<wxRadioButton> gradio0(new wxRadioButton(wxTheApp->GetTopWindow(),
|
wxScopedPtr<wxRadioButton> gradio0(new wxRadioButton(wxTheApp->GetTopWindow(),
|
||||||
@@ -197,9 +204,15 @@ void RadioButtonTestCase::Single()
|
|||||||
|
|
||||||
CHECK(gradio1->GetValue());
|
CHECK(gradio1->GetValue());
|
||||||
CHECK(ngradio->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
|
// Create a container panel just to be able to destroy all the windows
|
||||||
// created here at once by simply destroying it.
|
// created here at once by simply destroying it.
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
#ifndef _WX_TESTS_TESTWINDOW_H_
|
#ifndef _WX_TESTS_TESTWINDOW_H_
|
||||||
#define _WX_TESTS_TESTWINDOW_H_
|
#define _WX_TESTS_TESTWINDOW_H_
|
||||||
|
|
||||||
|
#include "wx/scopedptr.h"
|
||||||
#include "wx/window.h"
|
#include "wx/window.h"
|
||||||
|
|
||||||
// We need to wrap wxWindow* in a class as specializing StringMaker for
|
// We need to wrap wxWindow* in a class as specializing StringMaker for
|
||||||
@@ -17,6 +18,8 @@ class wxWindowPtr
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit wxWindowPtr(wxWindow* win) : m_win(win) {}
|
explicit wxWindowPtr(wxWindow* win) : m_win(win) {}
|
||||||
|
template <typename W>
|
||||||
|
explicit wxWindowPtr(const wxScopedPtr<W>& win) : m_win(win.get()) {}
|
||||||
|
|
||||||
wxString Dump() const
|
wxString Dump() const
|
||||||
{
|
{
|
||||||
@@ -44,7 +47,9 @@ private:
|
|||||||
|
|
||||||
// Macro providing more information about the current focus if comparison
|
// Macro providing more information about the current focus if comparison
|
||||||
// fails.
|
// 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
|
namespace Catch
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user