]> git.saurik.com Git - wxWidgets.git/blame - src/msw/radiobut.cpp
Avoid core dumps when SetImageList is used.
[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
5f199b71 105void wxRadioButton::Init()
621793f4 106{
f607434a 107 m_isChecked = false;
621793f4
JS
108}
109
5f199b71
VZ
110bool wxRadioButton::Create(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)
2bda0e17 118{
5f199b71 119 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
f607434a 120 return false;
2bda0e17 121
2b5f62a0
VZ
122 long msStyle = WS_TABSTOP;
123 if ( HasFlag(wxRB_GROUP) )
124 msStyle |= WS_GROUP;
125
126 /*
127 wxRB_SINGLE is a temporary workaround for the following problem: if you
128 have 2 radiobuttons in the same group but which are not consecutive in
129 the dialog, Windows can enter an infinite loop! The simplest way to
130 reproduce it is to create radio button, then a panel and then another
131 radio button: then checking the last button hangs the app.
2bda0e17 132
2b5f62a0
VZ
133 Ideally, we'd detect (and avoid) such situation automatically but for
134 now, as I don't know how to do it, just allow the user to create
135 BS_RADIOBUTTON buttons for such situations.
136 */
137 msStyle |= HasFlag(wxRB_SINGLE) ? BS_RADIOBUTTON : BS_AUTORADIOBUTTON;
2bda0e17 138
5f199b71 139 if ( HasFlag(wxCLIP_SIBLINGS) )
b0766406
JS
140 msStyle |= WS_CLIPSIBLINGS;
141
5f199b71 142 if ( !MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, 0) )
f607434a 143 return false;
b0766406 144
5f199b71
VZ
145 // for compatibility with wxGTK, the first radio button in a group is
146 // always checked (this makes sense anyhow as you need to ensure that at
147 // least one button in the group is checked and this is the simlpest way to
148 // do it)
149 if ( HasFlag(wxRB_GROUP) )
f607434a 150 SetValue(true);
c085e333 151
f607434a 152 return true;
2bda0e17
KB
153}
154
5f199b71
VZ
155// ----------------------------------------------------------------------------
156// wxRadioButton functions
157// ----------------------------------------------------------------------------
2bda0e17 158
5f199b71 159void wxRadioButton::SetValue(bool value)
2bda0e17 160{
3a5bcc4d 161 (void)::SendMessage(GetHwnd(), BM_SETCHECK, (value?BST_CHECKED:BST_UNCHECKED), 0L);
2b5f62a0 162
f607434a
VZ
163 m_isChecked = value;
164
2b5f62a0
VZ
165 // if we set the value of one radio button we also must clear all the other
166 // buttons in the same group: Windows doesn't do it automatically
f607434a 167 if ( m_isChecked )
2b5f62a0
VZ
168 {
169 const wxWindowList& siblings = GetParent()->GetChildren();
222ed1d6 170 wxWindowList::compatibility_iterator nodeThis = siblings.Find(this);
2b5f62a0
VZ
171 wxCHECK_RET( nodeThis, _T("radio button not a child of its parent?") );
172
2b17e391
VZ
173 // if it's not the first item of the group ...
174 if ( !HasFlag(wxRB_GROUP) )
2b5f62a0 175 {
2b17e391 176 // ... turn off all radio buttons before it
222ed1d6 177 for ( wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
2b17e391
VZ
178 nodeBefore;
179 nodeBefore = nodeBefore->GetPrevious() )
2b5f62a0 180 {
2b17e391
VZ
181 wxRadioButton *btn = wxDynamicCast(nodeBefore->GetData(),
182 wxRadioButton);
183 if ( !btn )
184 {
185 // the radio buttons in a group must be consecutive, so
186 // there are no more of them
187 break;
188 }
189
f607434a 190 btn->SetValue(false);
2b17e391
VZ
191
192 if ( btn->HasFlag(wxRB_GROUP) )
193 {
194 // even if there are other radio buttons before this one,
195 // they're not in the same group with us
196 break;
197 }
2b5f62a0
VZ
198 }
199 }
200
2b17e391 201 // ... and also turn off all buttons after this one
222ed1d6 202 for ( wxWindowList::compatibility_iterator nodeAfter = nodeThis->GetNext();
2b5f62a0
VZ
203 nodeAfter;
204 nodeAfter = nodeAfter->GetNext() )
205 {
206 wxRadioButton *btn = wxDynamicCast(nodeAfter->GetData(),
207 wxRadioButton);
208
209 if ( !btn || btn->HasFlag(wxRB_GROUP) )
210 {
211 // no more buttons or the first button of the next group
212 break;
213 }
214
f607434a 215 btn->SetValue(false);
2b5f62a0
VZ
216 }
217 }
2bda0e17
KB
218}
219
5f199b71 220bool wxRadioButton::GetValue() const
2bda0e17 221{
f607434a
VZ
222 wxASSERT_MSG( m_isChecked ==
223 (::SendMessage(GetHwnd(), BM_GETCHECK, 0, 0L) != 0),
224 _T("wxRadioButton::m_isChecked is out of sync?") );
225
226 return m_isChecked;
2bda0e17
KB
227}
228
5f199b71
VZ
229// ----------------------------------------------------------------------------
230// wxRadioButton event processing
231// ----------------------------------------------------------------------------
232
233void wxRadioButton::Command (wxCommandEvent& event)
2bda0e17 234{
5f199b71
VZ
235 SetValue(event.m_commandInt != 0);
236 ProcessCommand(event);
2bda0e17
KB
237}
238
5f199b71 239bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
f6bcfd97 240{
5f199b71 241 if ( param != BN_CLICKED )
f607434a 242 return false;
5f199b71 243
f607434a 244 if ( !m_isChecked )
f6bcfd97 245 {
f607434a
VZ
246 // we have to do this for BS_RADIOBUTTON anyhow and, strangely enough,
247 // sometimes this is needed even for BS_AUTORADIOBUTTON (when we
248 // receive focus the button gets BN_CLICKED but stays unchecked!)
249 SetValue(true);
2b5f62a0 250
5f199b71
VZ
251 wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, GetId());
252 event.SetEventObject( this );
f607434a 253 event.SetInt(true); // always checked
f6bcfd97 254
5f199b71
VZ
255 ProcessCommand(event);
256 }
f6bcfd97 257
f607434a 258 return true;
f6bcfd97 259}
2bda0e17 260
5f199b71
VZ
261// ----------------------------------------------------------------------------
262// wxRadioButton geometry
263// ----------------------------------------------------------------------------
264
265wxSize wxRadioButton::DoGetBestSize() const
2bda0e17 266{
5f199b71 267 static int s_radioSize = 0;
2bda0e17 268
5f199b71
VZ
269 if ( !s_radioSize )
270 {
271 wxScreenDC dc;
272 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
2bda0e17 273
5f199b71
VZ
274 s_radioSize = dc.GetCharHeight();
275 }
2bda0e17 276
5f199b71 277 wxString str = GetLabel();
2bda0e17 278
5f199b71
VZ
279 int wRadio, hRadio;
280 if ( !str.empty() )
281 {
282 GetTextExtent(str, &wRadio, &hRadio);
283 wRadio += s_radioSize + GetCharWidth();
2bda0e17 284
5f199b71
VZ
285 if ( hRadio < s_radioSize )
286 hRadio = s_radioSize;
287 }
288 else
289 {
290 wRadio = s_radioSize;
291 hRadio = s_radioSize;
292 }
2bda0e17 293
5f199b71 294 return wxSize(wRadio, hRadio);
2bda0e17
KB
295}
296
1e6feb95 297#endif // wxUSE_RADIOBTN
f607434a 298