]> git.saurik.com Git - wxWidgets.git/blame - src/msw/radiobut.cpp
Fixed style glitches
[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
2bda0e17 20#ifdef __GNUG__
c9baf9d7 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__
c9baf9d7 28#pragma hdrstop
2bda0e17
KB
29#endif
30
1e6feb95
VZ
31#if wxUSE_RADIOBTN
32
2bda0e17 33#ifndef WX_PRECOMP
c9baf9d7
RL
34#include "wx/radiobut.h"
35#include "wx/settings.h"
36#include "wx/brush.h"
37#include "wx/dcscreen.h"
2bda0e17
KB
38#endif
39
40#include "wx/msw/private.h"
41
5f199b71
VZ
42// ============================================================================
43// wxRadioButton implementation
44// ============================================================================
45
46// ----------------------------------------------------------------------------
47// wxRadioButton creation
48// ----------------------------------------------------------------------------
49
2bda0e17 50IMPLEMENT_DYNAMIC_CLASS(wxRadioButton, wxControl)
2bda0e17 51
5f199b71 52void wxRadioButton::Init()
621793f4 53{
5f199b71 54 m_focusJustSet = FALSE;
621793f4
JS
55}
56
5f199b71
VZ
57bool wxRadioButton::Create(wxWindow *parent,
58 wxWindowID id,
59 const wxString& label,
60 const wxPoint& pos,
61 const wxSize& size,
62 long style,
63 const wxValidator& validator,
64 const wxString& name)
2bda0e17 65{
5f199b71
VZ
66 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
67 return FALSE;
2bda0e17 68
2b5f62a0
VZ
69 long msStyle = WS_TABSTOP;
70 if ( HasFlag(wxRB_GROUP) )
71 msStyle |= WS_GROUP;
72
73 /*
74 wxRB_SINGLE is a temporary workaround for the following problem: if you
75 have 2 radiobuttons in the same group but which are not consecutive in
76 the dialog, Windows can enter an infinite loop! The simplest way to
77 reproduce it is to create radio button, then a panel and then another
78 radio button: then checking the last button hangs the app.
2bda0e17 79
2b5f62a0
VZ
80 Ideally, we'd detect (and avoid) such situation automatically but for
81 now, as I don't know how to do it, just allow the user to create
82 BS_RADIOBUTTON buttons for such situations.
83 */
84 msStyle |= HasFlag(wxRB_SINGLE) ? BS_RADIOBUTTON : BS_AUTORADIOBUTTON;
2bda0e17 85
5f199b71 86 if ( HasFlag(wxCLIP_SIBLINGS) )
b0766406
JS
87 msStyle |= WS_CLIPSIBLINGS;
88
5f199b71
VZ
89 if ( !MSWCreateControl(_T("BUTTON"), msStyle, pos, size, label, 0) )
90 return FALSE;
b0766406 91
5f199b71
VZ
92 // for compatibility with wxGTK, the first radio button in a group is
93 // always checked (this makes sense anyhow as you need to ensure that at
94 // least one button in the group is checked and this is the simlpest way to
95 // do it)
96 if ( HasFlag(wxRB_GROUP) )
97 SetValue(TRUE);
c085e333 98
5f199b71 99 return TRUE;
2bda0e17
KB
100}
101
5f199b71
VZ
102// ----------------------------------------------------------------------------
103// wxRadioButton functions
104// ----------------------------------------------------------------------------
2bda0e17 105
5f199b71 106void wxRadioButton::SetValue(bool value)
2bda0e17 107{
5f199b71 108 // BST_CHECKED is defined as 1, BST_UNCHECKED as 0, so we can just pass
2b5f62a0 109 // value as is (we don't use BST_XXX here as they're not defined for Win16)
5f199b71 110 (void)::SendMessage(GetHwnd(), BM_SETCHECK, (WPARAM)value, 0L);
2b5f62a0
VZ
111
112 // if we set the value of one radio button we also must clear all the other
113 // buttons in the same group: Windows doesn't do it automatically
114 if ( value )
115 {
116 const wxWindowList& siblings = GetParent()->GetChildren();
117 wxWindowList::Node *nodeThis = siblings.Find(this);
118 wxCHECK_RET( nodeThis, _T("radio button not a child of its parent?") );
119
2b17e391
VZ
120 // if it's not the first item of the group ...
121 if ( !HasFlag(wxRB_GROUP) )
2b5f62a0 122 {
2b17e391
VZ
123 // ... turn off all radio buttons before it
124 for ( wxWindowList::Node *nodeBefore = nodeThis->GetPrevious();
125 nodeBefore;
126 nodeBefore = nodeBefore->GetPrevious() )
2b5f62a0 127 {
2b17e391
VZ
128 wxRadioButton *btn = wxDynamicCast(nodeBefore->GetData(),
129 wxRadioButton);
130 if ( !btn )
131 {
132 // the radio buttons in a group must be consecutive, so
133 // there are no more of them
134 break;
135 }
136
137 btn->SetValue(FALSE);
138
139 if ( btn->HasFlag(wxRB_GROUP) )
140 {
141 // even if there are other radio buttons before this one,
142 // they're not in the same group with us
143 break;
144 }
2b5f62a0
VZ
145 }
146 }
147
2b17e391 148 // ... and also turn off all buttons after this one
2b5f62a0
VZ
149 for ( wxWindowList::Node *nodeAfter = nodeThis->GetNext();
150 nodeAfter;
151 nodeAfter = nodeAfter->GetNext() )
152 {
153 wxRadioButton *btn = wxDynamicCast(nodeAfter->GetData(),
154 wxRadioButton);
155
156 if ( !btn || btn->HasFlag(wxRB_GROUP) )
157 {
158 // no more buttons or the first button of the next group
159 break;
160 }
161
162 btn->SetValue(FALSE);
163 }
164 }
2bda0e17
KB
165}
166
5f199b71 167bool wxRadioButton::GetValue() const
2bda0e17 168{
5f199b71
VZ
169 // NB: this will also return TRUE for BST_INDETERMINATE value if we ever
170 // have 3-state radio buttons
171 return ::SendMessage(GetHwnd(), BM_GETCHECK, 0, 0L) != 0;
2bda0e17
KB
172}
173
5f199b71
VZ
174// ----------------------------------------------------------------------------
175// wxRadioButton event processing
176// ----------------------------------------------------------------------------
177
178void wxRadioButton::Command (wxCommandEvent& event)
2bda0e17 179{
5f199b71
VZ
180 SetValue(event.m_commandInt != 0);
181 ProcessCommand(event);
2bda0e17
KB
182}
183
5f199b71 184void wxRadioButton::SetFocus()
2bda0e17 185{
5f199b71
VZ
186 // when the radio button receives a WM_SETFOCUS message it generates a
187 // BN_CLICKED which is totally unexpected and leads to catastrophic results
188 // if you pop up a dialog from the radio button event handler as, when the
189 // dialog is dismissed, the focus is returned to the radio button which
190 // generates BN_CLICKED which leads to showing another dialog and so on
191 // without end!
192 //
2b5f62a0 193 // to avoid this, we drop the pseudo BN_CLICKED events generated when the
5f199b71
VZ
194 // button gains focus
195 m_focusJustSet = TRUE;
196
197 wxControl::SetFocus();
2bda0e17
KB
198}
199
5f199b71 200bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
f6bcfd97 201{
5f199b71
VZ
202 if ( param != BN_CLICKED )
203 return FALSE;
204
205 if ( m_focusJustSet )
f6bcfd97 206 {
5f199b71
VZ
207 // see above: we want to ignore this event
208 m_focusJustSet = FALSE;
f6bcfd97 209 }
5f199b71
VZ
210 else // a real clicked event
211 {
2b5f62a0
VZ
212 bool isChecked = GetValue();
213
214 if ( HasFlag(wxRB_SINGLE) )
215 {
216 // when we use a "manual" radio button, we have to check the button
217 // ourselves -- but it's reset to unchecked state by the user code
218 // (presumably when another button is pressed)
219 if ( !isChecked )
220 SetValue(TRUE);
221 }
222
5f199b71
VZ
223 wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, GetId());
224 event.SetEventObject( this );
2b5f62a0 225 event.SetInt(isChecked);
f6bcfd97 226
5f199b71
VZ
227 ProcessCommand(event);
228 }
f6bcfd97 229
5f199b71 230 return TRUE;
f6bcfd97 231}
2bda0e17 232
5f199b71
VZ
233// ----------------------------------------------------------------------------
234// wxRadioButton geometry
235// ----------------------------------------------------------------------------
236
237wxSize wxRadioButton::DoGetBestSize() const
2bda0e17 238{
5f199b71 239 static int s_radioSize = 0;
2bda0e17 240
5f199b71
VZ
241 if ( !s_radioSize )
242 {
243 wxScreenDC dc;
244 dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
2bda0e17 245
5f199b71
VZ
246 s_radioSize = dc.GetCharHeight();
247 }
2bda0e17 248
5f199b71 249 wxString str = GetLabel();
2bda0e17 250
5f199b71
VZ
251 int wRadio, hRadio;
252 if ( !str.empty() )
253 {
254 GetTextExtent(str, &wRadio, &hRadio);
255 wRadio += s_radioSize + GetCharWidth();
2bda0e17 256
5f199b71
VZ
257 if ( hRadio < s_radioSize )
258 hRadio = s_radioSize;
259 }
260 else
261 {
262 wRadio = s_radioSize;
263 hRadio = s_radioSize;
264 }
2bda0e17 265
5f199b71 266 return wxSize(wRadio, hRadio);
2bda0e17
KB
267}
268
aca78774
JS
269long wxRadioButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
270{
271 if (nMsg == WM_SETFOCUS)
272 {
273 m_focusJustSet = TRUE;
274
275 long ret = wxControl::MSWWindowProc(nMsg, wParam, lParam);
276
277 m_focusJustSet = FALSE;
278
279 return ret;
280 }
2b5f62a0 281 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
aca78774
JS
282}
283
1e6feb95 284#endif // wxUSE_RADIOBTN