]> git.saurik.com Git - wxWidgets.git/blame - src/msw/radiobut.cpp
Split some of the recent code out to make it more reusable.
[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
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);
c5b3143a 185 if ( btn && btn->HasFlag(wxRB_SINGLE) )
2b17e391 186 {
c5b3143a 187 // A wxRB_SINGLE button isn't part of this group
2b17e391
VZ
188 break;
189 }
c5b3143a
JS
190
191 if (btn)
2b17e391 192 {
c5b3143a
JS
193 btn->SetValue(false);
194
195 if ( btn->HasFlag(wxRB_GROUP) )
196 {
197 // even if there are other radio buttons before this one,
198 // they're not in the same group with us
199 break;
200 }
2b17e391 201 }
2b5f62a0
VZ
202 }
203 }
204
2b17e391 205 // ... and also turn off all buttons after this one
222ed1d6 206 for ( wxWindowList::compatibility_iterator nodeAfter = nodeThis->GetNext();
2b5f62a0
VZ
207 nodeAfter;
208 nodeAfter = nodeAfter->GetNext() )
209 {
210 wxRadioButton *btn = wxDynamicCast(nodeAfter->GetData(),
211 wxRadioButton);
212
c5b3143a 213 if ( btn && (btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) )
2b5f62a0
VZ
214 {
215 // no more buttons or the first button of the next group
216 break;
217 }
218
c5b3143a
JS
219 if (btn)
220 btn->SetValue(false);
2b5f62a0
VZ
221 }
222 }
2bda0e17
KB
223}
224
5f199b71 225bool wxRadioButton::GetValue() const
2bda0e17 226{
f607434a
VZ
227 wxASSERT_MSG( m_isChecked ==
228 (::SendMessage(GetHwnd(), BM_GETCHECK, 0, 0L) != 0),
229 _T("wxRadioButton::m_isChecked is out of sync?") );
230
231 return m_isChecked;
2bda0e17
KB
232}
233
5f199b71
VZ
234// ----------------------------------------------------------------------------
235// wxRadioButton event processing
236// ----------------------------------------------------------------------------
237
238void wxRadioButton::Command (wxCommandEvent& event)
2bda0e17 239{
5f199b71
VZ
240 SetValue(event.m_commandInt != 0);
241 ProcessCommand(event);
2bda0e17
KB
242}
243
5f199b71 244bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
f6bcfd97 245{
5f199b71 246 if ( param != BN_CLICKED )
f607434a 247 return false;
5f199b71 248
f607434a 249 if ( !m_isChecked )
f6bcfd97 250 {
f607434a
VZ
251 // we have to do this for BS_RADIOBUTTON anyhow and, strangely enough,
252 // sometimes this is needed even for BS_AUTORADIOBUTTON (when we
253 // receive focus the button gets BN_CLICKED but stays unchecked!)
254 SetValue(true);
2b5f62a0 255
5f199b71
VZ
256 wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, GetId());
257 event.SetEventObject( this );
f607434a 258 event.SetInt(true); // always checked
f6bcfd97 259
5f199b71
VZ
260 ProcessCommand(event);
261 }
f6bcfd97 262
f607434a 263 return true;
f6bcfd97 264}
2bda0e17 265
5f199b71
VZ
266// ----------------------------------------------------------------------------
267// wxRadioButton geometry
268// ----------------------------------------------------------------------------
269
270wxSize wxRadioButton::DoGetBestSize() const
2bda0e17 271{
5f199b71 272 static int s_radioSize = 0;
2bda0e17 273
5f199b71
VZ
274 if ( !s_radioSize )
275 {
276 wxScreenDC dc;
277 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
2bda0e17 278
5f199b71
VZ
279 s_radioSize = dc.GetCharHeight();
280 }
2bda0e17 281
5f199b71 282 wxString str = GetLabel();
2bda0e17 283
5f199b71
VZ
284 int wRadio, hRadio;
285 if ( !str.empty() )
286 {
287 GetTextExtent(str, &wRadio, &hRadio);
288 wRadio += s_radioSize + GetCharWidth();
2bda0e17 289
5f199b71
VZ
290 if ( hRadio < s_radioSize )
291 hRadio = s_radioSize;
292 }
293 else
294 {
295 wRadio = s_radioSize;
296 hRadio = s_radioSize;
297 }
2bda0e17 298
5f199b71 299 return wxSize(wRadio, hRadio);
2bda0e17
KB
300}
301
1e6feb95 302#endif // wxUSE_RADIOBTN
f607434a 303