1 // =================================
  2 // Copyright (c) 2021 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 
  8 namespace System.Windows
  9 {
 10     public nothrow ControlCreateParams& RadioButtonControlCreateParams(ControlCreateParams& controlCreateParamsButtonStyle buttonStyle)
 11     {
 12         return controlCreateParams.SetWindowClassName("BUTTON").
 13             SetWindowStyle(cast<WindowStyle>(DefaultChildWindowStyle() | WindowStyle.WS_TABSTOP | buttonStyle));
 14     }
 15 
 16     public nothrow ControlCreateParams& RadioButtonControlCreateParams(ControlCreateParams& controlCreateParams)
 17     {
 18         return RadioButtonControlCreateParams(controlCreateParamscast<ButtonStyle>(ButtonStyle.BS_RADIOBUTTON | ButtonStyle.BS_NOTIFY));
 19     }
 20     
 21     public class RadioButtonCreateParams
 22     {
 23         public nothrow RadioButtonCreateParams(ControlCreateParams& controlCreateParams_) : 
 24             controlCreateParams(controlCreateParams_)autoSize(true)
 25         {
 26         }
 27         public nothrow RadioButtonCreateParams& Defaults()
 28         {
 29             return *this;
 30         }
 31         public nothrow 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 = 0checked = 1 << 0autoSize = 1 << 1autoSized = 1 << 2
 45         }
 46 
 47         public RadioButton(const Color& backgroundColorconst string& textconst Point& locationconst Size& sizeDock dockAnchors anchors
 48             bool autoSize) : base("BUTTON"DefaultWindowClassStyle()
 49             cast<WindowStyle>(DefaultChildWindowStyle() | WindowStyle.WS_TABSTOP | ButtonStyle.BS_RADIOBUTTON | ButtonStyle.BS_NOTIFY)
 50             DefaultExtendedWindowStyle()backgroundColortextlocationsizedockanchors)flags(Flags.none)
 51         {
 52             if (autoSize)
 53             {
 54                 SetAutoSizeFlag();
 55             }
 56             else
 57             {
 58                 ResetAutoSizeFlag();
 59             }
 60         }
 61         public RadioButton(const string& textconst Point& locationconst Size& sizeDock dockAnchors anchorsbool autoSize) : 
 62             this(DefaultControlBackgroundColor()textlocationsizedockanchorsautoSize)
 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_SETCHECKBST_CHECKED0);
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_SETCHECKBST_UNCHECKED0);
121                 }
122             }
123         }
124         protected override void OnCreated()
125         {
126             base->OnCreated();
127             Graphics graphics = Graphics.FromWindowHandle(Handle());
128             const FontHandle& fontHandle = GetFontHandle(graphics);
129             if (!fontHandle.IsNull())
130             {
131                 SendSetFontMessage(fontHandle);
132             }
133             if (GetCheckedFlag())
134             {
135                 SetChecked(true);
136             }
137             else
138             {
139                 SetChecked(false);
140             }
141             if (GetAutoSizeFlag())
142             {
143                 DoAutoSize();
144             }
145         }
146         protected override void OnClick()
147         {
148             base->OnClick();
149             SetChecked(true);
150         }
151         protected override void OnTextChanged()
152         {
153             base->OnTextChanged();
154             if (GetAutoSizeFlag())
155             {
156                 ResetAutoSized();
157                 DoAutoSize();
158             }
159         }
160         protected virtual void OnCheckedChanged()
161         {
162             checkedChangedEvent.Fire();
163         }
164         public nothrow Event<CheckedChangedEventHandler>& CheckedChangedEvent() const
165         {
166             return checkedChangedEvent;
167         }
168         private void RetrieveCheckedState()
169         {
170             long result = WinSendMessage(Handle()BM_GETCHECK0u0);
171             if (result == BST_CHECKED)
172             {
173                 SetCheckedFlag();
174             }
175             else
176             {
177                 ResetCheckedFlag();
178             }
179         }
180         private void DoAutoSize()
181         {
182             if (AutoSized()) return;
183             if (Handle() == null) return;
184             Graphics graphics = Graphics.FromWindowHandle(Handle());
185             const Font& font = GetFont();
186             StringFormat stringFormat;
187             RectF r = graphics.MeasureStringChecked(Text()fontPointF(00)stringFormat);
188             Size buttonSize = GetButtonSize();
189             Size borderSize = GetBorderSize();
190             r.size.w = r.size.w + buttonSize.w + borderSize.w;
191             r.size.h = Max(r.size.hbuttonSize.h + borderSize.h);
192             SetSize(Size(cast<int>(r.size.w)cast<int>(r.size.h)));
193             SetAutoSized();
194         }
195         private nothrow Size GetButtonSize()
196         {
197             int x = GetSystemMetrics(SystemMetricsId.SM_CXMENUCHECK);
198             int y = GetSystemMetrics(SystemMetricsId.SM_CYMENUCHECK);
199             return Size(xy);
200         }
201         private nothrow Size GetBorderSize()
202         {
203             int x = GetSystemMetrics(SystemMetricsId.SM_CXBORDER);
204             int y = GetSystemMetrics(SystemMetricsId.SM_CYBORDER);
205             return Size(xy);
206         }
207         private inline nothrow bool GetCheckedFlag() const
208         {
209             return (flags & Flags.checked) != Flags.none;
210         }
211         private void SetCheckedFlag()
212         {
213             if (!GetCheckedFlag())
214             {
215                 flags = cast<Flags>(flags | Flags.checked);
216                 OnCheckedChanged();
217             }
218         }
219         private void ResetCheckedFlag()
220         {
221             if (GetCheckedFlag())
222             {
223                 flags = cast<Flags>(flags & ~Flags.checked);
224                 OnCheckedChanged();
225             }
226         }
227         private inline nothrow bool GetAutoSizeFlag() const
228         {
229             return (flags & Flags.autoSize) != Flags.none;
230         }
231         private inline nothrow void SetAutoSizeFlag()
232         {
233             flags = cast<Flags>(flags | Flags.autoSize);
234         }
235         private inline nothrow void ResetAutoSizeFlag()
236         {
237             flags = cast<Flags>(flags & ~Flags.autoSize);
238         }
239         private inline nothrow bool AutoSized() const
240         {
241             return (flags & Flags.autoSized) != Flags.none;
242         }
243         private inline nothrow void SetAutoSized()
244         {
245             flags = cast<Flags>(flags | Flags.autoSized);
246         }
247         private inline nothrow void ResetAutoSized()
248         {
249             flags = cast<Flags>(flags & ~Flags.autoSized);
250         }
251         private Flags flags;
252         private Event<CheckedChangedEventHandler> checkedChangedEvent;
253     }
254 }