]> git.saurik.com Git - wxWidgets.git/blob - src/msw/radiobut.cpp
Fix accelerstors with down and left
[wxWidgets.git] / src / msw / radiobut.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #ifndef WX_PRECOMP
30 #include "wx/radiobut.h"
31 #include "wx/settings.h"
32 #include "wx/dcscreen.h"
33 #endif
34
35 #include "wx/msw/private.h"
36
37 // ============================================================================
38 // wxRadioButton implementation
39 // ============================================================================
40
41 // ----------------------------------------------------------------------------
42 // wxRadioButton creation
43 // ----------------------------------------------------------------------------
44
45
46 #if wxUSE_EXTENDED_RTTI
47 WX_DEFINE_FLAGS( wxRadioButtonStyle )
48
49 wxBEGIN_FLAGS( wxRadioButtonStyle )
50 // new style border flags, we put them first to
51 // use them for streaming out
52 wxFLAGS_MEMBER(wxBORDER_SIMPLE)
53 wxFLAGS_MEMBER(wxBORDER_SUNKEN)
54 wxFLAGS_MEMBER(wxBORDER_DOUBLE)
55 wxFLAGS_MEMBER(wxBORDER_RAISED)
56 wxFLAGS_MEMBER(wxBORDER_STATIC)
57 wxFLAGS_MEMBER(wxBORDER_NONE)
58
59 // old style border flags
60 wxFLAGS_MEMBER(wxSIMPLE_BORDER)
61 wxFLAGS_MEMBER(wxSUNKEN_BORDER)
62 wxFLAGS_MEMBER(wxDOUBLE_BORDER)
63 wxFLAGS_MEMBER(wxRAISED_BORDER)
64 wxFLAGS_MEMBER(wxSTATIC_BORDER)
65 wxFLAGS_MEMBER(wxBORDER)
66
67 // standard window styles
68 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
69 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
70 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
71 wxFLAGS_MEMBER(wxWANTS_CHARS)
72 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
73 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
74 wxFLAGS_MEMBER(wxVSCROLL)
75 wxFLAGS_MEMBER(wxHSCROLL)
76
77 wxFLAGS_MEMBER(wxRB_GROUP)
78
79 wxEND_FLAGS( wxRadioButtonStyle )
80
81 IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioButton, wxControl,"wx/radiobut.h")
82
83 wxBEGIN_PROPERTIES_TABLE(wxRadioButton)
84 wxEVENT_PROPERTY( Click , wxEVT_COMMAND_RADIOBUTTON_SELECTED , wxCommandEvent )
85 wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
86 wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
87 wxPROPERTY( Value ,bool, SetValue, GetValue, EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
88 wxPROPERTY_FLAGS( WindowStyle , wxRadioButtonStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
89 wxEND_PROPERTIES_TABLE()
90
91 wxBEGIN_HANDLERS_TABLE(wxRadioButton)
92 wxEND_HANDLERS_TABLE()
93
94 wxCONSTRUCTOR_6( wxRadioButton , wxWindow* , Parent , wxWindowID , Id , wxString , Label , wxPoint , Position , wxSize , Size , long , WindowStyle )
95
96 #else
97 IMPLEMENT_DYNAMIC_CLASS(wxRadioButton, wxControl)
98 #endif
99
100
101 void wxRadioButton::Init()
102 {
103 m_isChecked = false;
104 }
105
106 bool wxRadioButton::Create(wxWindow *parent,
107 wxWindowID id,
108 const wxString& label,
109 const wxPoint& pos,
110 const wxSize& size,
111 long style,
112 const wxValidator& validator,
113 const wxString& name)
114 {
115 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
116 return false;
117
118 long msStyle = WS_TABSTOP;
119 if ( HasFlag(wxRB_GROUP) )
120 msStyle |= WS_GROUP;
121
122 /*
123 wxRB_SINGLE is a temporary workaround for the following problem: if you
124 have 2 radiobuttons in the same group but which are not consecutive in
125 the dialog, Windows can enter an infinite loop! The simplest way to
126 reproduce it is to create radio button, then a panel and then another
127 radio button: then checking the last button hangs the app.
128
129 Ideally, we'd detect (and avoid) such situation automatically but for
130 now, as I don't know how to do it, just allow the user to create
131 BS_RADIOBUTTON buttons for such situations.
132 */
133 msStyle |= HasFlag(wxRB_SINGLE) ? BS_RADIOBUTTON : BS_AUTORADIOBUTTON;
134
135 if ( HasFlag(wxCLIP_SIBLINGS) )
136 msStyle |= WS_CLIPSIBLINGS;
137 if ( HasFlag(wxALIGN_RIGHT) )
138 msStyle |= BS_LEFTTEXT | BS_RIGHT;
139
140 if ( !MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, 0) )
141 return false;
142
143 // for compatibility with wxGTK, the first radio button in a group is
144 // always checked (this makes sense anyhow as you need to ensure that at
145 // least one button in the group is checked and this is the simlpest way to
146 // do it)
147 if ( HasFlag(wxRB_GROUP) )
148 SetValue(true);
149
150 return true;
151 }
152
153 // ----------------------------------------------------------------------------
154 // wxRadioButton functions
155 // ----------------------------------------------------------------------------
156
157 void wxRadioButton::SetValue(bool value)
158 {
159 (void)::SendMessage(GetHwnd(), BM_SETCHECK, (value?BST_CHECKED:BST_UNCHECKED), 0L);
160
161 m_isChecked = value;
162
163 // if we set the value of one radio button we also must clear all the other
164 // buttons in the same group: Windows doesn't do it automatically
165 if ( m_isChecked )
166 {
167 // If another radiobutton in the group currently has the focus, we have to
168 // set it to this radiobutton, else the old readiobutton will be reselected
169 // automatically, if a parent window loses the focus and regains it.
170 bool shouldSetFocus = false;
171 wxWindow* pFocusWnd = FindFocus();
172
173 const wxWindowList& siblings = GetParent()->GetChildren();
174 wxWindowList::compatibility_iterator nodeThis = siblings.Find(this);
175 wxCHECK_RET( nodeThis, _T("radio button not a child of its parent?") );
176
177 // if it's not the first item of the group ...
178 if ( !HasFlag(wxRB_GROUP) )
179 {
180 // ... turn off all radio buttons before it
181 for ( wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
182 nodeBefore;
183 nodeBefore = nodeBefore->GetPrevious() )
184 {
185 wxRadioButton *btn = wxDynamicCast(nodeBefore->GetData(),
186 wxRadioButton);
187 if ( btn && btn->HasFlag(wxRB_SINGLE) )
188 {
189 // A wxRB_SINGLE button isn't part of this group
190 break;
191 }
192
193 if (btn)
194 {
195 if (btn == pFocusWnd)
196 shouldSetFocus = true;
197
198 btn->SetValue(false);
199
200 if ( btn->HasFlag(wxRB_GROUP) )
201 {
202 // even if there are other radio buttons before this one,
203 // they're not in the same group with us
204 break;
205 }
206 }
207 }
208 }
209
210 // ... and also turn off all buttons after this one
211 for ( wxWindowList::compatibility_iterator nodeAfter = nodeThis->GetNext();
212 nodeAfter;
213 nodeAfter = nodeAfter->GetNext() )
214 {
215 wxRadioButton *btn = wxDynamicCast(nodeAfter->GetData(),
216 wxRadioButton);
217
218 if ( btn && (btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) )
219 {
220 // no more buttons or the first button of the next group
221 break;
222 }
223
224 if (btn)
225 {
226 if (btn == pFocusWnd)
227 shouldSetFocus = true;
228
229 btn->SetValue(false);
230 }
231 }
232 if (shouldSetFocus)
233 SetFocus();
234 }
235 }
236
237 bool wxRadioButton::GetValue() const
238 {
239 wxASSERT_MSG( m_isChecked ==
240 (::SendMessage(GetHwnd(), BM_GETCHECK, 0, 0L) != 0),
241 _T("wxRadioButton::m_isChecked is out of sync?") );
242
243 return m_isChecked;
244 }
245
246 // ----------------------------------------------------------------------------
247 // wxRadioButton event processing
248 // ----------------------------------------------------------------------------
249
250 void wxRadioButton::Command (wxCommandEvent& event)
251 {
252 SetValue(event.GetInt() != 0);
253 ProcessCommand(event);
254 }
255
256 bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
257 {
258 if ( param != BN_CLICKED )
259 return false;
260
261 if ( !m_isChecked )
262 {
263 // we have to do this for BS_RADIOBUTTON anyhow and, strangely enough,
264 // sometimes this is needed even for BS_AUTORADIOBUTTON (when we
265 // receive focus the button gets BN_CLICKED but stays unchecked!)
266 SetValue(true);
267
268 wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, GetId());
269 event.SetEventObject( this );
270 event.SetInt(true); // always checked
271
272 ProcessCommand(event);
273 }
274
275 return true;
276 }
277
278 // ----------------------------------------------------------------------------
279 // wxRadioButton geometry
280 // ----------------------------------------------------------------------------
281
282 wxSize wxRadioButton::DoGetBestSize() const
283 {
284 static int s_radioSize = 0;
285
286 if ( !s_radioSize )
287 {
288 wxScreenDC dc;
289 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
290
291 s_radioSize = dc.GetCharHeight();
292 }
293
294 wxString str = GetLabel();
295
296 int wRadio, hRadio;
297 if ( !str.empty() )
298 {
299 GetTextExtent(wxStripMenuCodes(str), &wRadio, &hRadio);
300 wRadio += s_radioSize + GetCharWidth();
301
302 if ( hRadio < s_radioSize )
303 hRadio = s_radioSize;
304 }
305 else
306 {
307 wRadio = s_radioSize;
308 hRadio = s_radioSize;
309 }
310
311 wxSize best(wRadio, hRadio);
312 CacheBestSize(best);
313 return best;
314 }
315
316 #endif // wxUSE_RADIOBTN
317