diff --git a/osu.Game/Graphics/Containers/ExpandingContainer.cs b/osu.Game/Graphics/Containers/ExpandingContainer.cs index 477de616ac..93595f186f 100644 --- a/osu.Game/Graphics/Containers/ExpandingContainer.cs +++ b/osu.Game/Graphics/Containers/ExpandingContainer.cs @@ -40,21 +40,22 @@ namespace osu.Game.Graphics.Containers RelativeSizeAxes = Axes.Y; Width = contractedWidth; - InternalChild = new OsuScrollContainer + InternalChild = CreateScrollContainer().With(s => { - RelativeSizeAxes = Axes.Both, - ScrollbarVisible = false, - Child = FillFlow = new FillFlowContainer - { - Origin = Anchor.CentreLeft, - Anchor = Anchor.CentreLeft, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - }, - }; + s.RelativeSizeAxes = Axes.Both; + s.ScrollbarVisible = false; + }).WithChild(FillFlow = new FillFlowContainer + { + Origin = Anchor.CentreLeft, + Anchor = Anchor.CentreLeft, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + }); } + protected virtual OsuScrollContainer CreateScrollContainer() => new OsuScrollContainer(); + private ScheduledDelegate? hoverExpandEvent; protected override void LoadComplete() diff --git a/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs b/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs index 2a94ae6017..4119943f76 100644 --- a/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs +++ b/osu.Game/Rulesets/Edit/ExpandingToolboxContainer.cs @@ -1,10 +1,13 @@ // 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.Linq; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Input.Events; +using osu.Framework.Utils; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Screens.Edit; @@ -21,6 +24,7 @@ namespace osu.Game.Rulesets.Edit private readonly Bindable contractSidebars = new Bindable(); private bool expandOnHover; + private OffsetMaintainingScrollContainer scrollContainer = null!; [Resolved] private Editor? editor { get; set; } @@ -42,6 +46,25 @@ namespace osu.Game.Rulesets.Edit config.BindWith(OsuSetting.EditorContractSidebars, contractSidebars); } + protected override OsuScrollContainer CreateScrollContainer() => scrollContainer = new OffsetMaintainingScrollContainer(); + + protected override void LoadComplete() + { + base.LoadComplete(); + + var inputManager = GetContainingInputManager(); + + if (inputManager != null) + { + Expanded.BindValueChanged(_ => + { + var position = new Vector2(ScreenSpaceDrawQuad.Centre.X, inputManager.CurrentState.Mouse.Position.Y); + + scrollContainer.TargetDrawable = Children.FirstOrDefault(it => it.Contains(position)); + }); + } + } + protected override void Update() { base.Update(); @@ -53,10 +76,57 @@ namespace osu.Game.Rulesets.Edit expandOnHover = requireContracting; Expanded.Value = !expandOnHover; } + + if (scrollContainer.TargetDrawable != null && !TransformsForTargetMember(nameof(Width)).Any()) + scrollContainer.TargetDrawable = null; } protected override bool OnMouseDown(MouseDownEvent e) => true; protected override bool OnClick(ClickEvent e) => true; + + private partial class OffsetMaintainingScrollContainer : OsuScrollContainer + { + private Drawable? targetDrawable; + private float targetPosition; + + public Drawable? TargetDrawable + { + get => targetDrawable; + set + { + targetDrawable = value; + + if (value != null) + targetPosition = ToLocalSpace(value.ScreenSpaceDrawQuad.TopLeft).Y; + } + } + + protected override void UpdateAfterChildren() + { + if (targetDrawable != null) + { + float currentPosition = ToLocalSpace(targetDrawable.ScreenSpaceDrawQuad.TopLeft).Y; + + if (!Precision.AlmostEquals(targetPosition, currentPosition)) + { + double offset = currentPosition - targetPosition; + + double scrollTarget = Math.Clamp(Current + offset, 0, ScrollableExtent); + + ScrollTo(scrollTarget, false, double.PositiveInfinity); + } + } + + base.UpdateAfterChildren(); + } + + protected override void OnUserScroll(double value, bool animated = true, double? distanceDecay = null) + { + targetDrawable = null; + + base.OnUserScroll(value, animated, distanceDecay); + } + } } }