1 // =================================
  2 // Copyright (c) 2024 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Windows.API;
  8 
  9 namespace System.Windows
 10 {
 11     public enum LabelStyle : long
 12     {
 13         SS_BITMAP = 14
 14         SS_BLACKFRAME = 7
 15         SS_BLACKRECT = 4
 16         SS_CENTER = 1
 17         SS_CENTERIMAGE = 512
 18         SS_EDITCONTROL = 8192
 19         SS_ENDELLIPSIS = 16384
 20         SS_ENHMETAFILE = 15
 21         SS_ETCHEDFRAME = 18
 22         SS_ETCHEDHORZ = 16
 23         SS_ETCHEDVERT = 17
 24         SS_GRAYFRAME = 8
 25         SS_GRAYRECT = 5
 26         SS_ICON = 3
 27         SS_LEFT = 0
 28         SS_LEFTNOWORDWRAP = 12
 29         SS_NOPREFIX = 128u
 30         SS_NOTIFY = 256
 31         SS_OWNERDRAW = 13
 32         SS_PATHELLIPSIS = 32768u
 33         SS_REALSIZECONTROL = 64
 34         SS_REALSIZEIMAGE = 2048
 35         SS_RIGHT = 2
 36         SS_RIGHTJUST = 1024
 37         SS_SIMPLE = 11
 38         SS_SUNKEN = 4096
 39         SS_TYPEMASK = 31
 40         SS_WHITEFRAME = 9
 41         SS_WHITERECT = 6
 42         SS_WORDELLIPSIS = 49152u
 43     }
 44 
 45     public ControlCreateParams& LabelControlCreateParams(ControlCreateParams& controlCreateParamsLabelStyle labelStyle)
 46     {
 47         return controlCreateParams.SetWindowClassName("STATIC").SetWindowStyle(cast<WindowStyle>(DefaultChildWindowStyle() | labelStyle));
 48     }
 49 
 50     public ControlCreateParams& LabelControlCreateParams(ControlCreateParams& controlCreateParams)
 51     {
 52         return LabelControlCreateParams(controlCreateParamsLabelStyle.SS_LEFT);
 53     }
 54 
 55     public class LabelCreateParams
 56     {
 57         public LabelCreateParams(ControlCreateParams& controlCreateParams_) : controlCreateParams(controlCreateParams_)autoSize(true)
 58         {
 59         }
 60         public LabelCreateParams& Defaults()
 61         {
 62             return *this;
 63         }
 64         public LabelCreateParams& SetAutoSize(bool autoSize_)
 65         {
 66             autoSize = autoSize_;
 67             return *this;
 68         }
 69         public ControlCreateParams& controlCreateParams;
 70         public bool autoSize;
 71     }
 72 
 73     public class Label : Control
 74     {
 75         private enum Flags : sbyte
 76         {
 77             none = 0autoSize = 1 << 0autoSized = 1 << 1
 78         }
 79 
 80         public Label(LabelStyle labelStyleconst Color& backgroundColorconst string& textconst Point& locationconst Size& size
 81             Dock dockAnchors anchorsbool autoSize) : 
 82             base("STATIC"DefaultWindowClassStyle()cast<WindowStyle>(DefaultChildWindowStyle() | labelStyle)DefaultExtendedWindowStyle()
 83             backgroundColortextlocationsizedockanchors)flags(Flags.none)
 84         {
 85             if (autoSize)
 86             {
 87                 SetAutoSizeFlag();
 88                 DoAutoSize();
 89             }
 90         }
 91         public Label(const string& textconst Point& locationconst Size& sizeDock dockAnchors anchorsbool autoSize) : 
 92             this(LabelStyle.SS_LEFTDefaultControlBackgroundColor()textlocationsizedockanchorsautoSize)
 93         {
 94         }
 95         public Label(LabelCreateParams& createParams) : base(createParams.controlCreateParams)flags(Flags.none)
 96         {
 97             if (createParams.autoSize)
 98             {
 99                 SetAutoSizeFlag();
100                 auto result = DoAutoSize();
101                 if (result.Error())
102                 {
103                     SetErrorId(result.GetErrorId());
104                     return;
105                 }
106             }
107         }
108         protected override Result<bool> OnCreated()
109         {
110             auto result = base->OnCreated();
111             if (result.Error())
112             {
113                 return Result<bool>(ErrorId(result.GetErrorId()));
114             }
115             auto graphicsResult = Graphics.FromWindowHandle(Handle());
116             if (graphicsResult.Error())
117             {
118                 return Result<bool>(ErrorId(graphicsResult.GetErrorId()));
119             }
120             Graphics& graphics = graphicsResult.Value();
121             auto fontHandleResult = GetFontHandle(graphics);
122             if (fontHandleResult.Error())
123             {
124                 return Result<bool>(ErrorId(fontHandleResult.GetErrorId()));
125             }
126             FontHandle* fontHandle = fontHandleResult.Value();
127             if (!fontHandle->IsNull())
128             {
129                 SendSetFontMessage(*fontHandle);
130             }
131             if (AutoSize())
132             {
133                 auto result = DoAutoSize();
134                 if (result.Error())
135                 {
136                     return Result<bool>(ErrorId(result.GetErrorId()));
137                 }
138             }
139             return Result<bool>(true);
140         }
141         [nodiscard]
142         protected override Result<bool> OnTextChanged()
143         {
144             auto baseResult = base->OnTextChanged();
145             if (baseResult.Error())
146             {
147                 return Result<bool>(ErrorId(baseResult.GetErrorId()));
148             }
149             if (AutoSize())
150             {
151                 ResetAutoSized();
152                 auto result = DoAutoSize();
153                 if (result.Error())
154                 {
155                     return Result<bool>(ErrorId(result.GetErrorId()));
156                 }
157             }
158             return Result<bool>(true);
159         }
160         public inline bool AutoSize() const
161         {
162             return (flags & Flags.autoSize) != Flags.none;
163         }
164         [nodiscard]
165         public Result<bool> SetAutoSize(bool autoSize)
166         {
167             if (autoSize)
168             {
169                 if (!AutoSize())
170                 {
171                     SetAutoSizeFlag();
172                     if (!AutoSized())
173                     {
174                         auto result = DoAutoSize();
175                         if (result.Error())
176                         {
177                             return Result<bool>(ErrorId(result.GetErrorId()));
178                         }
179                     }
180                 }
181             }
182             else
183             {
184                 ResetAutoSizeFlag();
185                 ResetAutoSized();
186             }
187             return Result<bool>(true);
188         }
189         private Result<bool> DoAutoSize()
190         {
191             if (AutoSized()) return Result<bool>(true);
192             if (Handle() == null) Result<bool>(false);
193             auto graphicsResult = Graphics.FromWindowHandle(Handle());
194             if (graphicsResult.Error())
195             {
196                 return Result<bool>(ErrorId(graphicsResult.GetErrorId()));
197             }
198             Graphics& graphics = graphicsResult.Value();
199             const Font& font = GetFont();
200             StringFormat stringFormat;
201             if (stringFormat.Error())
202             {
203                 return Result<bool>(ErrorId(stringFormat.GetErrorId()));
204             }
205             auto measureResult = graphics.MeasureStringRectF(Text()fontPointF(00)stringFormat);
206             if (measureResult.Error())
207             {
208                 return Result<bool>(ErrorId(measureResult.GetErrorId()));
209             }
210             RectF r = measureResult.Value();
211             auto result = SetSize(Size(cast<int>(r.size.w)cast<int>(r.size.h)));
212             if (result.Error()) return result;
213             SetAutoSized();
214             return Result<bool>(true);
215         }
216         private inline void SetAutoSizeFlag()
217         {
218             flags = cast<Flags>(flags | Flags.autoSize);
219         }
220         private inline void ResetAutoSizeFlag()
221         {
222             flags = cast<Flags>(flags & ~Flags.autoSize);
223         }
224         private inline bool AutoSized() const
225         {
226             return (flags & Flags.autoSized) != Flags.none;
227         }
228         private inline void SetAutoSized()
229         {
230             flags = cast<Flags>(flags | Flags.autoSized);
231         }
232         private inline void ResetAutoSized()
233         {
234             flags = cast<Flags>(flags & ~Flags.autoSized);
235         }
236         private Flags flags;
237     }