1 // =================================
  2 // Copyright (c) 2022 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 using System;
  7 
  8 namespace System.Screen
  9 {
 10     public enum InvalidateKind
 11     {
 12         dontInvalidate = 0invalidateIfNotDefault = 1forceInvalidate = 2
 13     }
 14 
 15     public class InvalidateGuard
 16     {
 17         public nothrow InvalidateGuard(Control* control_InvalidateKind invalidateKind_) : control(control_)invalidateKind(invalidateKind_)
 18         {
 19             control->BeginInvalidate();
 20         }
 21         public ~InvalidateGuard()
 22         {
 23             control->EndInvalidate(invalidateKind);
 24         }
 25         private Control* control;
 26         private InvalidateKind invalidateKind;
 27     }
 28 
 29     public class ControlCreateParams
 30     {
 31         public nothrow ControlCreateParams() : location(Point.Default())size(Size.Default())foreColor(ConsoleColor.defaultColor)backColor(ConsoleColor.defaultColor)
 32         {
 33         }
 34         public nothrow ControlCreateParams& Defaults()
 35         {
 36             return *this;
 37         }
 38         public nothrow ControlCreateParams& SetLocation(const Point& location_)
 39         {
 40             location = location_;
 41             return *this;
 42         }
 43         public nothrow ControlCreateParams& SetSize(const Size& size_)
 44         {
 45             size = size_;
 46             return *this;
 47         }
 48         public nothrow ControlCreateParams& SetForeColor(ConsoleColor foreColor_)
 49         {
 50             foreColor = foreColor_;
 51             return *this;
 52         }
 53         public nothrow ControlCreateParams& SetBackColor(ConsoleColor backColor_)
 54         {
 55             backColor = backColor_;
 56             return *this;
 57         }
 58         public Point location;
 59         public Size size;
 60         public ConsoleColor foreColor;
 61         public ConsoleColor backColor;
 62     }
 63     
 64     public enum ControlFlags
 65     {
 66         none = 0disabled = 1 << 0
 67     }
 68 
 69     public class Control : Component
 70     {
 71         public nothrow Control(ControlCreateParams& createParams) : 
 72             flags(ControlFlags.none)
 73             handle(-1)
 74             location(createParams.location)
 75             size(createParams.size)
 76             foreColor(createParams.foreColor)
 77             backColor(createParams.backColor)
 78             invalidateCount(0)
 79         {
 80             Application.Instance().GetWindowManager().AddWindow(this);
 81         }
 82         public ~Control()
 83         {
 84             if (IsFocused())
 85             {
 86                 Application.Instance().SetFocusedControl(null);
 87             }
 88             Application.Instance().GetWindowManager().RemoveWindow(this);
 89         }
 90         public nothrow int Handle() const
 91         {
 92             return handle;
 93         }
 94         public nothrow void SetHandle(int handle_)
 95         {
 96             handle = handle_;
 97         }
 98         public nothrow void SetDisabled()
 99         {
100             if (!IsDisabled())
101             {
102                 flags = cast<ControlFlags>(flags | ControlFlags.disabled);
103                 OnEnabledChanged();
104                 Invalidate(GetRect());
105             }
106         }
107         public nothrow void SetEnabled()
108         {
109             if (IsDisabled())
110             {
111                 flags = cast<ControlFlags>(flags & ~ControlFlags.disabled);
112                 OnEnabledChanged();
113                 Invalidate(GetRect());
114             }
115         }
116         public nothrow bool IsDisabled() const
117         {
118             return (flags & ControlFlags.disabled) != ControlFlags.none;
119         }
120         public nothrow bool IsEnabled() const
121         {
122             return (flags & ControlFlags.disabled) == ControlFlags.none;
123         }
124         public nothrow const Point& Location() const
125         {
126             return location;
127         }
128         public nothrow void SetLocation(const Point& location_)
129         {
130             if (location != location_)
131             {
132                 location = location_;
133                 OnLocationChanged();
134                 Invalidate();
135             }
136         }
137         public nothrow const Size& GetSize() const
138         {
139             return size;
140         }
141         public nothrow void SetSize(const Size& size_)
142         {
143             if (size != size_)
144             {
145                 size = size_;
146                 OnSizeChanged();
147                 Invalidate();
148             }
149         }
150         public nothrow Rect GetRect() const
151         {
152             return Rect(locationsize);
153         }
154         public nothrow Window* GetWindow() const
155         {
156             Container* container = GetContainer();
157             if (container != null)
158             {
159                 Component* parent = container->Parent();
160                 if (parent != null)
161                 {
162                     if (parent is Window*)
163                     {
164                         return cast<Window*>(parent);
165                     }
166                     else if (parent is Control*)
167                     {
168                         return cast<Control*>(parent)->GetWindow();
169                     }
170                 }
171             }
172             return null;
173         }
174         public nothrow Control* ParentControl() const
175         {
176             Container* container = GetContainer();
177             if (container != null)
178             {
179                 Component* parent = container->Parent();
180                 if (parent != null)
181                 {
182                     if (parent is Control*)
183                     {
184                         return cast<Control*>(parent);
185                     }
186                 }
187             }
188             return null;
189         }
190         public nothrow Control* NextControl() const
191         {
192             Component* nextSibling = NextSibling();
193             while (nextSibling != null)
194             {
195                 if (nextSibling is Control*)
196                 {
197                     return cast<Control*>(nextSibling);
198                 }
199                 nextSibling = nextSibling->NextSibling();
200             }
201             return null;
202         }
203         public nothrow Control* PrevControl() const
204         {
205             Component* prevSibling = PrevSibling();
206             while (prevSibling != null)
207             {
208                 if (prevSibling is Control*)
209                 {
210                     return cast<Control*>(prevSibling);
211                 }
212                 prevSibling = prevSibling->PrevSibling();
213             }
214             return null;
215         }
216         public nothrow Control* NextFocusableControl() const
217         {
218             Control* nextControl = NextControl();
219             while (nextControl != null)
220             {
221                 if (nextControl->CanFocus())
222                 {
223                     return nextControl;
224                 }
225                 nextControl = nextControl->NextControl();
226             }
227             return null;
228         }
229         public nothrow Control* PrevFocusableControl() const
230         {
231             Control* prevControl = PrevControl();
232             while (prevControl != null)
233             {
234                 if (prevControl->CanFocus())
235                 {
236                     return prevControl;
237                 }
238                 prevControl = prevControl->PrevControl();
239             }
240             return null;
241         }
242         public nothrow ConsoleColor ForeColor() const
243         {
244             return foreColor;
245         }
246         public nothrow void SetForeColor(ConsoleColor foreColor_)
247         {
248             if (foreColor != foreColor_)
249             {
250                 foreColor = foreColor_;
251                 OnForeColorChanged();
252                 Invalidate();
253             }
254         }
255         public nothrow ConsoleColor BackColor() const
256         {
257             return backColor;
258         }
259         public nothrow void SetBackColor(ConsoleColor backColor_)
260         {
261             if (backColor != backColor_)
262             {
263                 backColor = backColor_;
264                 OnBackColorChanged();
265                 Invalidate();
266             }
267         }
268         public nothrow void Timer(const Duration& durationint timerId)
269         {
270             Application.Instance().Timer(durationthistimerId);
271         }
272         public nothrow void BeginInvalidate()
273         {
274             Control* parentControl = ParentControl();
275             if (parentControl != null && parentControl->InvalidateCount() > 0)
276             {
277                 return;
278             }
279             if (invalidateCount == 0)
280             {
281                 updateRect = Rect();
282             }
283             ++invalidateCount;
284         }
285         public nothrow void EndInvalidate(InvalidateKind invalidateKind)
286         {
287             Control* parentControl = ParentControl();
288             if (parentControl != null && parentControl->InvalidateCount() > 0)
289             {
290                 return;
291             }
292             --invalidateCount;
293             if (invalidateCount == 0 && invalidateKind != InvalidateKind.dontInvalidate)
294             {
295                 if (!updateRect.IsEmpty())
296                 {
297                     WriteScreenMessage message(updateRectinvalidateKind);
298                     message.SetTargetWindowHandle(handle);
299                     Application.Instance().PostMessage(message);
300                 }
301             }
302         }
303         public nothrow int InvalidateCount() const
304         {
305             return invalidateCount;
306         }
307         public void Invalidate()
308         {
309             Invalidate(Rect.Default());
310         }
311         public void Invalidate(const Rect& rect)
312         {
313             InvalidateGuard guard(thisInvalidateKind.invalidateIfNotDefault);
314             if (updateRect.IsEmpty())
315             {
316                 updateRect = rect;
317             }
318             else if (rect.IsDefault())
319             {
320                 updateRect = Rect.Default();
321             }
322             else
323             {
324                 updateRect = Rect.Union(updateRectrect);
325             }
326         }
327         public nothrow void SetControlCursorPos(const Point& controlCursorPos_)
328         {
329             controlCursorPos = controlCursorPos_;
330         }
331         public nothrow const Point& ControlCursorPos() const
332         {
333             return controlCursorPos;
334         }
335         public virtual nothrow bool CanFocus() const
336         {
337             return IsEnabled();
338         }
339         public nothrow bool IsFocused() const
340         {
341             return Application.Instance().FocusedControl() == this;
342         }
343         public virtual nothrow Rect FocusRect() const
344         {
345             return GetRect();
346         }
347         public virtual void SetFocus()
348         {
349             Control* prevFocusedControl = Application.Instance().FocusedControl();
350             if (prevFocusedControl != this)
351             {
352                 if (prevFocusedControl != null)
353                 {
354                     prevFocusedControl->OnLostFocus();
355                 }
356                 Application.Instance().SetFocusedControl(this);
357                 OnGotFocus();
358                 if (prevFocusedControl != null)
359                 {
360                     prevFocusedControl->Invalidate(prevFocusedControl->FocusRect());
361                 }
362                 Invalidate(FocusRect());
363             }
364         }
365         public virtual bool HandleMessage(Message* message)
366         {
367             return message->Dispatch(this);
368         }
369         public virtual bool HandleKeyPressed(KeyPressedMessage* message)
370         {
371             KeyEventArgs args(message->Key());
372             MenuBar* menuBar = Application.Instance().GetMenuBar();
373             if (menuBar != null)
374             {
375                 menuBar->OnKeyPressed(args);
376                 if (menuBar->IsOpen())
377                 {
378                     return true;
379                 }
380             }
381             if (args.Handled())
382             {
383                 return true;
384             }
385             Control* focusedControl = Application.Instance().FocusedControl();
386             if (focusedControl != null)
387             {
388                 focusedControl->OnKeyPressed(args);
389                 if (args.Handled())
390                 {
391                     return true;
392                 }
393             }
394             OnKeyPressed(args);
395             return args.Handled();
396         }
397         public virtual bool HandleWriteScreen(WriteScreenMessage* message)
398         {
399             WriteScreenEventArgs args(message->GetRect());
400             OnWriteScreen(args);
401             return true;
402         }
403         public virtual bool HandleTimerMessage(TimerMessage* message)
404         {
405             TimerEventArgs args(message->TimerId());
406             OnTimer(args);
407             return true;
408         }
409         public virtual void OnLocationChanged()
410         {
411             locationChangedEvent.Fire();
412         }
413         public virtual void OnSizeChanged()
414         {
415             sizeChangedEvent.Fire();
416         }
417         public virtual void OnForeColorChanged()
418         {
419             foreColorChangedEvent.Fire();
420         }
421         public virtual void OnBackColorChanged()
422         {
423             backColorChangedEvent.Fire();
424         }
425         public virtual void OnEnabledChanged()
426         {
427             enabledChangedEvent.Fire();
428         }
429         public virtual void OnGotFocus()
430         {
431             gotFocusEvent.Fire();
432         }
433         public virtual void OnLostFocus()
434         {
435             lostFocusEvent.Fire();
436         }
437         public virtual void OnWriteScreen(WriteScreenEventArgs& args)
438         {
439             writeScreenEvent.Fire(args);
440         }
441         public virtual void OnKeyPressed(KeyEventArgs& args)
442         {
443             keyPressedEvent.Fire(args);
444         }
445         public virtual void OnTimer(TimerEventArgs& args)
446         {
447             timerEvent.Fire(args);
448         }
449         public nothrow Event<ChangedEventHandler>& LocationChangedEvent()
450         {
451             return locationChangedEvent;
452         }
453         public nothrow Event<ChangedEventHandler>& SizeChangedEvent()
454         {
455             return sizeChangedEvent;
456         }
457         public nothrow Event<ChangedEventHandler>& ForeColorChangedEvent()
458         {
459             return foreColorChangedEvent;
460         }
461         public nothrow Event<ChangedEventHandler>& BackColorChangedEvent()
462         {
463             return backColorChangedEvent;
464         }
465         public nothrow Event<ChangedEventHandler>& EnabledChangedEvent()
466         {
467             return enabledChangedEvent;
468         }
469         public nothrow Event<FocusEventHandler>& GotFocusEvent()
470         {
471             return gotFocusEvent;
472         }
473         public nothrow Event<FocusEventHandler>& LostFocusEvent()
474         {
475             return lostFocusEvent;
476         }
477         public nothrow Event<WriteScreenEventHandlerWriteScreenEventArgs>& WriteScreenEvent()
478         {
479             return writeScreenEvent;
480         }
481         public nothrow Event<KeyEventHandlerKeyEventArgs>& KeyPressedEvent()
482         {
483             return keyPressedEvent;
484         }
485         public nothrow Event<TimerEventHandlerTimerEventArgs> TimerEvent()
486         {
487             return timerEvent;
488         }
489         private ControlFlags flags;
490         private int handle;
491         private Point location;
492         private Size size;
493         private ConsoleColor foreColor;
494         private ConsoleColor backColor;
495         private Event<ChangedEventHandler> locationChangedEvent;
496         private Event<ChangedEventHandler> sizeChangedEvent;
497         private Event<ChangedEventHandler> foreColorChangedEvent;
498         private Event<ChangedEventHandler> backColorChangedEvent;
499         private Event<ChangedEventHandler> enabledChangedEvent;
500         private Event<FocusEventHandler> gotFocusEvent;
501         private Event<FocusEventHandler> lostFocusEvent;
502         private Event<WriteScreenEventHandlerWriteScreenEventArgs> writeScreenEvent;
503         private Event<KeyEventHandlerKeyEventArgs> keyPressedEvent;
504         private Event<TimerEventHandlerTimerEventArgs> timerEvent;
505         private int invalidateCount;
506         private Rect updateRect;
507         private Point controlCursorPos;
508     }
509 }