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::Node
*nodeThis
= siblings
.Find(this);
118 wxCHECK_RET( nodeThis
, _T("radio button not a child of its parent?") );
120 // turn off all radio buttons before this one
121 for ( wxWindowList::Node
*nodeBefore
= nodeThis
->GetPrevious();
123 nodeBefore
= nodeBefore
->GetPrevious() )
125 wxRadioButton
*btn
= wxDynamicCast(nodeBefore
->GetData(),
129 // the radio buttons in a group must be consecutive, so there
130 // are no more of them
134 btn
->SetValue(FALSE
);
136 if ( btn
->HasFlag(wxRB_GROUP
) )
138 // even if there are other radio buttons before this one,
139 // they're not in the same group with us
144 // ... and all after this one
145 for ( wxWindowList::Node
*nodeAfter
= nodeThis
->GetNext();
147 nodeAfter
= nodeAfter
->GetNext() )
149 wxRadioButton
*btn
= wxDynamicCast(nodeAfter
->GetData(),
152 if ( !btn
|| btn
->HasFlag(wxRB_GROUP
) )
154 // no more buttons or the first button of the next group
158 btn
->SetValue(FALSE
);
163 bool wxRadioButton::GetValue() const
165 // NB: this will also return TRUE for BST_INDETERMINATE value if we ever
166 // have 3-state radio buttons
167 return ::SendMessage(GetHwnd(), BM_GETCHECK
, 0, 0L) != 0;
170 // ----------------------------------------------------------------------------
171 // wxRadioButton event processing
172 // ----------------------------------------------------------------------------
174 void wxRadioButton::Command (wxCommandEvent
& event
)
176 SetValue(event
.m_commandInt
!= 0);
177 ProcessCommand(event
);
180 void wxRadioButton::SetFocus()
182 // when the radio button receives a WM_SETFOCUS message it generates a
183 // BN_CLICKED which is totally unexpected and leads to catastrophic results
184 // if you pop up a dialog from the radio button event handler as, when the
185 // dialog is dismissed, the focus is returned to the radio button which
186 // generates BN_CLICKED which leads to showing another dialog and so on
189 // to avoid this, we drop the pseudo BN_CLICKED events generated when the
190 // button gains focus
191 m_focusJustSet
= TRUE
;
193 wxControl::SetFocus();
196 bool wxRadioButton::MSWCommand(WXUINT param
, WXWORD
WXUNUSED(id
))
198 if ( param
!= BN_CLICKED
)
201 if ( m_focusJustSet
)
203 // see above: we want to ignore this event
204 m_focusJustSet
= FALSE
;
206 else // a real clicked event
208 bool isChecked
= GetValue();
210 if ( HasFlag(wxRB_SINGLE
) )
212 // when we use a "manual" radio button, we have to check the button
213 // ourselves -- but it's reset to unchecked state by the user code
214 // (presumably when another button is pressed)
219 wxCommandEvent
event(wxEVT_COMMAND_RADIOBUTTON_SELECTED
, GetId());
220 event
.SetEventObject( this );
221 event
.SetInt(isChecked
);
223 ProcessCommand(event
);
229 // ----------------------------------------------------------------------------
230 // wxRadioButton geometry
231 // ----------------------------------------------------------------------------
233 wxSize
wxRadioButton::DoGetBestSize() const
235 static int s_radioSize
= 0;
240 dc
.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
));
242 s_radioSize
= dc
.GetCharHeight();
245 wxString str
= GetLabel();
250 GetTextExtent(str
, &wRadio
, &hRadio
);
251 wRadio
+= s_radioSize
+ GetCharWidth();
253 if ( hRadio
< s_radioSize
)
254 hRadio
= s_radioSize
;
258 wRadio
= s_radioSize
;
259 hRadio
= s_radioSize
;
262 return wxSize(wRadio
, hRadio
);
265 long wxRadioButton::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
267 if (nMsg
== WM_SETFOCUS
)
269 m_focusJustSet
= TRUE
;
271 long ret
= wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);
273 m_focusJustSet
= FALSE
;
277 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);
280 #endif // wxUSE_RADIOBTN