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 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
30 #include "wx/radiobut.h"
31 #include "wx/settings.h"
32 #include "wx/dcscreen.h"
35 #include "wx/msw/private.h"
37 // ============================================================================
38 // wxRadioButton implementation
39 // ============================================================================
41 // ----------------------------------------------------------------------------
42 // wxRadioButton creation
43 // ----------------------------------------------------------------------------
46 #if wxUSE_EXTENDED_RTTI
47 WX_DEFINE_FLAGS( wxRadioButtonStyle
)
49 wxBEGIN_FLAGS( wxRadioButtonStyle
)
50 // new style border flags, we put them first to
51 // use them for streaming out
52 wxFLAGS_MEMBER(wxBORDER_SIMPLE
)
53 wxFLAGS_MEMBER(wxBORDER_SUNKEN
)
54 wxFLAGS_MEMBER(wxBORDER_DOUBLE
)
55 wxFLAGS_MEMBER(wxBORDER_RAISED
)
56 wxFLAGS_MEMBER(wxBORDER_STATIC
)
57 wxFLAGS_MEMBER(wxBORDER_NONE
)
59 // old style border flags
60 wxFLAGS_MEMBER(wxSIMPLE_BORDER
)
61 wxFLAGS_MEMBER(wxSUNKEN_BORDER
)
62 wxFLAGS_MEMBER(wxDOUBLE_BORDER
)
63 wxFLAGS_MEMBER(wxRAISED_BORDER
)
64 wxFLAGS_MEMBER(wxSTATIC_BORDER
)
65 wxFLAGS_MEMBER(wxBORDER
)
67 // standard window styles
68 wxFLAGS_MEMBER(wxTAB_TRAVERSAL
)
69 wxFLAGS_MEMBER(wxCLIP_CHILDREN
)
70 wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW
)
71 wxFLAGS_MEMBER(wxWANTS_CHARS
)
72 wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE
)
73 wxFLAGS_MEMBER(wxALWAYS_SHOW_SB
)
74 wxFLAGS_MEMBER(wxVSCROLL
)
75 wxFLAGS_MEMBER(wxHSCROLL
)
77 wxFLAGS_MEMBER(wxRB_GROUP
)
79 wxEND_FLAGS( wxRadioButtonStyle
)
81 IMPLEMENT_DYNAMIC_CLASS_XTI(wxRadioButton
, wxControl
,"wx/radiobut.h")
83 wxBEGIN_PROPERTIES_TABLE(wxRadioButton
)
84 wxEVENT_PROPERTY( Click
, wxEVT_COMMAND_RADIOBUTTON_SELECTED
, wxCommandEvent
)
85 wxPROPERTY( Font
, wxFont
, SetFont
, GetFont
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group"))
86 wxPROPERTY( Label
,wxString
, SetLabel
, GetLabel
, wxString(), 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
87 wxPROPERTY( Value
,bool, SetValue
, GetValue
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group") )
88 wxPROPERTY_FLAGS( WindowStyle
, wxRadioButtonStyle
, long , SetWindowStyleFlag
, GetWindowStyleFlag
, EMPTY_MACROVALUE
, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style
89 wxEND_PROPERTIES_TABLE()
91 wxBEGIN_HANDLERS_TABLE(wxRadioButton
)
92 wxEND_HANDLERS_TABLE()
94 wxCONSTRUCTOR_6( wxRadioButton
, wxWindow
* , Parent
, wxWindowID
, Id
, wxString
, Label
, wxPoint
, Position
, wxSize
, Size
, long , WindowStyle
)
97 IMPLEMENT_DYNAMIC_CLASS(wxRadioButton
, wxControl
)
101 void wxRadioButton::Init()
106 bool wxRadioButton::Create(wxWindow
*parent
,
108 const wxString
& label
,
112 const wxValidator
& validator
,
113 const wxString
& name
)
115 if ( !CreateControl(parent
, id
, pos
, size
, style
, validator
, name
) )
118 long msStyle
= WS_TABSTOP
;
119 if ( HasFlag(wxRB_GROUP
) )
123 wxRB_SINGLE is a temporary workaround for the following problem: if you
124 have 2 radiobuttons in the same group but which are not consecutive in
125 the dialog, Windows can enter an infinite loop! The simplest way to
126 reproduce it is to create radio button, then a panel and then another
127 radio button: then checking the last button hangs the app.
129 Ideally, we'd detect (and avoid) such situation automatically but for
130 now, as I don't know how to do it, just allow the user to create
131 BS_RADIOBUTTON buttons for such situations.
133 msStyle
|= HasFlag(wxRB_SINGLE
) ? BS_RADIOBUTTON
: BS_AUTORADIOBUTTON
;
135 if ( HasFlag(wxCLIP_SIBLINGS
) )
136 msStyle
|= WS_CLIPSIBLINGS
;
137 if ( HasFlag(wxALIGN_RIGHT
) )
138 msStyle
|= BS_LEFTTEXT
| BS_RIGHT
;
140 if ( !MSWCreateControl(_T("BUTTON"), msStyle
, pos
, size
, label
, 0) )
143 // for compatibility with wxGTK, the first radio button in a group is
144 // always checked (this makes sense anyhow as you need to ensure that at
145 // least one button in the group is checked and this is the simlpest way to
147 if ( HasFlag(wxRB_GROUP
) )
153 // ----------------------------------------------------------------------------
154 // wxRadioButton functions
155 // ----------------------------------------------------------------------------
157 void wxRadioButton::SetValue(bool value
)
159 (void)::SendMessage(GetHwnd(), BM_SETCHECK
, (value
?BST_CHECKED
:BST_UNCHECKED
), 0L);
163 // if we set the value of one radio button we also must clear all the other
164 // buttons in the same group: Windows doesn't do it automatically
167 // If another radiobutton in the group currently has the focus, we have to
168 // set it to this radiobutton, else the old readiobutton will be reselected
169 // automatically, if a parent window loses the focus and regains it.
170 bool shouldSetFocus
= false;
171 wxWindow
* pFocusWnd
= FindFocus();
173 const wxWindowList
& siblings
= GetParent()->GetChildren();
174 wxWindowList::compatibility_iterator nodeThis
= siblings
.Find(this);
175 wxCHECK_RET( nodeThis
, _T("radio button not a child of its parent?") );
177 // if it's not the first item of the group ...
178 if ( !HasFlag(wxRB_GROUP
) )
180 // ... turn off all radio buttons before it
181 for ( wxWindowList::compatibility_iterator nodeBefore
= nodeThis
->GetPrevious();
183 nodeBefore
= nodeBefore
->GetPrevious() )
185 wxRadioButton
*btn
= wxDynamicCast(nodeBefore
->GetData(),
187 if ( btn
&& btn
->HasFlag(wxRB_SINGLE
) )
189 // A wxRB_SINGLE button isn't part of this group
195 if (btn
== pFocusWnd
)
196 shouldSetFocus
= true;
198 btn
->SetValue(false);
200 if ( btn
->HasFlag(wxRB_GROUP
) )
202 // even if there are other radio buttons before this one,
203 // they're not in the same group with us
210 // ... and also turn off all buttons after this one
211 for ( wxWindowList::compatibility_iterator nodeAfter
= nodeThis
->GetNext();
213 nodeAfter
= nodeAfter
->GetNext() )
215 wxRadioButton
*btn
= wxDynamicCast(nodeAfter
->GetData(),
218 if ( btn
&& (btn
->HasFlag(wxRB_GROUP
) || btn
->HasFlag(wxRB_SINGLE
) ) )
220 // no more buttons or the first button of the next group
226 if (btn
== pFocusWnd
)
227 shouldSetFocus
= true;
229 btn
->SetValue(false);
237 bool wxRadioButton::GetValue() const
239 wxASSERT_MSG( m_isChecked
==
240 (::SendMessage(GetHwnd(), BM_GETCHECK
, 0, 0L) != 0),
241 _T("wxRadioButton::m_isChecked is out of sync?") );
246 // ----------------------------------------------------------------------------
247 // wxRadioButton event processing
248 // ----------------------------------------------------------------------------
250 void wxRadioButton::Command (wxCommandEvent
& event
)
252 SetValue(event
.GetInt() != 0);
253 ProcessCommand(event
);
256 bool wxRadioButton::MSWCommand(WXUINT param
, WXWORD
WXUNUSED(id
))
258 if ( param
!= BN_CLICKED
)
263 // we have to do this for BS_RADIOBUTTON anyhow and, strangely enough,
264 // sometimes this is needed even for BS_AUTORADIOBUTTON (when we
265 // receive focus the button gets BN_CLICKED but stays unchecked!)
268 wxCommandEvent
event(wxEVT_COMMAND_RADIOBUTTON_SELECTED
, GetId());
269 event
.SetEventObject( this );
270 event
.SetInt(true); // always checked
272 ProcessCommand(event
);
278 // ----------------------------------------------------------------------------
279 // wxRadioButton geometry
280 // ----------------------------------------------------------------------------
282 wxSize
wxRadioButton::DoGetBestSize() const
284 static int s_radioSize
= 0;
289 dc
.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
));
291 s_radioSize
= dc
.GetCharHeight();
294 wxString str
= GetLabel();
299 GetTextExtent(wxStripMenuCodes(str
), &wRadio
, &hRadio
);
300 wRadio
+= s_radioSize
+ GetCharWidth();
302 if ( hRadio
< s_radioSize
)
303 hRadio
= s_radioSize
;
307 wRadio
= s_radioSize
;
308 hRadio
= s_radioSize
;
311 wxSize
best(wRadio
, hRadio
);
316 #endif // wxUSE_RADIOBTN