]> git.saurik.com Git - wxWidgets.git/blame - src/msw/radiobut.cpp
XTI extensions
[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)
c9baf9d7 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__
c9baf9d7 28#pragma hdrstop
2bda0e17
KB
29#endif
30
1e6feb95
VZ
31#if wxUSE_RADIOBTN
32
2bda0e17 33#ifndef WX_PRECOMP
c9baf9d7
RL
34#include "wx/radiobut.h"
35#include "wx/settings.h"
36#include "wx/brush.h"
37#include "wx/dcscreen.h"
2bda0e17
KB
38#endif
39
40#include "wx/msw/private.h"
41
5f199b71
VZ
42// ============================================================================
43// wxRadioButton implementation
44// ============================================================================
45
46// ----------------------------------------------------------------------------
47// wxRadioButton creation
48// ----------------------------------------------------------------------------
49
2bda0e17 50
51741307
SC
51#if wxUSE_EXTENDED_RTTI
52IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioButton, wxControl,"wx/radiobut.h")
53
54WX_BEGIN_PROPERTIES_TABLE(wxRadioButton)
55 WX_DELEGATE( OnClick , wxEVT_COMMAND_RADIOBUTTON_SELECTED , wxCommandEvent )
6a89f9ee
SC
56 WX_PROPERTY( Font , wxFont , SetFont , GetWindowFont , )
57 WX_PROPERTY( Label,wxString, SetLabel, GetLabel, wxT("") )
51741307
SC
58 WX_PROPERTY( Value ,bool, SetValue, GetValue, )
59WX_END_PROPERTIES_TABLE()
60
61WX_BEGIN_HANDLERS_TABLE(wxRadioButton)
62WX_END_HANDLERS_TABLE()
63
64WX_CONSTRUCTOR_6( wxRadioButton , wxWindow* , Parent , wxWindowID , Id , wxString , Label , wxPoint , Position , wxSize , Size , long , WindowStyle )
65
66#else
67IMPLEMENT_DYNAMIC_CLASS(wxRadioButton, wxControl)
68#endif
066f1b7a 69
066f1b7a 70
5f199b71 71void wxRadioButton::Init()
621793f4 72{
5f199b71 73 m_focusJustSet = FALSE;
621793f4
JS
74}
75
5f199b71
VZ
76bool wxRadioButton::Create(wxWindow *parent,
77 wxWindowID id,
78 const wxString& label,
79 const wxPoint& pos,
80 const wxSize& size,
81 long style,
82 const wxValidator& validator,
83 const wxString& name)
2bda0e17 84{
5f199b71
VZ
85 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
86 return FALSE;
2bda0e17 87
2b5f62a0
VZ
88 long msStyle = WS_TABSTOP;
89 if ( HasFlag(wxRB_GROUP) )
90 msStyle |= WS_GROUP;
91
92 /*
93 wxRB_SINGLE is a temporary workaround for the following problem: if you
94 have 2 radiobuttons in the same group but which are not consecutive in
95 the dialog, Windows can enter an infinite loop! The simplest way to
96 reproduce it is to create radio button, then a panel and then another
97 radio button: then checking the last button hangs the app.
2bda0e17 98
2b5f62a0
VZ
99 Ideally, we'd detect (and avoid) such situation automatically but for
100 now, as I don't know how to do it, just allow the user to create
101 BS_RADIOBUTTON buttons for such situations.
102 */
103 msStyle |= HasFlag(wxRB_SINGLE) ? BS_RADIOBUTTON : BS_AUTORADIOBUTTON;
2bda0e17 104
5f199b71 105 if ( HasFlag(wxCLIP_SIBLINGS) )
b0766406
JS
106 msStyle |= WS_CLIPSIBLINGS;
107
5f199b71
VZ
108 if ( !MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, 0) )
109 return FALSE;
b0766406 110
5f199b71
VZ
111 // for compatibility with wxGTK, the first radio button in a group is
112 // always checked (this makes sense anyhow as you need to ensure that at
113 // least one button in the group is checked and this is the simlpest way to
114 // do it)
115 if ( HasFlag(wxRB_GROUP) )
116 SetValue(TRUE);
c085e333 117
5f199b71 118 return TRUE;
2bda0e17
KB
119}
120
5f199b71
VZ
121// ----------------------------------------------------------------------------
122// wxRadioButton functions
123// ----------------------------------------------------------------------------
2bda0e17 124
5f199b71 125void wxRadioButton::SetValue(bool value)
2bda0e17 126{
5f199b71 127 // BST_CHECKED is defined as 1, BST_UNCHECKED as 0, so we can just pass
2b5f62a0 128 // value as is (we don't use BST_XXX here as they're not defined for Win16)
5f199b71 129 (void)::SendMessage(GetHwnd(), BM_SETCHECK, (WPARAM)value, 0L);
2b5f62a0
VZ
130
131 // if we set the value of one radio button we also must clear all the other
132 // buttons in the same group: Windows doesn't do it automatically
133 if ( value )
134 {
135 const wxWindowList& siblings = GetParent()->GetChildren();
222ed1d6 136 wxWindowList::compatibility_iterator nodeThis = siblings.Find(this);
2b5f62a0
VZ
137 wxCHECK_RET( nodeThis, _T("radio button not a child of its parent?") );
138
2b17e391
VZ
139 // if it's not the first item of the group ...
140 if ( !HasFlag(wxRB_GROUP) )
2b5f62a0 141 {
2b17e391 142 // ... turn off all radio buttons before it
222ed1d6 143 for ( wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
2b17e391
VZ
144 nodeBefore;
145 nodeBefore = nodeBefore->GetPrevious() )
2b5f62a0 146 {
2b17e391
VZ
147 wxRadioButton *btn = wxDynamicCast(nodeBefore->GetData(),
148 wxRadioButton);
149 if ( !btn )
150 {
151 // the radio buttons in a group must be consecutive, so
152 // there are no more of them
153 break;
154 }
155
156 btn->SetValue(FALSE);
157
158 if ( btn->HasFlag(wxRB_GROUP) )
159 {
160 // even if there are other radio buttons before this one,
161 // they're not in the same group with us
162 break;
163 }
2b5f62a0
VZ
164 }
165 }
166
2b17e391 167 // ... and also turn off all buttons after this one
222ed1d6 168 for ( wxWindowList::compatibility_iterator nodeAfter = nodeThis->GetNext();
2b5f62a0
VZ
169 nodeAfter;
170 nodeAfter = nodeAfter->GetNext() )
171 {
172 wxRadioButton *btn = wxDynamicCast(nodeAfter->GetData(),
173 wxRadioButton);
174
175 if ( !btn || btn->HasFlag(wxRB_GROUP) )
176 {
177 // no more buttons or the first button of the next group
178 break;
179 }
180
181 btn->SetValue(FALSE);
182 }
183 }
2bda0e17
KB
184}
185
5f199b71 186bool wxRadioButton::GetValue() const
2bda0e17 187{
5f199b71
VZ
188 // NB: this will also return TRUE for BST_INDETERMINATE value if we ever
189 // have 3-state radio buttons
190 return ::SendMessage(GetHwnd(), BM_GETCHECK, 0, 0L) != 0;
2bda0e17
KB
191}
192
5f199b71
VZ
193// ----------------------------------------------------------------------------
194// wxRadioButton event processing
195// ----------------------------------------------------------------------------
196
197void wxRadioButton::Command (wxCommandEvent& event)
2bda0e17 198{
5f199b71
VZ
199 SetValue(event.m_commandInt != 0);
200 ProcessCommand(event);
2bda0e17
KB
201}
202
5f199b71 203void wxRadioButton::SetFocus()
2bda0e17 204{
5f199b71
VZ
205 // when the radio button receives a WM_SETFOCUS message it generates a
206 // BN_CLICKED which is totally unexpected and leads to catastrophic results
207 // if you pop up a dialog from the radio button event handler as, when the
208 // dialog is dismissed, the focus is returned to the radio button which
209 // generates BN_CLICKED which leads to showing another dialog and so on
210 // without end!
211 //
2b5f62a0 212 // to avoid this, we drop the pseudo BN_CLICKED events generated when the
5f199b71
VZ
213 // button gains focus
214 m_focusJustSet = TRUE;
215
216 wxControl::SetFocus();
2bda0e17
KB
217}
218
5f199b71 219bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
f6bcfd97 220{
5f199b71
VZ
221 if ( param != BN_CLICKED )
222 return FALSE;
223
224 if ( m_focusJustSet )
f6bcfd97 225 {
5f199b71
VZ
226 // see above: we want to ignore this event
227 m_focusJustSet = FALSE;
f6bcfd97 228 }
5f199b71
VZ
229 else // a real clicked event
230 {
2b5f62a0
VZ
231 bool isChecked = GetValue();
232
233 if ( HasFlag(wxRB_SINGLE) )
234 {
235 // when we use a "manual" radio button, we have to check the button
236 // ourselves -- but it's reset to unchecked state by the user code
237 // (presumably when another button is pressed)
238 if ( !isChecked )
239 SetValue(TRUE);
240 }
241
5f199b71
VZ
242 wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, GetId());
243 event.SetEventObject( this );
2b5f62a0 244 event.SetInt(isChecked);
f6bcfd97 245
5f199b71
VZ
246 ProcessCommand(event);
247 }
f6bcfd97 248
5f199b71 249 return TRUE;
f6bcfd97 250}
2bda0e17 251
5f199b71
VZ
252// ----------------------------------------------------------------------------
253// wxRadioButton geometry
254// ----------------------------------------------------------------------------
255
256wxSize wxRadioButton::DoGetBestSize() const
2bda0e17 257{
5f199b71 258 static int s_radioSize = 0;
2bda0e17 259
5f199b71
VZ
260 if ( !s_radioSize )
261 {
262 wxScreenDC dc;
263 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
2bda0e17 264
5f199b71
VZ
265 s_radioSize = dc.GetCharHeight();
266 }
2bda0e17 267
5f199b71 268 wxString str = GetLabel();
2bda0e17 269
5f199b71
VZ
270 int wRadio, hRadio;
271 if ( !str.empty() )
272 {
273 GetTextExtent(str, &wRadio, &hRadio);
274 wRadio += s_radioSize + GetCharWidth();
2bda0e17 275
5f199b71
VZ
276 if ( hRadio < s_radioSize )
277 hRadio = s_radioSize;
278 }
279 else
280 {
281 wRadio = s_radioSize;
282 hRadio = s_radioSize;
283 }
2bda0e17 284
5f199b71 285 return wxSize(wRadio, hRadio);
2bda0e17
KB
286}
287
aca78774
JS
288long wxRadioButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
289{
290 if (nMsg == WM_SETFOCUS)
291 {
292 m_focusJustSet = TRUE;
293
294 long ret = wxControl::MSWWindowProc(nMsg, wParam, lParam);
295
296 m_focusJustSet = FALSE;
297
298 return ret;
299 }
2b5f62a0 300 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
aca78774
JS
301}
302
1e6feb95 303#endif // wxUSE_RADIOBTN