]> git.saurik.com Git - wxWidgets.git/blame - src/msw/radiobut.cpp
(blind) fix for keyboard cues display under XP (bug 1298512)
[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
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
2bda0e17 29#ifndef WX_PRECOMP
f607434a
VZ
30 #include "wx/radiobut.h"
31 #include "wx/settings.h"
32 #include "wx/dcscreen.h"
2bda0e17
KB
33#endif
34
35#include "wx/msw/private.h"
36
5f199b71
VZ
37// ============================================================================
38// wxRadioButton implementation
39// ============================================================================
40
41// ----------------------------------------------------------------------------
42// wxRadioButton creation
43// ----------------------------------------------------------------------------
44
2bda0e17 45
51741307 46#if wxUSE_EXTENDED_RTTI
bc9fb572
JS
47WX_DEFINE_FLAGS( wxRadioButtonStyle )
48
3ff066a4 49wxBEGIN_FLAGS( wxRadioButtonStyle )
bc9fb572
JS
50 // new style border flags, we put them first to
51 // use them for streaming out
3ff066a4
SC
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)
4d08943e 58
bc9fb572 59 // old style border flags
3ff066a4
SC
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)
cb0afb26 65 wxFLAGS_MEMBER(wxBORDER)
bc9fb572
JS
66
67 // standard window styles
3ff066a4
SC
68 wxFLAGS_MEMBER(wxTAB_TRAVERSAL)
69 wxFLAGS_MEMBER(wxCLIP_CHILDREN)
70 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW)
71 wxFLAGS_MEMBER(wxWANTS_CHARS)
cb0afb26 72 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE)
3ff066a4
SC
73 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB )
74 wxFLAGS_MEMBER(wxVSCROLL)
75 wxFLAGS_MEMBER(wxHSCROLL)
bc9fb572 76
3ff066a4 77 wxFLAGS_MEMBER(wxRB_GROUP)
bc9fb572 78
3ff066a4 79wxEND_FLAGS( wxRadioButtonStyle )
bc9fb572 80
51741307
SC
81IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioButton, wxControl,"wx/radiobut.h")
82
3ff066a4 83wxBEGIN_PROPERTIES_TABLE(wxRadioButton)
f607434a 84 wxEVENT_PROPERTY( Click , wxEVT_COMMAND_RADIOBUTTON_SELECTED , wxCommandEvent )
af498247 85 wxPROPERTY( Font , wxFont , SetFont , GetFont , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
f607434a 86 wxPROPERTY( Label,wxString, SetLabel, GetLabel, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
af498247
VZ
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
3ff066a4 89wxEND_PROPERTIES_TABLE()
51741307 90
3ff066a4
SC
91wxBEGIN_HANDLERS_TABLE(wxRadioButton)
92wxEND_HANDLERS_TABLE()
51741307 93
4d08943e 94wxCONSTRUCTOR_6( wxRadioButton , wxWindow* , Parent , wxWindowID , Id , wxString , Label , wxPoint , Position , wxSize , Size , long , WindowStyle )
51741307
SC
95
96#else
97IMPLEMENT_DYNAMIC_CLASS(wxRadioButton, wxControl)
98#endif
066f1b7a 99
066f1b7a 100
5f199b71 101void wxRadioButton::Init()
621793f4 102{
f607434a 103 m_isChecked = false;
621793f4
JS
104}
105
5f199b71
VZ
106bool 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)
2bda0e17 114{
5f199b71 115 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
f607434a 116 return false;
2bda0e17 117
2b5f62a0
VZ
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.
2bda0e17 128
2b5f62a0
VZ
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;
2bda0e17 134
5f199b71 135 if ( HasFlag(wxCLIP_SIBLINGS) )
b0766406 136 msStyle |= WS_CLIPSIBLINGS;
93212fee
VZ
137 if ( HasFlag(wxALIGN_RIGHT) )
138 msStyle |= BS_LEFTTEXT | BS_RIGHT;
b0766406 139
5f199b71 140 if ( !MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, 0) )
f607434a 141 return false;
b0766406 142
5f199b71
VZ
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) )
f607434a 148 SetValue(true);
c085e333 149
f607434a 150 return true;
2bda0e17
KB
151}
152
5f199b71
VZ
153// ----------------------------------------------------------------------------
154// wxRadioButton functions
155// ----------------------------------------------------------------------------
2bda0e17 156
5f199b71 157void wxRadioButton::SetValue(bool value)
2bda0e17 158{
3a5bcc4d 159 (void)::SendMessage(GetHwnd(), BM_SETCHECK, (value?BST_CHECKED:BST_UNCHECKED), 0L);
2b5f62a0 160
f607434a
VZ
161 m_isChecked = value;
162
2b5f62a0
VZ
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
f607434a 165 if ( m_isChecked )
2b5f62a0 166 {
f469584d
VZ
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
2b5f62a0 173 const wxWindowList& siblings = GetParent()->GetChildren();
222ed1d6 174 wxWindowList::compatibility_iterator nodeThis = siblings.Find(this);
2b5f62a0
VZ
175 wxCHECK_RET( nodeThis, _T("radio button not a child of its parent?") );
176
2b17e391
VZ
177 // if it's not the first item of the group ...
178 if ( !HasFlag(wxRB_GROUP) )
2b5f62a0 179 {
2b17e391 180 // ... turn off all radio buttons before it
222ed1d6 181 for ( wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
2b17e391
VZ
182 nodeBefore;
183 nodeBefore = nodeBefore->GetPrevious() )
2b5f62a0 184 {
2b17e391
VZ
185 wxRadioButton *btn = wxDynamicCast(nodeBefore->GetData(),
186 wxRadioButton);
c5b3143a 187 if ( btn && btn->HasFlag(wxRB_SINGLE) )
2b17e391 188 {
c5b3143a 189 // A wxRB_SINGLE button isn't part of this group
2b17e391
VZ
190 break;
191 }
c5b3143a
JS
192
193 if (btn)
2b17e391 194 {
f469584d
VZ
195 if (btn == pFocusWnd)
196 shouldSetFocus = true;
197
c5b3143a
JS
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 }
2b17e391 206 }
2b5f62a0
VZ
207 }
208 }
209
2b17e391 210 // ... and also turn off all buttons after this one
222ed1d6 211 for ( wxWindowList::compatibility_iterator nodeAfter = nodeThis->GetNext();
2b5f62a0
VZ
212 nodeAfter;
213 nodeAfter = nodeAfter->GetNext() )
214 {
215 wxRadioButton *btn = wxDynamicCast(nodeAfter->GetData(),
216 wxRadioButton);
217
c5b3143a 218 if ( btn && (btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) )
2b5f62a0
VZ
219 {
220 // no more buttons or the first button of the next group
221 break;
222 }
223
c5b3143a 224 if (btn)
f469584d
VZ
225 {
226 if (btn == pFocusWnd)
227 shouldSetFocus = true;
228
c5b3143a 229 btn->SetValue(false);
f469584d 230 }
2b5f62a0 231 }
f469584d
VZ
232 if (shouldSetFocus)
233 SetFocus();
2b5f62a0 234 }
2bda0e17
KB
235}
236
5f199b71 237bool wxRadioButton::GetValue() const
2bda0e17 238{
f607434a
VZ
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;
2bda0e17
KB
244}
245
5f199b71
VZ
246// ----------------------------------------------------------------------------
247// wxRadioButton event processing
248// ----------------------------------------------------------------------------
249
250void wxRadioButton::Command (wxCommandEvent& event)
2bda0e17 251{
687706f5 252 SetValue(event.GetInt() != 0);
5f199b71 253 ProcessCommand(event);
2bda0e17
KB
254}
255
5f199b71 256bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
f6bcfd97 257{
5f199b71 258 if ( param != BN_CLICKED )
f607434a 259 return false;
5f199b71 260
f607434a 261 if ( !m_isChecked )
f6bcfd97 262 {
f607434a
VZ
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);
2b5f62a0 267
5f199b71
VZ
268 wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, GetId());
269 event.SetEventObject( this );
f607434a 270 event.SetInt(true); // always checked
f6bcfd97 271
5f199b71
VZ
272 ProcessCommand(event);
273 }
f6bcfd97 274
f607434a 275 return true;
f6bcfd97 276}
2bda0e17 277
5f199b71
VZ
278// ----------------------------------------------------------------------------
279// wxRadioButton geometry
280// ----------------------------------------------------------------------------
281
282wxSize wxRadioButton::DoGetBestSize() const
2bda0e17 283{
5f199b71 284 static int s_radioSize = 0;
2bda0e17 285
5f199b71
VZ
286 if ( !s_radioSize )
287 {
288 wxScreenDC dc;
289 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
2bda0e17 290
5f199b71
VZ
291 s_radioSize = dc.GetCharHeight();
292 }
2bda0e17 293
5f199b71 294 wxString str = GetLabel();
2bda0e17 295
5f199b71
VZ
296 int wRadio, hRadio;
297 if ( !str.empty() )
298 {
299 GetTextExtent(str, &wRadio, &hRadio);
300 wRadio += s_radioSize + GetCharWidth();
2bda0e17 301
5f199b71
VZ
302 if ( hRadio < s_radioSize )
303 hRadio = s_radioSize;
304 }
305 else
306 {
307 wRadio = s_radioSize;
308 hRadio = s_radioSize;
309 }
2bda0e17 310
31582e4e
RD
311 wxSize best(wRadio, hRadio);
312 CacheBestSize(best);
313 return best;
2bda0e17
KB
314}
315
1e6feb95 316#endif // wxUSE_RADIOBTN
f607434a 317