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 class delegate void CheckedChangedEventHandler();
 11 
 12     public nothrow ControlCreateParams& CheckBoxControlCreateParams(ControlCreateParams& controlCreateParamsButtonStyle buttonStyle)
 13     {
 14         controlCreateParams.SetWindowClassName("BUTTON");
 15         controlCreateParams.SetWindowStyle(cast<WindowStyle>(DefaultChildWindowStyle() | WindowStyle.WS_TABSTOP | buttonStyle));
 16         controlCreateParams.SetBackgroundColor(DefaultControlBackgroundColor());
 17         return controlCreateParams;
 18     }
 19 
 20     public nothrow ControlCreateParams& CheckBoxControlCreateParams(ControlCreateParams& controlCreateParams)
 21     {
 22         return CheckBoxControlCreateParams(controlCreateParamscast<ButtonStyle>(ButtonStyle.BS_CHECKBOX | ButtonStyle.BS_NOTIFY));
 23     }
 24 
 25     public class CheckBoxCreateParams
 26     {
 27         public nothrow CheckBoxCreateParams(ControlCreateParams& controlCreateParams_) : controlCreateParams(controlCreateParams_)autoSize(true)
 28         {
 29         }
 30         public nothrow CheckBoxCreateParams& Defaults()
 31         {
 32             return *this;
 33         }
 34         public CheckBoxCreateParams& SetAutoSize(bool autoSize_)
 35         {
 36             autoSize = autoSize_;
 37             return *this;
 38         }
 39         public ControlCreateParams& controlCreateParams;
 40         public bool autoSize;
 41     }
 42 
 43     public class CheckBox : ButtonBase
 44     {
 45         private enum Flags : sbyte
 46         {
 47             none = 0checked = 1 << 0autoSize = 1 << 1autoSized = 1 << 2
 48         }
 49         public CheckBox(const Color& backgroundColorconst string& textconst Point& locationconst Size& sizeDock dockAnchors anchorsbool autoSize) : 
 50             base("BUTTON"DefaultWindowClassStyle()
 51             cast<WindowStyle>(DefaultChildWindowStyle() | WindowStyle.WS_TABSTOP | ButtonStyle.BS_CHECKBOX | ButtonStyle.BS_NOTIFY)
 52             DefaultExtendedWindowStyle()backgroundColortextlocationsizedockanchors)flags(Flags.none)
 53         {
 54             if (autoSize)
 55             {
 56                 SetAutoSizeFlag();
 57             }
 58             else
 59             {
 60                 ResetAutoSizeFlag();
 61             }
 62         }
 63         public CheckBox(const string& textconst Point& locationconst Size& sizeDock dockAnchors anchorsbool autoSize) : 
 64             this(DefaultControlBackgroundColor()textlocationsizedockanchorsautoSize)
 65         {
 66         }
 67         public CheckBox(CheckBoxCreateParams& createParams) : base(createParams.controlCreateParams)
 68         {
 69             if (createParams.autoSize)
 70             {
 71                 SetAutoSizeFlag();
 72             }
 73             else
 74             {
 75                 ResetAutoSizeFlag();
 76             }
 77         }
 78         public bool Checked()
 79         {
 80             return GetCheckedFlag();
 81         }
 82         public void SetChecked(bool checked)
 83         {
 84             if (checked)
 85             {
 86                 SetCheckedFlag();
 87                 if (Handle() != null)
 88                 {
 89                     WinSendMessage(Handle()BM_SETCHECKBST_CHECKED0);
 90                 }
 91             }
 92             else
 93             {
 94                 ResetCheckedFlag();
 95                 if (Handle() != null)
 96                 {
 97                     WinSendMessage(Handle()BM_SETCHECKBST_UNCHECKED0);
 98                 }
 99             }
100         }
101         protected override void OnCreated()
102         {
103             base->OnCreated();
104             Graphics graphics = Graphics.FromWindowHandle(Handle());
105             const FontHandle& fontHandle = GetFontHandle(graphics);
106             if (!fontHandle.IsNull())
107             {
108                 SendSetFontMessage(fontHandle);
109             }
110             if (GetCheckedFlag())
111             {
112                 SetChecked(true);
113             }
114             else
115             {
116                 SetChecked(false);
117             }
118             if (GetAutoSizeFlag())
119             {
120                 DoAutoSize();
121             }
122         }
123         protected override void OnClick()
124         {
125             base->OnClick();
126             SetChecked(!GetCheckedFlag());
127         }
128         protected override void OnTextChanged()
129         {
130             base->OnTextChanged();
131             if (GetAutoSizeFlag())
132             {
133                 ResetAutoSized();
134                 DoAutoSize();
135             }
136         }
137         protected virtual void OnCheckedChanged()
138         {
139             checkedChangedEvent.Fire();
140         }
141         public nothrow Event<CheckedChangedEventHandler>& CheckedChangedEvent() const
142         {
143             return checkedChangedEvent;
144         }
145         private void RetrieveCheckedState()
146         {
147             long result = WinSendMessage(Handle()BM_GETCHECK0u0);
148             if (result == BST_CHECKED)
149             {
150                 SetCheckedFlag();
151             }
152             else
153             {
154                 ResetCheckedFlag();
155             }
156         }
157         private void DoAutoSize()
158         {
159             if (AutoSized()) return;
160             if (Handle() == null) return;
161             Graphics graphics = Graphics.FromWindowHandle(Handle());
162             const Font& font = GetFont();
163             StringFormat stringFormat;
164             RectF r = graphics.MeasureStringChecked(Text()fontPointF(00)stringFormat);
165             Size checkSize = GetCheckSize();
166             Size borderSize = GetBorderSize();
167             r.size.w = r.size.w + checkSize.w + borderSize.w;
168             r.size.h = Max(r.size.hcheckSize.h + borderSize.h);
169             SetSize(Size(cast<int>(r.size.w)cast<int>(r.size.h)));
170             SetAutoSized();
171         }
172         private nothrow Size GetCheckSize()
173         {
174             int x = GetSystemMetrics(SystemMetricsId.SM_CXMENUCHECK);
175             int y = GetSystemMetrics(SystemMetricsId.SM_CYMENUCHECK);
176             return Size(xy);
177         }
178         private nothrow Size GetBorderSize()
179         {
180             int x = GetSystemMetrics(SystemMetricsId.SM_CXBORDER);
181             int y = GetSystemMetrics(SystemMetricsId.SM_CYBORDER);
182             return Size(xy);
183         }
184         private inline nothrow bool GetCheckedFlag() const
185         {
186             return (flags & Flags.checked) != Flags.none;
187         }
188         private void SetCheckedFlag()
189         {
190             if (!GetCheckedFlag())
191             {
192                 flags = cast<Flags>(flags | Flags.checked);
193                 OnCheckedChanged();
194             }
195         }
196         private void ResetCheckedFlag()
197         {
198             if (GetCheckedFlag())
199             {
200                 flags = cast<Flags>(flags & ~Flags.checked);
201                 OnCheckedChanged();
202             }
203         }
204         private inline nothrow bool GetAutoSizeFlag() const
205         {
206             return (flags & Flags.autoSize) != Flags.none;
207         }
208         private inline nothrow void SetAutoSizeFlag()
209         {
210             flags = cast<Flags>(flags | Flags.autoSize);
211         }
212         private inline nothrow void ResetAutoSizeFlag()
213         {
214             flags = cast<Flags>(flags & ~Flags.autoSize);
215         }
216         private inline nothrow bool AutoSized() const
217         {
218             return (flags & Flags.autoSized) != Flags.none;
219         }
220         private inline nothrow void SetAutoSized()
221         {
222             flags = cast<Flags>(flags | Flags.autoSized);
223         }
224         private inline nothrow void ResetAutoSized()
225         {
226             flags = cast<Flags>(flags & ~Flags.autoSized);
227         }
228         private Flags flags;
229         private Event<CheckedChangedEventHandler> checkedChangedEvent;
230     }
231 }