1 // =================================
  2 // Copyright (c) 2021 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         public void AddChild(Control* child)
 22         {
 23             children.AddChild(child);
 24             ControlEventArgs args(child);
 25             OnControlAdded(args);
 26         }
 27         public UniquePtr<Control> RemoveChild(Control* child)
 28         {
 29             UniquePtr<Component> childComponent = children.RemoveChild(child);
 30             ControlEventArgs args(child);
 31             OnControlRemoved(args);
 32             return UniquePtr<Control>(childComponent.Release() as Control*);
 33         }
 34         public void InsertChildBefore(Control* childControl* before)
 35         {
 36             children.InsertBefore(childbefore);
 37             ControlEventArgs args(child);
 38             OnControlAdded(args);
 39         }
 40         public void InsertChildAfter(Control* childControl* after)
 41         {
 42             children.InsertAfter(childafter);
 43             ControlEventArgs args(child);
 44             OnControlAdded(args);
 45         }
 46         public nothrow const Container& Children() const
 47         {
 48             return children;
 49         }
 50         public override nothrow ContainerControl* GetContainerControl() const
 51         {
 52             return this;
 53         }
 54         internal override nothrow Control* GetFirstEnabledTabStopControl() const
 55         {
 56             Component* child = children.FirstChild();
 57             while (child != null)
 58             {
 59                 if (child is Control*)
 60                 {
 61                     Control* control = cast<Control*>(child);
 62                     Control* tabStopChild = control->GetFirstEnabledTabStopControl();
 63                     if (tabStopChild != null)
 64                     {
 65                         return tabStopChild;
 66                     }
 67                 }
 68                 child = child->NextSibling();
 69             }
 70             return null;
 71         }
 72         internal override nothrow Control* GetLastEnabledTabStopControl() const
 73         {
 74             Component* child = children.LastChild();
 75             while (child != null)
 76             {
 77                 if (child is Control*)
 78                 {
 79                     Control* control = cast<Control*>(child);
 80                     Control* tabStopChild = control->GetLastEnabledTabStopControl();
 81                     if (tabStopChild != null)
 82                     {
 83                         return tabStopChild;
 84                     }
 85                 }
 86                 child = child->PrevSibling();
 87             }
 88             return null;
 89         }
 90         protected override void OnSizeChanging(SizeChangingEventArgs& args)
 91         {
 92             base->OnSizeChanging(args);
 93             int dx = args.newSize.w - args.oldSize.w;
 94             int dy = args.newSize.h - args.oldSize.h;
 95             MoveChildren(dxdy);
 96         }
 97         protected override void OnChildSizeChanged(ControlEventArgs& args)
 98         {
 99             base->OnChildSizeChanged(args);
100             Control* parentControl = ParentControl();
101             if (parentControl != null)
102             {
103                 parentControl->FireChildSizeChanged(args);
104             }
105         }
106         protected override void OnChildContentLocationChanged(ControlEventArgs& args)
107         {
108             base->OnChildContentLocationChanged(args);
109             Control* parentControl = ParentControl();
110             if (parentControl != null)
111             {
112                 parentControl->OnChildContentLocationChanged(args);
113             }
114         }
115         protected override void OnChildContentChanged(ControlEventArgs& args)
116         {
117             base->OnChildContentChanged(args);
118             Control* parentControl = ParentControl();
119             if (parentControl != null)
120             {
121                 parentControl->OnChildContentChanged(args);
122             }
123         }
124         protected override void OnChildContentSizeChanged(ControlEventArgs& args)
125         {
126             base->OnChildContentSizeChanged(args);
127             Control* parentControl = ParentControl();
128             if (parentControl != null)
129             {
130                 parentControl->OnChildContentSizeChanged(args);
131             }
132         }
133         protected override void OnChildGotFocus(ControlEventArgs& args)
134         {
135             base->OnChildContentChanged(args);
136             Control* parentControl = ParentControl();
137             if (parentControl != null)
138             {
139                 parentControl->OnChildContentChanged(args);
140             }
141         }
142         protected override void OnChildLostFocus(ControlEventArgs& args)
143         {
144             base->OnChildLostFocus(args);
145             Control* parentControl = ParentControl();
146             if (parentControl != null)
147             {
148                 parentControl->OnChildContentChanged(args);
149             }
150         }
151         public override void PrintWindowTree(int level)
152         {
153             LogView* log = Application.GetLogView();
154             if (log != null)
155             {
156                 log->WriteLine(string(' 'level) + "ContainerControl." + Text() + ".handle=" + ToHexString(cast<ulong>(Handle())) + " " + ParentText() + "[" + Rect(Point()GetSize()).ToString() + "]");
157             }
158             Component* child = children.FirstChild();
159             while (child != null)
160             {
161                 if (child is Control*)
162                 {
163                     Control* childControl = cast<Control*>(child);
164                     childControl->PrintWindowTree(level + 1);
165                 }
166                 child = child->NextSibling();
167             }
168         }
169         protected override bool ProcessMessage(Message& message)
170         {
171             switch (message.msg)
172             {
173                 case WM_SIZE:
174                 {
175                     Size newSize = message.LParamSize();
176                     Size oldSize = GetSize();
177                     if (newSize != oldSize)
178                     {
179                         Rect parentRect(Point()newSize);
180                         int dx = newSize.w - oldSize.w;
181                         int dy = newSize.h - oldSize.h;
182                         MoveChildren(dxdy);
183                         uint windowState = message.wparam;
184                         SetSizeInternal(newSizewindowState);
185                         DockChildren();
186                         OnSizeChanged(windowState);
187                     }
188                     message.result = 0;
189                     return true;
190                 }
191                 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:
192                 case WM_CHAR: case WM_KEYDOWN: case WM_KEYUP: case WM_SYSCOMMAND: case WM_HSCROLL: case WM_VSCROLL: case WM_MOUSEWHEEL:
193                 case WM_SETFOCUS: case WM_KILLFOCUS: case WM_TIMER: case WM_COMMAND: case WM_SHOWWINDOW: case WM_CLIPBOARDUPDATE:
194                 {
195                     return base->ProcessMessage(message);
196                 }
197             }
198             return false;
199         }
200         public void MoveChildren(int dxint dy)
201         {
202             Component* child = children.FirstChild();
203             while (child != null)
204             {
205                 if (child is Control*)
206                 {
207                     Control* childControl = cast<Control*>(child);
208                     if (childControl->GetDock() == Dock.none)
209                     {
210                         childControl->MoveWindow(dxdy);
211                     }
212                 }
213                 child = child->NextSibling();
214             }
215         }
216         public void DockChildren()
217         {
218             Rect parentRect(Point()GetSize());
219             DockChildren(parentRect);
220         }
221         public void DockChildren(Rect& parentRect)
222         {
223             List<Control*> filledControls;
224             List<ContainerControl*> containers;
225             Component* child = children.FirstChild();
226             while (child != null)
227             {
228                 if (child is Control*)
229                 {
230                     Control* childControl = cast<Control*>(child);
231                     switch (childControl->GetDock())
232                     {
233                         case Dock.none: break;
234                         case Dock.fill: filledControls.Add(childControl); break;
235                         default:
236                         {
237                             childControl->DockWindow(parentRect);
238                             break;
239                         }
240                     }
241                     if (childControl is ContainerControl*)
242                     {
243                         ContainerControl* containerChild = cast<ContainerControl*>(childControl);
244                         containers.Add(containerChild);
245                     }
246                 }
247                 child = child->NextSibling();
248             }
249             for (Control* filledControl : filledControls)
250             {
251                 filledControl->DockWindow(parentRect);
252             }
253             for (ContainerControl* container : containers)
254             {
255                 container->DockChildren();
256             }
257         }
258         internal override void PaintAll(PaintEventArgs& argsbool skipMenuBar)
259         {
260             try
261             {
262                 base->PaintAll(argsskipMenuBar);
263                 Control* topControl = TopControl();
264                 Component* child = children.FirstChild();
265                 while (child != null)
266                 {
267                     if (child is Control*)
268                     {
269                         Control* childControl = cast<Control*>(child);
270                         if (childControl != topControl)
271                         {
272                             bool skip = false;
273                             if (skipMenuBar)
274                             {
275                                 if (childControl is MenuBar*)
276                                 {
277                                     skip = true;
278                                 }
279                                 else if (childControl is MenuBox*)
280                                 {
281                                     MenuBox* menuBox = cast<MenuBox*>(childControl);
282                                     if (!menuBox->PaintThisMenuBox())
283                                     {
284                                         skip = true;
285                                     }
286                                 }
287                             }
288                             if (!skip)
289                             {
290                                 GraphicsState state = args.graphics.SaveChecked();
291                                 Point loc = childControl->Location();
292                                 args.graphics.SetClipChecked(Rect(childControl->Location()childControl->GetSize()));
293                                 args.graphics.TranslateTransformChecked(loc.xloc.y);
294                                 childControl->PaintAll(argsskipMenuBar);
295                                 args.graphics.RestoreChecked(state);
296                             }
297                         }
298                     }
299                     child = child->NextSibling();
300                 }
301                 if (topControl != null)
302                 {
303                     GraphicsState state = args.graphics.SaveChecked();
304                     Point loc = topControl->Location();
305                     args.graphics.SetClipChecked(Rect(topControl->Location()topControl->GetSize()));
306                     args.graphics.TranslateTransformChecked(loc.xloc.y);
307                     topControl->PaintAll(argsskipMenuBar);
308                     args.graphics.RestoreChecked(state);
309                 }
310             }
311             catch (const Exception& ex)
312             {
313                 MessageBox.Show(ex.Message());
314             }
315         }
316         private Container children;
317     }
318 }