1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/radiobut.cpp
3 // Purpose: wxRadioButton
4 // Author: Julian Smart
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "radiobut.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
34 #include "wx/radiobut.h"
35 #include "wx/settings.h"
36 #include "wx/dcscreen.h"
39 #include "wx/msw/private.h"
41 // ============================================================================
42 // wxRadioButton implementation
43 // ============================================================================
45 // ----------------------------------------------------------------------------
46 // wxRadioButton creation
47 // ----------------------------------------------------------------------------
50 #if wxUSE_EXTENDED_RTTI
51 WX_DEFINE_FLAGS( wxRadioButtonStyle
)
53 wxBEGIN_FLAGS( wxRadioButtonStyle
)
54 // new style border flags, we put them first to
55 // use them for streaming out
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
)
63 // old style border flags
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
)
69 wxFLAGS_MEMBER(wxBORDER
)
71 // standard window styles
72 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
73 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
74 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
75 wxFLAGS_MEMBER(wxWANTS_CHARS
)
76 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
77 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
78 wxFLAGS_MEMBER(wxVSCROLL
)
79 wxFLAGS_MEMBER(wxHSCROLL
)
81 wxFLAGS_MEMBER(wxRB_GROUP
)
83 wxEND_FLAGS( wxRadioButtonStyle
)
85 IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioButton
, wxControl
,"wx/radiobut.h")
87 wxBEGIN_PROPERTIES_TABLE(wxRadioButton
)
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") )
92 wxPROPERTY_FLAGS( WindowStyle
, wxRadioButtonStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
93 wxEND_PROPERTIES_TABLE()
95 wxBEGIN_HANDLERS_TABLE(wxRadioButton
)
96 wxEND_HANDLERS_TABLE()
98 wxCONSTRUCTOR_6( wxRadioButton
, wxWindow
* , Parent
, wxWindowID
, Id
, wxString
, Label
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
101 IMPLEMENT_DYNAMIC_CLASS(wxRadioButton
, wxControl
)
105 wxRadioButton::wxRadioButton()
110 wxRadioButton::wxRadioButton(wxWindow
*parent
,
112 const wxString
& label
,
116 const wxValidator
& validator
,
117 const wxString
& name
)
121 Create(parent
, id
, label
, pos
, size
, style
, validator
, name
);
124 void wxRadioButton::Init()
129 bool wxRadioButton::Create(wxWindow
*parent
,
131 const wxString
& label
,
135 const wxValidator
& validator
,
136 const wxString
& name
)
138 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
141 long msStyle
= WS_TABSTOP
;
142 if ( HasFlag(wxRB_GROUP
) )
146 wxRB_SINGLE is a temporary workaround for the following problem: if you
147 have 2 radiobuttons in the same group but which are not consecutive in
148 the dialog, Windows can enter an infinite loop! The simplest way to
149 reproduce it is to create radio button, then a panel and then another
150 radio button: then checking the last button hangs the app.
152 Ideally, we'd detect (and avoid) such situation automatically but for
153 now, as I don't know how to do it, just allow the user to create
154 BS_RADIOBUTTON buttons for such situations.
156 msStyle
|= HasFlag(wxRB_SINGLE
) ? BS_RADIOBUTTON
: BS_AUTORADIOBUTTON
;
158 if ( HasFlag(wxCLIP_SIBLINGS
) )
159 msStyle
|= WS_CLIPSIBLINGS
;
161 if ( !MSWCreateControl(_T("BUTTON"), msStyle
, pos
, size
, label
, 0) )
164 // for compatibility with wxGTK, the first radio button in a group is
165 // always checked (this makes sense anyhow as you need to ensure that at
166 // least one button in the group is checked and this is the simlpest way to
168 if ( HasFlag(wxRB_GROUP
) )
174 // ----------------------------------------------------------------------------
175 // wxRadioButton functions
176 // ----------------------------------------------------------------------------
178 void wxRadioButton::SetValue(bool value
)
180 // BST_CHECKED is defined as 1, BST_UNCHECKED as 0, so we can just pass
181 // value as is (we don't use BST_XXX here as they're not defined for Win16)
182 (void)::SendMessage(GetHwnd(), BM_SETCHECK
, (WPARAM
)value
, 0L);
186 // if we set the value of one radio button we also must clear all the other
187 // buttons in the same group: Windows doesn't do it automatically
190 const wxWindowList
& siblings
= GetParent()->GetChildren();
191 wxWindowList::compatibility_iterator nodeThis
= siblings
.Find(this);
192 wxCHECK_RET( nodeThis
, _T("radio button not a child of its parent?") );
194 // if it's not the first item of the group ...
195 if ( !HasFlag(wxRB_GROUP
) )
197 // ... turn off all radio buttons before it
198 for ( wxWindowList::compatibility_iterator nodeBefore
= nodeThis
->GetPrevious();
200 nodeBefore
= nodeBefore
->GetPrevious() )
202 wxRadioButton
*btn
= wxDynamicCast(nodeBefore
->GetData(),
206 // the radio buttons in a group must be consecutive, so
207 // there are no more of them
211 btn
->SetValue(false);
213 if ( btn
->HasFlag(wxRB_GROUP
) )
215 // even if there are other radio buttons before this one,
216 // they're not in the same group with us
222 // ... and also turn off all buttons after this one
223 for ( wxWindowList::compatibility_iterator nodeAfter
= nodeThis
->GetNext();
225 nodeAfter
= nodeAfter
->GetNext() )
227 wxRadioButton
*btn
= wxDynamicCast(nodeAfter
->GetData(),
230 if ( !btn
|| btn
->HasFlag(wxRB_GROUP
) )
232 // no more buttons or the first button of the next group
236 btn
->SetValue(false);
241 bool wxRadioButton::GetValue() const
243 wxASSERT_MSG( m_isChecked
==
244 (::SendMessage(GetHwnd(), BM_GETCHECK
, 0, 0L) != 0),
245 _T("wxRadioButton::m_isChecked is out of sync?") );
250 // ----------------------------------------------------------------------------
251 // wxRadioButton event processing
252 // ----------------------------------------------------------------------------
254 void wxRadioButton::Command (wxCommandEvent
& event
)
256 SetValue(event
.m_commandInt
!= 0);
257 ProcessCommand(event
);
260 bool wxRadioButton::MSWCommand(WXUINT param
, WXWORD
WXUNUSED(id
))
262 if ( param
!= BN_CLICKED
)
267 // we have to do this for BS_RADIOBUTTON anyhow and, strangely enough,
268 // sometimes this is needed even for BS_AUTORADIOBUTTON (when we
269 // receive focus the button gets BN_CLICKED but stays unchecked!)
272 wxCommandEvent
event(wxEVT_COMMAND_RADIOBUTTON_SELECTED
, GetId());
273 event
.SetEventObject( this );
274 event
.SetInt(true); // always checked
276 ProcessCommand(event
);
282 // ----------------------------------------------------------------------------
283 // wxRadioButton geometry
284 // ----------------------------------------------------------------------------
286 wxSize
wxRadioButton::DoGetBestSize() const
288 static int s_radioSize
= 0;
293 dc
.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
));
295 s_radioSize
= dc
.GetCharHeight();
298 wxString str
= GetLabel();
303 GetTextExtent(str
, &wRadio
, &hRadio
);
304 wRadio
+= s_radioSize
+ GetCharWidth();
306 if ( hRadio
< s_radioSize
)
307 hRadio
= s_radioSize
;
311 wRadio
= s_radioSize
;
312 hRadio
= s_radioSize
;
315 return wxSize(wRadio
, hRadio
);
318 #endif // wxUSE_RADIOBTN