2023-02-10 16:37:31 +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.
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Linq;
|
|
|
|
using osu.Framework.Allocation;
|
|
|
|
using osu.Framework.Bindables;
|
|
|
|
using osu.Framework.Graphics;
|
|
|
|
using osu.Framework.Graphics.Containers;
|
2024-09-08 21:59:23 +08:00
|
|
|
using osu.Framework.Graphics.Shapes;
|
2023-02-10 16:37:31 +08:00
|
|
|
using osu.Framework.Input.Events;
|
|
|
|
using osu.Game.Beatmaps.ControlPoints;
|
2024-08-21 15:05:10 +08:00
|
|
|
using osu.Game.Graphics;
|
2023-02-10 16:37:31 +08:00
|
|
|
using osu.Game.Graphics.UserInterface;
|
|
|
|
using osu.Game.Graphics.UserInterfaceV2;
|
2024-09-08 21:59:23 +08:00
|
|
|
using osu.Game.Overlays;
|
2023-02-10 16:37:31 +08:00
|
|
|
using osuTK;
|
|
|
|
|
|
|
|
namespace osu.Game.Screens.Edit.Timing
|
|
|
|
{
|
|
|
|
public partial class ControlPointList : CompositeDrawable
|
|
|
|
{
|
|
|
|
private OsuButton deleteButton = null!;
|
|
|
|
private RoundedButton addButton = null!;
|
|
|
|
|
|
|
|
[Resolved]
|
|
|
|
private EditorClock clock { get; set; } = null!;
|
|
|
|
|
|
|
|
[Resolved]
|
|
|
|
protected EditorBeatmap Beatmap { get; private set; } = null!;
|
|
|
|
|
|
|
|
[Resolved]
|
|
|
|
private Bindable<ControlPointGroup?> selectedGroup { get; set; } = null!;
|
|
|
|
|
2024-09-08 21:59:23 +08:00
|
|
|
[Cached]
|
2024-09-08 22:04:10 +08:00
|
|
|
private OverlayColourProvider overlayColourProvider = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
|
2024-09-08 21:59:23 +08:00
|
|
|
|
2023-02-10 16:37:31 +08:00
|
|
|
[BackgroundDependencyLoader]
|
2024-08-21 15:05:10 +08:00
|
|
|
private void load(OsuColour colours)
|
2023-02-10 16:37:31 +08:00
|
|
|
{
|
|
|
|
RelativeSizeAxes = Axes.Both;
|
|
|
|
|
|
|
|
const float margins = 10;
|
|
|
|
InternalChildren = new Drawable[]
|
|
|
|
{
|
2024-06-21 16:54:40 +08:00
|
|
|
new ControlPointTable
|
2023-02-10 16:37:31 +08:00
|
|
|
{
|
|
|
|
RelativeSizeAxes = Axes.Both,
|
2024-06-21 16:54:40 +08:00
|
|
|
Groups = { BindTarget = Beatmap.ControlPointInfo.Groups, },
|
2023-02-10 16:37:31 +08:00
|
|
|
},
|
2024-09-08 21:59:23 +08:00
|
|
|
new Container
|
2024-08-22 13:15:36 +08:00
|
|
|
{
|
2024-09-08 21:59:23 +08:00
|
|
|
AutoSizeAxes = Axes.Y,
|
|
|
|
RelativeSizeAxes = Axes.X,
|
|
|
|
Anchor = Anchor.BottomCentre,
|
|
|
|
Origin = Anchor.BottomCentre,
|
2024-08-22 13:15:36 +08:00
|
|
|
Children = new Drawable[]
|
|
|
|
{
|
2024-09-08 21:59:23 +08:00
|
|
|
new Box
|
2024-08-22 13:15:36 +08:00
|
|
|
{
|
2024-09-08 21:59:23 +08:00
|
|
|
Height = 50,
|
|
|
|
RelativeSizeAxes = Axes.X,
|
|
|
|
Anchor = Anchor.CentreLeft,
|
|
|
|
Colour = overlayColourProvider.Background2,
|
2024-08-22 13:15:36 +08:00
|
|
|
},
|
2024-09-08 21:59:23 +08:00
|
|
|
new FillFlowContainer
|
2023-02-10 16:37:31 +08:00
|
|
|
{
|
2024-09-08 21:59:23 +08:00
|
|
|
Anchor = Anchor.BottomLeft,
|
|
|
|
Padding = new MarginPadding { Left = margins, Bottom = margins },
|
|
|
|
Children = new Drawable[]
|
|
|
|
{
|
|
|
|
new RoundedButton
|
|
|
|
{
|
|
|
|
Text = "Select closest to current time",
|
|
|
|
Action = goToCurrentGroup,
|
|
|
|
Size = new Vector2(220, 30),
|
|
|
|
Anchor = Anchor.BottomLeft,
|
|
|
|
Origin = Anchor.BottomLeft,
|
|
|
|
},
|
|
|
|
}
|
2023-02-10 16:37:31 +08:00
|
|
|
},
|
2024-09-08 21:59:23 +08:00
|
|
|
new FillFlowContainer
|
2023-02-10 16:37:31 +08:00
|
|
|
{
|
2024-09-08 21:59:23 +08:00
|
|
|
Direction = FillDirection.Horizontal,
|
2023-02-10 16:37:31 +08:00
|
|
|
Anchor = Anchor.BottomRight,
|
2024-09-08 21:59:23 +08:00
|
|
|
Spacing = new Vector2(5),
|
|
|
|
Padding = new MarginPadding { Right = margins, Bottom = margins },
|
|
|
|
Children = new Drawable[]
|
|
|
|
{
|
|
|
|
deleteButton = new RoundedButton
|
|
|
|
{
|
|
|
|
Text = "-",
|
|
|
|
Size = new Vector2(30, 30),
|
|
|
|
Action = delete,
|
|
|
|
Anchor = Anchor.BottomRight,
|
|
|
|
Origin = Anchor.BottomRight,
|
|
|
|
BackgroundColour = colours.Red3,
|
|
|
|
},
|
|
|
|
addButton = new RoundedButton
|
|
|
|
{
|
|
|
|
Action = addNew,
|
|
|
|
Size = new Vector2(160, 30),
|
|
|
|
Anchor = Anchor.BottomRight,
|
|
|
|
Origin = Anchor.BottomRight,
|
|
|
|
},
|
|
|
|
}
|
Redesign timing table tracking
- On entering the screen, the timing point active at the current instant
of the map is selected. This is the *only* time where the selected
point is changed automatically for the user.
- The ongoing automatic tracking of the relevant point after the initial
selection is *gone*. Even knowing the fact that it was supposed to
track the supposedly relevant "last selected type" of control point,
I always found the tracking to be fairly arbitrary in how it works.
Removing this behaviour also incidentally fixes
https://github.com/ppy/osu/issues/23147.
In its stead, to indicate which timing groups are having an effect,
they receive an indicator line on the left (coloured using the
relevant control points' representing colours), as well as a slight
highlight effect.
- If there is no control point selected, the table will autoscroll to
the latest timing group, unless the user manually scrolled the table
before.
- If the selected control point changes, the table will autoscroll to
the newly selected point, *regardless* of whether the user manually
scrolled the table before.
- A new button is added which permits the user to select the latest
timing group. As per the point above, this will autoscroll the user
to that group at the same time.
2024-08-20 17:14:42 +08:00
|
|
|
},
|
2023-02-10 16:37:31 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void LoadComplete()
|
|
|
|
{
|
|
|
|
base.LoadComplete();
|
|
|
|
|
|
|
|
selectedGroup.BindValueChanged(selected =>
|
|
|
|
{
|
|
|
|
deleteButton.Enabled.Value = selected.NewValue != null;
|
|
|
|
|
|
|
|
addButton.Text = selected.NewValue != null
|
|
|
|
? "+ Clone to current time"
|
|
|
|
: "+ Add at current time";
|
|
|
|
}, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override bool OnClick(ClickEvent e)
|
|
|
|
{
|
|
|
|
selectedGroup.Value = null;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected override void Update()
|
|
|
|
{
|
|
|
|
base.Update();
|
|
|
|
|
|
|
|
addButton.Enabled.Value = clock.CurrentTimeAccurate != selectedGroup.Value?.Time;
|
|
|
|
}
|
|
|
|
|
Redesign timing table tracking
- On entering the screen, the timing point active at the current instant
of the map is selected. This is the *only* time where the selected
point is changed automatically for the user.
- The ongoing automatic tracking of the relevant point after the initial
selection is *gone*. Even knowing the fact that it was supposed to
track the supposedly relevant "last selected type" of control point,
I always found the tracking to be fairly arbitrary in how it works.
Removing this behaviour also incidentally fixes
https://github.com/ppy/osu/issues/23147.
In its stead, to indicate which timing groups are having an effect,
they receive an indicator line on the left (coloured using the
relevant control points' representing colours), as well as a slight
highlight effect.
- If there is no control point selected, the table will autoscroll to
the latest timing group, unless the user manually scrolled the table
before.
- If the selected control point changes, the table will autoscroll to
the newly selected point, *regardless* of whether the user manually
scrolled the table before.
- A new button is added which permits the user to select the latest
timing group. As per the point above, this will autoscroll the user
to that group at the same time.
2024-08-20 17:14:42 +08:00
|
|
|
private void goToCurrentGroup()
|
2023-02-10 16:37:31 +08:00
|
|
|
{
|
Redesign timing table tracking
- On entering the screen, the timing point active at the current instant
of the map is selected. This is the *only* time where the selected
point is changed automatically for the user.
- The ongoing automatic tracking of the relevant point after the initial
selection is *gone*. Even knowing the fact that it was supposed to
track the supposedly relevant "last selected type" of control point,
I always found the tracking to be fairly arbitrary in how it works.
Removing this behaviour also incidentally fixes
https://github.com/ppy/osu/issues/23147.
In its stead, to indicate which timing groups are having an effect,
they receive an indicator line on the left (coloured using the
relevant control points' representing colours), as well as a slight
highlight effect.
- If there is no control point selected, the table will autoscroll to
the latest timing group, unless the user manually scrolled the table
before.
- If the selected control point changes, the table will autoscroll to
the newly selected point, *regardless* of whether the user manually
scrolled the table before.
- A new button is added which permits the user to select the latest
timing group. As per the point above, this will autoscroll the user
to that group at the same time.
2024-08-20 17:14:42 +08:00
|
|
|
double accurateTime = clock.CurrentTimeAccurate;
|
2024-03-10 01:50:54 +08:00
|
|
|
|
Redesign timing table tracking
- On entering the screen, the timing point active at the current instant
of the map is selected. This is the *only* time where the selected
point is changed automatically for the user.
- The ongoing automatic tracking of the relevant point after the initial
selection is *gone*. Even knowing the fact that it was supposed to
track the supposedly relevant "last selected type" of control point,
I always found the tracking to be fairly arbitrary in how it works.
Removing this behaviour also incidentally fixes
https://github.com/ppy/osu/issues/23147.
In its stead, to indicate which timing groups are having an effect,
they receive an indicator line on the left (coloured using the
relevant control points' representing colours), as well as a slight
highlight effect.
- If there is no control point selected, the table will autoscroll to
the latest timing group, unless the user manually scrolled the table
before.
- If the selected control point changes, the table will autoscroll to
the newly selected point, *regardless* of whether the user manually
scrolled the table before.
- A new button is added which permits the user to select the latest
timing group. As per the point above, this will autoscroll the user
to that group at the same time.
2024-08-20 17:14:42 +08:00
|
|
|
var activeTimingPoint = Beatmap.ControlPointInfo.TimingPointAt(accurateTime);
|
|
|
|
var activeEffectPoint = Beatmap.ControlPointInfo.EffectPointAt(accurateTime);
|
2023-02-10 16:37:31 +08:00
|
|
|
|
Redesign timing table tracking
- On entering the screen, the timing point active at the current instant
of the map is selected. This is the *only* time where the selected
point is changed automatically for the user.
- The ongoing automatic tracking of the relevant point after the initial
selection is *gone*. Even knowing the fact that it was supposed to
track the supposedly relevant "last selected type" of control point,
I always found the tracking to be fairly arbitrary in how it works.
Removing this behaviour also incidentally fixes
https://github.com/ppy/osu/issues/23147.
In its stead, to indicate which timing groups are having an effect,
they receive an indicator line on the left (coloured using the
relevant control points' representing colours), as well as a slight
highlight effect.
- If there is no control point selected, the table will autoscroll to
the latest timing group, unless the user manually scrolled the table
before.
- If the selected control point changes, the table will autoscroll to
the newly selected point, *regardless* of whether the user manually
scrolled the table before.
- A new button is added which permits the user to select the latest
timing group. As per the point above, this will autoscroll the user
to that group at the same time.
2024-08-20 17:14:42 +08:00
|
|
|
double latestActiveTime = Math.Max(activeTimingPoint.Time, activeEffectPoint.Time);
|
|
|
|
selectedGroup.Value = Beatmap.ControlPointInfo.GroupAt(latestActiveTime);
|
2023-02-10 16:37:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private void delete()
|
|
|
|
{
|
|
|
|
if (selectedGroup.Value == null)
|
|
|
|
return;
|
|
|
|
|
|
|
|
Beatmap.ControlPointInfo.RemoveGroup(selectedGroup.Value);
|
|
|
|
|
|
|
|
selectedGroup.Value = Beatmap.ControlPointInfo.Groups.FirstOrDefault(g => g.Time >= clock.CurrentTime);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void addNew()
|
|
|
|
{
|
|
|
|
bool isFirstControlPoint = !Beatmap.ControlPointInfo.TimingPoints.Any();
|
|
|
|
|
|
|
|
var group = Beatmap.ControlPointInfo.GroupAt(clock.CurrentTime, true);
|
|
|
|
|
|
|
|
if (isFirstControlPoint)
|
|
|
|
group.Add(new TimingControlPoint());
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Try and create matching types from the currently selected control point.
|
|
|
|
var selected = selectedGroup.Value;
|
|
|
|
|
|
|
|
if (selected != null && !ReferenceEquals(selected, group))
|
|
|
|
{
|
|
|
|
foreach (var controlPoint in selected.ControlPoints)
|
|
|
|
{
|
|
|
|
group.Add(controlPoint.DeepClone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
selectedGroup.Value = group;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|