]> git.saurik.com Git - wxWidgets.git/blame - src/msw/radiobut.cpp
create the DIBs in correct (and not down up) line order
[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
120 // turn off all radio buttons before this one
121 for ( wxWindowList::Node *nodeBefore = nodeThis->GetPrevious();
122 nodeBefore;
123 nodeBefore = nodeBefore->GetPrevious() )
124 {
125 wxRadioButton *btn = wxDynamicCast(nodeBefore->GetData(),
126 wxRadioButton);
127 if ( !btn )
128 {
129 // the radio buttons in a group must be consecutive, so there
130 // are no more of them
131 break;
132 }
133
134 btn->SetValue(FALSE);
135
136 if ( btn->HasFlag(wxRB_GROUP) )
137 {
138 // even if there are other radio buttons before this one,
139 // they're not in the same group with us
140 break;
141 }
142 }
143
144 // ... and all after this one
145 for ( wxWindowList::Node *nodeAfter = nodeThis->GetNext();
146 nodeAfter;
147 nodeAfter = nodeAfter->GetNext() )
148 {
149 wxRadioButton *btn = wxDynamicCast(nodeAfter->GetData(),
150 wxRadioButton);
151
152 if ( !btn || btn->HasFlag(wxRB_GROUP) )
153 {
154 // no more buttons or the first button of the next group
155 break;
156 }
157
158 btn->SetValue(FALSE);
159 }
160 }
2bda0e17
KB
161}
162
5f199b71 163bool wxRadioButton::GetValue() const
2bda0e17 164{
5f199b71
VZ
165 // NB: this will also return TRUE for BST_INDETERMINATE value if we ever
166 // have 3-state radio buttons
167 return ::SendMessage(GetHwnd(), BM_GETCHECK, 0, 0L) != 0;
2bda0e17
KB
168}
169
5f199b71
VZ
170// ----------------------------------------------------------------------------
171// wxRadioButton event processing
172// ----------------------------------------------------------------------------
173
174void wxRadioButton::Command (wxCommandEvent& event)
2bda0e17 175{
5f199b71
VZ
176 SetValue(event.m_commandInt != 0);
177 ProcessCommand(event);
2bda0e17
KB
178}
179
5f199b71 180void wxRadioButton::SetFocus()
2bda0e17 181{
5f199b71
VZ
182 // when the radio button receives a WM_SETFOCUS message it generates a
183 // BN_CLICKED which is totally unexpected and leads to catastrophic results
184 // if you pop up a dialog from the radio button event handler as, when the
185 // dialog is dismissed, the focus is returned to the radio button which
186 // generates BN_CLICKED which leads to showing another dialog and so on
187 // without end!
188 //
2b5f62a0 189 // to avoid this, we drop the pseudo BN_CLICKED events generated when the
5f199b71
VZ
190 // button gains focus
191 m_focusJustSet = TRUE;
192
193 wxControl::SetFocus();
2bda0e17
KB
194}
195
5f199b71 196bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
f6bcfd97 197{
5f199b71
VZ
198 if ( param != BN_CLICKED )
199 return FALSE;
200
201 if ( m_focusJustSet )
f6bcfd97 202 {
5f199b71
VZ
203 // see above: we want to ignore this event
204 m_focusJustSet = FALSE;
f6bcfd97 205 }
5f199b71
VZ
206 else // a real clicked event
207 {
2b5f62a0
VZ
208 bool isChecked = GetValue();
209
210 if ( HasFlag(wxRB_SINGLE) )
211 {
212 // when we use a "manual" radio button, we have to check the button
213 // ourselves -- but it's reset to unchecked state by the user code
214 // (presumably when another button is pressed)
215 if ( !isChecked )
216 SetValue(TRUE);
217 }
218
5f199b71
VZ
219 wxCommandEvent event(wxEVT_COMMAND_RADIOBUTTON_SELECTED, GetId());
220 event.SetEventObject( this );
2b5f62a0 221 event.SetInt(isChecked);
f6bcfd97 222
5f199b71
VZ
223 ProcessCommand(event);
224 }
f6bcfd97 225
5f199b71 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
VZ
242 s_radioSize = dc.GetCharHeight();
243 }
2bda0e17 244
5f199b71 245 wxString str = GetLabel();
2bda0e17 246
5f199b71
VZ
247 int wRadio, hRadio;
248 if ( !str.empty() )
249 {
250 GetTextExtent(str, &wRadio, &hRadio);
251 wRadio += s_radioSize + GetCharWidth();
2bda0e17 252
5f199b71
VZ
253 if ( hRadio < s_radioSize )
254 hRadio = s_radioSize;
255 }
256 else
257 {
258 wRadio = s_radioSize;
259 hRadio = s_radioSize;
260 }
2bda0e17 261
5f199b71 262 return wxSize(wRadio, hRadio);
2bda0e17
KB
263}
264
aca78774
JS
265long wxRadioButton::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
266{
267 if (nMsg == WM_SETFOCUS)
268 {
269 m_focusJustSet = TRUE;
270
271 long ret = wxControl::MSWWindowProc(nMsg, wParam, lParam);
272
273 m_focusJustSet = FALSE;
274
275 return ret;
276 }
2b5f62a0 277 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
aca78774
JS
278}
279
1e6feb95 280#endif // wxUSE_RADIOBTN