]> git.saurik.com Git - wxWidgets.git/blob - src/msw/radiobut.cpp
IsInAssert is only available (and only makes sense) in a debug build so
[wxWidgets.git] / src / msw / radiobut.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/radiobut.cpp
3 // Purpose: wxRadioButton
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "radiobut.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_RADIOBTN
32
33 #ifndef WX_PRECOMP
34 #include "wx/radiobut.h"
35 #include "wx/settings.h"
36 #include "wx/dcscreen.h"
37 #endif
38
39 #include "wx/msw/private.h"
40
41 // ============================================================================
42 // wxRadioButton implementation
43 // ============================================================================
44
45 // ----------------------------------------------------------------------------
46 // wxRadioButton creation
47 // ----------------------------------------------------------------------------
48
49
50 #if wxUSE_EXTENDED_RTTI
51 WX_DEFINE_FLAGS( wxRadioButtonStyle )
52
53 wxBEGIN_FLAGS( wxRadioButtonStyle )
54 // new style border flags, we put them first to
55 // use them for streaming out
56 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
57 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
58 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
59 wxFLAGS_MEMBER(wxBORDER_RAISED)
60 wxFLAGS_MEMBER(wxBORDER_STATIC)
61 wxFLAGS_MEMBER(wxBORDER_NONE)
62
63 // old style border flags
64 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
65 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
66 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
67 wxFLAGS_MEMBER(wxRAISED_BORDER)
68 wxFLAGS_MEMBER(wxSTATIC_BORDER)
69 wxFLAGS_MEMBER(wxBORDER)
70
71 // standard window styles
72 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
73 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
74 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
75 wxFLAGS_MEMBER(wxWANTS_CHARS)
76 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
77 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
78 wxFLAGS_MEMBER(wxVSCROLL)
79 wxFLAGS_MEMBER(wxHSCROLL)
80
81 wxFLAGS_MEMBER(wxRB_GROUP)
82
83 wxEND_FLAGS( wxRadioButtonStyle )
84
85 IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioButton, wxControl,"wx/radiobut.h")
86
87 wxBEGIN_PROPERTIES_TABLE(wxRadioButton)
88 wxEVENT_PROPERTY( Click , wxEVT_COMMAND_RADIOBUTTON_SELECTED , wxCommandEvent )
89 wxPROPERTY( Font , wxFont , SetFont , GetFont , , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
90 wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
91 wxPROPERTY( Value ,bool, SetValue, GetValue,, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
92 wxPROPERTY_FLAGS( WindowStyle , wxRadioButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
93 wxEND_PROPERTIES_TABLE()
94
95 wxBEGIN_HANDLERS_TABLE(wxRadioButton)
96 wxEND_HANDLERS_TABLE()
97
98 wxCONSTRUCTOR_6( wxRadioButton , wxWindow* , Parent , wxWindowID , Id , wxString , Label , wxPoint , Position , wxSize , Size , long , WindowStyle )
99
100 #else
101 IMPLEMENT_DYNAMIC_CLASS(wxRadioButton, wxControl)
102 #endif
103
104
105 wxRadioButton::wxRadioButton()
106 {
107 Init();
108 }
109
110 wxRadioButton::wxRadioButton(wxWindow *parent,
111 wxWindowID id,
112 const wxString& label,
113 const wxPoint& pos,
114 const wxSize& size,
115 long style,
116 const wxValidator& validator,
117 const wxString& name)
118 {
119 Init();
120
121 Create(parent, id, label, pos, size, style, validator, name);
122 }
123
124 void wxRadioButton::Init()
125 {
126 m_isChecked = false;
127 }
128
129 bool wxRadioButton::Create(wxWindow *parent,
130 wxWindowID id,
131 const wxString& label,
132 const wxPoint& pos,
133 const wxSize& size,
134 long style,
135 const wxValidator& validator,
136 const wxString& name)
137 {
138 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
139 return false;
140
141 long msStyle = WS_TABSTOP;
142 if ( HasFlag(wxRB_GROUP) )
143 msStyle |= WS_GROUP;
144
145 /*
146 wxRB_SINGLE is a temporary workaround for the following problem: if you
147 have 2 radiobuttons in the same group but which are not consecutive in
148 the dialog, Windows can enter an infinite loop! The simplest way to
149 reproduce it is to create radio button, then a panel and then another
150 radio button: then checking the last button hangs the app.
151
152 Ideally, we'd detect (and avoid) such situation automatically but for
153 now, as I don't know how to do it, just allow the user to create
154 BS_RADIOBUTTON buttons for such situations.
155 */
156 msStyle |= HasFlag(wxRB_SINGLE) ? BS_RADIOBUTTON : BS_AUTORADIOBUTTON;
157
158 if ( HasFlag(wxCLIP_SIBLINGS) )
159 msStyle |= WS_CLIPSIBLINGS;
160
161 if ( !MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, 0) )
162 return false;
163
164 // for compatibility with wxGTK, the first radio button in a group is
165 // always checked (this makes sense anyhow as you need to ensure that at
166 // least one button in the group is checked and this is the simlpest way to
167 // do it)
168 if ( HasFlag(wxRB_GROUP) )
169 SetValue(true);
170
171 return true;
172 }
173
174 // ----------------------------------------------------------------------------
175 // wxRadioButton functions
176 // ----------------------------------------------------------------------------
177
178 void wxRadioButton::SetValue(bool value)
179 {
180 // BST_CHECKED is defined as 1, BST_UNCHECKED as 0, so we can just pass
181 // value as is (we don't use BST_XXX here as they're not defined for Win16)
182 (void)::SendMessage(GetHwnd(), BM_SETCHECK, (WPARAM)value, 0L);
183
184 m_isChecked = value;
185
186 // if we set the value of one radio button we also must clear all the other
187 // buttons in the same group: Windows doesn't do it automatically
188 if ( m_isChecked )
189 {
190 const wxWindowList& siblings = GetParent()->GetChildren();
191 wxWindowList::compatibility_iterator nodeThis = siblings.Find(this);
192 wxCHECK_RET( nodeThis, _T("radio button not a child of its parent?") );
193
194 // if it's not the first item of the group ...
195 if ( !HasFlag(wxRB_GROUP) )
196 {
197 // ... turn off all radio buttons before it
198 for ( wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
199 nodeBefore;
200 nodeBefore = nodeBefore->GetPrevious() )
201 {
202 wxRadioButton *btn = wxDynamicCast(nodeBefore->GetData(),
203 wxRadioButton);
204 if ( !btn )
205 {
206 // the radio buttons in a group must be consecutive, so
207 // there are no more of them
208 break;
209 }
210
211 btn->SetValue(false);
212
213 if ( btn->HasFlag(wxRB_GROUP) )
214 {
215 // even if there are other radio buttons before this one,
216 // they're not in the same group with us
217 break;
218 }
219 }
220 }
221
222 // ... and also turn off all buttons after this one
223 for ( wxWindowList::compatibility_iterator nodeAfter = nodeThis->GetNext();
224 nodeAfter;
225 nodeAfter = nodeAfter->GetNext() )
226 {
227 wxRadioButton *btn = wxDynamicCast(nodeAfter->GetData(),
228 wxRadioButton);
229
230 if ( !btn || btn->HasFlag(wxRB_GROUP) )
231 {
232 // no more buttons or the first button of the next group
233 break;
234 }
235
236 btn->SetValue(false);
237 }
238 }
239 }
240
241 bool wxRadioButton::GetValue() const
242 {
243 wxASSERT_MSG( m_isChecked ==
244 (::SendMessage(GetHwnd(), BM_GETCHECK, 0, 0L) != 0),
245 _T("wxRadioButton::m_isChecked is out of sync?") );
246
247 return m_isChecked;
248 }
249
250 // ----------------------------------------------------------------------------
251 // wxRadioButton event processing
252 // ----------------------------------------------------------------------------
253
254 void wxRadioButton::Command (wxCommandEvent& event)
255 {
256 SetValue(event.m_commandInt != 0);
257 ProcessCommand(event);
258 }
259
260 bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
261 {
262 if ( param != BN_CLICKED )
263 return false;
264
265 if ( !m_isChecked )
266 {
267 // we have to do this for BS_RADIOBUTTON anyhow and, strangely enough,
268 // sometimes this is needed even for BS_AUTORADIOBUTTON (when we
269 // receive focus the button gets BN_CLICKED but stays unchecked!)
270 SetValue(true);
271
272 wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, GetId());
273 event.SetEventObject( this );
274 event.SetInt(true); // always checked
275
276 ProcessCommand(event);
277 }
278
279 return true;
280 }
281
282 // ----------------------------------------------------------------------------
283 // wxRadioButton geometry
284 // ----------------------------------------------------------------------------
285
286 wxSize wxRadioButton::DoGetBestSize() const
287 {
288 static int s_radioSize = 0;
289
290 if ( !s_radioSize )
291 {
292 wxScreenDC dc;
293 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
294
295 s_radioSize = dc.GetCharHeight();
296 }
297
298 wxString str = GetLabel();
299
300 int wRadio, hRadio;
301 if ( !str.empty() )
302 {
303 GetTextExtent(str, &wRadio, &hRadio);
304 wRadio += s_radioSize + GetCharWidth();
305
306 if ( hRadio < s_radioSize )
307 hRadio = s_radioSize;
308 }
309 else
310 {
311 wRadio = s_radioSize;
312 hRadio = s_radioSize;
313 }
314
315 return wxSize(wRadio, hRadio);
316 }
317
318 #endif // wxUSE_RADIOBTN
319