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 // ----------------------------------------------------------------------------
48 #if wxUSE_EXTENDED_RTTI
49 WX_DEFINE_FLAGS( wxRadioButtonStyle
)
51 wxBEGIN_FLAGS( wxRadioButtonStyle
)
52 // new style border flags, we put them first to
53 // use them for streaming out
54 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
55 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
56 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
57 wxFLAGS_MEMBER(wxBORDER_RAISED
)
58 wxFLAGS_MEMBER(wxBORDER_STATIC
)
59 wxFLAGS_MEMBER(wxBORDER_NONE
)
61 // old style border flags
62 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
63 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
64 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
65 wxFLAGS_MEMBER(wxRAISED_BORDER
)
66 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
67 wxFLAGS_MEMBER(wxBORDER
)
69 // standard window styles
70 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
71 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
72 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
73 wxFLAGS_MEMBER(wxWANTS_CHARS
)
74 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
75 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
76 wxFLAGS_MEMBER(wxVSCROLL
)
77 wxFLAGS_MEMBER(wxHSCROLL
)
79 wxFLAGS_MEMBER(wxRB_GROUP
)
81 wxEND_FLAGS( wxRadioButtonStyle
)
83 IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioButton
, wxControl
,"wx/radiobut.h")
85 wxBEGIN_PROPERTIES_TABLE(wxRadioButton
)
86 wxEVENT_PROPERTY( Click
, wxEVT_COMMAND_RADIOBUTTON_SELECTED
, wxCommandEvent
)
87 wxPROPERTY( Font
, wxFont
, SetFont
, GetFont
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
88 wxPROPERTY( Label
,wxString
, SetLabel
, GetLabel
, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
89 wxPROPERTY( Value
,bool, SetValue
, GetValue
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
90 wxPROPERTY_FLAGS( WindowStyle
, wxRadioButtonStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
91 wxEND_PROPERTIES_TABLE()
93 wxBEGIN_HANDLERS_TABLE(wxRadioButton
)
94 wxEND_HANDLERS_TABLE()
96 wxCONSTRUCTOR_6( wxRadioButton
, wxWindow
* , Parent
, wxWindowID
, Id
, wxString
, Label
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
99 IMPLEMENT_DYNAMIC_CLASS(wxRadioButton
, wxControl
)
103 void wxRadioButton::Init()
108 bool wxRadioButton::Create(wxWindow
*parent
,
110 const wxString
& label
,
114 const wxValidator
& validator
,
115 const wxString
& name
)
117 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
120 long msStyle
= WS_TABSTOP
;
121 if ( HasFlag(wxRB_GROUP
) )
124 // we use BS_RADIOBUTTON and not BS_AUTORADIOBUTTON because the use of the
125 // latter can easily result in the application entering an infinite loop
126 // inside IsDialogMessage()
128 // we used to use BS_RADIOBUTTON only for wxRB_SINGLE buttons but there
129 // doesn't seem to be any harm to always use it and it prevents some hangs,
131 msStyle
|= BS_RADIOBUTTON
;
133 if ( HasFlag(wxCLIP_SIBLINGS
) )
134 msStyle
|= WS_CLIPSIBLINGS
;
135 if ( HasFlag(wxALIGN_RIGHT
) )
136 msStyle
|= BS_LEFTTEXT
| BS_RIGHT
;
138 if ( !MSWCreateControl(_T("BUTTON"), msStyle
, pos
, size
, label
, 0) )
141 // for compatibility with wxGTK, the first radio button in a group is
142 // always checked (this makes sense anyhow as you need to ensure that at
143 // least one button in the group is checked and this is the simplest way to
145 if ( HasFlag(wxRB_GROUP
) )
151 // ----------------------------------------------------------------------------
152 // wxRadioButton functions
153 // ----------------------------------------------------------------------------
155 void wxRadioButton::SetValue(bool value
)
157 ::SendMessage(GetHwnd(), BM_SETCHECK
,
158 value
? BST_CHECKED
: BST_UNCHECKED
, 0);
165 // if we set the value of one radio button we also must clear all the other
166 // buttons in the same group: Windows doesn't do it automatically
168 // moreover, if another radiobutton in the group currently has the focus,
169 // we have to set it to this radiobutton, else the old radiobutton will be
170 // reselected automatically, if a parent window loses the focus and regains
172 wxWindow
* const focus
= FindFocus();
173 wxTopLevelWindow
* const
174 tlw
= wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow
);
175 wxCHECK_RET( tlw
, _T("radio button outside of TLW?") );
176 wxWindow
* const focusInTLW
= tlw
->GetLastFocus();
178 const wxWindowList
& siblings
= GetParent()->GetChildren();
179 wxWindowList::compatibility_iterator nodeThis
= siblings
.Find(this);
180 wxCHECK_RET( nodeThis
, _T("radio button not a child of its parent?") );
182 // this will be set to true in the code below if the focus is in our TLW
183 // and belongs to one of the other buttons in the same group
184 bool shouldSetFocus
= false;
186 // this will be set to true if the focus is outside of our TLW currently
187 // but the remembered focus of this TLW is one of the other buttons in the
189 bool shouldSetTLWFocus
= false;
191 // if it's not the first item of the group ...
192 if ( !HasFlag(wxRB_GROUP
) )
194 // ... turn off all radio buttons before it
195 for ( wxWindowList::compatibility_iterator nodeBefore
= nodeThis
->GetPrevious();
197 nodeBefore
= nodeBefore
->GetPrevious() )
199 wxRadioButton
*btn
= wxDynamicCast(nodeBefore
->GetData(),
203 // don't stop on non radio buttons, we could have intermixed
204 // buttons and e.g. static labels
208 if ( btn
->HasFlag(wxRB_SINGLE
) )
210 // A wxRB_SINGLE button isn't part of this group
215 shouldSetFocus
= true;
216 else if ( btn
== focusInTLW
)
217 shouldSetTLWFocus
= true;
219 btn
->SetValue(false);
221 if ( btn
->HasFlag(wxRB_GROUP
) )
223 // even if there are other radio buttons before this one,
224 // they're not in the same group with us
230 // ... and also turn off all buttons after this one
231 for ( wxWindowList::compatibility_iterator nodeAfter
= nodeThis
->GetNext();
233 nodeAfter
= nodeAfter
->GetNext() )
235 wxRadioButton
*btn
= wxDynamicCast(nodeAfter
->GetData(),
241 if ( btn
->HasFlag(wxRB_GROUP
| wxRB_SINGLE
) )
243 // no more buttons or the first button of the next group
248 shouldSetFocus
= true;
249 else if ( btn
== focusInTLW
)
250 shouldSetTLWFocus
= true;
252 btn
->SetValue(false);
255 if ( shouldSetFocus
)
257 else if ( shouldSetTLWFocus
)
258 tlw
->SetLastFocus(this);
261 bool wxRadioButton::GetValue() const
263 wxASSERT_MSG( m_isChecked
==
264 (::SendMessage(GetHwnd(), BM_GETCHECK
, 0, 0L) != 0),
265 _T("wxRadioButton::m_isChecked is out of sync?") );
270 // ----------------------------------------------------------------------------
271 // wxRadioButton event processing
272 // ----------------------------------------------------------------------------
274 void wxRadioButton::Command (wxCommandEvent
& event
)
276 SetValue(event
.GetInt() != 0);
277 ProcessCommand(event
);
280 bool wxRadioButton::MSWCommand(WXUINT param
, WXWORD
WXUNUSED(id
))
282 if ( param
!= BN_CLICKED
)
287 // we need to manually update the button state as we use BS_RADIOBUTTON
288 // and not BS_AUTORADIOBUTTON
291 wxCommandEvent
event(wxEVT_COMMAND_RADIOBUTTON_SELECTED
, GetId());
292 event
.SetEventObject( this );
293 event
.SetInt(true); // always checked
295 ProcessCommand(event
);
301 // ----------------------------------------------------------------------------
302 // wxRadioButton geometry
303 // ----------------------------------------------------------------------------
305 wxSize
wxRadioButton::DoGetBestSize() const
307 static int s_radioSize
= 0;
312 dc
.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
));
314 s_radioSize
= dc
.GetCharHeight();
316 // radio button bitmap size under CE is bigger than the font height,
317 // adding just one pixel seems to work fine for the default font but it
318 // would be nice to find some better way to find the correct height
321 #endif // __WXWINCE__
324 wxString str
= GetLabel();
329 GetTextExtent(GetLabelText(str
), &wRadio
, &hRadio
);
330 wRadio
+= s_radioSize
+ GetCharWidth();
332 if ( hRadio
< s_radioSize
)
333 hRadio
= s_radioSize
;
337 wRadio
= s_radioSize
;
338 hRadio
= s_radioSize
;
341 wxSize
best(wRadio
, hRadio
);
346 WXDWORD
wxRadioButton::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
348 WXDWORD styleMSW
= wxControl::MSWGetStyle(style
, exstyle
);
350 if ( style
& wxRB_GROUP
)
351 styleMSW
|= WS_GROUP
;
356 #endif // wxUSE_RADIOBTN