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