// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.Collections.Generic; using System.Linq; using JetBrains.Annotations; using osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Framework.Input.StateChanges; using osu.Framework.Input.States; using osu.Framework.Logging; namespace osu.Framework.Input { /// /// Manages state and events for a single button. /// public abstract class ButtonEventManager { /// /// The button this manages. /// public readonly TButton Button; /// /// The input queue for propagating button up events. /// This is created from when the button is pressed. /// [CanBeNull] protected List ButtonDownInputQueue { get; private set; } /// /// The input queue. /// [NotNull] protected IEnumerable InputQueue => GetInputQueue.Invoke() ?? Enumerable.Empty(); /// /// A function to retrieve the input queue. /// internal Func> GetInputQueue; protected ButtonEventManager(TButton button) { Button = button; } /// /// Handles the button state changing. /// /// The current . /// The type of change in the button's state. public void HandleButtonStateChange(InputState state, ButtonStateChangeKind kind) { if (kind == ButtonStateChangeKind.Pressed) handleButtonDown(state); else handleButtonUp(state); } /// /// Handles the button being pressed. /// /// The current . /// Whether the event was handled. private bool handleButtonDown(InputState state) { List inputQueue = InputQueue.ToList(); Drawable handledBy = HandleButtonDown(state, inputQueue); if (handledBy != null) { // only drawables up to the one that handled mouse down should handle mouse up, so remove all subsequent drawables from the queue (for future use). var count = inputQueue.IndexOf(handledBy) + 1; inputQueue.RemoveRange(count, inputQueue.Count - count); } ButtonDownInputQueue = inputQueue; return handledBy != null; } /// /// Handles the button being pressed. /// /// The current . /// The list of possible targets that can handle the event. /// The that handled the event. protected abstract Drawable HandleButtonDown(InputState state, List targets); /// /// Handles the button being released. /// /// The current . private void handleButtonUp(InputState state) { HandleButtonUp(state, ButtonDownInputQueue); ButtonDownInputQueue = null; } /// /// Handles the button being released. /// /// The current . /// The list of targets that must handle the event. This will contain targets up to the target that handled the button down event. protected abstract void HandleButtonUp(InputState state, List targets); /// /// Triggers events on drawables in until it is handled. /// /// The drawables in the queue. /// The event. /// The drawable which handled the event or null if none. protected Drawable PropagateButtonEvent(IEnumerable drawables, UIEvent e) { var handledBy = drawables.FirstOrDefault(target => target.TriggerEvent(e)); if (handledBy != null) Logger.Log($"{e} handled by {handledBy}.", LoggingTarget.Runtime, LogLevel.Debug); return handledBy; } } }