1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-16 19:33:01 +08:00
osu-lazer/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs

372 lines
13 KiB
C#
Raw Normal View History

// 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.
2018-04-13 17:19:50 +08:00
using System;
using System.Linq;
using osu.Framework.Allocation;
2019-02-21 18:04:31 +08:00
using osu.Framework.Bindables;
2018-04-13 17:19:50 +08:00
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.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
2018-10-02 11:02:47 +08:00
using osu.Framework.Input.Events;
2018-04-13 17:19:50 +08:00
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
2018-11-20 15:51:59 +08:00
using osuTK;
using osuTK.Graphics;
using osuTK.Input;
2018-04-13 17:19:50 +08:00
2018-11-06 17:28:22 +08:00
namespace osu.Game.Screens.Edit.Compose.Components
2018-04-13 17:19:50 +08:00
{
public class BeatDivisorControl : CompositeDrawable
{
private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor();
public BeatDivisorControl(BindableBeatDivisor beatDivisor)
{
this.beatDivisor.BindTo(beatDivisor);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Masking = true;
CornerRadius = 5;
InternalChildren = new Drawable[]
{
new Box
{
Name = "Gray Background",
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray4
},
new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[]
{
new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
Name = "Black Background",
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black
},
new TickSliderBar(beatDivisor, BindableBeatDivisor.VALID_DIVISORS)
{
RelativeSizeAxes = Axes.Both,
}
}
}
},
new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.Gray4
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = 5 },
Child = new GridContainer
{
RelativeSizeAxes = Axes.Both,
Content = new[]
{
new Drawable[]
{
new DivisorButton
{
2019-04-02 18:55:24 +08:00
Icon = FontAwesome.Solid.ChevronLeft,
2018-04-13 17:19:50 +08:00
Action = beatDivisor.Previous
},
new DivisorText(beatDivisor),
new DivisorButton
{
2019-04-02 18:55:24 +08:00
Icon = FontAwesome.Solid.ChevronRight,
2018-04-13 17:19:50 +08:00
Action = beatDivisor.Next
}
},
},
ColumnDimensions = new[]
{
new Dimension(GridSizeMode.Absolute, 20),
new Dimension(),
new Dimension(GridSizeMode.Absolute, 20)
}
}
}
}
}
},
new Drawable[]
{
new TextFlowContainer(s => s.Font = s.Font.With(size: 14))
2018-04-13 17:19:50 +08:00
{
Padding = new MarginPadding { Horizontal = 15 },
Text = "beat snap divisor",
RelativeSizeAxes = Axes.X,
TextAnchor = Anchor.TopCentre
},
}
},
RowDimensions = new[]
{
new Dimension(GridSizeMode.Absolute, 30),
new Dimension(GridSizeMode.Absolute, 25),
}
}
};
}
private class DivisorText : SpriteText
{
private readonly Bindable<int> beatDivisor = new Bindable<int>();
public DivisorText(BindableBeatDivisor beatDivisor)
{
this.beatDivisor.BindTo(beatDivisor);
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = colours.BlueLighter;
}
protected override void LoadComplete()
{
base.LoadComplete();
beatDivisor.BindValueChanged(val => Text = $"1/{val.NewValue}", true);
2018-04-13 17:19:50 +08:00
}
}
private class DivisorButton : IconButton
{
public DivisorButton()
{
Anchor = Anchor.Centre;
Origin = Anchor.Centre;
// Small offset to look a bit better centered along with the divisor text
Y = 1;
Size = new Vector2(20);
2018-04-13 17:19:50 +08:00
IconScale = new Vector2(0.6f);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
IconColour = Color4.Black;
HoverColour = colours.Gray7;
FlashColour = colours.Gray9;
}
}
private class TickSliderBar : SliderBar<int>
{
private Marker marker;
[Resolved]
private OsuColour colours { get; set; }
2018-04-13 17:19:50 +08:00
private readonly BindableBeatDivisor beatDivisor;
private readonly int[] availableDivisors;
public TickSliderBar(BindableBeatDivisor beatDivisor, params int[] divisors)
{
CurrentNumber.BindTo(this.beatDivisor = beatDivisor);
availableDivisors = divisors;
Padding = new MarginPadding { Horizontal = 5 };
}
[BackgroundDependencyLoader]
private void load()
{
foreach (var t in availableDivisors)
{
AddInternal(new Tick
2018-04-13 17:19:50 +08:00
{
Anchor = Anchor.TopLeft,
Origin = Anchor.TopCentre,
RelativePositionAxes = Axes.X,
2019-08-31 20:32:02 +08:00
Colour = BindableBeatDivisor.GetColourFor(t, colours),
2018-04-13 17:19:50 +08:00
X = getMappedPosition(t)
});
}
AddInternal(marker = new Marker());
}
protected override void LoadComplete()
{
base.LoadComplete();
2018-04-13 17:19:50 +08:00
CurrentNumber.BindValueChanged(div =>
2018-04-13 17:19:50 +08:00
{
marker.MoveToX(getMappedPosition(div.NewValue), 100, Easing.OutQuint);
2018-04-13 17:19:50 +08:00
marker.Flash();
}, true);
2018-04-13 17:19:50 +08:00
}
protected override void UpdateValue(float value)
{
}
public override bool HandleNonPositionalInput => IsHovered && !CurrentNumber.Disabled;
2018-04-13 17:19:50 +08:00
2018-10-02 11:02:47 +08:00
protected override bool OnKeyDown(KeyDownEvent e)
2018-04-13 17:19:50 +08:00
{
2018-10-02 11:02:47 +08:00
switch (e.Key)
2018-04-13 17:19:50 +08:00
{
case Key.Right:
beatDivisor.Next();
2019-02-21 17:56:34 +08:00
OnUserChange(Current.Value);
2018-04-13 17:19:50 +08:00
return true;
2019-04-01 11:44:46 +08:00
2018-04-13 17:19:50 +08:00
case Key.Left:
beatDivisor.Previous();
2019-02-21 17:56:34 +08:00
OnUserChange(Current.Value);
2018-04-13 17:19:50 +08:00
return true;
2019-04-01 11:44:46 +08:00
2018-04-13 17:19:50 +08:00
default:
return false;
}
}
2018-10-02 11:02:47 +08:00
protected override bool OnMouseDown(MouseDownEvent e)
2018-04-13 17:19:50 +08:00
{
marker.Active = true;
2018-10-02 11:02:47 +08:00
return base.OnMouseDown(e);
2018-04-13 17:19:50 +08:00
}
protected override void OnMouseUp(MouseUpEvent e)
2018-04-13 17:19:50 +08:00
{
marker.Active = false;
base.OnMouseUp(e);
2018-04-13 17:19:50 +08:00
}
2018-10-02 11:02:47 +08:00
protected override bool OnClick(ClickEvent e)
2018-04-13 17:19:50 +08:00
{
handleMouseInput(e.ScreenSpaceMousePosition);
2018-04-13 17:19:50 +08:00
return true;
}
protected override void OnDrag(DragEvent e)
2018-04-13 17:19:50 +08:00
{
handleMouseInput(e.ScreenSpaceMousePosition);
2018-04-13 17:19:50 +08:00
}
private void handleMouseInput(Vector2 screenSpaceMousePosition)
2018-04-13 17:19:50 +08:00
{
// copied from SliderBar so we can do custom spacing logic.
var xPosition = (ToLocalSpace(screenSpaceMousePosition).X - RangePadding) / UsableWidth;
2018-04-13 17:19:50 +08:00
CurrentNumber.Value = availableDivisors.OrderBy(d => Math.Abs(getMappedPosition(d) - xPosition)).First();
2019-02-21 17:56:34 +08:00
OnUserChange(Current.Value);
2018-04-13 17:19:50 +08:00
}
private float getMappedPosition(float divisor) => MathF.Pow((divisor - 1) / (availableDivisors.Last() - 1), 0.90f);
2018-04-13 17:19:50 +08:00
private class Tick : CompositeDrawable
{
public Tick()
2018-04-13 17:19:50 +08:00
{
Size = new Vector2(2.5f, 10);
InternalChild = new Box { RelativeSizeAxes = Axes.Both };
CornerRadius = 0.5f;
Masking = true;
}
}
private class Marker : CompositeDrawable
{
private Color4 defaultColour;
private const float size = 7;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = defaultColour = colours.Gray4;
Anchor = Anchor.TopLeft;
Origin = Anchor.TopCentre;
Width = size;
RelativeSizeAxes = Axes.Y;
RelativePositionAxes = Axes.X;
InternalChildren = new Drawable[]
{
new Box
{
Width = 2,
RelativeSizeAxes = Axes.Y,
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
Colour = ColourInfo.GradientVertical(Color4.White.Opacity(0.2f), Color4.White),
2019-08-21 12:29:50 +08:00
Blending = BlendingParameters.Additive,
2018-04-13 17:19:50 +08:00
},
new EquilateralTriangle
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
Height = size,
EdgeSmoothness = new Vector2(1),
Colour = Color4.White,
}
};
}
private bool active;
public bool Active
{
get => active;
set
{
this.FadeColour(value ? Color4.White : defaultColour, 500, Easing.OutQuint);
active = value;
}
}
public void Flash()
{
bool wasActive = active;
Active = true;
if (wasActive) return;
using (BeginDelayedSequence(50))
Active = false;
}
}
}
}
}