1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 13:22:55 +08:00

Merge pull request #10077 from peppy/editor-bpm-usability

Improve usability of BPM modifying in timing setup view
This commit is contained in:
Dan Balasescu 2020-09-07 20:02:49 +09:00 committed by GitHub
commit f19d9a29c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,30 +1,30 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // 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. // See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Timing; using osu.Game.Beatmaps.Timing;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings;
namespace osu.Game.Screens.Edit.Timing namespace osu.Game.Screens.Edit.Timing
{ {
internal class TimingSection : Section<TimingControlPoint> internal class TimingSection : Section<TimingControlPoint>
{ {
private SettingsSlider<double> bpm; private SettingsSlider<double> bpmSlider;
private SettingsEnumDropdown<TimeSignatures> timeSignature; private SettingsEnumDropdown<TimeSignatures> timeSignature;
private BPMTextBox bpmTextEntry;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Flow.AddRange(new Drawable[] Flow.AddRange(new Drawable[]
{ {
bpm = new BPMSlider bpmTextEntry = new BPMTextBox(),
{ bpmSlider = new BPMSlider(),
Bindable = new TimingControlPoint().BeatLengthBindable,
LabelText = "BPM",
},
timeSignature = new SettingsEnumDropdown<TimeSignatures> timeSignature = new SettingsEnumDropdown<TimeSignatures>
{ {
LabelText = "Time Signature" LabelText = "Time Signature"
@ -36,7 +36,8 @@ namespace osu.Game.Screens.Edit.Timing
{ {
if (point.NewValue != null) if (point.NewValue != null)
{ {
bpm.Bindable = point.NewValue.BeatLengthBindable; bpmSlider.Bindable = point.NewValue.BeatLengthBindable;
bpmTextEntry.Bindable = point.NewValue.BeatLengthBindable;
timeSignature.Bindable = point.NewValue.TimeSignatureBindable; timeSignature.Bindable = point.NewValue.TimeSignatureBindable;
} }
} }
@ -52,34 +53,88 @@ namespace osu.Game.Screens.Edit.Timing
}; };
} }
private class BPMTextBox : LabelledTextBox
{
private readonly BindableNumber<double> beatLengthBindable = new TimingControlPoint().BeatLengthBindable;
public BPMTextBox()
{
Label = "BPM";
OnCommit += (val, isNew) =>
{
if (!isNew) return;
if (double.TryParse(Current.Value, out double doubleVal))
{
try
{
beatLengthBindable.Value = beatLengthToBpm(doubleVal);
}
catch
{
// will restore the previous text value on failure.
beatLengthBindable.TriggerChange();
}
}
};
beatLengthBindable.BindValueChanged(val =>
{
Current.Value = beatLengthToBpm(val.NewValue).ToString("N2");
}, true);
}
public Bindable<double> Bindable
{
get => beatLengthBindable;
set
{
// incoming will be beat length, not bpm
beatLengthBindable.UnbindBindings();
beatLengthBindable.BindTo(value);
}
}
}
private class BPMSlider : SettingsSlider<double> private class BPMSlider : SettingsSlider<double>
{ {
private readonly BindableDouble beatLengthBindable = new BindableDouble(); private const double sane_minimum = 60;
private const double sane_maximum = 240;
private BindableDouble bpmBindable; private readonly BindableNumber<double> beatLengthBindable = new TimingControlPoint().BeatLengthBindable;
private readonly BindableDouble bpmBindable = new BindableDouble();
public BPMSlider()
{
beatLengthBindable.BindValueChanged(beatLength => updateCurrent(beatLengthToBpm(beatLength.NewValue)), true);
bpmBindable.BindValueChanged(bpm => bpmBindable.Default = beatLengthBindable.Value = beatLengthToBpm(bpm.NewValue));
base.Bindable = bpmBindable;
}
public override Bindable<double> Bindable public override Bindable<double> Bindable
{ {
get => base.Bindable; get => base.Bindable;
set set
{ {
// incoming will be beatlength // incoming will be beat length, not bpm
beatLengthBindable.UnbindBindings(); beatLengthBindable.UnbindBindings();
beatLengthBindable.BindTo(value); beatLengthBindable.BindTo(value);
base.Bindable = bpmBindable = new BindableDouble(beatLengthToBpm(beatLengthBindable.Value))
{
MinValue = beatLengthToBpm(beatLengthBindable.MaxValue),
MaxValue = beatLengthToBpm(beatLengthBindable.MinValue),
Default = beatLengthToBpm(beatLengthBindable.Default),
};
bpmBindable.BindValueChanged(bpm => beatLengthBindable.Value = beatLengthToBpm(bpm.NewValue));
} }
} }
private double beatLengthToBpm(double beatLength) => 60000 / beatLength; private void updateCurrent(double newValue)
{
// we use a more sane range for the slider display unless overridden by the user.
// if a value comes in outside our range, we should expand temporarily.
bpmBindable.MinValue = Math.Min(newValue, sane_minimum);
bpmBindable.MaxValue = Math.Max(newValue, sane_maximum);
bpmBindable.Value = newValue;
}
} }
private static double beatLengthToBpm(double beatLength) => 60000 / beatLength;
} }
} }