1 // =================================
  2 // Copyright (c) 2024 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 using System.Collections;
  8 
  9 namespace System.Windows
 10 {
 11     public abstract class ContainerControl : Control
 12     {
 13         public ContainerControl(const string& windowClassNameWindowClassStyle windowClassStyleWindowStyle styleExtendedWindowStyle exStyle
 14             const Color& backgroundColorconst string& textconst Point& locationconst Size& sizeDock dockAnchors anchors) : 
 15             base(windowClassNamewindowClassStylestyleexStylebackgroundColortextlocationsizedockanchors)children(this)
 16         {
 17         }
 18         public ContainerControl(ControlCreateParams& createParams) : base(createParams)children(this)
 19         {
 20         }
 21         [nodiscard]
 22         public Result<bool> AddChild(Control* child)
 23         {
 24             auto result = children.AddChild(child);
 25             if (result.Error()) return result;
 26             ControlEventArgs args(child);
 27             result = OnControlAdded(args);
 28             if (result.Error()) return result;
 29             if (args.errorId != 0)
 30             {
 31                 return Result<bool>(ErrorId(args.errorId));
 32             }
 33             return Result<bool>(true);
 34         }
 35         [nodiscard]
 36         public Result<UniquePtr<Control>> RemoveChild(Control* child)
 37         {
 38             UniquePtr<Component> childComponent = children.RemoveChild(child);
 39             ControlEventArgs args(child);
 40             auto result = OnControlRemoved(args);
 41             if (result.Error())
 42             {
 43                 return Result<UniquePtr<Control>>(ErrorId(result.GetErrorId()));
 44             }
 45             return UniquePtr<Control>(childComponent.Release() as Control*);
 46         }
 47         [nodiscard]
 48         public Result<bool> InsertChildBefore(Control* childControl* before)
 49         {
 50             auto result = children.InsertBefore(childbefore);
 51             if (result.Error()) return result;
 52             ControlEventArgs args(child);
 53             result = OnControlAdded(args);
 54             if (result.Error()) return result;
 55             if (args.errorId != 0)
 56             {
 57                 return Result<bool>(ErrorId(args.errorId));
 58             }
 59             return Result<bool>(true);
 60         }
 61         [nodiscard]
 62         public Result<bool> InsertChildAfter(Control* childControl* after)
 63         {
 64             auto result = children.InsertAfter(childafter);
 65             if (result.Error()) return result;
 66             ControlEventArgs args(child);
 67             result = OnControlAdded(args);
 68             if (result.Error()) return result;
 69             if (args.errorId != 0)
 70             {
 71                 return Result<bool>(ErrorId(args.errorId));
 72             }
 73             return Result<bool>(true);
 74         }
 75         public const ComponentContainer& Children() const
 76         {
 77             return children;
 78         }
 79         public override ContainerControl* GetContainerControl() const
 80         {
 81             return this;
 82         }
 83         internal override Control* GetFirstEnabledTabStopControl() const
 84         {
 85             Component* child = children.FirstChild();
 86             while (child != null)
 87             {
 88                 if (child is Control*)
 89                 {
 90                     Control* control = cast<Control*>(child);
 91                     Control* tabStopChild = control->GetFirstEnabledTabStopControl();
 92                     if (tabStopChild != null)
 93                     {
 94                         return tabStopChild;
 95                     }
 96                 }
 97                 child = child->NextSibling();
 98             }
 99             return null;
100         }
101         internal override Control* GetLastEnabledTabStopControl() const
102         {
103             Component* child = children.LastChild();
104             while (child != null)
105             {
106                 if (child is Control*)
107                 {
108                     Control* control = cast<Control*>(child);
109                     Control* tabStopChild = control->GetLastEnabledTabStopControl();
110                     if (tabStopChild != null)
111                     {
112                         return tabStopChild;
113                     }
114                 }
115                 child = child->PrevSibling();
116             }
117             return null;
118         }
119         [nodiscard]
120         protected override Result<bool> OnSizeChanging(SizeChangingEventArgs& args)
121         {
122             auto result = base->OnSizeChanging(args);
123             if (result.Error()) return result;
124             int dx = args.newSize.w - args.oldSize.w;
125             int dy = args.newSize.h - args.oldSize.h;
126             result = MoveChildren(dxdy);
127             if (result.Error()) return result;
128             return Result<bool>(true);
129         }
130         [nodiscard]
131         protected override Result<bool> OnChildSizeChanged(ControlEventArgs& args)
132         {
133             auto result = base->OnChildSizeChanged(args);
134             if (result.Error()) return result;
135             Control* parentControl = ParentControl();
136             if (parentControl != null)
137             {
138                 result = parentControl->FireChildSizeChanged(args);
139                 if (result.Error()) return result;
140             }
141             return Result<bool>(true);
142         }
143         protected override void OnChildContentLocationChanged(ControlEventArgs& args)
144         {
145             base->OnChildContentLocationChanged(args);
146             Control* parentControl = ParentControl();
147             if (parentControl != null)
148             {
149                 parentControl->OnChildContentLocationChanged(args);
150             }
151         }
152         protected override void OnChildContentChanged(ControlEventArgs& args)
153         {
154             base->OnChildContentChanged(args);
155             Control* parentControl = ParentControl();
156             if (parentControl != null)
157             {
158                 parentControl->OnChildContentChanged(args);
159             }
160         }
161         [nodiscard]
162         protected override Result<bool> OnChildContentSizeChanged(ControlEventArgs& args)
163         {
164             auto result = base->OnChildContentSizeChanged(args);
165             if (result.Error()) return result;
166             Control* parentControl = ParentControl();
167             if (parentControl != null)
168             {
169                 result = parentControl->OnChildContentSizeChanged(args);
170                 if (result.Error()) return result;
171             }
172             return Result<bool>(true);
173         }
174         [nodiscard]
175         protected override Result<bool> OnChildGotFocus(ControlEventArgs& args)
176         {
177             auto result = base->OnChildGotFocus(args);
178             if (result.Error()) return result;
179             Control* parentControl = ParentControl();
180             if (parentControl != null)
181             {
182                 result = parentControl->OnChildGotFocus(args);
183                 if (result.Error()) return result;
184             }
185             return Result<bool>(true);
186         }
187         [nodiscard]
188         protected override Result<bool> OnChildLostFocus(ControlEventArgs& args)
189         {
190             auto result = base->OnChildLostFocus(args);
191             if (result.Error()) return result;
192             Control* parentControl = ParentControl();
193             if (parentControl != null)
194             {
195                 result = parentControl->OnChildLostFocus(args);
196                 if (result.Error()) return result;
197             }
198             return Result<bool>(true);
199         }
200         [nodiscard]
201         public override Result<bool> PrintWindowTree(int level)
202         {
203             LogView* log = Application.GetLogView();
204             if (log != null)
205             {
206                 auto handleResult = ToHexString(cast<ulong>(Handle()));
207                 if (handleResult.Error())
208                 {
209                     return Result<bool>(ErrorId(handleResult.GetErrorId()));
210                 }
211                 else
212                 {
213                     const string& handleStr = handleResult.Value();
214                     auto parentTextResult = ParentText();
215                     if (parentTextResult.Error())
216                     {
217                         return Result<bool>(ErrorId(parentTextResult.GetErrorId()));
218                     }
219                     else
220                     {
221                         const string& parentText = parentTextResult.Value();
222                         auto result = log->WriteLine(string(' 'level) + "ContainerControl." + Text() + ".handle=" + handleStr + " " + 
223                             parentText + "[" + Rect(Point()GetSize()).ToString() + "]");
224                         if (result.Error()) return result;
225                     }
226                 }
227             }
228             Component* child = children.FirstChild();
229             while (child != null)
230             {
231                 if (child is Control*)
232                 {
233                     Control* childControl = cast<Control*>(child);
234                     auto result = childControl->PrintWindowTree(level + 1);
235                     if (result.Error())
236                     {
237                         return Result<bool>(ErrorId(result.GetErrorId()));
238                     }
239                 }
240                 child = child->NextSibling();
241             }
242             return Result<bool>(true);
243         }
244         [nodiscard]
245         protected override Result<bool> ProcessMessage(Message& message)
246         {
247             switch (message.msg)
248             {
249                 case WM_SIZE:
250                 {
251                     Size newSize = message.LParamSize();
252                     Size oldSize = GetSize();
253                     if (newSize != oldSize)
254                     {
255                         Rect parentRect(Point()newSize);
256                         int dx = newSize.w - oldSize.w;
257                         int dy = newSize.h - oldSize.h;
258                         auto result = MoveChildren(dxdy);
259                         if (result.Error()) return result;
260                         uint windowState = cast<uint>(message.wparam);
261                         result = SetSizeInternal(newSizewindowState);
262                         if (result.Error()) return result;
263                         result = DockChildren();
264                         if (result.Error()) return result;
265                         SizeChangedEventArgs args(windowState);
266                         result = OnSizeChanged(args);
267                         if (result.Error()) return result;
268                     }
269                     message.result = 0;
270                     return Result<bool>(true);
271                 }
272                 case WM_PAINT: case WM_MOVE: case WM_MOUSEMOVE: case WM_MOUSELEAVE: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_LBUTTONDBLCLK: case WM_RBUTTONDOWN: case WM_RBUTTONUP:
273                 case WM_CHAR: case WM_KEYDOWN: case WM_KEYUP: case WM_SYSCOMMAND: case WM_HSCROLL: case WM_VSCROLL: case WM_MOUSEWHEEL:
274                 case WM_SETFOCUS: case WM_KILLFOCUS: case WM_TIMER: case WM_COMMAND: case WM_SHOWWINDOW: case WM_CLIPBOARDUPDATE:
275                 {
276                     return base->ProcessMessage(message);
277                 }
278             }
279             return Result<bool>(false);
280         }
281         [nodiscard]
282         public Result<bool> MoveChildren(int dxint dy)
283         {
284             Component* child = children.FirstChild();
285             while (child != null)
286             {
287                 if (child is Control*)
288                 {
289                     Control* childControl = cast<Control*>(child);
290                     if (childControl->GetDock() == Dock.none)
291                     {
292                         auto result = childControl->MoveWindow(dxdy);
293                         if (result.Error()) return result;
294                     }
295                 }
296                 child = child->NextSibling();
297             }
298             return Result<bool>(true);
299         }
300         [nodiscard]
301         public Result<bool> DockChildren()
302         {
303             Rect parentRect(Point()GetSize());
304             return DockChildren(parentRect);
305         }
306         [nodiscard]
307         public Result<bool> DockChildren(Rect& parentRect)
308         {
309             List<Control*> filledControls;
310             List<ContainerControl*> containers;
311             Component* child = children.FirstChild();
312             while (child != null)
313             {
314                 if (child is Control*)
315                 {
316                     Control* childControl = cast<Control*>(child);
317                     switch (childControl->GetDock())
318                     {
319                         case Dock.none: break;
320                         case Dock.fill: filledControls.Add(childControl); break;
321                         default:
322                         {
323                             auto result = childControl->DockWindow(parentRect);
324                             if (result.Error()) return result;
325                             break;
326                         }
327                     }
328                     if (childControl is ContainerControl*)
329                     {
330                         ContainerControl* containerChild = cast<ContainerControl*>(childControl);
331                         containers.Add(containerChild);
332                     }
333                 }
334                 child = child->NextSibling();
335             }
336             for (Control* filledControl : filledControls)
337             {
338                 auto result = filledControl->DockWindow(parentRect);
339                 if (result.Error()) return result;
340             }
341             for (ContainerControl* container : containers)
342             {
343                 auto result = container->DockChildren();
344                 if (result.Error()) return result;
345             }
346             return Result<bool>(true);
347         }
348         [nodiscard]
349         internal override Result<bool> PaintAll(PaintEventArgs& argsbool skipMenuBar)
350         {
351             auto baseResult = base->PaintAll(argsskipMenuBar);
352             if (baseResult.Error())
353             {
354                 return Result<bool>(ErrorId(baseResult.GetErrorId()));
355             }
356             Control* topControl = TopControl();
357             Component* child = children.FirstChild();
358             while (child != null)
359             {
360                 if (child is Control*)
361                 {
362                     Control* childControl = cast<Control*>(child);
363                     if (childControl != topControl)
364                     {
365                         bool skip = false;
366                         if (skipMenuBar)
367                         {
368                             if (childControl is MenuBar*)
369                             {
370                                 skip = true;
371                             }
372                             else if (childControl is MenuBox*)
373                             {
374                                 MenuBox* menuBox = cast<MenuBox*>(childControl);
375                                 if (!menuBox->PaintThisMenuBox())
376                                 {
377                                     skip = true;
378                                 }
379                             }
380                         }
381                         if (!skip)
382                         {
383                             auto saveResult = args.graphics.Save();
384                             if (saveResult.Error())
385                             {
386                                 return Result<bool>(ErrorId(saveResult.GetErrorId()));
387                             }
388                             GraphicsState state = saveResult.Value();
389                             Result<Point> locResult = childControl->Location();
390                             if (locResult.Error())
391                             {
392                                 return Result<bool>(ErrorId(locResult.GetErrorId()));
393                             }
394                             Point loc = locResult.Value();
395                             auto childLocResult = childControl->Location();
396                             if (childLocResult.Error())
397                             {
398                                 return Result<bool>(ErrorId(childLocResult.GetErrorId()));
399                             }
400                             Point childLoc = childLocResult.Value();
401                             auto setClipResult = args.graphics.SetClip(Rect(childLocchildControl->GetSize()));
402                             if (setClipResult.Error())
403                             {
404                                 return Result<bool>(ErrorId(setClipResult.GetErrorId()));
405                             }
406                             auto translateResult = args.graphics.TranslateTransform(loc.xloc.y);
407                             if (translateResult.Error())
408                             {
409                                 return Result<bool>(ErrorId(translateResult.GetErrorId()));
410                             }
411                             auto childResult = childControl->PaintAll(argsskipMenuBar);
412                             if (childResult.Error())
413                             {
414                                 return Result<bool>(ErrorId(childResult.GetErrorId()));
415                             }
416                             auto restoreResult = args.graphics.Restore(state);
417                             if (restoreResult.Error())
418                             {
419                                 return Result<bool>(ErrorId(restoreResult.GetErrorId()));
420                             }
421                         }
422                     }
423                 }
424                 child = child->NextSibling();
425             }
426             if (topControl != null)
427             {
428                 auto saveResult = args.graphics.Save();
429                 if (saveResult.Error())
430                 {
431                     return Result<bool>(ErrorId(saveResult.GetErrorId()));
432                 }
433                 GraphicsState state = saveResult.Value();
434                 auto locResult = topControl->Location();
435                 if (locResult.Error())
436                 {
437                     return Result<bool>(ErrorId(locResult.GetErrorId()));
438                 }
439                 Point loc = locResult.Value();
440                 auto setClipResult = args.graphics.SetClip(Rect(loctopControl->GetSize()));
441                 if (setClipResult.Error())
442                 {
443                     return Result<bool>(ErrorId(setClipResult.GetErrorId()));
444                 }
445                 auto translateResult = args.graphics.TranslateTransform(loc.xloc.y);
446                 if (translateResult.Error())
447                 {
448                     return Result<bool>(ErrorId(translateResult.GetErrorId()));
449                 }
450                 auto topResult = topControl->PaintAll(argsskipMenuBar);
451                 if (topResult.Error())
452                 {
453                     return Result<bool>(ErrorId(topResult.GetErrorId()));
454                 }
455                 auto restoreResult = args.graphics.Restore(state);
456                 if (restoreResult.Error())
457                 {
458                     return Result<bool>(ErrorId(restoreResult.GetErrorId()));
459                 }
460             }
461             return Result<bool>(true);
462         }
463         private ComponentContainer children;
464     }