// Copyright (c) Wojciech Figat. All rights reserved. using System; using System.Collections.Generic; namespace FlaxEngine.GUI { /// /// GUI root control that is represented by a window or a canvas and can contain children but has no parent at all. It's a source of the input events. /// public abstract class RootControl : ContainerControl { private static ContainerControl _gameRoot; private static CanvasContainer _canvasContainer = new CanvasContainer(); /// /// Gets the main GUI control (it can be window or editor overriden control). Use it to plug-in custom GUI controls. /// public static ContainerControl GameRoot { get => _gameRoot; internal set { _gameRoot = value; _canvasContainer.Parent = _gameRoot; } } /// /// Gets the canvas controls root container. /// internal static CanvasContainer CanvasRoot => _canvasContainer; /// /// Gets or sets the current focused control /// public abstract Control FocusedControl { get; set; } /// /// Gets the tracking mouse offset. /// public abstract Float2 TrackingMouseOffset { get; } /// /// Gets or sets the position of the mouse in the window space coordinates. /// public abstract Float2 MousePosition { get; set; } /// /// The update callbacks collection. Controls can register for this to get the update event for logic handling. /// public readonly List UpdateCallbacks = new List(1024); /// /// The update callbacks to add before invoking the update. /// public List UpdateCallbacksToAdd = new List(); /// /// The update callbacks to remove before invoking the update. /// public List UpdateCallbacksToRemove = new List(); /// /// Initializes a new instance of the class. /// protected RootControl() : base(0, 0, 100, 60) { AutoFocus = false; } #region Navigation /// /// The custom callback function for UI navigation. Can be used to override the default behaviour. /// public Action CustomNavigation; /// /// Performs the UI navigation. /// /// The navigation direction. public void Navigate(NavDirection direction) { if (direction == NavDirection.None) return; if (CustomNavigation != null) { // Custom CustomNavigation.Invoke(direction); return; } var focused = FocusedControl; if (focused == null) { // Nothing is focused so go to the first control focused = OnNavigate(direction, Float2.Zero, this, new List()); focused?.NavigationFocus(); return; } var target = focused.GetNavTarget(direction); if (target != null) { // Explicitly specified focus target target.NavigationFocus(); return; } // Automatic navigation routine target = focused.OnNavigate(direction, focused.GetNavOrigin(direction), this, new List()); target?.NavigationFocus(); } /// /// Submits the currently focused control. /// public void SubmitFocused() { FocusedControl?.OnSubmit(); } #endregion /// public override void Update(float deltaTime) { base.Update(deltaTime); // Flush requests Profiler.BeginEvent("RootControl.SyncCallbacks"); for (int i = 0; i < UpdateCallbacksToAdd.Count; i++) { UpdateCallbacks.Add(UpdateCallbacksToAdd[i]); } UpdateCallbacksToAdd.Clear(); for (int i = 0; i < UpdateCallbacksToRemove.Count; i++) { UpdateCallbacks.Remove(UpdateCallbacksToRemove[i]); } UpdateCallbacksToRemove.Clear(); Profiler.EndEvent(); // Perform the UI update try { Profiler.BeginEvent("RootControl.Update"); for (int i = 0; i < UpdateCallbacks.Count; i++) { UpdateCallbacks[i](deltaTime); } } finally { Profiler.EndEvent(); } } /// public override bool RayCast(ref Float2 location, out Control hit) { // Ignore self return RayCastChildren(ref location, out hit); } /// public override bool ContainsPoint(ref Float2 location, bool precise = false) { if (precise) // Ignore as utility-only element return false; return base.ContainsPoint(ref location, precise); } /// /// Starts the mouse tracking. Used by the scrollbars, splitters, etc. /// /// The target control that want to track mouse. It will receive OnMouseMove event. /// If set to true will use mouse screen offset. public abstract void StartTrackingMouse(Control control, bool useMouseScreenOffset); /// /// Ends the mouse tracking. /// public abstract void EndTrackingMouse(); /// /// Gets keyboard key state. /// /// Key to check. /// True while the user holds down the key identified by id. public abstract bool GetKey(KeyboardKeys key); /// /// Gets keyboard key down state. /// /// Key to check. /// True during the frame the user starts pressing down the key. public abstract bool GetKeyDown(KeyboardKeys key); /// /// Gets keyboard key up state. /// /// Key to check. /// True during the frame the user releases the button. public abstract bool GetKeyUp(KeyboardKeys key); /// /// Gets mouse button state. /// /// Mouse button to check. /// True while the user holds down the button. public abstract bool GetMouseButton(MouseButton button); /// /// Gets mouse button down state. /// /// Mouse button to check. /// True during the frame the user starts pressing down the button. public abstract bool GetMouseButtonDown(MouseButton button); /// /// Gets mouse button up state. /// /// Mouse button to check. /// True during the frame the user releases the button. public abstract bool GetMouseButtonUp(MouseButton button); /// public override RootControl Root => this; } }