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