Dean Herbert 31de4de720 Remove median/mode slider velocity display
The intention was to give an idea of what the most common velocity of
the beatmap is, but in hindsight, because the "base" velocity is being
set elsewhere this doesn't make sense. It will/should be 1.0x.

Showing this range is still valuable, though.
2023-05-08 13:13:09 +09:00

179 lines
6.7 KiB
C#

// 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.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Screens.Edit.Timing;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
{
public partial class DifficultyPointPiece : HitObjectPointPiece, IHasPopover
{
public readonly HitObject HitObject;
private readonly BindableNumber<double> speedMultiplier;
public DifficultyPointPiece(HitObject hitObject)
{
HitObject = hitObject;
speedMultiplier = (hitObject as IHasSliderVelocity)?.SliderVelocityBindable.GetBoundCopy();
}
protected override Color4 GetRepresentingColour(OsuColour colours) => colours.Lime1;
protected override void LoadComplete()
{
base.LoadComplete();
speedMultiplier.BindValueChanged(multiplier => Label.Text = $"{multiplier.NewValue:n2}x", true);
}
protected override bool OnClick(ClickEvent e)
{
this.ShowPopover();
return true;
}
public Popover GetPopover() => new DifficultyEditPopover(HitObject);
public partial class DifficultyEditPopover : OsuPopover
{
private readonly HitObject hitObject;
private IndeterminateSliderWithTextBoxInput<double> sliderVelocitySlider;
[Resolved(canBeNull: true)]
private EditorBeatmap beatmap { get; set; }
public DifficultyEditPopover(HitObject hitObject)
{
this.hitObject = hitObject;
}
[BackgroundDependencyLoader]
private void load()
{
Children = new Drawable[]
{
new FillFlowContainer
{
Width = 200,
Direction = FillDirection.Vertical,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(0, 15),
Children = new Drawable[]
{
sliderVelocitySlider = new IndeterminateSliderWithTextBoxInput<double>("Velocity", new BindableDouble(1)
{
Precision = 0.01,
MinValue = 0.1,
MaxValue = 10
})
{
KeyboardStep = 0.1f
},
new OsuTextFlowContainer
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Text = "Hold shift while dragging the end of an object to adjust velocity while snapping."
},
new SliderVelocityInspector(),
}
}
};
// if the piece belongs to a currently selected object, assume that the user wants to change all selected objects.
// if the piece belongs to an unselected object, operate on that object alone, independently of the selection.
var relevantObjects = (beatmap.SelectedHitObjects.Contains(hitObject) ? beatmap.SelectedHitObjects : hitObject.Yield()).Where(o => o is IHasSliderVelocity).ToArray();
// even if there are multiple objects selected, we can still display a value if they all have the same value.
var selectedPointBindable = relevantObjects.Select(point => ((IHasSliderVelocity)point).SliderVelocity).Distinct().Count() == 1
? ((IHasSliderVelocity)relevantObjects.First()).SliderVelocityBindable
: null;
if (selectedPointBindable != null)
{
// there may be legacy control points, which contain infinite precision for compatibility reasons (see LegacyDifficultyControlPoint).
// generally that level of precision could only be set by externally editing the .osu file, so at the point
// a user is looking to update this within the editor it should be safe to obliterate this additional precision.
sliderVelocitySlider.Current.Value = selectedPointBindable.Value;
}
sliderVelocitySlider.Current.BindValueChanged(val =>
{
if (val.NewValue == null)
return;
beatmap.BeginChange();
foreach (var h in relevantObjects)
{
((IHasSliderVelocity)h).SliderVelocity = val.NewValue.Value;
beatmap.Update(h);
}
beatmap.EndChange();
});
}
protected override void LoadComplete()
{
base.LoadComplete();
ScheduleAfterChildren(() => GetContainingInputManager().ChangeFocus(sliderVelocitySlider));
}
}
}
internal partial class SliderVelocityInspector : EditorInspector
{
[BackgroundDependencyLoader]
private void load()
{
EditorBeatmap.TransactionBegan += updateInspectorText;
EditorBeatmap.TransactionEnded += updateInspectorText;
updateInspectorText();
}
private void updateInspectorText()
{
InspectorText.Clear();
double[] sliderVelocities = EditorBeatmap.HitObjects.OfType<IHasSliderVelocity>().Select(sv => sv.SliderVelocity).OrderBy(v => v).ToArray();
if (sliderVelocities.First() != sliderVelocities.Last())
{
AddHeader("Used velocity range");
AddValue($"{sliderVelocities.First():#,0.00}x - {sliderVelocities.Last():#,0.00}x");
}
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
EditorBeatmap.TransactionBegan -= updateInspectorText;
EditorBeatmap.TransactionEnded -= updateInspectorText;
}
}
}