A game framework written with osu! in mind.
at master 4.9 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using System.Collections.Generic; 6using System.Linq; 7using JetBrains.Annotations; 8using osu.Framework.Graphics; 9using osu.Framework.Input.Events; 10using osu.Framework.Input.StateChanges; 11using osu.Framework.Input.States; 12using osu.Framework.Logging; 13 14namespace osu.Framework.Input 15{ 16 /// <summary> 17 /// Manages state and events for a single button. 18 /// </summary> 19 public abstract class ButtonEventManager<TButton> 20 { 21 /// <summary> 22 /// The button this <see cref="ButtonEventManager{TButton}"/> manages. 23 /// </summary> 24 public readonly TButton Button; 25 26 /// <summary> 27 /// The input queue for propagating button up events. 28 /// This is created from <see cref="InputQueue"/> when the button is pressed. 29 /// </summary> 30 [CanBeNull] 31 protected List<Drawable> ButtonDownInputQueue { get; private set; } 32 33 /// <summary> 34 /// The input queue. 35 /// </summary> 36 [NotNull] 37 protected IEnumerable<Drawable> InputQueue => GetInputQueue.Invoke() ?? Enumerable.Empty<Drawable>(); 38 39 /// <summary> 40 /// A function to retrieve the input queue. 41 /// </summary> 42 internal Func<IEnumerable<Drawable>> GetInputQueue; 43 44 protected ButtonEventManager(TButton button) 45 { 46 Button = button; 47 } 48 49 /// <summary> 50 /// Handles the button state changing. 51 /// </summary> 52 /// <param name="state">The current <see cref="InputState"/>.</param> 53 /// <param name="kind">The type of change in the button's state.</param> 54 public void HandleButtonStateChange(InputState state, ButtonStateChangeKind kind) 55 { 56 if (kind == ButtonStateChangeKind.Pressed) 57 handleButtonDown(state); 58 else 59 handleButtonUp(state); 60 } 61 62 /// <summary> 63 /// Handles the button being pressed. 64 /// </summary> 65 /// <param name="state">The current <see cref="InputState"/>.</param> 66 /// <returns>Whether the event was handled.</returns> 67 private bool handleButtonDown(InputState state) 68 { 69 List<Drawable> inputQueue = InputQueue.ToList(); 70 Drawable handledBy = HandleButtonDown(state, inputQueue); 71 72 if (handledBy != null) 73 { 74 // 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). 75 var count = inputQueue.IndexOf(handledBy) + 1; 76 inputQueue.RemoveRange(count, inputQueue.Count - count); 77 } 78 79 ButtonDownInputQueue = inputQueue; 80 81 return handledBy != null; 82 } 83 84 /// <summary> 85 /// Handles the button being pressed. 86 /// </summary> 87 /// <param name="state">The current <see cref="InputState"/>.</param> 88 /// <param name="targets">The list of possible targets that can handle the event.</param> 89 /// <returns>The <see cref="Drawable"/> that handled the event.</returns> 90 protected abstract Drawable HandleButtonDown(InputState state, List<Drawable> targets); 91 92 /// <summary> 93 /// Handles the button being released. 94 /// </summary> 95 /// <param name="state">The current <see cref="InputState"/>.</param> 96 private void handleButtonUp(InputState state) 97 { 98 HandleButtonUp(state, ButtonDownInputQueue); 99 ButtonDownInputQueue = null; 100 } 101 102 /// <summary> 103 /// Handles the button being released. 104 /// </summary> 105 /// <param name="state">The current <see cref="InputState"/>.</param> 106 /// <param name="targets">The list of targets that must handle the event. This will contain targets up to the target that handled the button down event.</param> 107 protected abstract void HandleButtonUp(InputState state, List<Drawable> targets); 108 109 /// <summary> 110 /// Triggers events on drawables in <paramref name="drawables"/> until it is handled. 111 /// </summary> 112 /// <param name="drawables">The drawables in the queue.</param> 113 /// <param name="e">The event.</param> 114 /// <returns>The drawable which handled the event or null if none.</returns> 115 protected Drawable PropagateButtonEvent(IEnumerable<Drawable> drawables, UIEvent e) 116 { 117 var handledBy = drawables.FirstOrDefault(target => target.TriggerEvent(e)); 118 119 if (handledBy != null) 120 Logger.Log($"{e} handled by {handledBy}.", LoggingTarget.Runtime, LogLevel.Debug); 121 122 return handledBy; 123 } 124 } 125}