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 // ----------------------------------------------------------------------------
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"
37 #include "wx/dcscreen.h"
40 #include "wx/msw/private.h"
42 // ============================================================================
43 // wxRadioButton implementation
44 // ============================================================================
46 // ----------------------------------------------------------------------------
47 // wxRadioButton creation
48 // ----------------------------------------------------------------------------
50 IMPLEMENT_DYNAMIC_CLASS(wxRadioButton
, wxControl
)
52 void wxRadioButton::Init()
54 m_focusJustSet
= FALSE
;
57 bool wxRadioButton::Create(wxWindow
*parent
,
59 const wxString
& label
,
63 const wxValidator
& validator
,
66 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
69 long msStyle
= WS_TABSTOP
;
70 if ( HasFlag(wxRB_GROUP
) )
74 wxRB_SINGLE is a temporary workaround for the following problem: if you
75 have 2 radiobuttons in the same group but which are not consecutive in
76 the dialog, Windows can enter an infinite loop! The simplest way to
77 reproduce it is to create radio button, then a panel and then another
78 radio button: then checking the last button hangs the app.
80 Ideally, we'd detect (and avoid) such situation automatically but for
81 now, as I don't know how to do it, just allow the user to create
82 BS_RADIOBUTTON buttons for such situations.
84 msStyle
|= HasFlag(wxRB_SINGLE
) ? BS_RADIOBUTTON
: BS_AUTORADIOBUTTON
;
86 if ( HasFlag(wxCLIP_SIBLINGS
) )
87 msStyle
|= WS_CLIPSIBLINGS
;
89 if ( !MSWCreateControl(_T("BUTTON"), msStyle
, pos
, size
, label
, 0) )
92 // for compatibility with wxGTK, the first radio button in a group is
93 // always checked (this makes sense anyhow as you need to ensure that at
94 // least one button in the group is checked and this is the simlpest way to
96 if ( HasFlag(wxRB_GROUP
) )
102 // ----------------------------------------------------------------------------
103 // wxRadioButton functions
104 // ----------------------------------------------------------------------------
106 void wxRadioButton::SetValue(bool value
)
108 // BST_CHECKED is defined as 1, BST_UNCHECKED as 0, so we can just pass
109 // value as is (we don't use BST_XXX here as they're not defined for Win16)
110 (void)::SendMessage(GetHwnd(), BM_SETCHECK
, (WPARAM
)value
, 0L);
112 // if we set the value of one radio button we also must clear all the other
113 // buttons in the same group: Windows doesn't do it automatically
116 const wxWindowList
& siblings
= GetParent()->GetChildren();
117 wxWindowList::compatibility_iterator nodeThis
= siblings
.Find(this);
118 wxCHECK_RET( nodeThis
, _T("radio button not a child of its parent?") );
120 // if it's not the first item of the group ...
121 if ( !HasFlag(wxRB_GROUP
) )
123 // ... turn off all radio buttons before it
124 for ( wxWindowList::compatibility_iterator nodeBefore
= nodeThis
->GetPrevious();
126 nodeBefore
= nodeBefore
->GetPrevious() )
128 wxRadioButton
*btn
= wxDynamicCast(nodeBefore
->GetData(),
132 // the radio buttons in a group must be consecutive, so
133 // there are no more of them
137 btn
->SetValue(FALSE
);
139 if ( btn
->HasFlag(wxRB_GROUP
) )
141 // even if there are other radio buttons before this one,
142 // they're not in the same group with us
148 // ... and also turn off all buttons after this one
149 for ( wxWindowList::compatibility_iterator nodeAfter
= nodeThis
->GetNext();
151 nodeAfter
= nodeAfter
->GetNext() )
153 wxRadioButton
*btn
= wxDynamicCast(nodeAfter
->GetData(),
156 if ( !btn
|| btn
->HasFlag(wxRB_GROUP
) )
158 // no more buttons or the first button of the next group
162 btn
->SetValue(FALSE
);
167 bool wxRadioButton::GetValue() const
169 // NB: this will also return TRUE for BST_INDETERMINATE value if we ever
170 // have 3-state radio buttons
171 return ::SendMessage(GetHwnd(), BM_GETCHECK
, 0, 0L) != 0;
174 // ----------------------------------------------------------------------------
175 // wxRadioButton event processing
176 // ----------------------------------------------------------------------------
178 void wxRadioButton::Command (wxCommandEvent
& event
)
180 SetValue(event
.m_commandInt
!= 0);
181 ProcessCommand(event
);
184 void wxRadioButton::SetFocus()
186 // when the radio button receives a WM_SETFOCUS message it generates a
187 // BN_CLICKED which is totally unexpected and leads to catastrophic results
188 // if you pop up a dialog from the radio button event handler as, when the
189 // dialog is dismissed, the focus is returned to the radio button which
190 // generates BN_CLICKED which leads to showing another dialog and so on
193 // to avoid this, we drop the pseudo BN_CLICKED events generated when the
194 // button gains focus
195 m_focusJustSet
= TRUE
;
197 wxControl::SetFocus();
200 bool wxRadioButton::MSWCommand(WXUINT param
, WXWORD
WXUNUSED(id
))
202 if ( param
!= BN_CLICKED
)
205 if ( m_focusJustSet
)
207 // see above: we want to ignore this event
208 m_focusJustSet
= FALSE
;
210 else // a real clicked event
212 bool isChecked
= GetValue();
214 if ( HasFlag(wxRB_SINGLE
) )
216 // when we use a "manual" radio button, we have to check the button
217 // ourselves -- but it's reset to unchecked state by the user code
218 // (presumably when another button is pressed)
223 wxCommandEvent
event(wxEVT_COMMAND_RADIOBUTTON_SELECTED
, GetId());
224 event
.SetEventObject( this );
225 event
.SetInt(isChecked
);
227 ProcessCommand(event
);
233 // ----------------------------------------------------------------------------
234 // wxRadioButton geometry
235 // ----------------------------------------------------------------------------
237 wxSize
wxRadioButton::DoGetBestSize() const
239 static int s_radioSize
= 0;
244 dc
.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
));
246 s_radioSize
= dc
.GetCharHeight();
249 wxString str
= GetLabel();
254 GetTextExtent(str
, &wRadio
, &hRadio
);
255 wRadio
+= s_radioSize
+ GetCharWidth();
257 if ( hRadio
< s_radioSize
)
258 hRadio
= s_radioSize
;
262 wRadio
= s_radioSize
;
263 hRadio
= s_radioSize
;
266 return wxSize(wRadio
, hRadio
);
269 long wxRadioButton::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
271 if (nMsg
== WM_SETFOCUS
)
273 m_focusJustSet
= TRUE
;
275 long ret
= wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);
277 m_focusJustSet
= FALSE
;
281 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);
284 #endif // wxUSE_RADIOBTN