1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/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 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
29 #include "wx/radiobut.h"
32 #include "wx/settings.h"
33 #include "wx/dcscreen.h"
34 #include "wx/toplevel.h"
37 #include "wx/msw/private.h"
39 // ============================================================================
40 // wxRadioButton implementation
41 // ============================================================================
43 // ----------------------------------------------------------------------------
44 // wxRadioButton creation
45 // ----------------------------------------------------------------------------
47 void wxRadioButton::Init()
52 bool wxRadioButton::Create(wxWindow
*parent
,
54 const wxString
& label
,
58 const wxValidator
& validator
,
61 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
64 long msStyle
= WS_TABSTOP
;
65 if ( HasFlag(wxRB_GROUP
) )
68 // we use BS_RADIOBUTTON and not BS_AUTORADIOBUTTON because the use of the
69 // latter can easily result in the application entering an infinite loop
70 // inside IsDialogMessage()
72 // we used to use BS_RADIOBUTTON only for wxRB_SINGLE buttons but there
73 // doesn't seem to be any harm to always use it and it prevents some hangs,
75 msStyle
|= BS_RADIOBUTTON
;
77 if ( HasFlag(wxCLIP_SIBLINGS
) )
78 msStyle
|= WS_CLIPSIBLINGS
;
79 if ( HasFlag(wxALIGN_RIGHT
) )
80 msStyle
|= BS_LEFTTEXT
| BS_RIGHT
;
82 if ( !MSWCreateControl(wxT("BUTTON"), msStyle
, pos
, size
, label
, 0) )
85 // for compatibility with wxGTK, the first radio button in a group is
86 // always checked (this makes sense anyhow as you need to ensure that at
87 // least one button in the group is checked and this is the simplest way to
89 if ( HasFlag(wxRB_GROUP
) )
95 // ----------------------------------------------------------------------------
96 // wxRadioButton functions
97 // ----------------------------------------------------------------------------
99 void wxRadioButton::SetValue(bool value
)
101 ::SendMessage(GetHwnd(), BM_SETCHECK
,
102 value
? BST_CHECKED
: BST_UNCHECKED
, 0);
109 // if we set the value of one radio button we also must clear all the other
110 // buttons in the same group: Windows doesn't do it automatically
112 // moreover, if another radiobutton in the group currently has the focus,
113 // we have to set it to this radiobutton, else the old radiobutton will be
114 // reselected automatically, if a parent window loses the focus and regains
116 wxWindow
* const focus
= FindFocus();
117 wxTopLevelWindow
* const
118 tlw
= wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow
);
119 wxCHECK_RET( tlw
, wxT("radio button outside of TLW?") );
120 wxWindow
* const focusInTLW
= tlw
->GetLastFocus();
122 const wxWindowList
& siblings
= GetParent()->GetChildren();
123 wxWindowList::compatibility_iterator nodeThis
= siblings
.Find(this);
124 wxCHECK_RET( nodeThis
, wxT("radio button not a child of its parent?") );
126 // this will be set to true in the code below if the focus is in our TLW
127 // and belongs to one of the other buttons in the same group
128 bool shouldSetFocus
= false;
130 // this will be set to true if the focus is outside of our TLW currently
131 // but the remembered focus of this TLW is one of the other buttons in the
133 bool shouldSetTLWFocus
= false;
135 // if it's not the first item of the group ...
136 if ( !HasFlag(wxRB_GROUP
) )
138 // ... turn off all radio buttons before it
139 for ( wxWindowList::compatibility_iterator nodeBefore
= nodeThis
->GetPrevious();
141 nodeBefore
= nodeBefore
->GetPrevious() )
143 wxRadioButton
*btn
= wxDynamicCast(nodeBefore
->GetData(),
147 // don't stop on non radio buttons, we could have intermixed
148 // buttons and e.g. static labels
152 if ( btn
->HasFlag(wxRB_SINGLE
) )
154 // A wxRB_SINGLE button isn't part of this group
159 shouldSetFocus
= true;
160 else if ( btn
== focusInTLW
)
161 shouldSetTLWFocus
= true;
163 btn
->SetValue(false);
165 if ( btn
->HasFlag(wxRB_GROUP
) )
167 // even if there are other radio buttons before this one,
168 // they're not in the same group with us
174 // ... and also turn off all buttons after this one
175 for ( wxWindowList::compatibility_iterator nodeAfter
= nodeThis
->GetNext();
177 nodeAfter
= nodeAfter
->GetNext() )
179 wxRadioButton
*btn
= wxDynamicCast(nodeAfter
->GetData(),
185 if ( btn
->HasFlag(wxRB_GROUP
| wxRB_SINGLE
) )
187 // no more buttons or the first button of the next group
192 shouldSetFocus
= true;
193 else if ( btn
== focusInTLW
)
194 shouldSetTLWFocus
= true;
196 btn
->SetValue(false);
199 if ( shouldSetFocus
)
201 else if ( shouldSetTLWFocus
)
202 tlw
->SetLastFocus(this);
205 bool wxRadioButton::GetValue() const
207 wxASSERT_MSG( m_isChecked
==
208 (::SendMessage(GetHwnd(), BM_GETCHECK
, 0, 0L) != 0),
209 wxT("wxRadioButton::m_isChecked is out of sync?") );
214 // ----------------------------------------------------------------------------
215 // wxRadioButton event processing
216 // ----------------------------------------------------------------------------
218 void wxRadioButton::Command (wxCommandEvent
& event
)
220 SetValue(event
.GetInt() != 0);
221 ProcessCommand(event
);
224 bool wxRadioButton::MSWCommand(WXUINT param
, WXWORD
WXUNUSED(id
))
226 if ( param
!= BN_CLICKED
)
231 // we need to manually update the button state as we use BS_RADIOBUTTON
232 // and not BS_AUTORADIOBUTTON
235 wxCommandEvent
event(wxEVT_COMMAND_RADIOBUTTON_SELECTED
, GetId());
236 event
.SetEventObject( this );
237 event
.SetInt(true); // always checked
239 ProcessCommand(event
);
245 // ----------------------------------------------------------------------------
246 // wxRadioButton geometry
247 // ----------------------------------------------------------------------------
249 wxSize
wxRadioButton::DoGetBestSize() const
251 static int s_radioSize
= 0;
256 dc
.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
));
258 s_radioSize
= dc
.GetCharHeight();
260 // radio button bitmap size under CE is bigger than the font height,
261 // adding just one pixel seems to work fine for the default font but it
262 // would be nice to find some better way to find the correct height
265 #endif // __WXWINCE__
268 wxString str
= GetLabel();
273 GetTextExtent(GetLabelText(str
), &wRadio
, &hRadio
);
274 wRadio
+= s_radioSize
+ GetCharWidth();
276 if ( hRadio
< s_radioSize
)
277 hRadio
= s_radioSize
;
281 wRadio
= s_radioSize
;
282 hRadio
= s_radioSize
;
285 wxSize
best(wRadio
, hRadio
);
290 WXDWORD
wxRadioButton::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
292 WXDWORD styleMSW
= wxControl::MSWGetStyle(style
, exstyle
);
294 if ( style
& wxRB_GROUP
)
295 styleMSW
|= WS_GROUP
;
300 #endif // wxUSE_RADIOBTN