mirror of
https://github.com/ppy/osu.git
synced 2024-12-14 07:42:57 +08:00
Merge branch 'master' into crop-texture-uploads-song-select
This commit is contained in:
commit
e6503c24c8
@ -15,187 +15,175 @@ namespace osu.Game.Rulesets.Taiko.Tests.Judgements
|
||||
[Test]
|
||||
public void TestHitAllDrumRoll()
|
||||
{
|
||||
const double hit_time = 1000;
|
||||
|
||||
PerformTest(new List<ReplayFrame>
|
||||
{
|
||||
new TaikoReplayFrame(0),
|
||||
new TaikoReplayFrame(1000, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(1001),
|
||||
new TaikoReplayFrame(1250, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(1251),
|
||||
new TaikoReplayFrame(1500, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(1501),
|
||||
new TaikoReplayFrame(1750, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(1751),
|
||||
new TaikoReplayFrame(2000, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(2001),
|
||||
}, CreateBeatmap(new DrumRoll
|
||||
{
|
||||
StartTime = hit_time,
|
||||
Duration = 1000
|
||||
}));
|
||||
}, CreateBeatmap(createDrumRoll(false)));
|
||||
|
||||
AssertJudgementCount(3);
|
||||
AssertJudgementCount(6);
|
||||
AssertResult<DrumRollTick>(0, HitResult.SmallBonus);
|
||||
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
|
||||
AssertResult<DrumRollTick>(2, HitResult.SmallBonus);
|
||||
AssertResult<DrumRollTick>(3, HitResult.SmallBonus);
|
||||
AssertResult<DrumRollTick>(4, HitResult.SmallBonus);
|
||||
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHitSomeDrumRoll()
|
||||
{
|
||||
const double hit_time = 1000;
|
||||
|
||||
PerformTest(new List<ReplayFrame>
|
||||
{
|
||||
new TaikoReplayFrame(0),
|
||||
new TaikoReplayFrame(2000, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(2001),
|
||||
}, CreateBeatmap(new DrumRoll
|
||||
{
|
||||
StartTime = hit_time,
|
||||
Duration = 1000
|
||||
}));
|
||||
}, CreateBeatmap(createDrumRoll(false)));
|
||||
|
||||
AssertJudgementCount(3);
|
||||
AssertJudgementCount(6);
|
||||
AssertResult<DrumRollTick>(0, HitResult.IgnoreMiss);
|
||||
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
|
||||
AssertResult<DrumRollTick>(1, HitResult.IgnoreMiss);
|
||||
AssertResult<DrumRollTick>(2, HitResult.IgnoreMiss);
|
||||
AssertResult<DrumRollTick>(3, HitResult.IgnoreMiss);
|
||||
AssertResult<DrumRollTick>(4, HitResult.SmallBonus);
|
||||
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHitNoneDrumRoll()
|
||||
{
|
||||
const double hit_time = 1000;
|
||||
|
||||
PerformTest(new List<ReplayFrame>
|
||||
{
|
||||
new TaikoReplayFrame(0),
|
||||
}, CreateBeatmap(new DrumRoll
|
||||
{
|
||||
StartTime = hit_time,
|
||||
Duration = 1000
|
||||
}));
|
||||
}, CreateBeatmap(createDrumRoll(false)));
|
||||
|
||||
AssertJudgementCount(3);
|
||||
AssertJudgementCount(6);
|
||||
AssertResult<DrumRollTick>(0, HitResult.IgnoreMiss);
|
||||
AssertResult<DrumRollTick>(1, HitResult.IgnoreMiss);
|
||||
AssertResult<DrumRollTick>(2, HitResult.IgnoreMiss);
|
||||
AssertResult<DrumRollTick>(3, HitResult.IgnoreMiss);
|
||||
AssertResult<DrumRollTick>(4, HitResult.IgnoreMiss);
|
||||
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHitAllStrongDrumRollWithOneKey()
|
||||
{
|
||||
const double hit_time = 1000;
|
||||
|
||||
PerformTest(new List<ReplayFrame>
|
||||
{
|
||||
new TaikoReplayFrame(0),
|
||||
new TaikoReplayFrame(1000, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(1001),
|
||||
new TaikoReplayFrame(1250, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(1251),
|
||||
new TaikoReplayFrame(1500, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(1501),
|
||||
new TaikoReplayFrame(1750, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(1751),
|
||||
new TaikoReplayFrame(2000, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(2001),
|
||||
}, CreateBeatmap(new DrumRoll
|
||||
}, CreateBeatmap(createDrumRoll(true)));
|
||||
|
||||
AssertJudgementCount(12);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
StartTime = hit_time,
|
||||
Duration = 1000,
|
||||
IsStrong = true
|
||||
}));
|
||||
|
||||
AssertJudgementCount(6);
|
||||
|
||||
AssertResult<DrumRollTick>(0, HitResult.SmallBonus);
|
||||
AssertResult<StrongNestedHitObject>(0, HitResult.LargeBonus);
|
||||
|
||||
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
|
||||
AssertResult<StrongNestedHitObject>(1, HitResult.LargeBonus);
|
||||
AssertResult<DrumRollTick>(i, HitResult.SmallBonus);
|
||||
AssertResult<StrongNestedHitObject>(i, HitResult.LargeBonus);
|
||||
}
|
||||
|
||||
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
|
||||
AssertResult<StrongNestedHitObject>(2, HitResult.IgnoreHit);
|
||||
AssertResult<StrongNestedHitObject>(5, HitResult.IgnoreHit);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHitSomeStrongDrumRollWithOneKey()
|
||||
{
|
||||
const double hit_time = 1000;
|
||||
|
||||
PerformTest(new List<ReplayFrame>
|
||||
{
|
||||
new TaikoReplayFrame(0),
|
||||
new TaikoReplayFrame(2000, TaikoAction.LeftCentre),
|
||||
new TaikoReplayFrame(2001),
|
||||
}, CreateBeatmap(new DrumRoll
|
||||
{
|
||||
StartTime = hit_time,
|
||||
Duration = 1000,
|
||||
IsStrong = true
|
||||
}));
|
||||
}, CreateBeatmap(createDrumRoll(true)));
|
||||
|
||||
AssertJudgementCount(6);
|
||||
AssertJudgementCount(12);
|
||||
|
||||
AssertResult<DrumRollTick>(0, HitResult.IgnoreMiss);
|
||||
AssertResult<StrongNestedHitObject>(0, HitResult.IgnoreMiss);
|
||||
|
||||
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
|
||||
AssertResult<StrongNestedHitObject>(1, HitResult.LargeBonus);
|
||||
AssertResult<DrumRollTick>(4, HitResult.SmallBonus);
|
||||
AssertResult<StrongNestedHitObject>(4, HitResult.LargeBonus);
|
||||
|
||||
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
|
||||
AssertResult<StrongNestedHitObject>(2, HitResult.IgnoreHit);
|
||||
AssertResult<StrongNestedHitObject>(5, HitResult.IgnoreHit);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHitAllStrongDrumRollWithBothKeys()
|
||||
{
|
||||
const double hit_time = 1000;
|
||||
|
||||
PerformTest(new List<ReplayFrame>
|
||||
{
|
||||
new TaikoReplayFrame(0),
|
||||
new TaikoReplayFrame(1000, TaikoAction.LeftCentre, TaikoAction.RightCentre),
|
||||
new TaikoReplayFrame(1001),
|
||||
new TaikoReplayFrame(1250, TaikoAction.LeftCentre, TaikoAction.RightCentre),
|
||||
new TaikoReplayFrame(1251),
|
||||
new TaikoReplayFrame(1500, TaikoAction.LeftCentre, TaikoAction.RightCentre),
|
||||
new TaikoReplayFrame(1501),
|
||||
new TaikoReplayFrame(1750, TaikoAction.LeftCentre, TaikoAction.RightCentre),
|
||||
new TaikoReplayFrame(1751),
|
||||
new TaikoReplayFrame(2000, TaikoAction.LeftCentre, TaikoAction.RightCentre),
|
||||
new TaikoReplayFrame(2001),
|
||||
}, CreateBeatmap(new DrumRoll
|
||||
}, CreateBeatmap(createDrumRoll(true)));
|
||||
|
||||
AssertJudgementCount(12);
|
||||
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
StartTime = hit_time,
|
||||
Duration = 1000,
|
||||
IsStrong = true
|
||||
}));
|
||||
|
||||
AssertJudgementCount(6);
|
||||
|
||||
AssertResult<DrumRollTick>(0, HitResult.SmallBonus);
|
||||
AssertResult<StrongNestedHitObject>(0, HitResult.LargeBonus);
|
||||
|
||||
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
|
||||
AssertResult<StrongNestedHitObject>(1, HitResult.LargeBonus);
|
||||
AssertResult<DrumRollTick>(i, HitResult.SmallBonus);
|
||||
AssertResult<StrongNestedHitObject>(i, HitResult.LargeBonus);
|
||||
}
|
||||
|
||||
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
|
||||
AssertResult<StrongNestedHitObject>(2, HitResult.IgnoreHit);
|
||||
AssertResult<StrongNestedHitObject>(5, HitResult.IgnoreHit);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHitSomeStrongDrumRollWithBothKeys()
|
||||
{
|
||||
const double hit_time = 1000;
|
||||
|
||||
PerformTest(new List<ReplayFrame>
|
||||
{
|
||||
new TaikoReplayFrame(0),
|
||||
new TaikoReplayFrame(2000, TaikoAction.LeftCentre, TaikoAction.RightCentre),
|
||||
new TaikoReplayFrame(2001),
|
||||
}, CreateBeatmap(new DrumRoll
|
||||
{
|
||||
StartTime = hit_time,
|
||||
Duration = 1000,
|
||||
IsStrong = true
|
||||
}));
|
||||
}, CreateBeatmap(createDrumRoll(true)));
|
||||
|
||||
AssertJudgementCount(6);
|
||||
AssertJudgementCount(12);
|
||||
|
||||
AssertResult<DrumRollTick>(0, HitResult.IgnoreMiss);
|
||||
AssertResult<StrongNestedHitObject>(0, HitResult.IgnoreMiss);
|
||||
|
||||
AssertResult<DrumRollTick>(1, HitResult.SmallBonus);
|
||||
AssertResult<StrongNestedHitObject>(1, HitResult.LargeBonus);
|
||||
AssertResult<DrumRollTick>(4, HitResult.SmallBonus);
|
||||
AssertResult<StrongNestedHitObject>(4, HitResult.LargeBonus);
|
||||
|
||||
AssertResult<DrumRoll>(0, HitResult.IgnoreHit);
|
||||
AssertResult<StrongNestedHitObject>(2, HitResult.IgnoreHit);
|
||||
AssertResult<StrongNestedHitObject>(5, HitResult.IgnoreHit);
|
||||
}
|
||||
|
||||
private DrumRoll createDrumRoll(bool strong) => new DrumRoll
|
||||
{
|
||||
StartTime = 1000,
|
||||
Duration = 1000,
|
||||
IsStrong = strong
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -92,6 +92,14 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
}).ToList();
|
||||
}
|
||||
|
||||
// TODO: stable makes the last tick of a drumroll non-required when the next object is too close.
|
||||
// This probably needs to be reimplemented:
|
||||
//
|
||||
// List<HitObject> hitobjects = hitObjectManager.hitObjects;
|
||||
// int ind = hitobjects.IndexOf(this);
|
||||
// if (i < hitobjects.Count - 1 && hitobjects[i + 1].HittableStartTime - (EndTime + (int)TickSpacing) <= (int)TickSpacing)
|
||||
// lastTickHittable = false;
|
||||
|
||||
return converted;
|
||||
}
|
||||
|
||||
@ -133,7 +141,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
||||
StartTime = obj.StartTime,
|
||||
Samples = obj.Samples,
|
||||
Duration = taikoDuration,
|
||||
TickRate = beatmap.Difficulty.SliderTickRate == 3 ? 3 : 4,
|
||||
SliderVelocity = obj is IHasSliderVelocity velocityData ? velocityData.SliderVelocity : 1
|
||||
};
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using System.Threading;
|
||||
using osu.Framework.Bindables;
|
||||
@ -69,6 +67,8 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
||||
double scoringDistance = base_distance * difficulty.SliderMultiplier * SliderVelocity;
|
||||
Velocity = scoringDistance / timingPoint.BeatLength;
|
||||
|
||||
TickRate = difficulty.SliderTickRate == 3 ? 3 : 4;
|
||||
|
||||
tickSpacing = timingPoint.BeatLength / TickRate;
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ namespace osu.Game.Tests.Editing.Checks
|
||||
|
||||
var mock = new Mock<IWorkingBeatmap>();
|
||||
mock.SetupGet(w => w.Beatmap).Returns(beatmap);
|
||||
mock.SetupGet(w => w.GetBackground()).Returns(background);
|
||||
mock.Setup(w => w.GetBackground()).Returns(background);
|
||||
mock.Setup(w => w.GetStream(It.IsAny<string>())).Returns(stream);
|
||||
|
||||
return mock;
|
||||
|
@ -80,6 +80,24 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCorrectScrollToWhenContentLoads()
|
||||
{
|
||||
AddRepeatStep("add many sections", () => append(1f), 3);
|
||||
|
||||
AddStep("add section with delayed load content", () =>
|
||||
{
|
||||
container.Add(new TestDelayedLoadSection("delayed"));
|
||||
});
|
||||
|
||||
AddStep("add final section", () => append(0.5f));
|
||||
|
||||
AddStep("scroll to final section", () => container.ScrollTo(container.Children.Last()));
|
||||
|
||||
AddUntilStep("correct section selected", () => container.SelectedSection.Value == container.Children.Last());
|
||||
AddUntilStep("wait for scroll to section", () => container.ScreenSpaceDrawQuad.AABBFloat.Contains(container.Children.Last().ScreenSpaceDrawQuad.AABBFloat));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSelection()
|
||||
{
|
||||
@ -196,6 +214,33 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
InputManager.ScrollVerticalBy(direction);
|
||||
}
|
||||
|
||||
private partial class TestDelayedLoadSection : TestSection
|
||||
{
|
||||
public TestDelayedLoadSection(string label)
|
||||
: base(label)
|
||||
{
|
||||
BackgroundColour = default_colour;
|
||||
Width = 300;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
Box box;
|
||||
|
||||
Add(box = new Box
|
||||
{
|
||||
Alpha = 0.01f,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
});
|
||||
|
||||
// Emulate an operation that will be inhibited by IsMaskedAway.
|
||||
box.ResizeHeightTo(2000, 50);
|
||||
}
|
||||
}
|
||||
|
||||
private partial class TestSection : TestBox
|
||||
{
|
||||
public bool Selected
|
||||
|
@ -1,17 +1,16 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Layout;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Framework.Utils;
|
||||
|
||||
namespace osu.Game.Graphics.Containers
|
||||
@ -23,11 +22,35 @@ namespace osu.Game.Graphics.Containers
|
||||
public partial class SectionsContainer<T> : Container<T>
|
||||
where T : Drawable
|
||||
{
|
||||
public Bindable<T> SelectedSection { get; } = new Bindable<T>();
|
||||
public Bindable<T?> SelectedSection { get; } = new Bindable<T?>();
|
||||
|
||||
private T lastClickedSection;
|
||||
private T? lastClickedSection;
|
||||
|
||||
public Drawable ExpandableHeader
|
||||
protected override Container<T> Content => scrollContentContainer;
|
||||
|
||||
private readonly UserTrackingScrollContainer scrollContainer;
|
||||
private readonly Container headerBackgroundContainer;
|
||||
private readonly MarginPadding originalSectionsMargin;
|
||||
|
||||
private Drawable? fixedHeader;
|
||||
|
||||
private Drawable? footer;
|
||||
private Drawable? headerBackground;
|
||||
|
||||
private FlowContainer<T> scrollContentContainer = null!;
|
||||
|
||||
private float? headerHeight, footerHeight;
|
||||
|
||||
private float? lastKnownScroll;
|
||||
|
||||
/// <summary>
|
||||
/// The percentage of the container to consider the centre-point for deciding the active section (and scrolling to a requested section).
|
||||
/// </summary>
|
||||
private const float scroll_y_centre = 0.1f;
|
||||
|
||||
private Drawable? expandableHeader;
|
||||
|
||||
public Drawable? ExpandableHeader
|
||||
{
|
||||
get => expandableHeader;
|
||||
set
|
||||
@ -42,11 +65,12 @@ namespace osu.Game.Graphics.Containers
|
||||
if (value == null) return;
|
||||
|
||||
AddInternal(expandableHeader);
|
||||
|
||||
lastKnownScroll = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Drawable FixedHeader
|
||||
public Drawable? FixedHeader
|
||||
{
|
||||
get => fixedHeader;
|
||||
set
|
||||
@ -63,7 +87,7 @@ namespace osu.Game.Graphics.Containers
|
||||
}
|
||||
}
|
||||
|
||||
public Drawable Footer
|
||||
public Drawable? Footer
|
||||
{
|
||||
get => footer;
|
||||
set
|
||||
@ -75,16 +99,17 @@ namespace osu.Game.Graphics.Containers
|
||||
|
||||
footer = value;
|
||||
|
||||
if (value == null) return;
|
||||
if (footer == null) return;
|
||||
|
||||
footer.Anchor |= Anchor.y2;
|
||||
footer.Origin |= Anchor.y2;
|
||||
|
||||
scrollContainer.Add(footer);
|
||||
lastKnownScroll = null;
|
||||
}
|
||||
}
|
||||
|
||||
public Drawable HeaderBackground
|
||||
public Drawable? HeaderBackground
|
||||
{
|
||||
get => headerBackground;
|
||||
set
|
||||
@ -102,23 +127,6 @@ namespace osu.Game.Graphics.Containers
|
||||
}
|
||||
}
|
||||
|
||||
protected override Container<T> Content => scrollContentContainer;
|
||||
|
||||
private readonly UserTrackingScrollContainer scrollContainer;
|
||||
private readonly Container headerBackgroundContainer;
|
||||
private readonly MarginPadding originalSectionsMargin;
|
||||
private Drawable expandableHeader, fixedHeader, footer, headerBackground;
|
||||
private FlowContainer<T> scrollContentContainer;
|
||||
|
||||
private float? headerHeight, footerHeight;
|
||||
|
||||
private float? lastKnownScroll;
|
||||
|
||||
/// <summary>
|
||||
/// The percentage of the container to consider the centre-point for deciding the active section (and scrolling to a requested section).
|
||||
/// </summary>
|
||||
private const float scroll_y_centre = 0.1f;
|
||||
|
||||
public SectionsContainer()
|
||||
{
|
||||
AddRangeInternal(new Drawable[]
|
||||
@ -150,31 +158,63 @@ namespace osu.Game.Graphics.Containers
|
||||
footerHeight = null;
|
||||
}
|
||||
|
||||
private ScheduledDelegate? scrollToTargetDelegate;
|
||||
|
||||
public void ScrollTo(Drawable target)
|
||||
{
|
||||
Logger.Log($"Scrolling to {target}..");
|
||||
|
||||
lastKnownScroll = null;
|
||||
|
||||
// implementation similar to ScrollIntoView but a bit more nuanced.
|
||||
float top = scrollContainer.GetChildPosInContent(target);
|
||||
float scrollTarget = getScrollTargetForDrawable(target);
|
||||
|
||||
float bottomScrollExtent = scrollContainer.ScrollableExtent;
|
||||
float scrollTarget = top - scrollContainer.DisplayableContent * scroll_y_centre;
|
||||
|
||||
if (scrollTarget > bottomScrollExtent)
|
||||
if (scrollTarget > scrollContainer.ScrollableExtent)
|
||||
scrollContainer.ScrollToEnd();
|
||||
else
|
||||
scrollContainer.ScrollTo(scrollTarget);
|
||||
|
||||
if (target is T section)
|
||||
lastClickedSection = section;
|
||||
|
||||
// Content may load in as a scroll occurs, changing the scroll target we need to aim for.
|
||||
// This scheduled operation ensures that we keep trying until actually arriving at the target.
|
||||
scrollToTargetDelegate?.Cancel();
|
||||
scrollToTargetDelegate = Scheduler.AddDelayed(() =>
|
||||
{
|
||||
if (scrollContainer.UserScrolling)
|
||||
{
|
||||
Logger.Log("Scroll operation interrupted by user scroll");
|
||||
scrollToTargetDelegate?.Cancel();
|
||||
scrollToTargetDelegate = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Precision.AlmostEquals(scrollContainer.Current, scrollTarget, 1))
|
||||
{
|
||||
Logger.Log($"Finished scrolling to {target}!");
|
||||
scrollToTargetDelegate?.Cancel();
|
||||
scrollToTargetDelegate = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Precision.AlmostEquals(getScrollTargetForDrawable(target), scrollTarget, 1))
|
||||
{
|
||||
Logger.Log($"Reattempting scroll to {target} due to change in position");
|
||||
ScrollTo(target);
|
||||
}
|
||||
}, 50, true);
|
||||
}
|
||||
|
||||
private float getScrollTargetForDrawable(Drawable target)
|
||||
{
|
||||
// implementation similar to ScrollIntoView but a bit more nuanced.
|
||||
return scrollContainer.GetChildPosInContent(target) - scrollContainer.DisplayableContent * scroll_y_centre;
|
||||
}
|
||||
|
||||
public void ScrollToTop() => scrollContainer.ScrollTo(0);
|
||||
|
||||
[NotNull]
|
||||
protected virtual UserTrackingScrollContainer CreateScrollContainer() => new UserTrackingScrollContainer();
|
||||
|
||||
[NotNull]
|
||||
protected virtual FlowContainer<T> CreateScrollContentContainer() =>
|
||||
new FillFlowContainer<T>
|
||||
{
|
||||
|
@ -328,7 +328,7 @@ namespace osu.Game.Overlays
|
||||
base.UpdateAfterChildren();
|
||||
|
||||
// no null check because the usage of this class is strict
|
||||
HeaderBackground.Alpha = -ExpandableHeader.Y / ExpandableHeader.LayoutSize.Y;
|
||||
HeaderBackground!.Alpha = -ExpandableHeader!.Y / ExpandableHeader.LayoutSize.Y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ namespace osu.Game.Overlays
|
||||
if (lastSection != section.NewValue)
|
||||
{
|
||||
lastSection = section.NewValue;
|
||||
tabs.Current.Value = lastSection;
|
||||
tabs.Current.Value = lastSection!;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -65,7 +65,7 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
sections.SelectedSection.BindValueChanged(section => tabControl.Current.Value = section.NewValue);
|
||||
sections.SelectedSection.BindValueChanged(section => tabControl.Current.Value = section.NewValue!);
|
||||
tabControl.Current.BindValueChanged(section =>
|
||||
{
|
||||
if (section.NewValue != sections.SelectedSection.Value)
|
||||
|
Loading…
Reference in New Issue
Block a user