]> git.saurik.com Git - wxWidgets.git/blame - src/msw/radiobut.cpp
Don't use DDEExec registry key in wxMSW wxExecute() if it's empty.
[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
6c9a19aa 7// Copyright: (c) Julian Smart
65571936 8// Licence: wxWindows licence
2bda0e17
KB
9/////////////////////////////////////////////////////////////////////////////
10
5f199b71
VZ
11// ============================================================================
12// declarations
13// ============================================================================
14
15// ----------------------------------------------------------------------------
16// headers
17// ----------------------------------------------------------------------------
18
2bda0e17
KB
19// For compilers that support precompilation, includes "wx.h".
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
f607434a 23 #pragma hdrstop
2bda0e17
KB
24#endif
25
1e6feb95
VZ
26#if wxUSE_RADIOBTN
27
b0b5881a
WS
28#include "wx/radiobut.h"
29
2bda0e17 30#ifndef WX_PRECOMP
f607434a
VZ
31 #include "wx/settings.h"
32 #include "wx/dcscreen.h"
6b81a8ea 33 #include "wx/toplevel.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
5f199b71 46void wxRadioButton::Init()
621793f4 47{
f607434a 48 m_isChecked = false;
621793f4
JS
49}
50
5f199b71
VZ
51bool wxRadioButton::Create(wxWindow *parent,
52 wxWindowID id,
53 const wxString& label,
54 const wxPoint& pos,
55 const wxSize& size,
56 long style,
57 const wxValidator& validator,
58 const wxString& name)
2bda0e17 59{
5f199b71 60 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
f607434a 61 return false;
2bda0e17 62
687823a1
VZ
63 WXDWORD exstyle = 0;
64 WXDWORD msStyle = MSWGetStyle(style, &exstyle);
2b5f62a0 65
687823a1 66 if ( !MSWCreateControl(wxT("BUTTON"), msStyle, pos, size, label, exstyle) )
f607434a 67 return false;
b0766406 68
5f199b71
VZ
69 // for compatibility with wxGTK, the first radio button in a group is
70 // always checked (this makes sense anyhow as you need to ensure that at
cb738de0 71 // least one button in the group is checked and this is the simplest way to
5f199b71
VZ
72 // do it)
73 if ( HasFlag(wxRB_GROUP) )
f607434a 74 SetValue(true);
c085e333 75
f607434a 76 return true;
2bda0e17
KB
77}
78
5f199b71
VZ
79// ----------------------------------------------------------------------------
80// wxRadioButton functions
81// ----------------------------------------------------------------------------
2bda0e17 82
5f199b71 83void wxRadioButton::SetValue(bool value)
2bda0e17 84{
48fbe8ee
VZ
85 ::SendMessage(GetHwnd(), BM_SETCHECK,
86 value ? BST_CHECKED : BST_UNCHECKED, 0);
2b5f62a0 87
f607434a
VZ
88 m_isChecked = value;
89
48fbe8ee
VZ
90 if ( !value )
91 return;
92
2b5f62a0
VZ
93 // if we set the value of one radio button we also must clear all the other
94 // buttons in the same group: Windows doesn't do it automatically
48fbe8ee
VZ
95 //
96 // moreover, if another radiobutton in the group currently has the focus,
cb738de0 97 // we have to set it to this radiobutton, else the old radiobutton will be
48fbe8ee
VZ
98 // reselected automatically, if a parent window loses the focus and regains
99 // it.
100 wxWindow * const focus = FindFocus();
101 wxTopLevelWindow * const
102 tlw = wxDynamicCast(wxGetTopLevelParent(this), wxTopLevelWindow);
9a83f860 103 wxCHECK_RET( tlw, wxT("radio button outside of TLW?") );
48fbe8ee
VZ
104 wxWindow * const focusInTLW = tlw->GetLastFocus();
105
106 const wxWindowList& siblings = GetParent()->GetChildren();
107 wxWindowList::compatibility_iterator nodeThis = siblings.Find(this);
9a83f860 108 wxCHECK_RET( nodeThis, wxT("radio button not a child of its parent?") );
48fbe8ee
VZ
109
110 // this will be set to true in the code below if the focus is in our TLW
111 // and belongs to one of the other buttons in the same group
112 bool shouldSetFocus = false;
113
114 // this will be set to true if the focus is outside of our TLW currently
115 // but the remembered focus of this TLW is one of the other buttons in the
116 // same group
117 bool shouldSetTLWFocus = false;
118
119 // if it's not the first item of the group ...
120 if ( !HasFlag(wxRB_GROUP) )
2b5f62a0 121 {
48fbe8ee
VZ
122 // ... turn off all radio buttons before it
123 for ( wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious();
124 nodeBefore;
125 nodeBefore = nodeBefore->GetPrevious() )
2b5f62a0 126 {
48fbe8ee
VZ
127 wxRadioButton *btn = wxDynamicCast(nodeBefore->GetData(),
128 wxRadioButton);
129 if ( !btn )
2b5f62a0 130 {
48fbe8ee
VZ
131 // don't stop on non radio buttons, we could have intermixed
132 // buttons and e.g. static labels
133 continue;
134 }
135
136 if ( btn->HasFlag(wxRB_SINGLE) )
2b17e391 137 {
c5b3143a 138 // A wxRB_SINGLE button isn't part of this group
2b17e391
VZ
139 break;
140 }
b0b5881a 141
48fbe8ee
VZ
142 if ( btn == focus )
143 shouldSetFocus = true;
144 else if ( btn == focusInTLW )
145 shouldSetTLWFocus = true;
c5b3143a 146
48fbe8ee 147 btn->SetValue(false);
2b5f62a0 148
48fbe8ee 149 if ( btn->HasFlag(wxRB_GROUP) )
2b5f62a0 150 {
48fbe8ee
VZ
151 // even if there are other radio buttons before this one,
152 // they're not in the same group with us
2b5f62a0
VZ
153 break;
154 }
48fbe8ee
VZ
155 }
156 }
2b5f62a0 157
48fbe8ee
VZ
158 // ... and also turn off all buttons after this one
159 for ( wxWindowList::compatibility_iterator nodeAfter = nodeThis->GetNext();
160 nodeAfter;
161 nodeAfter = nodeAfter->GetNext() )
162 {
163 wxRadioButton *btn = wxDynamicCast(nodeAfter->GetData(),
164 wxRadioButton);
f469584d 165
48fbe8ee
VZ
166 if ( !btn )
167 continue;
168
169 if ( btn->HasFlag(wxRB_GROUP | wxRB_SINGLE) )
170 {
171 // no more buttons or the first button of the next group
172 break;
2b5f62a0 173 }
48fbe8ee
VZ
174
175 if ( btn == focus )
176 shouldSetFocus = true;
177 else if ( btn == focusInTLW )
178 shouldSetTLWFocus = true;
179
180 btn->SetValue(false);
2b5f62a0 181 }
48fbe8ee
VZ
182
183 if ( shouldSetFocus )
184 SetFocus();
185 else if ( shouldSetTLWFocus )
186 tlw->SetLastFocus(this);
2bda0e17
KB
187}
188
5f199b71 189bool wxRadioButton::GetValue() const
2bda0e17 190{
f607434a
VZ
191 wxASSERT_MSG( m_isChecked ==
192 (::SendMessage(GetHwnd(), BM_GETCHECK, 0, 0L) != 0),
9a83f860 193 wxT("wxRadioButton::m_isChecked is out of sync?") );
f607434a
VZ
194
195 return m_isChecked;
2bda0e17
KB
196}
197
5f199b71
VZ
198// ----------------------------------------------------------------------------
199// wxRadioButton event processing
200// ----------------------------------------------------------------------------
201
202void wxRadioButton::Command (wxCommandEvent& event)
2bda0e17 203{
687706f5 204 SetValue(event.GetInt() != 0);
5f199b71 205 ProcessCommand(event);
2bda0e17
KB
206}
207
5f199b71 208bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
f6bcfd97 209{
5f199b71 210 if ( param != BN_CLICKED )
f607434a 211 return false;
5f199b71 212
f607434a 213 if ( !m_isChecked )
f6bcfd97 214 {
cb738de0
VZ
215 // we need to manually update the button state as we use BS_RADIOBUTTON
216 // and not BS_AUTORADIOBUTTON
f607434a 217 SetValue(true);
2b5f62a0 218
ce7fe42e 219 wxCommandEvent event(wxEVT_RADIOBUTTON, GetId());
5f199b71 220 event.SetEventObject( this );
f607434a 221 event.SetInt(true); // always checked
f6bcfd97 222
5f199b71
VZ
223 ProcessCommand(event);
224 }
f6bcfd97 225
f607434a 226 return true;
f6bcfd97 227}
2bda0e17 228
5f199b71
VZ
229// ----------------------------------------------------------------------------
230// wxRadioButton geometry
231// ----------------------------------------------------------------------------
232
233wxSize wxRadioButton::DoGetBestSize() const
2bda0e17 234{
5f199b71 235 static int s_radioSize = 0;
2bda0e17 236
5f199b71
VZ
237 if ( !s_radioSize )
238 {
239 wxScreenDC dc;
240 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
2bda0e17 241
5f199b71 242 s_radioSize = dc.GetCharHeight();
7eee3607
VZ
243
244 // radio button bitmap size under CE is bigger than the font height,
245 // adding just one pixel seems to work fine for the default font but it
246 // would be nice to find some better way to find the correct height
247#ifdef __WXWINCE__
248 s_radioSize++;
249#endif // __WXWINCE__
5f199b71 250 }
2bda0e17 251
5f199b71 252 wxString str = GetLabel();
2bda0e17 253
5f199b71
VZ
254 int wRadio, hRadio;
255 if ( !str.empty() )
256 {
32cd189d 257 GetTextExtent(GetLabelText(str), &wRadio, &hRadio);
5f199b71 258 wRadio += s_radioSize + GetCharWidth();
2bda0e17 259
5f199b71
VZ
260 if ( hRadio < s_radioSize )
261 hRadio = s_radioSize;
262 }
263 else
264 {
265 wRadio = s_radioSize;
266 hRadio = s_radioSize;
267 }
2bda0e17 268
31582e4e
RD
269 wxSize best(wRadio, hRadio);
270 CacheBestSize(best);
271 return best;
2bda0e17
KB
272}
273
bec08b39
VZ
274WXDWORD wxRadioButton::MSWGetStyle(long style, WXDWORD *exstyle) const
275{
687823a1
VZ
276 WXDWORD msStyle = wxControl::MSWGetStyle(style, exstyle);
277
278 if ( HasFlag(wxRB_GROUP) )
279 msStyle |= WS_GROUP;
280
281 // we use BS_RADIOBUTTON and not BS_AUTORADIOBUTTON because the use of the
282 // latter can easily result in the application entering an infinite loop
283 // inside IsDialogMessage()
284 //
285 // we used to use BS_RADIOBUTTON only for wxRB_SINGLE buttons but there
286 // doesn't seem to be any harm to always use it and it prevents some hangs,
287 // see #9786
288 msStyle |= BS_RADIOBUTTON;
289
290 if ( style & wxCLIP_SIBLINGS )
291 msStyle |= WS_CLIPSIBLINGS;
292 if ( style & wxALIGN_RIGHT )
293 msStyle |= BS_LEFTTEXT | BS_RIGHT;
bec08b39 294
bec08b39 295
687823a1 296 return msStyle;
bec08b39
VZ
297}
298
1e6feb95 299#endif // wxUSE_RADIOBTN