1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/radiobut.cpp
3 // Purpose: wxRadioButton
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "radiobut.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
34 #include "wx/radiobut.h"
35 #include "wx/settings.h"
36 #include "wx/dcscreen.h"
39 #include "wx/msw/private.h"
41 // ============================================================================
42 // wxRadioButton implementation
43 // ============================================================================
45 // ----------------------------------------------------------------------------
46 // wxRadioButton creation
47 // ----------------------------------------------------------------------------
50 #if wxUSE_EXTENDED_RTTI
51 WX_DEFINE_FLAGS( wxRadioButtonStyle
)
53 wxBEGIN_FLAGS( wxRadioButtonStyle
)
54 // new style border flags, we put them first to
55 // use them for streaming out
56 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
57 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
58 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
59 wxFLAGS_MEMBER(wxBORDER_RAISED
)
60 wxFLAGS_MEMBER(wxBORDER_STATIC
)
61 wxFLAGS_MEMBER(wxBORDER_NONE
)
63 // old style border flags
64 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
65 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
66 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
67 wxFLAGS_MEMBER(wxRAISED_BORDER
)
68 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
69 wxFLAGS_MEMBER(wxBORDER
)
71 // standard window styles
72 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
73 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
74 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
75 wxFLAGS_MEMBER(wxWANTS_CHARS
)
76 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
77 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
78 wxFLAGS_MEMBER(wxVSCROLL
)
79 wxFLAGS_MEMBER(wxHSCROLL
)
81 wxFLAGS_MEMBER(wxRB_GROUP
)
83 wxEND_FLAGS( wxRadioButtonStyle
)
85 IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioButton
, wxControl
,"wx/radiobut.h")
87 wxBEGIN_PROPERTIES_TABLE(wxRadioButton
)
88 wxEVENT_PROPERTY( Click
, wxEVT_COMMAND_RADIOBUTTON_SELECTED
, wxCommandEvent
)
89 wxPROPERTY( Font
, wxFont
, SetFont
, GetFont
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
90 wxPROPERTY( Label
,wxString
, SetLabel
, GetLabel
, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
91 wxPROPERTY( Value
,bool, SetValue
, GetValue
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
92 wxPROPERTY_FLAGS( WindowStyle
, wxRadioButtonStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
93 wxEND_PROPERTIES_TABLE()
95 wxBEGIN_HANDLERS_TABLE(wxRadioButton
)
96 wxEND_HANDLERS_TABLE()
98 wxCONSTRUCTOR_6( wxRadioButton
, wxWindow
* , Parent
, wxWindowID
, Id
, wxString
, Label
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
101 IMPLEMENT_DYNAMIC_CLASS(wxRadioButton
, wxControl
)
105 void wxRadioButton::Init()
110 bool wxRadioButton::Create(wxWindow
*parent
,
112 const wxString
& label
,
116 const wxValidator
& validator
,
117 const wxString
& name
)
119 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
122 long msStyle
= WS_TABSTOP
;
123 if ( HasFlag(wxRB_GROUP
) )
127 wxRB_SINGLE is a temporary workaround for the following problem: if you
128 have 2 radiobuttons in the same group but which are not consecutive in
129 the dialog, Windows can enter an infinite loop! The simplest way to
130 reproduce it is to create radio button, then a panel and then another
131 radio button: then checking the last button hangs the app.
133 Ideally, we'd detect (and avoid) such situation automatically but for
134 now, as I don't know how to do it, just allow the user to create
135 BS_RADIOBUTTON buttons for such situations.
137 msStyle
|= HasFlag(wxRB_SINGLE
) ? BS_RADIOBUTTON
: BS_AUTORADIOBUTTON
;
139 if ( HasFlag(wxCLIP_SIBLINGS
) )
140 msStyle
|= WS_CLIPSIBLINGS
;
141 if ( HasFlag(wxALIGN_RIGHT
) )
142 msStyle
|= BS_LEFTTEXT
| BS_RIGHT
;
144 if ( !MSWCreateControl(_T("BUTTON"), msStyle
, pos
, size
, label
, 0) )
147 // for compatibility with wxGTK, the first radio button in a group is
148 // always checked (this makes sense anyhow as you need to ensure that at
149 // least one button in the group is checked and this is the simlpest way to
151 if ( HasFlag(wxRB_GROUP
) )
157 // ----------------------------------------------------------------------------
158 // wxRadioButton functions
159 // ----------------------------------------------------------------------------
161 void wxRadioButton::SetValue(bool value
)
163 (void)::SendMessage(GetHwnd(), BM_SETCHECK
, (value
?BST_CHECKED
:BST_UNCHECKED
), 0L);
167 // if we set the value of one radio button we also must clear all the other
168 // buttons in the same group: Windows doesn't do it automatically
171 const wxWindowList
& siblings
= GetParent()->GetChildren();
172 wxWindowList::compatibility_iterator nodeThis
= siblings
.Find(this);
173 wxCHECK_RET( nodeThis
, _T("radio button not a child of its parent?") );
175 // if it's not the first item of the group ...
176 if ( !HasFlag(wxRB_GROUP
) )
178 // ... turn off all radio buttons before it
179 for ( wxWindowList::compatibility_iterator nodeBefore
= nodeThis
->GetPrevious();
181 nodeBefore
= nodeBefore
->GetPrevious() )
183 wxRadioButton
*btn
= wxDynamicCast(nodeBefore
->GetData(),
185 if ( btn
&& btn
->HasFlag(wxRB_SINGLE
) )
187 // A wxRB_SINGLE button isn't part of this group
193 btn
->SetValue(false);
195 if ( btn
->HasFlag(wxRB_GROUP
) )
197 // even if there are other radio buttons before this one,
198 // they're not in the same group with us
205 // ... and also turn off all buttons after this one
206 for ( wxWindowList::compatibility_iterator nodeAfter
= nodeThis
->GetNext();
208 nodeAfter
= nodeAfter
->GetNext() )
210 wxRadioButton
*btn
= wxDynamicCast(nodeAfter
->GetData(),
213 if ( btn
&& (btn
->HasFlag(wxRB_GROUP
) || btn
->HasFlag(wxRB_SINGLE
) ) )
215 // no more buttons or the first button of the next group
220 btn
->SetValue(false);
225 bool wxRadioButton::GetValue() const
227 wxASSERT_MSG( m_isChecked
==
228 (::SendMessage(GetHwnd(), BM_GETCHECK
, 0, 0L) != 0),
229 _T("wxRadioButton::m_isChecked is out of sync?") );
234 // ----------------------------------------------------------------------------
235 // wxRadioButton event processing
236 // ----------------------------------------------------------------------------
238 void wxRadioButton::Command (wxCommandEvent
& event
)
240 SetValue(event
.m_commandInt
!= 0);
241 ProcessCommand(event
);
244 bool wxRadioButton::MSWCommand(WXUINT param
, WXWORD
WXUNUSED(id
))
246 if ( param
!= BN_CLICKED
)
251 // we have to do this for BS_RADIOBUTTON anyhow and, strangely enough,
252 // sometimes this is needed even for BS_AUTORADIOBUTTON (when we
253 // receive focus the button gets BN_CLICKED but stays unchecked!)
256 wxCommandEvent
event(wxEVT_COMMAND_RADIOBUTTON_SELECTED
, GetId());
257 event
.SetEventObject( this );
258 event
.SetInt(true); // always checked
260 ProcessCommand(event
);
266 // ----------------------------------------------------------------------------
267 // wxRadioButton geometry
268 // ----------------------------------------------------------------------------
270 wxSize
wxRadioButton::DoGetBestSize() const
272 static int s_radioSize
= 0;
277 dc
.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
));
279 s_radioSize
= dc
.GetCharHeight();
282 wxString str
= GetLabel();
287 GetTextExtent(str
, &wRadio
, &hRadio
);
288 wRadio
+= s_radioSize
+ GetCharWidth();
290 if ( hRadio
< s_radioSize
)
291 hRadio
= s_radioSize
;
295 wRadio
= s_radioSize
;
296 hRadio
= s_radioSize
;
299 return wxSize(wRadio
, hRadio
);
302 #endif // wxUSE_RADIOBTN