]> git.saurik.com Git - wxWidgets.git/blame - src/msw/radiobut.cpp
Implement undo and redo for the ie and gtk webkit backends. Extend the sample to...
[wxWidgets.git] / src / msw / radiobut.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
b0b5881a 2// Name: src/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
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
f607434a 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
1e6feb95
VZ
27#if wxUSE_RADIOBTN
28
b0b5881a
WS
29#include "wx/radiobut.h"
30
2bda0e17 31#ifndef WX_PRECOMP
f607434a
VZ
32 #include "wx/settings.h"
33 #include "wx/dcscreen.h"
6b81a8ea 34 #include "wx/toplevel.h"
2bda0e17
KB
35#endif
36
37#include "wx/msw/private.h"
38
5f199b71
VZ
39// ============================================================================
40// wxRadioButton implementation
41// ============================================================================
42
43// ----------------------------------------------------------------------------
44// wxRadioButton creation
45// ----------------------------------------------------------------------------
46
5f199b71 47void wxRadioButton::Init()
621793f4 48{
f607434a 49 m_isChecked = false;
621793f4
JS
50}
51
5f199b71
VZ
52bool wxRadioButton::Create(wxWindow *parent,
53 wxWindowID id,
54 const wxString& label,
55 const wxPoint& pos,
56 const wxSize& size,
57 long style,
58 const wxValidator& validator,
59 const wxString& name)
2bda0e17 60{
5f199b71 61 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
f607434a 62 return false;
2bda0e17 63
2b5f62a0
VZ
64 long msStyle = WS_TABSTOP;
65 if ( HasFlag(wxRB_GROUP) )
66 msStyle |= WS_GROUP;
67
cb738de0
VZ
68 // we use BS_RADIOBUTTON and not BS_AUTORADIOBUTTON because the use of the
69 // latter can easily result in the application entering an infinite loop
70 // inside IsDialogMessage()
71 //
72 // we used to use BS_RADIOBUTTON only for wxRB_SINGLE buttons but there
73 // doesn't seem to be any harm to always use it and it prevents some hangs,
74 // see #9786
75 msStyle |= BS_RADIOBUTTON;
2bda0e17 76
5f199b71 77 if ( HasFlag(wxCLIP_SIBLINGS) )
b0766406 78 msStyle |= WS_CLIPSIBLINGS;
93212fee
VZ
79 if ( HasFlag(wxALIGN_RIGHT) )
80 msStyle |= BS_LEFTTEXT | BS_RIGHT;
b0766406 81
9a83f860 82 if ( !MSWCreateControl(wxT("BUTTON"), msStyle, pos, size, label, 0) )
f607434a 83 return false;
b0766406 84
5f199b71
VZ
85 // for compatibility with wxGTK, the first radio button in a group is
86 // always checked (this makes sense anyhow as you need to ensure that at
cb738de0 87 // least one button in the group is checked and this is the simplest way to
5f199b71
VZ
88 // do it)
89 if ( HasFlag(wxRB_GROUP) )
f607434a 90 SetValue(true);
c085e333 91
f607434a 92 return true;
2bda0e17
KB
93}
94
5f199b71
VZ
95// ----------------------------------------------------------------------------
96// wxRadioButton functions
97// ----------------------------------------------------------------------------
2bda0e17 98
5f199b71 99void wxRadioButton::SetValue(bool value)
2bda0e17 100{
48fbe8ee
VZ
101 ::SendMessage(GetHwnd(), BM_SETCHECK,
102 value ? BST_CHECKED : BST_UNCHECKED, 0);
2b5f62a0 103
f607434a
VZ
104 m_isChecked = value;
105
48fbe8ee
VZ
106 if ( !value )
107 return;
108
2b5f62a0
VZ
109 // if we set the value of one radio button we also must clear all the other
110 // buttons in the same group: Windows doesn't do it automatically
48fbe8ee
VZ
111 //
112 // moreover, if another radiobutton in the group currently has the focus,
cb738de0 113 // we have to set it to this radiobutton, else the old radiobutton will be
48fbe8ee
VZ
114 // reselected automatically, if a parent window loses the focus and regains
115 // it.
116 wxWindow * const focus = FindFocus();
117 wxTopLevelWindow * const
118 tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
9a83f860 119 wxCHECK_RET( tlw, wxT("radio button outside of TLW?") );
48fbe8ee
VZ
120 wxWindow * const focusInTLW = tlw->GetLastFocus();
121
122 const wxWindowList& siblings = GetParent()->GetChildren();
123 wxWindowList::compatibility_iterator nodeThis = siblings.Find(this);
9a83f860 124 wxCHECK_RET( nodeThis, wxT("radio button not a child of its parent?") );
48fbe8ee
VZ
125
126 // this will be set to true in the code below if the focus is in our TLW
127 // and belongs to one of the other buttons in the same group
128 bool shouldSetFocus = false;
129
130 // this will be set to true if the focus is outside of our TLW currently
131 // but the remembered focus of this TLW is one of the other buttons in the
132 // same group
133 bool shouldSetTLWFocus = false;
134
135 // if it's not the first item of the group ...
136 if ( !HasFlag(wxRB_GROUP) )
2b5f62a0 137 {
48fbe8ee
VZ
138 // ... turn off all radio buttons before it
139 for ( wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
140 nodeBefore;
141 nodeBefore = nodeBefore->GetPrevious() )
2b5f62a0 142 {
48fbe8ee
VZ
143 wxRadioButton *btn = wxDynamicCast(nodeBefore->GetData(),
144 wxRadioButton);
145 if ( !btn )
2b5f62a0 146 {
48fbe8ee
VZ
147 // don't stop on non radio buttons, we could have intermixed
148 // buttons and e.g. static labels
149 continue;
150 }
151
152 if ( btn->HasFlag(wxRB_SINGLE) )
2b17e391 153 {
c5b3143a 154 // A wxRB_SINGLE button isn't part of this group
2b17e391
VZ
155 break;
156 }
b0b5881a 157
48fbe8ee
VZ
158 if ( btn == focus )
159 shouldSetFocus = true;
160 else if ( btn == focusInTLW )
161 shouldSetTLWFocus = true;
c5b3143a 162
48fbe8ee 163 btn->SetValue(false);
2b5f62a0 164
48fbe8ee 165 if ( btn->HasFlag(wxRB_GROUP) )
2b5f62a0 166 {
48fbe8ee
VZ
167 // even if there are other radio buttons before this one,
168 // they're not in the same group with us
2b5f62a0
VZ
169 break;
170 }
48fbe8ee
VZ
171 }
172 }
2b5f62a0 173
48fbe8ee
VZ
174 // ... and also turn off all buttons after this one
175 for ( wxWindowList::compatibility_iterator nodeAfter = nodeThis->GetNext();
176 nodeAfter;
177 nodeAfter = nodeAfter->GetNext() )
178 {
179 wxRadioButton *btn = wxDynamicCast(nodeAfter->GetData(),
180 wxRadioButton);
f469584d 181
48fbe8ee
VZ
182 if ( !btn )
183 continue;
184
185 if ( btn->HasFlag(wxRB_GROUP | wxRB_SINGLE) )
186 {
187 // no more buttons or the first button of the next group
188 break;
2b5f62a0 189 }
48fbe8ee
VZ
190
191 if ( btn == focus )
192 shouldSetFocus = true;
193 else if ( btn == focusInTLW )
194 shouldSetTLWFocus = true;
195
196 btn->SetValue(false);
2b5f62a0 197 }
48fbe8ee
VZ
198
199 if ( shouldSetFocus )
200 SetFocus();
201 else if ( shouldSetTLWFocus )
202 tlw->SetLastFocus(this);
2bda0e17
KB
203}
204
5f199b71 205bool wxRadioButton::GetValue() const
2bda0e17 206{
f607434a
VZ
207 wxASSERT_MSG( m_isChecked ==
208 (::SendMessage(GetHwnd(), BM_GETCHECK, 0, 0L) != 0),
9a83f860 209 wxT("wxRadioButton::m_isChecked is out of sync?") );
f607434a
VZ
210
211 return m_isChecked;
2bda0e17
KB
212}
213
5f199b71
VZ
214// ----------------------------------------------------------------------------
215// wxRadioButton event processing
216// ----------------------------------------------------------------------------
217
218void wxRadioButton::Command (wxCommandEvent& event)
2bda0e17 219{
687706f5 220 SetValue(event.GetInt() != 0);
5f199b71 221 ProcessCommand(event);
2bda0e17
KB
222}
223
5f199b71 224bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
f6bcfd97 225{
5f199b71 226 if ( param != BN_CLICKED )
f607434a 227 return false;
5f199b71 228
f607434a 229 if ( !m_isChecked )
f6bcfd97 230 {
cb738de0
VZ
231 // we need to manually update the button state as we use BS_RADIOBUTTON
232 // and not BS_AUTORADIOBUTTON
f607434a 233 SetValue(true);
2b5f62a0 234
5f199b71
VZ
235 wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, GetId());
236 event.SetEventObject( this );
f607434a 237 event.SetInt(true); // always checked
f6bcfd97 238
5f199b71
VZ
239 ProcessCommand(event);
240 }
f6bcfd97 241
f607434a 242 return true;
f6bcfd97 243}
2bda0e17 244
5f199b71
VZ
245// ----------------------------------------------------------------------------
246// wxRadioButton geometry
247// ----------------------------------------------------------------------------
248
249wxSize wxRadioButton::DoGetBestSize() const
2bda0e17 250{
5f199b71 251 static int s_radioSize = 0;
2bda0e17 252
5f199b71
VZ
253 if ( !s_radioSize )
254 {
255 wxScreenDC dc;
256 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
2bda0e17 257
5f199b71 258 s_radioSize = dc.GetCharHeight();
7eee3607
VZ
259
260 // radio button bitmap size under CE is bigger than the font height,
261 // adding just one pixel seems to work fine for the default font but it
262 // would be nice to find some better way to find the correct height
263#ifdef __WXWINCE__
264 s_radioSize++;
265#endif // __WXWINCE__
5f199b71 266 }
2bda0e17 267
5f199b71 268 wxString str = GetLabel();
2bda0e17 269
5f199b71
VZ
270 int wRadio, hRadio;
271 if ( !str.empty() )
272 {
32cd189d 273 GetTextExtent(GetLabelText(str), &wRadio, &hRadio);
5f199b71 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
31582e4e
RD
285 wxSize best(wRadio, hRadio);
286 CacheBestSize(best);
287 return best;
2bda0e17
KB
288}
289
bec08b39
VZ
290WXDWORD wxRadioButton::MSWGetStyle(long style, WXDWORD *exstyle) const
291{
292 WXDWORD styleMSW = wxControl::MSWGetStyle(style, exstyle);
293
294 if ( style & wxRB_GROUP )
295 styleMSW |= WS_GROUP;
296
297 return styleMSW;
298}
299
1e6feb95 300#endif // wxUSE_RADIOBTN