Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Collapse sample point indicators into dots if they cannot be displayed in full #29896

Merged
merged 12 commits into from
Nov 14, 2024
Merged
2 changes: 1 addition & 1 deletion osu.Game.Rulesets.Mania/Edit/ManiaHitObjectComposer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ protected override void Update()
base.Update();

if (screenWithTimeline?.TimelineArea.Timeline != null)
drawableRuleset.TimelineTimeRange = EditorClock.TrackLength / screenWithTimeline.TimelineArea.Timeline.CurrentZoom / 2;
drawableRuleset.TimelineTimeRange = EditorClock.TrackLength / screenWithTimeline.TimelineArea.Timeline.CurrentZoom.Value / 2;
}
}
}
4 changes: 3 additions & 1 deletion osu.Game/Configuration/OsuConfigManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ protected override void InitialiseDefaults()

SetDefault(OsuSetting.EditorTimelineShowTimingChanges, true);
SetDefault(OsuSetting.EditorTimelineShowTicks, true);
SetDefault(OsuSetting.EditorTimelineShowSamples, true);

SetDefault(OsuSetting.AlwaysShowHoldForMenuButton, false);
}
Expand Down Expand Up @@ -431,6 +432,7 @@ public enum OsuSetting
HideCountryFlags,
EditorTimelineShowTimingChanges,
EditorTimelineShowTicks,
AlwaysShowHoldForMenuButton
AlwaysShowHoldForMenuButton,
EditorTimelineShowSamples
}
}
5 changes: 5 additions & 0 deletions osu.Game/Localisation/EditorStrings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ public static class EditorStrings
/// </summary>
public static LocalisableString TimelineShowTicks => new TranslatableString(getKey(@"timeline_show_ticks"), @"Show ticks");

/// <summary>
/// "Show samples"
/// </summary>
public static LocalisableString TimelineShowSamples => new TranslatableString(getKey(@"timeline_show_samples"), @"Show samples");

private static string getKey(string key) => $@"{prefix}:{key}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ public partial class HitObjectPointPiece : CircularContainer
{
protected OsuSpriteText Label { get; private set; }

protected Container LabelContainer { get; private set; }

[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Expand All @@ -26,7 +28,7 @@ private void load(OsuColour colours)

InternalChildren = new Drawable[]
{
new Container
LabelContainer = new Container
{
AutoSizeAxes = Axes.X,
Height = 16,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using osu.Framework.Input.Events;
using osu.Framework.Utils;
using osu.Game.Audio;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Graphics.UserInterfaceV2;
Expand All @@ -40,6 +41,11 @@ public partial class SamplePointPiece : HitObjectPointPiece, IHasPopover
[Resolved]
private Editor? editor { get; set; }

[Resolved]
private TimelineBlueprintContainer? timelineBlueprintContainer { get; set; }

private Bindable<bool> samplesVisible = null!;

public SamplePointPiece(HitObject hitObject)
{
HitObject = hitObject;
Expand All @@ -53,13 +59,46 @@ public SamplePointPiece(HitObject hitObject)
protected virtual double GetTime() => HitObject is IHasRepeats r ? HitObject.StartTime + r.Duration / r.SpanCount() / 2 : HitObject.StartTime;

[BackgroundDependencyLoader]
private void load()
private void load(OsuConfigManager config)
{
HitObject.DefaultsApplied += _ => updateText();
Label.AllowMultiline = false;
LabelContainer.AutoSizeAxes = Axes.None;
updateText();

if (editor != null)
editor.ShowSampleEditPopoverRequested += onShowSampleEditPopoverRequested;

samplesVisible = config.GetBindable<bool>(OsuSetting.EditorTimelineShowSamples);
}

private readonly Bindable<bool> contracted = new Bindable<bool>();

protected override void LoadComplete()
{
base.LoadComplete();

samplesVisible.BindValueChanged(visible => this.FadeTo(visible.NewValue ? 1 : 0, 200, Easing.OutQuint));
this.FadeTo(samplesVisible.Value ? 1 : 0);

if (timelineBlueprintContainer != null)
contracted.BindTo(timelineBlueprintContainer.SamplePointContracted);

contracted.BindValueChanged(v =>
{
if (v.NewValue)
{
Label.FadeOut(200, Easing.OutQuint);
LabelContainer.ResizeTo(new Vector2(12), 200, Easing.OutQuint);
LabelContainer.CornerRadius = 6;
}
else
{
Label.FadeIn(200, Easing.OutQuint);
LabelContainer.ResizeTo(new Vector2(Label.Width, 16), 200, Easing.OutQuint);
LabelContainer.CornerRadius = 8;
}
}, true);
}

protected override void Dispose(bool isDisposing)
Expand Down Expand Up @@ -87,6 +126,9 @@ protected override bool OnClick(ClickEvent e)
private void updateText()
{
Label.Text = $"{abbreviateBank(GetBankValue(GetSamples()))} {GetVolumeValue(GetSamples())}";

if (!contracted.Value)
LabelContainer.ResizeWidthTo(Label.Width, 200, Easing.OutQuint);
}

private static string? abbreviateBank(string? bank)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,19 @@
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)]
Expand All @@ -35,6 +38,8 @@ internal partial class TimelineBlueprintContainer : EditorBlueprintContainer

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.
Expand All @@ -49,6 +54,8 @@ public TimelineBlueprintContainer(HitObjectComposer composer)
Origin = Anchor.Centre;

Height = 0.6f;

AddLayout(samplePointContractedStateCache);
}

[BackgroundDependencyLoader]
Expand Down Expand Up @@ -116,11 +123,43 @@ protected override void Update()
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)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can't be done. While SelectionBlueprints will only contain the visible blueprints in the general case... it will also contain more blueprints if they are selected. In fact if you select every object you may see these contract for no reason:

2024-10-21.12-00-51.mp4

I imagine this will also make selecting all objects even slower than it usually is, although crude profiling shows maybe not very much:

1729505224

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're very right. I forgot the Ctrl+A loads every single selection blueprint. I'll find some way to get only the visible blueprints.

The performance impact is probably small because it only does a simple operation per each blueprint.

{
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()
Expand Down Expand Up @@ -288,6 +327,8 @@ protected partial class TimelineSelectionBlueprintContainer : Container<Selectio
{
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 });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transforms;
Expand Down Expand Up @@ -32,10 +33,10 @@ public partial class ZoomableScrollContainer : OsuScrollContainer
protected override Container<Drawable> Content => zoomedContent;

/// <summary>
/// The current zoom level of <see cref="ZoomableScrollContainer"/>.
/// The current (final) zoom level of <see cref="ZoomableScrollContainer"/>.
/// It may differ from <see cref="Zoom"/> during transitions.
/// </summary>
public float CurrentZoom { get; private set; } = 1;
public BindableFloat CurrentZoom { get; private set; } = new BindableFloat(1);

private bool isZoomSetUp;

Expand Down Expand Up @@ -98,7 +99,7 @@ protected void SetupZoom(float initial, float minimum, float maximum)
minZoom = minimum;
maxZoom = maximum;

CurrentZoom = zoomTarget = initial;
CurrentZoom.Value = zoomTarget = initial;
zoomedContentWidthCache.Invalidate();

isZoomSetUp = true;
Expand All @@ -124,7 +125,7 @@ private void updateZoom(float value)
if (IsLoaded)
setZoomTarget(newZoom, ToSpaceOfOtherDrawable(new Vector2(DrawWidth / 2, 0), zoomedContent).X);
else
CurrentZoom = zoomTarget = newZoom;
CurrentZoom.Value = zoomTarget = newZoom;
}

protected override void UpdateAfterChildren()
Expand Down Expand Up @@ -154,7 +155,7 @@ protected override bool OnScroll(ScrollEvent e)

private void updateZoomedContentWidth()
{
zoomedContent.Width = DrawWidth * CurrentZoom;
zoomedContent.Width = DrawWidth * CurrentZoom.Value;
zoomedContentWidthCache.Validate();
}

Expand Down Expand Up @@ -238,7 +239,7 @@ protected override void Apply(ZoomableScrollContainer d, double time)
float expectedWidth = d.DrawWidth * newZoom;
float targetOffset = expectedWidth * (focusPoint / contentSize) - focusOffset;

d.CurrentZoom = newZoom;
d.CurrentZoom.Value = newZoom;
d.updateZoomedContentWidth();

// Temporarily here to make sure ScrollTo gets the correct DrawSize for scrollable area.
Expand All @@ -247,7 +248,7 @@ protected override void Apply(ZoomableScrollContainer d, double time)
d.ScrollTo(targetOffset, false);
}

protected override void ReadIntoStartValue(ZoomableScrollContainer d) => StartValue = d.CurrentZoom;
protected override void ReadIntoStartValue(ZoomableScrollContainer d) => StartValue = d.CurrentZoom.Value;
}
}
}
6 changes: 6 additions & 0 deletions osu.Game/Screens/Edit/Editor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnl
private Bindable<bool> editorLimitedDistanceSnap;
private Bindable<bool> editorTimelineShowTimingChanges;
private Bindable<bool> editorTimelineShowTicks;
private Bindable<bool> editorTimelineShowSamples;

/// <summary>
/// This controls the opacity of components like the timelines, sidebars, etc.
Expand Down Expand Up @@ -323,6 +324,7 @@ private void load(OsuConfigManager config)
editorLimitedDistanceSnap = config.GetBindable<bool>(OsuSetting.EditorLimitedDistanceSnap);
editorTimelineShowTimingChanges = config.GetBindable<bool>(OsuSetting.EditorTimelineShowTimingChanges);
editorTimelineShowTicks = config.GetBindable<bool>(OsuSetting.EditorTimelineShowTicks);
editorTimelineShowSamples = config.GetBindable<bool>(OsuSetting.EditorTimelineShowSamples);

AddInternal(new OsuContextMenuContainer
{
Expand Down Expand Up @@ -388,6 +390,10 @@ private void load(OsuConfigManager config)
{
State = { BindTarget = editorTimelineShowTicks }
},
new ToggleMenuItem(EditorStrings.TimelineShowSamples)
{
State = { BindTarget = editorTimelineShowSamples }
}
]
},
new BackgroundDimMenuItem(editorBackgroundDim),
Expand Down
Loading