using System; using Quik.CommandMachine; namespace Quik.Controls { public class Control { public string Name { get; set; } = null; public Control Parent { get; set; } = null; protected RootControl Root { get; set; } = null; public QRectangle Bounds { get; set; } public bool Focused { get => Root.FocusedControl == this; } public QRectangle AbsoluteBounds { get => Parent is null ? Bounds : new QRectangle(Parent.Bounds.Min + Bounds.Max, Parent.Bounds.Min + Bounds.Min); set => Bounds = Parent is null ? value : new QRectangle(value.Min - Parent.Bounds.Min, value.Max - Parent.Bounds.Min); } private MouseButton DownButtons; // Hierarchy events. public event EventHandler Update; public event EventHandler Paint; public event EventHandler RootChanging; public event EventHandler ParentChanging; public event EventHandler FocusLost; public event EventHandler FocusAcquired; // Mouse events. public event EventHandler Clicked; public event EventHandler MouseDown; public event EventHandler MouseUp; public event EventHandler MouseEnter; public event EventHandler MouseMove; // public event EventHandler MouseHover; public event EventHandler MouseLeave; protected virtual void OnUpdate() => Update?.Invoke(this, EventArgs.Empty); protected virtual void OnPaint(CommandQueue draw) => Paint?.Invoke(this, draw); protected virtual void OnParentChanging(ParentChangedEventArgs args) => ParentChanging?.Invoke(this, args); protected virtual void OnRootChanging(RootChangedEventArgs args) => RootChanging?.Invoke(this, args); protected virtual void OnFocusLost(FocusChangedEventArgs args) => FocusLost?.Invoke(this, args); protected virtual void OnFocusAcquired(FocusChangedEventArgs args) => FocusAcquired?.Invoke(this, args); protected virtual void OnClicked(MouseButtonEventArgs args) => Clicked?.Invoke(this, args); protected virtual void OnMouseDown(MouseButtonEventArgs args) => MouseDown?.Invoke(this, args); protected virtual void OnMouseUp(MouseButtonEventArgs args) => MouseUp?.Invoke(this, args); protected virtual void OnMouseEnter(MouseMoveEventArgs args) => MouseEnter?.Invoke(this, args); protected virtual void OnMouseMove(MouseMoveEventArgs args) => MouseMove?.Invoke(this, args); // protected virtual void OnMouseHover(MouseMoveEventArgs args) => MouseHover?.Invoke(this, args); protected virtual void OnMouseLeave(MouseMoveEventArgs args) => MouseLeave?.Invoke(this, args); public void Focus() { Root?.Focus(this); } internal virtual void NotifyUpdate() { OnUpdate(); } internal virtual void NotifyPaint(CommandQueue draw) { OnPaint(draw); } internal void NotifyFocusChanged(FocusChangedEventArgs args) { if (args.Focused == this) { OnFocusAcquired(args); } else { OnFocusLost(args); } } internal virtual void NotifyParentChanged(ParentChangedEventArgs args) { OnParentChanging(args); Parent = args.NewParent; } internal virtual void NotifyRootChanged(RootChangedEventArgs args) { OnRootChanging(args); Root = args.NewRoot; } internal virtual void NotifyMouseMove(MouseMoveEventArgs args) { QRectangle bounds = AbsoluteBounds; if (bounds.Contains(args.AbsolutePosition)) { if (!bounds.Contains(args.AbsolutePosition - args.Motion)) { OnMouseEnter(args); } OnMouseMove(args); } else if (bounds.Contains(args.AbsolutePosition - args.Motion)) { OnMouseLeave(args); } } internal virtual void NotifyMouseDown(MouseButtonEventArgs args) { if (AbsoluteBounds.Contains(args.AbsolutePosition)) { OnMouseDown(args); DownButtons = args.Buttons; } } internal virtual void NotifyMouseUp(MouseButtonEventArgs args) { if (AbsoluteBounds.Contains(args.AbsolutePosition)) { MouseButton mask; OnMouseUp(args); if ((mask = DownButtons & args.Buttons) > 0) { MouseButtonEventArgs nargs = new MouseButtonEventArgs(args.AbsolutePosition, mask); Focus(); OnClicked(nargs); } DownButtons &= ~mask; } else { DownButtons = 0; } } } }