diff --git a/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandleDisplay.cs b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandleDisplay.cs new file mode 100644 index 0000000000..1cba8ca6b3 --- /dev/null +++ b/osu.Game/Screens/Edit/Compose/Components/SelectionBoxDragHandleDisplay.cs @@ -0,0 +1,103 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; + +namespace osu.Game.Screens.Edit.Compose.Components +{ + /// + /// Represents a display composite containing and managing the visibility state of the selection box's drag handles. + /// + public class SelectionBoxDragHandleDisplay : CompositeDrawable + { + private Container scaleHandles; + private Container rotationHandles; + + private readonly List allDragHandles = new List(); + + public new MarginPadding Padding + { + get => base.Padding; + set => base.Padding = value; + } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + scaleHandles = new Container + { + RelativeSizeAxes = Axes.Both, + }, + rotationHandles = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(-12.5f), + }, + }; + } + + public void AddScaleHandle(SelectionBoxScaleHandle handle) + { + bindDragHandle(handle); + scaleHandles.Add(handle); + } + + public void AddRotationHandle(SelectionBoxRotationHandle handle) + { + handle.Alpha = 0; + handle.AlwaysPresent = true; + + bindDragHandle(handle); + rotationHandles.Add(handle); + } + + private void bindDragHandle(SelectionBoxDragHandle handle) + { + handle.HoverGained += updateRotationHandlesVisibility; + handle.HoverLost += updateRotationHandlesVisibility; + handle.OperationStarted += updateRotationHandlesVisibility; + handle.OperationEnded += updateRotationHandlesVisibility; + allDragHandles.Add(handle); + } + + private SelectionBoxRotationHandle displayedRotationHandle; + private SelectionBoxDragHandle activeHandle; + + private void updateRotationHandlesVisibility() + { + if (activeHandle?.InOperation == true || activeHandle?.IsHovered == true) + return; + + displayedRotationHandle?.FadeOut(SelectionBoxControl.TRANSFORM_DURATION, Easing.OutQuint); + displayedRotationHandle = null; + + activeHandle = allDragHandles.SingleOrDefault(h => h.InOperation); + activeHandle ??= allDragHandles.SingleOrDefault(h => h.IsHovered); + + if (activeHandle != null) + { + displayedRotationHandle = getCorrespondingRotationHandle(activeHandle, rotationHandles); + displayedRotationHandle?.FadeIn(SelectionBoxControl.TRANSFORM_DURATION, Easing.OutQuint); + } + } + + /// + /// Gets the rotation handle corresponding to the given handle. + /// + [CanBeNull] + private static SelectionBoxRotationHandle getCorrespondingRotationHandle(SelectionBoxDragHandle handle, IEnumerable rotationHandles) + { + if (handle is SelectionBoxRotationHandle rotationHandle) + return rotationHandle; + + return rotationHandles.SingleOrDefault(r => r.Anchor == handle.Anchor); + } + } +}