1
2
3
4
5
6 using System;
7
8 namespace System.Windows
9 {
10 public ControlCreateParams& RadioButtonControlCreateParams(ControlCreateParams& controlCreateParams, ButtonStyle buttonStyle)
11 {
12 return controlCreateParams.SetWindowClassName("BUTTON").
13 SetWindowStyle(cast<WindowStyle>(DefaultChildWindowStyle() | WindowStyle.WS_TABSTOP | buttonStyle));
14 }
15
16 public ControlCreateParams& RadioButtonControlCreateParams(ControlCreateParams& controlCreateParams)
17 {
18 return RadioButtonControlCreateParams(controlCreateParams, cast<ButtonStyle>(ButtonStyle.BS_RADIOBUTTON | ButtonStyle.BS_NOTIFY));
19 }
20
21 public class RadioButtonCreateParams
22 {
23 public RadioButtonCreateParams(ControlCreateParams& controlCreateParams_) :
24 controlCreateParams(controlCreateParams_), autoSize(true)
25 {
26 }
27 public RadioButtonCreateParams& Defaults()
28 {
29 return *this;
30 }
31 public RadioButtonCreateParams& SetAutoSize(bool autoSize_)
32 {
33 autoSize = autoSize_;
34 return *this;
35 }
36 public ControlCreateParams& controlCreateParams;
37 public bool autoSize;
38 }
39
40 public class RadioButton : ButtonBase
41 {
42 private enum Flags : sbyte
43 {
44 none = 0, checked = 1 << 0, autoSize = 1 << 1, autoSized = 1 << 2
45 }
46
47 public RadioButton(const Color& backgroundColor, const string& text, const Point& location, const Size& size, Dock dock, Anchors anchors,
48 bool autoSize) : base("BUTTON", DefaultWindowClassStyle(),
49 cast<WindowStyle>(DefaultChildWindowStyle() | WindowStyle.WS_TABSTOP | ButtonStyle.BS_RADIOBUTTON | ButtonStyle.BS_NOTIFY),
50 DefaultExtendedWindowStyle(), backgroundColor, text, location, size, dock, anchors), flags(Flags.none)
51 {
52 if (autoSize)
53 {
54 SetAutoSizeFlag();
55 }
56 else
57 {
58 ResetAutoSizeFlag();
59 }
60 }
61 public RadioButton(const string& text, const Point& location, const Size& size, Dock dock, Anchors anchors, bool autoSize) :
62 this(DefaultControlBackgroundColor(), text, location, size, dock, anchors, autoSize)
63 {
64 }
65 public RadioButton(RadioButtonCreateParams& createParams) : base(createParams.controlCreateParams), flags(Flags.none)
66 {
67 if (createParams.autoSize)
68 {
69 SetAutoSizeFlag();
70 }
71 else
72 {
73 ResetAutoSizeFlag();
74 }
75 }
76 public bool Checked()
77 {
78 return GetCheckedFlag();
79 }
80 public void SetChecked(bool checked)
81 {
82 if (checked)
83 {
84 Control* parent = ParentControl();
85 if (parent != null)
86 {
87 if (parent is GroupBox*)
88 {
89 GroupBox* groupBox = cast<GroupBox*>(parent);
90 if (groupBox->CheckedRadioButton() != this)
91 {
92 groupBox->SetCheckedRadioButton(this);
93 }
94 }
95 }
96 SetCheckedFlag();
97 if (Handle() != null)
98 {
99 WinSendMessage(Handle(), BM_SETCHECK, BST_CHECKED, 0);
100 }
101 SetFocus();
102 }
103 else
104 {
105 Control* parent = ParentControl();
106 if (parent != null)
107 {
108 if (parent is GroupBox*)
109 {
110 GroupBox* groupBox = cast<GroupBox*>(parent);
111 if (groupBox->CheckedRadioButton() == this)
112 {
113 groupBox->ResetCheckedRadioButton();
114 }
115 }
116 }
117 ResetCheckedFlag();
118 if (Handle() != null)
119 {
120 WinSendMessage(Handle(), BM_SETCHECK, BST_UNCHECKED, 0);
121 }
122 }
123 }
124 protected override Result<bool> OnCreated()
125 {
126 auto result = base->OnCreated();
127 if (result.Error())
128 {
129 return Result<bool>(ErrorId(result.GetErrorId()));
130 }
131 auto graphicsResult = Graphics.FromWindowHandle(Handle());
132 if (graphicsResult.Error())
133 {
134 return Result<bool>(ErrorId(graphicsResult.GetErrorId()));
135 }
136 Graphics& graphics = graphicsResult.Value();
137 auto fontHandleResult = GetFontHandle(graphics);
138 if (fontHandleResult.Error())
139 {
140 return Result<bool>(ErrorId(fontHandleResult.GetErrorId()));
141 }
142 FontHandle* fontHandle = fontHandleResult.Value();
143 if (!fontHandle->IsNull())
144 {
145 SendSetFontMessage(*fontHandle);
146 }
147 if (GetCheckedFlag())
148 {
149 SetChecked(true);
150 }
151 else
152 {
153 SetChecked(false);
154 }
155 if (GetAutoSizeFlag())
156 {
157 auto result = DoAutoSize();
158 if (result.Error())
159 {
160 return Result<bool>(ErrorId(result.GetErrorId()));
161 }
162 }
163 return Result<bool>(true);
164 }
165 [nodiscard]
166 protected override Result<bool> OnClick(ClickEventArgs& args)
167 {
168 auto result = base->OnClick(args);
169 if (result.Error()) return result;
170 SetChecked(true);
171 return Result<bool>(true);
172 }
173 [nodiscard]
174 protected override Result<bool> OnTextChanged()
175 {
176 auto baseResult = base->OnTextChanged();
177 if (baseResult.Error())
178 {
179 return Result<bool>(ErrorId(baseResult.GetErrorId()));
180 }
181 if (GetAutoSizeFlag())
182 {
183 ResetAutoSized();
184 auto result = DoAutoSize();
185 if (result.Error())
186 {
187 return Result<bool>(ErrorId(result.GetErrorId()));
188 }
189 }
190 return Result<bool>(true);
191 }
192 protected virtual void OnCheckedChanged()
193 {
194 checkedChangedEvent.Fire();
195 }
196 public Event<CheckedChangedEventHandler>& CheckedChangedEvent() const
197 {
198 return checkedChangedEvent;
199 }
200 private void RetrieveCheckedState()
201 {
202 long result = WinSendMessage(Handle(), BM_GETCHECK, 0u, 0);
203 if (result == BST_CHECKED)
204 {
205 SetCheckedFlag();
206 }
207 else
208 {
209 ResetCheckedFlag();
210 }
211 }
212 [nodiscard]
213 private Result<bool> DoAutoSize()
214 {
215 if (AutoSized()) return Result<bool>(true);
216 if (Handle() == null) return Result<bool>(false);
217 auto graphicsResult = Graphics.FromWindowHandle(Handle());
218 if (graphicsResult.Error())
219 {
220 return Result<bool>(ErrorId(graphicsResult.GetErrorId()));
221 }
222 Graphics& graphics = graphicsResult.Value();
223 const Font& font = GetFont();
224 StringFormat stringFormat;
225 if (stringFormat.Error())
226 {
227 return Result<bool>(ErrorId(stringFormat.GetErrorId()));
228 }
229 auto measureResult = graphics.MeasureStringRectF(Text(), font, PointF(0, 0), stringFormat);
230 if (measureResult.Error())
231 {
232 return Result<bool>(ErrorId(measureResult.GetErrorId()));
233 }
234 RectF r = measureResult.Value();
235 Size buttonSize = GetButtonSize();
236 Size borderSize = GetBorderSize();
237 r.size.w = r.size.w + buttonSize.w + borderSize.w;
238 r.size.h = Max(r.size.h, buttonSize.h + borderSize.h);
239 auto result = SetSize(Size(cast<int>(r.size.w), cast<int>(r.size.h)));
240 if (result.Error()) return result;
241 SetAutoSized();
242 return Result<bool>(true);
243 }
244 private Size GetButtonSize()
245 {
246 int x = GetSystemMetrics(SystemMetricsId.SM_CXMENUCHECK);
247 int y = GetSystemMetrics(SystemMetricsId.SM_CYMENUCHECK);
248 return Size(x, y);
249 }
250 private Size GetBorderSize()
251 {
252 int x = GetSystemMetrics(SystemMetricsId.SM_CXBORDER);
253 int y = GetSystemMetrics(SystemMetricsId.SM_CYBORDER);
254 return Size(x, y);
255 }
256 private inline bool GetCheckedFlag() const
257 {
258 return (flags & Flags.checked) != Flags.none;
259 }
260 private void SetCheckedFlag()
261 {
262 if (!GetCheckedFlag())
263 {
264 flags = cast<Flags>(flags | Flags.checked);
265 OnCheckedChanged();
266 }
267 }
268 private void ResetCheckedFlag()
269 {
270 if (GetCheckedFlag())
271 {
272 flags = cast<Flags>(flags & ~Flags.checked);
273 OnCheckedChanged();
274 }
275 }
276 private inline bool GetAutoSizeFlag() const
277 {
278 return (flags & Flags.autoSize) != Flags.none;
279 }
280 private inline void SetAutoSizeFlag()
281 {
282 flags = cast<Flags>(flags | Flags.autoSize);
283 }
284 private inline void ResetAutoSizeFlag()
285 {
286 flags = cast<Flags>(flags & ~Flags.autoSize);
287 }
288 private inline bool AutoSized() const
289 {
290 return (flags & Flags.autoSized) != Flags.none;
291 }
292 private inline void SetAutoSized()
293 {
294 flags = cast<Flags>(flags | Flags.autoSized);
295 }
296 private inline void ResetAutoSized()
297 {
298 flags = cast<Flags>(flags & ~Flags.autoSized);
299 }
300 private Flags flags;
301 private Event<CheckedChangedEventHandler> checkedChangedEvent;
302 }