2019-10-28 11:42:17 +08:00
|
|
|
// 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.
|
|
|
|
|
2019-10-27 14:19:36 +08:00
|
|
|
using osu.Framework.Allocation;
|
2019-10-28 15:21:31 +08:00
|
|
|
using osu.Framework.Bindables;
|
|
|
|
using osu.Framework.Graphics;
|
2019-10-27 14:19:36 +08:00
|
|
|
using osu.Game.Beatmaps.ControlPoints;
|
2020-09-07 16:39:13 +08:00
|
|
|
using osu.Game.Graphics.UserInterfaceV2;
|
2019-10-27 14:19:36 +08:00
|
|
|
|
|
|
|
namespace osu.Game.Screens.Edit.Timing
|
|
|
|
{
|
|
|
|
internal partial class TimingSection : Section<TimingControlPoint>
|
|
|
|
{
|
2023-01-14 07:23:21 +08:00
|
|
|
private LabelledTimeSignature timeSignature = null!;
|
2023-02-28 18:29:31 +08:00
|
|
|
private LabelledSwitchButton omitBarLine = null!;
|
2023-01-14 07:23:21 +08:00
|
|
|
private BPMTextBox bpmTextEntry = null!;
|
2019-10-27 14:19:36 +08:00
|
|
|
|
|
|
|
[BackgroundDependencyLoader]
|
|
|
|
private void load()
|
|
|
|
{
|
2019-10-28 15:21:31 +08:00
|
|
|
Flow.AddRange(new Drawable[]
|
2019-10-27 14:19:36 +08:00
|
|
|
{
|
2022-05-20 13:34:33 +08:00
|
|
|
new TapTimingControl(),
|
2020-09-07 17:18:34 +08:00
|
|
|
bpmTextEntry = new BPMTextBox(),
|
2022-01-23 01:54:28 +08:00
|
|
|
timeSignature = new LabelledTimeSignature
|
2019-10-28 15:21:31 +08:00
|
|
|
{
|
2022-01-23 01:54:28 +08:00
|
|
|
Label = "Time Signature"
|
2023-02-28 18:29:31 +08:00
|
|
|
},
|
|
|
|
omitBarLine = new LabelledSwitchButton { Label = "Skip Bar Line" },
|
2019-10-27 14:19:36 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-05-31 17:27:18 +08:00
|
|
|
protected override void LoadComplete()
|
|
|
|
{
|
|
|
|
base.LoadComplete();
|
|
|
|
|
|
|
|
bpmTextEntry.Current.BindValueChanged(_ => saveChanges());
|
2023-02-28 18:29:31 +08:00
|
|
|
omitBarLine.Current.BindValueChanged(_ => saveChanges());
|
2022-05-31 17:27:18 +08:00
|
|
|
timeSignature.Current.BindValueChanged(_ => saveChanges());
|
|
|
|
|
|
|
|
void saveChanges()
|
|
|
|
{
|
|
|
|
if (!isRebinding) ChangeHandler?.SaveState();
|
|
|
|
}
|
2024-06-09 17:29:25 +08:00
|
|
|
|
|
|
|
bpmTextEntry.Bindable.BindValueChanged(val =>
|
|
|
|
{
|
2024-06-10 00:04:27 +08:00
|
|
|
if (!Beatmap.AdjustNotesOnOffsetBPMChange.Value || ControlPoint.Value == null)
|
2024-06-09 17:29:25 +08:00
|
|
|
return;
|
|
|
|
|
2024-06-13 01:57:17 +08:00
|
|
|
TimingSectionAdjustments.SetHitObjectBPM(Beatmap, ControlPoint.Value, val.OldValue);
|
2024-06-09 17:29:25 +08:00
|
|
|
Beatmap.UpdateAllHitObjects();
|
|
|
|
});
|
2022-05-31 17:27:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private bool isRebinding;
|
|
|
|
|
2023-01-14 07:23:21 +08:00
|
|
|
protected override void OnControlPointChanged(ValueChangedEvent<TimingControlPoint?> point)
|
2019-10-27 14:19:36 +08:00
|
|
|
{
|
2019-11-06 15:22:55 +08:00
|
|
|
if (point.NewValue != null)
|
2019-10-27 14:19:36 +08:00
|
|
|
{
|
2022-05-31 17:27:18 +08:00
|
|
|
isRebinding = true;
|
2020-10-02 16:55:47 +08:00
|
|
|
|
2022-05-31 17:27:18 +08:00
|
|
|
bpmTextEntry.Bindable = point.NewValue.BeatLengthBindable;
|
2020-10-06 16:18:41 +08:00
|
|
|
timeSignature.Current = point.NewValue.TimeSignatureBindable;
|
2023-02-28 18:29:31 +08:00
|
|
|
omitBarLine.Current = point.NewValue.OmitFirstBarLineBindable;
|
2022-05-31 17:27:18 +08:00
|
|
|
|
|
|
|
isRebinding = false;
|
2019-11-06 15:22:55 +08:00
|
|
|
}
|
2019-10-27 14:19:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
protected override TimingControlPoint CreatePoint()
|
|
|
|
{
|
2021-01-04 15:38:15 +08:00
|
|
|
var reference = Beatmap.ControlPointInfo.TimingPointAt(SelectedGroup.Value.Time);
|
2019-10-27 14:19:36 +08:00
|
|
|
|
|
|
|
return new TimingControlPoint
|
|
|
|
{
|
|
|
|
BeatLength = reference.BeatLength,
|
2023-02-28 18:29:31 +08:00
|
|
|
TimeSignature = reference.TimeSignature,
|
|
|
|
OmitFirstBarLine = reference.OmitFirstBarLine,
|
2019-10-27 14:19:36 +08:00
|
|
|
};
|
|
|
|
}
|
2019-10-28 15:21:31 +08:00
|
|
|
|
2020-09-07 16:39:13 +08:00
|
|
|
private partial class BPMTextBox : LabelledTextBox
|
|
|
|
{
|
2020-09-07 17:18:34 +08:00
|
|
|
private readonly BindableNumber<double> beatLengthBindable = new TimingControlPoint().BeatLengthBindable;
|
|
|
|
|
2020-09-07 16:39:13 +08:00
|
|
|
public BPMTextBox()
|
|
|
|
{
|
2020-09-07 17:18:34 +08:00
|
|
|
Label = "BPM";
|
2024-07-11 15:54:27 +08:00
|
|
|
SelectAllOnFocus = true;
|
2020-09-07 17:18:34 +08:00
|
|
|
|
2022-06-24 20:25:23 +08:00
|
|
|
OnCommit += (_, isNew) =>
|
2020-09-07 16:39:13 +08:00
|
|
|
{
|
|
|
|
if (!isNew) return;
|
|
|
|
|
2020-10-01 12:06:24 +08:00
|
|
|
try
|
2020-09-07 16:39:13 +08:00
|
|
|
{
|
2020-10-01 12:06:24 +08:00
|
|
|
if (double.TryParse(Current.Value, out double doubleVal) && doubleVal > 0)
|
2020-09-07 16:39:13 +08:00
|
|
|
beatLengthBindable.Value = beatLengthToBpm(doubleVal);
|
|
|
|
}
|
2020-10-01 12:06:24 +08:00
|
|
|
catch
|
|
|
|
{
|
|
|
|
// TriggerChange below will restore the previous text value on failure.
|
|
|
|
}
|
|
|
|
|
|
|
|
// This is run regardless of parsing success as the parsed number may not actually trigger a change
|
|
|
|
// due to bindable clamping. Even in such a case we want to update the textbox to a sane visual state.
|
|
|
|
beatLengthBindable.TriggerChange();
|
2020-09-07 16:39:13 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
beatLengthBindable.BindValueChanged(val =>
|
|
|
|
{
|
2020-09-07 17:18:34 +08:00
|
|
|
Current.Value = beatLengthToBpm(val.NewValue).ToString("N2");
|
|
|
|
}, true);
|
2020-09-07 16:39:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public Bindable<double> Bindable
|
|
|
|
{
|
|
|
|
get => beatLengthBindable;
|
|
|
|
set
|
|
|
|
{
|
|
|
|
// incoming will be beat length, not bpm
|
|
|
|
beatLengthBindable.UnbindBindings();
|
|
|
|
beatLengthBindable.BindTo(value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private static double beatLengthToBpm(double beatLength) => 60000 / beatLength;
|
2019-10-27 14:19:36 +08:00
|
|
|
}
|
|
|
|
}
|