1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-15 15:17:44 +08:00

contract sample point pieces based on smallest gap on the timeline

It finds the smallest distance between two sample point pieces on the alive timeline blueprints
This commit is contained in:
OliBomby 2024-10-05 20:52:45 +02:00
parent 9dcce67b81
commit 48da758c39
2 changed files with 49 additions and 12 deletions

View File

@ -42,7 +42,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
private Editor? editor { get; set; }
[Resolved]
private Timeline? timeline { get; set; }
private TimelineBlueprintContainer? timelineBlueprintContainer { get; set; }
private Bindable<bool> samplesVisible = null!;
@ -72,9 +72,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
samplesVisible = config.GetBindable<bool>(OsuSetting.EditorTimelineShowSamples);
}
private BindableNumber<float>? timelineZoom;
private bool contracted;
private readonly Bindable<bool> contracted = new Bindable<bool>();
protected override void LoadComplete()
{
@ -83,21 +81,19 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
samplesVisible.BindValueChanged(visible => this.FadeTo(visible.NewValue ? 1 : 0, 200, Easing.OutQuint));
this.FadeTo(samplesVisible.Value ? 1 : 0);
timelineZoom = timeline?.CurrentZoom.GetBoundCopy();
timelineZoom?.BindValueChanged(zoom =>
{
const float zoom_threshold = 40f;
if (timelineBlueprintContainer != null)
contracted.BindTo(timelineBlueprintContainer.SamplePointContracted);
if (zoom.NewValue < zoom_threshold)
contracted.BindValueChanged(v =>
{
if (v.NewValue)
{
contracted = true;
Label.FadeOut(200, Easing.OutQuint);
LabelContainer.ResizeTo(new Vector2(12), 200, Easing.OutQuint);
LabelContainer.CornerRadius = 6;
}
else
{
contracted = false;
Label.FadeIn(200, Easing.OutQuint);
LabelContainer.ResizeTo(new Vector2(Label.Width, 16), 200, Easing.OutQuint);
LabelContainer.CornerRadius = 8;
@ -131,7 +127,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
{
Label.Text = $"{abbreviateBank(GetBankValue(GetSamples()))} {GetVolumeValue(GetSamples())}";
if (!contracted)
if (!contracted.Value)
LabelContainer.ResizeWidthTo(Label.Width, 200, Easing.OutQuint);
}

View File

@ -15,16 +15,19 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Framework.Layout;
using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Rulesets.Edit;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
{
[Cached]
internal partial class TimelineBlueprintContainer : EditorBlueprintContainer
{
[Resolved(CanBeNull = true)]
@ -35,6 +38,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
private bool hitObjectDragged;
private readonly LayoutValue samplePointContractedStateCache = new LayoutValue(Invalidation.DrawSize);
/// <remarks>
/// Positional input must be received outside the container's bounds,
/// in order to handle timeline blueprints which are stacked offscreen.
@ -49,6 +54,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
Origin = Anchor.Centre;
Height = 0.6f;
AddLayout(samplePointContractedStateCache);
}
[BackgroundDependencyLoader]
@ -116,11 +123,43 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
Composer.Playfield.FutureLifetimeExtension = timeline.VisibleRange / 2;
}
updateSamplePointContractedState();
base.Update();
updateStacking();
}
public Bindable<bool> SamplePointContracted = new Bindable<bool>();
private void updateSamplePointContractedState()
{
if (samplePointContractedStateCache.IsValid)
return;
const double minimum_gap = 28;
// Find the smallest time gap between any two sample point pieces
double smallestTimeGap = double.PositiveInfinity;
double lastTime = double.PositiveInfinity;
// The blueprints are ordered in reverse chronological order
foreach (var selectionBlueprint in SelectionBlueprints)
{
var hitObject = selectionBlueprint.Item;
if (hitObject is IHasRepeats hasRepeats)
smallestTimeGap = Math.Min(smallestTimeGap, hasRepeats.Duration / hasRepeats.SpanCount() / 2);
smallestTimeGap = Math.Min(smallestTimeGap, lastTime - hitObject.GetEndTime());
lastTime = hitObject.StartTime;
}
double smallestAbsoluteGap = ((TimelineSelectionBlueprintContainer)SelectionBlueprints).ContentRelativeToAbsoluteFactor.X * smallestTimeGap;
SamplePointContracted.Value = smallestAbsoluteGap < minimum_gap;
samplePointContractedStateCache.Validate();
}
private readonly Stack<HitObject> currentConcurrentObjects = new Stack<HitObject>();
private void updateStacking()
@ -288,6 +327,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
{
protected override Container<SelectionBlueprint<HitObject>> Content { get; }
public Vector2 ContentRelativeToAbsoluteFactor => Content.RelativeToAbsoluteFactor;
public TimelineSelectionBlueprintContainer()
{
AddInternal(new TimelinePart<SelectionBlueprint<HitObject>>(Content = new HitObjectOrderedSelectionContainer { RelativeSizeAxes = Axes.Both }) { RelativeSizeAxes = Axes.Both });