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