]> git.saurik.com Git - wxWidgets.git/blame_incremental - 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
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/radiobut.cpp
3// Purpose: wxRadioButton
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#if wxUSE_RADIOBTN
28
29#include "wx/radiobut.h"
30
31#ifndef WX_PRECOMP
32 #include "wx/settings.h"
33 #include "wx/dcscreen.h"
34 #include "wx/toplevel.h"
35#endif
36
37#include "wx/msw/private.h"
38
39// ============================================================================
40// wxRadioButton implementation
41// ============================================================================
42
43// ----------------------------------------------------------------------------
44// wxRadioButton creation
45// ----------------------------------------------------------------------------
46
47void wxRadioButton::Init()
48{
49 m_isChecked = false;
50}
51
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)
60{
61 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
62 return false;
63
64 long msStyle = WS_TABSTOP;
65 if ( HasFlag(wxRB_GROUP) )
66 msStyle |= WS_GROUP;
67
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;
76
77 if ( HasFlag(wxCLIP_SIBLINGS) )
78 msStyle |= WS_CLIPSIBLINGS;
79 if ( HasFlag(wxALIGN_RIGHT) )
80 msStyle |= BS_LEFTTEXT | BS_RIGHT;
81
82 if ( !MSWCreateControl(wxT("BUTTON"), msStyle, pos, size, label, 0) )
83 return false;
84
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
87 // least one button in the group is checked and this is the simplest way to
88 // do it)
89 if ( HasFlag(wxRB_GROUP) )
90 SetValue(true);
91
92 return true;
93}
94
95// ----------------------------------------------------------------------------
96// wxRadioButton functions
97// ----------------------------------------------------------------------------
98
99void wxRadioButton::SetValue(bool value)
100{
101 ::SendMessage(GetHwnd(), BM_SETCHECK,
102 value ? BST_CHECKED : BST_UNCHECKED, 0);
103
104 m_isChecked = value;
105
106 if ( !value )
107 return;
108
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
111 //
112 // moreover, if another radiobutton in the group currently has the focus,
113 // we have to set it to this radiobutton, else the old radiobutton will be
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);
119 wxCHECK_RET( tlw, wxT("radio button outside of TLW?") );
120 wxWindow * const focusInTLW = tlw->GetLastFocus();
121
122 const wxWindowList& siblings = GetParent()->GetChildren();
123 wxWindowList::compatibility_iterator nodeThis = siblings.Find(this);
124 wxCHECK_RET( nodeThis, wxT("radio button not a child of its parent?") );
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) )
137 {
138 // ... turn off all radio buttons before it
139 for ( wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
140 nodeBefore;
141 nodeBefore = nodeBefore->GetPrevious() )
142 {
143 wxRadioButton *btn = wxDynamicCast(nodeBefore->GetData(),
144 wxRadioButton);
145 if ( !btn )
146 {
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) )
153 {
154 // A wxRB_SINGLE button isn't part of this group
155 break;
156 }
157
158 if ( btn == focus )
159 shouldSetFocus = true;
160 else if ( btn == focusInTLW )
161 shouldSetTLWFocus = true;
162
163 btn->SetValue(false);
164
165 if ( btn->HasFlag(wxRB_GROUP) )
166 {
167 // even if there are other radio buttons before this one,
168 // they're not in the same group with us
169 break;
170 }
171 }
172 }
173
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);
181
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;
189 }
190
191 if ( btn == focus )
192 shouldSetFocus = true;
193 else if ( btn == focusInTLW )
194 shouldSetTLWFocus = true;
195
196 btn->SetValue(false);
197 }
198
199 if ( shouldSetFocus )
200 SetFocus();
201 else if ( shouldSetTLWFocus )
202 tlw->SetLastFocus(this);
203}
204
205bool wxRadioButton::GetValue() const
206{
207 wxASSERT_MSG( m_isChecked ==
208 (::SendMessage(GetHwnd(), BM_GETCHECK, 0, 0L) != 0),
209 wxT("wxRadioButton::m_isChecked is out of sync?") );
210
211 return m_isChecked;
212}
213
214// ----------------------------------------------------------------------------
215// wxRadioButton event processing
216// ----------------------------------------------------------------------------
217
218void wxRadioButton::Command (wxCommandEvent& event)
219{
220 SetValue(event.GetInt() != 0);
221 ProcessCommand(event);
222}
223
224bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
225{
226 if ( param != BN_CLICKED )
227 return false;
228
229 if ( !m_isChecked )
230 {
231 // we need to manually update the button state as we use BS_RADIOBUTTON
232 // and not BS_AUTORADIOBUTTON
233 SetValue(true);
234
235 wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, GetId());
236 event.SetEventObject( this );
237 event.SetInt(true); // always checked
238
239 ProcessCommand(event);
240 }
241
242 return true;
243}
244
245// ----------------------------------------------------------------------------
246// wxRadioButton geometry
247// ----------------------------------------------------------------------------
248
249wxSize wxRadioButton::DoGetBestSize() const
250{
251 static int s_radioSize = 0;
252
253 if ( !s_radioSize )
254 {
255 wxScreenDC dc;
256 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
257
258 s_radioSize = dc.GetCharHeight();
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__
266 }
267
268 wxString str = GetLabel();
269
270 int wRadio, hRadio;
271 if ( !str.empty() )
272 {
273 GetTextExtent(GetLabelText(str), &wRadio, &hRadio);
274 wRadio += s_radioSize + GetCharWidth();
275
276 if ( hRadio < s_radioSize )
277 hRadio = s_radioSize;
278 }
279 else
280 {
281 wRadio = s_radioSize;
282 hRadio = s_radioSize;
283 }
284
285 wxSize best(wRadio, hRadio);
286 CacheBestSize(best);
287 return best;
288}
289
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
300#endif // wxUSE_RADIOBTN