]> git.saurik.com Git - wxWidgets.git/blame - src/msw/radiobut.cpp
refactoring in preparation for further changes: moved data in a private struct, let...
[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 8// Copyright: (c) Julian Smart
65571936 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)
4d08943e 62
bc9fb572 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 88 wxEVENT_PROPERTY( Click , wxEVT_COMMAND_RADIOBUTTON_SELECTED , wxCommandEvent )
af498247 89 wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
f607434a 90 wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
af498247
VZ
91 wxPROPERTY( Value ,bool, SetValue, GetValue, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
92 wxPROPERTY_FLAGS( WindowStyle , wxRadioButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
3ff066a4 93wxEND_PROPERTIES_TABLE()
51741307 94
3ff066a4
SC
95wxBEGIN_HANDLERS_TABLE(wxRadioButton)
96wxEND_HANDLERS_TABLE()
51741307 97
4d08943e 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 140 msStyle |= WS_CLIPSIBLINGS;
93212fee
VZ
141 if ( HasFlag(wxALIGN_RIGHT) )
142 msStyle |= BS_LEFTTEXT | BS_RIGHT;
b0766406 143
5f199b71 144 if ( !MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, 0) )
f607434a 145 return false;
b0766406 146
5f199b71
VZ
147 // for compatibility with wxGTK, the first radio button in a group is
148 // always checked (this makes sense anyhow as you need to ensure that at
149 // least one button in the group is checked and this is the simlpest way to
150 // do it)
151 if ( HasFlag(wxRB_GROUP) )
f607434a 152 SetValue(true);
c085e333 153
f607434a 154 return true;
2bda0e17
KB
155}
156
5f199b71
VZ
157// ----------------------------------------------------------------------------
158// wxRadioButton functions
159// ----------------------------------------------------------------------------
2bda0e17 160
5f199b71 161void wxRadioButton::SetValue(bool value)
2bda0e17 162{
3a5bcc4d 163 (void)::SendMessage(GetHwnd(), BM_SETCHECK, (value?BST_CHECKED:BST_UNCHECKED), 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 170 {
f469584d
VZ
171 // If another radiobutton in the group currently has the focus, we have to
172 // set it to this radiobutton, else the old readiobutton will be reselected
173 // automatically, if a parent window loses the focus and regains it.
174 bool shouldSetFocus = false;
175 wxWindow* pFocusWnd = FindFocus();
176
2b5f62a0 177 const wxWindowList& siblings = GetParent()->GetChildren();
222ed1d6 178 wxWindowList::compatibility_iterator nodeThis = siblings.Find(this);
2b5f62a0
VZ
179 wxCHECK_RET( nodeThis, _T("radio button not a child of its parent?") );
180
2b17e391
VZ
181 // if it's not the first item of the group ...
182 if ( !HasFlag(wxRB_GROUP) )
2b5f62a0 183 {
2b17e391 184 // ... turn off all radio buttons before it
222ed1d6 185 for ( wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
2b17e391
VZ
186 nodeBefore;
187 nodeBefore = nodeBefore->GetPrevious() )
2b5f62a0 188 {
2b17e391
VZ
189 wxRadioButton *btn = wxDynamicCast(nodeBefore->GetData(),
190 wxRadioButton);
c5b3143a 191 if ( btn && btn->HasFlag(wxRB_SINGLE) )
2b17e391 192 {
c5b3143a 193 // A wxRB_SINGLE button isn't part of this group
2b17e391
VZ
194 break;
195 }
c5b3143a
JS
196
197 if (btn)
2b17e391 198 {
f469584d
VZ
199 if (btn == pFocusWnd)
200 shouldSetFocus = true;
201
c5b3143a
JS
202 btn->SetValue(false);
203
204 if ( btn->HasFlag(wxRB_GROUP) )
205 {
206 // even if there are other radio buttons before this one,
207 // they're not in the same group with us
208 break;
209 }
2b17e391 210 }
2b5f62a0
VZ
211 }
212 }
213
2b17e391 214 // ... and also turn off all buttons after this one
222ed1d6 215 for ( wxWindowList::compatibility_iterator nodeAfter = nodeThis->GetNext();
2b5f62a0
VZ
216 nodeAfter;
217 nodeAfter = nodeAfter->GetNext() )
218 {
219 wxRadioButton *btn = wxDynamicCast(nodeAfter->GetData(),
220 wxRadioButton);
221
c5b3143a 222 if ( btn && (btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) )
2b5f62a0
VZ
223 {
224 // no more buttons or the first button of the next group
225 break;
226 }
227
c5b3143a 228 if (btn)
f469584d
VZ
229 {
230 if (btn == pFocusWnd)
231 shouldSetFocus = true;
232
c5b3143a 233 btn->SetValue(false);
f469584d 234 }
2b5f62a0 235 }
f469584d
VZ
236 if (shouldSetFocus)
237 SetFocus();
2b5f62a0 238 }
2bda0e17
KB
239}
240
5f199b71 241bool wxRadioButton::GetValue() const
2bda0e17 242{
f607434a
VZ
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;
2bda0e17
KB
248}
249
5f199b71
VZ
250// ----------------------------------------------------------------------------
251// wxRadioButton event processing
252// ----------------------------------------------------------------------------
253
254void wxRadioButton::Command (wxCommandEvent& event)
2bda0e17 255{
687706f5 256 SetValue(event.GetInt() != 0);
5f199b71 257 ProcessCommand(event);
2bda0e17
KB
258}
259
5f199b71 260bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
f6bcfd97 261{
5f199b71 262 if ( param != BN_CLICKED )
f607434a 263 return false;
5f199b71 264
f607434a 265 if ( !m_isChecked )
f6bcfd97 266 {
f607434a
VZ
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);
2b5f62a0 271
5f199b71
VZ
272 wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, GetId());
273 event.SetEventObject( this );
f607434a 274 event.SetInt(true); // always checked
f6bcfd97 275
5f199b71
VZ
276 ProcessCommand(event);
277 }
f6bcfd97 278
f607434a 279 return true;
f6bcfd97 280}
2bda0e17 281
5f199b71
VZ
282// ----------------------------------------------------------------------------
283// wxRadioButton geometry
284// ----------------------------------------------------------------------------
285
286wxSize wxRadioButton::DoGetBestSize() const
2bda0e17 287{
5f199b71 288 static int s_radioSize = 0;
2bda0e17 289
5f199b71
VZ
290 if ( !s_radioSize )
291 {
292 wxScreenDC dc;
293 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
2bda0e17 294
5f199b71
VZ
295 s_radioSize = dc.GetCharHeight();
296 }
2bda0e17 297
5f199b71 298 wxString str = GetLabel();
2bda0e17 299
5f199b71
VZ
300 int wRadio, hRadio;
301 if ( !str.empty() )
302 {
303 GetTextExtent(str, &wRadio, &hRadio);
304 wRadio += s_radioSize + GetCharWidth();
2bda0e17 305
5f199b71
VZ
306 if ( hRadio < s_radioSize )
307 hRadio = s_radioSize;
308 }
309 else
310 {
311 wRadio = s_radioSize;
312 hRadio = s_radioSize;
313 }
2bda0e17 314
31582e4e
RD
315 wxSize best(wRadio, hRadio);
316 CacheBestSize(best);
317 return best;
2bda0e17
KB
318}
319
1e6feb95 320#endif // wxUSE_RADIOBTN
f607434a 321