mirror of
https://github.com/ppy/osu
synced 2025-02-21 13:07:18 +00:00
Merge pull request #29545 from peppy/timeline-redesign-in-circles
Further timeline usability tweaks
This commit is contained in:
commit
df94c22a29
@ -145,18 +145,18 @@ namespace osu.Game.Screens.Edit
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
return new Vector2(0.6f, 0.9f);
|
||||
return new Vector2(1, 0.9f);
|
||||
|
||||
case 3:
|
||||
case 4:
|
||||
return new Vector2(0.5f, 0.8f);
|
||||
return new Vector2(0.8f, 0.8f);
|
||||
|
||||
case 6:
|
||||
case 8:
|
||||
return new Vector2(0.4f, 0.7f);
|
||||
return new Vector2(0.8f, 0.7f);
|
||||
|
||||
default:
|
||||
return new Vector2(0.3f, 0.6f);
|
||||
return new Vector2(0.8f, 0.6f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -526,7 +526,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
||||
AlwaysDisplayed = alwaysDisplayed;
|
||||
Divisor = divisor;
|
||||
|
||||
Size = new Vector2(6f, 18) * BindableBeatDivisor.GetSize(divisor);
|
||||
Size = new Vector2(4, 18) * BindableBeatDivisor.GetSize(divisor);
|
||||
Alpha = alwaysDisplayed ? 1 : 0;
|
||||
|
||||
InternalChild = new Box { RelativeSizeAxes = Axes.Both };
|
||||
|
@ -2,9 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Overlays;
|
||||
@ -14,32 +12,28 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
public partial class CentreMarker : CompositeDrawable
|
||||
{
|
||||
private const float triangle_width = 8;
|
||||
|
||||
private const float bar_width = 1.6f;
|
||||
|
||||
public CentreMarker()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
Size = new Vector2(triangle_width, 1);
|
||||
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colours)
|
||||
{
|
||||
const float triangle_width = 8;
|
||||
const float bar_width = 2f;
|
||||
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
|
||||
Anchor = Anchor.TopCentre;
|
||||
Origin = Anchor.TopCentre;
|
||||
|
||||
Size = new Vector2(triangle_width, 1);
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
new Circle
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = bar_width,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Colour = ColourInfo.GradientVertical(colours.Colour2.Opacity(0.6f), colours.Colour2.Opacity(0)),
|
||||
Colour = colours.Colour2,
|
||||
},
|
||||
new Triangle
|
||||
{
|
||||
@ -47,6 +41,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
Origin = Anchor.BottomCentre,
|
||||
Size = new Vector2(triangle_width, triangle_width * 0.8f),
|
||||
Scale = new Vector2(1, -1),
|
||||
EdgeSmoothness = new Vector2(1, 0),
|
||||
Colour = colours.Colour2,
|
||||
},
|
||||
new Triangle
|
||||
{
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Origin = Anchor.BottomCentre,
|
||||
Size = new Vector2(triangle_width, triangle_width * 0.8f),
|
||||
Scale = new Vector2(1, 1),
|
||||
Colour = colours.Colour2,
|
||||
},
|
||||
};
|
||||
|
@ -14,6 +14,7 @@ using osu.Framework.Input.Events;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
@ -24,7 +25,6 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
public partial class Timeline : ZoomableScrollContainer, IPositionSnapProvider
|
||||
{
|
||||
private const float timeline_height = 80;
|
||||
private const float timeline_expanded_height = 94;
|
||||
|
||||
private readonly Drawable userContent;
|
||||
|
||||
@ -78,9 +78,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
|
||||
private TimelineTickDisplay ticks = null!;
|
||||
|
||||
private TimelineControlPointDisplay controlPoints = null!;
|
||||
|
||||
private Container mainContent = null!;
|
||||
private TimelineTimingChangeDisplay controlPoints = null!;
|
||||
|
||||
private Bindable<float> waveformOpacity = null!;
|
||||
private Bindable<bool> controlPointsVisible = null!;
|
||||
@ -103,31 +101,34 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(IBindable<WorkingBeatmap> beatmap, OsuColour colours, OsuConfigManager config)
|
||||
private void load(IBindable<WorkingBeatmap> beatmap, OsuColour colours, OverlayColourProvider colourProvider, OsuConfigManager config)
|
||||
{
|
||||
CentreMarker centreMarker;
|
||||
|
||||
// We don't want the centre marker to scroll
|
||||
AddInternal(centreMarker = new CentreMarker());
|
||||
|
||||
ticks = new TimelineTickDisplay
|
||||
{
|
||||
Padding = new MarginPadding { Vertical = 2, },
|
||||
};
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
controlPoints = new TimelineControlPointDisplay
|
||||
ticks = new TimelineTickDisplay(),
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = timeline_expanded_height,
|
||||
Name = "zero marker",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = TimelineTickDisplay.TICK_WIDTH / 2,
|
||||
Origin = Anchor.TopCentre,
|
||||
Colour = colourProvider.Background1,
|
||||
},
|
||||
ticks,
|
||||
mainContent = new Container
|
||||
controlPoints = new TimelineTimingChangeDisplay
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = timeline_height,
|
||||
Depth = float.MaxValue,
|
||||
Children = new[]
|
||||
{
|
||||
waveform = new WaveformGraph
|
||||
@ -138,16 +139,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
MidColour = colours.BlueDark,
|
||||
HighColour = colours.BlueDarker,
|
||||
},
|
||||
ticks.CreateProxy(),
|
||||
centreMarker.CreateProxy(),
|
||||
new Box
|
||||
{
|
||||
Name = "zero marker",
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 2,
|
||||
Origin = Anchor.TopCentre,
|
||||
Colour = colours.YellowDarker,
|
||||
},
|
||||
ticks.CreateProxy(),
|
||||
userContent,
|
||||
}
|
||||
},
|
||||
@ -192,21 +185,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
controlPointsVisible.BindValueChanged(visible =>
|
||||
{
|
||||
if (visible.NewValue || alwaysShowControlPoints)
|
||||
{
|
||||
this.ResizeHeightTo(timeline_expanded_height, 200, Easing.OutQuint);
|
||||
mainContent.MoveToY(15, 200, Easing.OutQuint);
|
||||
|
||||
// delay the fade in else masking looks weird.
|
||||
controlPoints.Delay(180).FadeIn(400, Easing.OutQuint);
|
||||
}
|
||||
controlPoints.FadeIn(400, Easing.OutQuint);
|
||||
else
|
||||
{
|
||||
controlPoints.FadeOut(200, Easing.OutQuint);
|
||||
|
||||
// likewise, delay the resize until the fade is complete.
|
||||
this.Delay(180).ResizeHeightTo(timeline_height, 200, Easing.OutQuint);
|
||||
mainContent.Delay(180).MoveToY(0, 200, Easing.OutQuint);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
|
@ -1,98 +0,0 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
/// <summary>
|
||||
/// The part of the timeline that displays the control points.
|
||||
/// </summary>
|
||||
public partial class TimelineControlPointDisplay : TimelinePart<TimelineControlPointGroup>
|
||||
{
|
||||
[Resolved]
|
||||
private Timeline timeline { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The visible time/position range of the timeline.
|
||||
/// </summary>
|
||||
private (float min, float max) visibleRange = (float.MinValue, float.MaxValue);
|
||||
|
||||
private readonly Cached groupCache = new Cached();
|
||||
|
||||
private readonly IBindableList<ControlPointGroup> controlPointGroups = new BindableList<ControlPointGroup>();
|
||||
|
||||
protected override void LoadBeatmap(EditorBeatmap beatmap)
|
||||
{
|
||||
base.LoadBeatmap(beatmap);
|
||||
|
||||
controlPointGroups.UnbindAll();
|
||||
controlPointGroups.BindTo(beatmap.ControlPointInfo.Groups);
|
||||
controlPointGroups.BindCollectionChanged((_, _) => groupCache.Invalidate(), true);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (DrawWidth <= 0) return;
|
||||
|
||||
(float, float) newRange = (
|
||||
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopLeft).X - TopPointPiece.WIDTH) / DrawWidth * Content.RelativeChildSize.X,
|
||||
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopRight).X) / DrawWidth * Content.RelativeChildSize.X);
|
||||
|
||||
if (visibleRange != newRange)
|
||||
{
|
||||
visibleRange = newRange;
|
||||
groupCache.Invalidate();
|
||||
}
|
||||
|
||||
if (!groupCache.IsValid)
|
||||
{
|
||||
recreateDrawableGroups();
|
||||
groupCache.Validate();
|
||||
}
|
||||
}
|
||||
|
||||
private void recreateDrawableGroups()
|
||||
{
|
||||
// Remove groups outside the visible range
|
||||
foreach (TimelineControlPointGroup drawableGroup in this)
|
||||
{
|
||||
if (!shouldBeVisible(drawableGroup.Group))
|
||||
drawableGroup.Expire();
|
||||
}
|
||||
|
||||
// Add remaining ones
|
||||
for (int i = 0; i < controlPointGroups.Count; i++)
|
||||
{
|
||||
var group = controlPointGroups[i];
|
||||
|
||||
if (!shouldBeVisible(group))
|
||||
continue;
|
||||
|
||||
bool alreadyVisible = false;
|
||||
|
||||
foreach (var g in this)
|
||||
{
|
||||
if (ReferenceEquals(g.Group, group))
|
||||
{
|
||||
alreadyVisible = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadyVisible)
|
||||
continue;
|
||||
|
||||
Add(new TimelineControlPointGroup(group));
|
||||
}
|
||||
}
|
||||
|
||||
private bool shouldBeVisible(ControlPointGroup group) => group.Time >= visibleRange.min && group.Time <= visibleRange.max;
|
||||
}
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
// 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 osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
public partial class TimelineControlPointGroup : CompositeDrawable
|
||||
{
|
||||
public readonly ControlPointGroup Group;
|
||||
|
||||
private readonly IBindableList<ControlPoint> controlPoints = new BindableList<ControlPoint>();
|
||||
|
||||
public TimelineControlPointGroup(ControlPointGroup group)
|
||||
{
|
||||
Group = group;
|
||||
|
||||
RelativePositionAxes = Axes.X;
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
AutoSizeAxes = Axes.X;
|
||||
|
||||
Origin = Anchor.TopLeft;
|
||||
|
||||
// offset visually to avoid overlapping timeline tick display.
|
||||
X = (float)group.Time + 6;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
controlPoints.BindTo(Group.ControlPoints);
|
||||
controlPoints.BindCollectionChanged((_, _) =>
|
||||
{
|
||||
ClearInternal();
|
||||
|
||||
foreach (var point in controlPoints)
|
||||
{
|
||||
switch (point)
|
||||
{
|
||||
case TimingControlPoint timingPoint:
|
||||
AddInternal(new TimingPointPiece(timingPoint));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
public partial class TimelineHitObjectBlueprint : SelectionBlueprint<HitObject>
|
||||
{
|
||||
private const float circle_size = 38;
|
||||
private const float circle_size = 32;
|
||||
|
||||
private Container? repeatsContainer;
|
||||
|
||||
|
@ -17,6 +17,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
public partial class TimelineTickDisplay : TimelinePart<PointVisualisation>
|
||||
{
|
||||
public const float TICK_WIDTH = 3;
|
||||
|
||||
// With current implementation every tick in the sub-tree should be visible, no need to check whether they are masked away.
|
||||
public override bool UpdateSubTreeMasking() => false;
|
||||
|
||||
@ -138,20 +140,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
|
||||
// even though "bar lines" take up the full vertical space, we render them in two pieces because it allows for less anchor/origin churn.
|
||||
|
||||
Vector2 size = Vector2.One;
|
||||
|
||||
if (indexInBar != 0)
|
||||
size = BindableBeatDivisor.GetSize(divisor);
|
||||
var size = indexInBar == 0
|
||||
? new Vector2(1.3f, 1)
|
||||
: BindableBeatDivisor.GetSize(divisor);
|
||||
|
||||
var line = getNextUsableLine();
|
||||
line.X = xPos;
|
||||
|
||||
line.Anchor = Anchor.CentreLeft;
|
||||
line.Origin = Anchor.Centre;
|
||||
|
||||
line.Height = 0.6f + size.Y * 0.4f;
|
||||
line.Width = PointVisualisation.MAX_WIDTH * (0.6f + 0.4f * size.X);
|
||||
|
||||
line.Width = TICK_WIDTH * size.X;
|
||||
line.Height = size.Y;
|
||||
line.Colour = colour;
|
||||
}
|
||||
|
||||
@ -174,8 +171,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
Drawable getNextUsableLine()
|
||||
{
|
||||
PointVisualisation point;
|
||||
|
||||
if (drawableIndex >= Count)
|
||||
Add(point = new PointVisualisation(0));
|
||||
{
|
||||
Add(point = new PointVisualisation(0)
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.Centre,
|
||||
});
|
||||
}
|
||||
else
|
||||
point = Children[drawableIndex];
|
||||
|
||||
|
@ -0,0 +1,161 @@
|
||||
// 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.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Caching;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
/// <summary>
|
||||
/// The part of the timeline that displays the control points.
|
||||
/// </summary>
|
||||
public partial class TimelineTimingChangeDisplay : TimelinePart<TimelineTimingChangeDisplay.TimingPointPiece>
|
||||
{
|
||||
[Resolved]
|
||||
private Timeline timeline { get; set; } = null!;
|
||||
|
||||
/// <summary>
|
||||
/// The visible time/position range of the timeline.
|
||||
/// </summary>
|
||||
private (float min, float max) visibleRange = (float.MinValue, float.MaxValue);
|
||||
|
||||
private readonly Cached groupCache = new Cached();
|
||||
|
||||
private ControlPointInfo controlPointInfo = null!;
|
||||
|
||||
protected override void LoadBeatmap(EditorBeatmap beatmap)
|
||||
{
|
||||
base.LoadBeatmap(beatmap);
|
||||
|
||||
beatmap.ControlPointInfo.ControlPointsChanged += () => groupCache.Invalidate();
|
||||
controlPointInfo = beatmap.ControlPointInfo;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (DrawWidth <= 0) return;
|
||||
|
||||
(float, float) newRange = (
|
||||
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopLeft).X - TimingPointPiece.WIDTH) / DrawWidth * Content.RelativeChildSize.X,
|
||||
(ToLocalSpace(timeline.ScreenSpaceDrawQuad.TopRight).X + TimingPointPiece.WIDTH) / DrawWidth * Content.RelativeChildSize.X);
|
||||
|
||||
if (visibleRange != newRange)
|
||||
{
|
||||
visibleRange = newRange;
|
||||
groupCache.Invalidate();
|
||||
}
|
||||
|
||||
if (!groupCache.IsValid)
|
||||
{
|
||||
recreateDrawableGroups();
|
||||
groupCache.Validate();
|
||||
}
|
||||
}
|
||||
|
||||
private void recreateDrawableGroups()
|
||||
{
|
||||
// Remove groups outside the visible range (or timing points which have since been removed from the beatmap).
|
||||
foreach (TimingPointPiece drawableGroup in this)
|
||||
{
|
||||
if (!controlPointInfo.TimingPoints.Contains(drawableGroup.Point) || !shouldBeVisible(drawableGroup.Point))
|
||||
drawableGroup.Expire();
|
||||
}
|
||||
|
||||
// Add remaining / new ones.
|
||||
foreach (TimingControlPoint t in controlPointInfo.TimingPoints)
|
||||
attemptAddTimingPoint(t);
|
||||
}
|
||||
|
||||
private void attemptAddTimingPoint(TimingControlPoint point)
|
||||
{
|
||||
if (!shouldBeVisible(point))
|
||||
return;
|
||||
|
||||
foreach (var child in this)
|
||||
{
|
||||
if (ReferenceEquals(child.Point, point))
|
||||
return;
|
||||
}
|
||||
|
||||
Add(new TimingPointPiece(point));
|
||||
}
|
||||
|
||||
private bool shouldBeVisible(TimingControlPoint point) => point.Time >= visibleRange.min && point.Time <= visibleRange.max;
|
||||
|
||||
public partial class TimingPointPiece : CompositeDrawable
|
||||
{
|
||||
public const float WIDTH = 16;
|
||||
|
||||
public readonly TimingControlPoint Point;
|
||||
|
||||
private readonly BindableNumber<double> beatLength;
|
||||
|
||||
protected OsuSpriteText Label { get; private set; } = null!;
|
||||
|
||||
public TimingPointPiece(TimingControlPoint timingPoint)
|
||||
{
|
||||
RelativePositionAxes = Axes.X;
|
||||
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
Width = WIDTH;
|
||||
|
||||
Origin = Anchor.TopRight;
|
||||
|
||||
Point = timingPoint;
|
||||
|
||||
beatLength = timingPoint.BeatLengthBindable.GetBoundCopy();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Point.GetRepresentingColour(colours),
|
||||
Masking = true,
|
||||
CornerRadius = TimelineTickDisplay.TICK_WIDTH / 2,
|
||||
Child = new Box
|
||||
{
|
||||
Colour = Color4.White,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
},
|
||||
Label = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Rotation = 90,
|
||||
Padding = new MarginPadding { Horizontal = 2 },
|
||||
Font = OsuFont.Default.With(size: 12, weight: FontWeight.SemiBold),
|
||||
}
|
||||
};
|
||||
|
||||
beatLength.BindValueChanged(beatLength =>
|
||||
{
|
||||
Label.Text = $"{60000 / beatLength.NewValue:n1} BPM";
|
||||
}, true);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
X = (float)Point.Time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
public partial class TimingPointPiece : TopPointPiece
|
||||
{
|
||||
private readonly BindableNumber<double> beatLength;
|
||||
|
||||
public TimingPointPiece(TimingControlPoint point)
|
||||
: base(point)
|
||||
{
|
||||
beatLength = point.BeatLengthBindable.GetBoundCopy();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
beatLength.BindValueChanged(beatLength =>
|
||||
{
|
||||
Label.Text = $"{60000 / beatLength.NewValue:n1} BPM";
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||
{
|
||||
public partial class TopPointPiece : CompositeDrawable
|
||||
{
|
||||
protected readonly ControlPoint Point;
|
||||
|
||||
protected OsuSpriteText Label { get; private set; } = null!;
|
||||
|
||||
public const float WIDTH = 80;
|
||||
|
||||
public TopPointPiece(ControlPoint point)
|
||||
{
|
||||
Point = point;
|
||||
Width = WIDTH;
|
||||
Height = 16;
|
||||
Margin = new MarginPadding { Vertical = 4 };
|
||||
|
||||
Origin = Anchor.TopCentre;
|
||||
Anchor = Anchor.TopCentre;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
const float corner_radius = 4;
|
||||
const float arrow_extension = 3;
|
||||
const float triangle_portion = 15;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
// This is a triangle, trust me.
|
||||
// Doing it this way looks okay. Doing it using Triangle primitive is basically impossible.
|
||||
new Container
|
||||
{
|
||||
Colour = Point.GetRepresentingColour(colours),
|
||||
X = -corner_radius,
|
||||
Size = new Vector2(triangle_portion * arrow_extension, Height),
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
Masking = true,
|
||||
CornerRadius = Height,
|
||||
CornerExponent = 1.4f,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.White,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = WIDTH - triangle_portion,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Colour = Point.GetRepresentingColour(colours),
|
||||
Masking = true,
|
||||
CornerRadius = corner_radius,
|
||||
Child = new Box
|
||||
{
|
||||
Colour = Color4.White,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
},
|
||||
Label = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Padding = new MarginPadding(3),
|
||||
Font = OsuFont.Default.With(size: 14, weight: FontWeight.SemiBold),
|
||||
Colour = colours.B5,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user