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"
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
)
59 void wxRadioButton::Init()
61 m_focusJustSet
= FALSE
;
64 bool wxRadioButton::Create(wxWindow
*parent
,
66 const wxString
& label
,
70 const wxValidator
& validator
,
73 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
76 long msStyle
= WS_TABSTOP
;
77 if ( HasFlag(wxRB_GROUP
) )
81 wxRB_SINGLE is a temporary workaround for the following problem: if you
82 have 2 radiobuttons in the same group but which are not consecutive in
83 the dialog, Windows can enter an infinite loop! The simplest way to
84 reproduce it is to create radio button, then a panel and then another
85 radio button: then checking the last button hangs the app.
87 Ideally, we'd detect (and avoid) such situation automatically but for
88 now, as I don't know how to do it, just allow the user to create
89 BS_RADIOBUTTON buttons for such situations.
91 msStyle
|= HasFlag(wxRB_SINGLE
) ? BS_RADIOBUTTON
: BS_AUTORADIOBUTTON
;
93 if ( HasFlag(wxCLIP_SIBLINGS
) )
94 msStyle
|= WS_CLIPSIBLINGS
;
96 if ( !MSWCreateControl(_T("BUTTON"), msStyle
, pos
, size
, label
, 0) )
99 // for compatibility with wxGTK, the first radio button in a group is
100 // always checked (this makes sense anyhow as you need to ensure that at
101 // least one button in the group is checked and this is the simlpest way to
103 if ( HasFlag(wxRB_GROUP
) )
109 // ----------------------------------------------------------------------------
110 // wxRadioButton functions
111 // ----------------------------------------------------------------------------
113 void wxRadioButton::SetValue(bool value
)
115 // BST_CHECKED is defined as 1, BST_UNCHECKED as 0, so we can just pass
116 // value as is (we don't use BST_XXX here as they're not defined for Win16)
117 (void)::SendMessage(GetHwnd(), BM_SETCHECK
, (WPARAM
)value
, 0L);
119 // if we set the value of one radio button we also must clear all the other
120 // buttons in the same group: Windows doesn't do it automatically
123 const wxWindowList
& siblings
= GetParent()->GetChildren();
124 wxWindowList::compatibility_iterator nodeThis
= siblings
.Find(this);
125 wxCHECK_RET( nodeThis
, _T("radio button not a child of its parent?") );
127 // if it's not the first item of the group ...
128 if ( !HasFlag(wxRB_GROUP
) )
130 // ... turn off all radio buttons before it
131 for ( wxWindowList::compatibility_iterator nodeBefore
= nodeThis
->GetPrevious();
133 nodeBefore
= nodeBefore
->GetPrevious() )
135 wxRadioButton
*btn
= wxDynamicCast(nodeBefore
->GetData(),
139 // the radio buttons in a group must be consecutive, so
140 // there are no more of them
144 btn
->SetValue(FALSE
);
146 if ( btn
->HasFlag(wxRB_GROUP
) )
148 // even if there are other radio buttons before this one,
149 // they're not in the same group with us
155 // ... and also turn off all buttons after this one
156 for ( wxWindowList::compatibility_iterator nodeAfter
= nodeThis
->GetNext();
158 nodeAfter
= nodeAfter
->GetNext() )
160 wxRadioButton
*btn
= wxDynamicCast(nodeAfter
->GetData(),
163 if ( !btn
|| btn
->HasFlag(wxRB_GROUP
) )
165 // no more buttons or the first button of the next group
169 btn
->SetValue(FALSE
);
174 bool wxRadioButton::GetValue() const
176 // NB: this will also return TRUE for BST_INDETERMINATE value if we ever
177 // have 3-state radio buttons
178 return ::SendMessage(GetHwnd(), BM_GETCHECK
, 0, 0L) != 0;
181 // ----------------------------------------------------------------------------
182 // wxRadioButton event processing
183 // ----------------------------------------------------------------------------
185 void wxRadioButton::Command (wxCommandEvent
& event
)
187 SetValue(event
.m_commandInt
!= 0);
188 ProcessCommand(event
);
191 void wxRadioButton::SetFocus()
193 // when the radio button receives a WM_SETFOCUS message it generates a
194 // BN_CLICKED which is totally unexpected and leads to catastrophic results
195 // if you pop up a dialog from the radio button event handler as, when the
196 // dialog is dismissed, the focus is returned to the radio button which
197 // generates BN_CLICKED which leads to showing another dialog and so on
200 // to avoid this, we drop the pseudo BN_CLICKED events generated when the
201 // button gains focus
202 m_focusJustSet
= TRUE
;
204 wxControl::SetFocus();
207 bool wxRadioButton::MSWCommand(WXUINT param
, WXWORD
WXUNUSED(id
))
209 if ( param
!= BN_CLICKED
)
212 if ( m_focusJustSet
)
214 // see above: we want to ignore this event
215 m_focusJustSet
= FALSE
;
217 else // a real clicked event
219 bool isChecked
= GetValue();
221 if ( HasFlag(wxRB_SINGLE
) )
223 // when we use a "manual" radio button, we have to check the button
224 // ourselves -- but it's reset to unchecked state by the user code
225 // (presumably when another button is pressed)
230 wxCommandEvent
event(wxEVT_COMMAND_RADIOBUTTON_SELECTED
, GetId());
231 event
.SetEventObject( this );
232 event
.SetInt(isChecked
);
234 ProcessCommand(event
);
240 // ----------------------------------------------------------------------------
241 // wxRadioButton geometry
242 // ----------------------------------------------------------------------------
244 wxSize
wxRadioButton::DoGetBestSize() const
246 static int s_radioSize
= 0;
251 dc
.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
));
253 s_radioSize
= dc
.GetCharHeight();
256 wxString str
= GetLabel();
261 GetTextExtent(str
, &wRadio
, &hRadio
);
262 wRadio
+= s_radioSize
+ GetCharWidth();
264 if ( hRadio
< s_radioSize
)
265 hRadio
= s_radioSize
;
269 wRadio
= s_radioSize
;
270 hRadio
= s_radioSize
;
273 return wxSize(wRadio
, hRadio
);
276 long wxRadioButton::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
278 if (nMsg
== WM_SETFOCUS
)
280 m_focusJustSet
= TRUE
;
282 long ret
= wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);
284 m_focusJustSet
= FALSE
;
288 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);
291 #endif // wxUSE_RADIOBTN