Move value change logic to bindable

Also add drag support
This commit is contained in:
Dean Herbert 2018-03-20 20:09:55 +09:00
parent 786e6242e1
commit 6fd650777c
3 changed files with 106 additions and 52 deletions

View File

@ -1,6 +1,8 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Screens.Edit.Screens.Compose; using osu.Game.Screens.Edit.Screens.Compose;
@ -10,6 +12,8 @@ namespace osu.Game.Tests.Visual
{ {
public class TestCaseDrawableBeatDivisor : OsuTestCase public class TestCaseDrawableBeatDivisor : OsuTestCase
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(BindableBeatDivisor) };
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {

View File

@ -1,15 +1,55 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Framework.Configuration; using osu.Framework.Configuration;
namespace osu.Game.Screens.Edit.Screens.Compose namespace osu.Game.Screens.Edit.Screens.Compose
{ {
public class BindableBeatDivisor : Bindable<int> public class BindableBeatDivisor : BindableNumber<int>
{ {
public static readonly int[] VALID_DIVISORS = { 1, 2, 3, 4, 6, 8, 12, 16 };
public BindableBeatDivisor(int value = 1) public BindableBeatDivisor(int value = 1)
: base(value) : base(value)
{ {
} }
public void Next() => Value = VALID_DIVISORS[Math.Min(VALID_DIVISORS.Length - 1, Array.IndexOf(VALID_DIVISORS, Value) + 1)];
public void Previous() => Value = VALID_DIVISORS[Math.Max(0, Array.IndexOf(VALID_DIVISORS, Value) - 1)];
public override int Value
{
get { return base.Value; }
set
{
int snapped = 1;
for (int i = 1; i < VALID_DIVISORS.Length; i++)
{
var curr = VALID_DIVISORS[i];
var prev = VALID_DIVISORS[i - 1];
if (value < prev + (curr - prev) / 2f)
{
snapped = prev;
break;
}
snapped = curr;
}
if (snapped == Value)
// it may be that we are already at the snapped value, but we want bound components to still be made aware that we possibly modified an incoming ValueChanged.
TriggerValueChange();
else
base.Value = snapped;
}
}
protected override int DefaultMinValue => VALID_DIVISORS.First();
protected override int DefaultMaxValue => VALID_DIVISORS.Last();
protected override int DefaultPrecision => 1;
} }
} }

View File

@ -1,13 +1,14 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using OpenTK; using OpenTK;
@ -17,10 +18,9 @@ namespace osu.Game.Screens.Edit.Screens.Compose
{ {
public class DrawableBeatDivisor : CompositeDrawable public class DrawableBeatDivisor : CompositeDrawable
{ {
private static readonly int[] available_divisors = { 1, 2, 3, 4, 6, 8, 12, 16 };
private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor(); private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor();
private int currentDivisorIndex; private int currentDivisorIndex;
private TickSliderBar slider;
public DrawableBeatDivisor(BindableBeatDivisor beatDivisor) public DrawableBeatDivisor(BindableBeatDivisor beatDivisor)
{ {
@ -48,7 +48,7 @@ namespace osu.Game.Screens.Edit.Screens.Compose
{ {
new Drawable[] new Drawable[]
{ {
new TickContainer(beatDivisor, 1, 2, 3, 4, 6, 8, 12, 16) slider = new TickSliderBar(beatDivisor, 1, 2, 3, 4, 6, 8, 12, 16)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = 5 } Padding = new MarginPadding { Horizontal = 5 }
@ -80,13 +80,13 @@ namespace osu.Game.Screens.Edit.Screens.Compose
new DivisorButton new DivisorButton
{ {
Icon = FontAwesome.fa_chevron_left, Icon = FontAwesome.fa_chevron_left,
Action = selectPrevious Action = beatDivisor.Previous
}, },
new DivisorText(beatDivisor), new DivisorText(beatDivisor),
new DivisorButton new DivisorButton
{ {
Icon = FontAwesome.fa_chevron_right, Icon = FontAwesome.fa_chevron_right,
Action = selectNext Action = beatDivisor.Next
} }
}, },
new Drawable[] new Drawable[]
@ -118,20 +118,8 @@ namespace osu.Game.Screens.Edit.Screens.Compose
} }
} }
}; };
}
private void selectPrevious() slider.Current.BindTo(beatDivisor);
{
if (currentDivisorIndex == 0)
return;
beatDivisor.Value = available_divisors[--currentDivisorIndex];
}
private void selectNext()
{
if (currentDivisorIndex == available_divisors.Length - 1)
return;
beatDivisor.Value = available_divisors[++currentDivisorIndex];
} }
private class DivisorText : SpriteText private class DivisorText : SpriteText
@ -186,61 +174,46 @@ namespace osu.Game.Screens.Edit.Screens.Compose
} }
} }
private class TickContainer : CompositeDrawable private class TickSliderBar : SliderBar<int>
{ {
private readonly Bindable<int> beatDivisor = new Bindable<int>(); public new MarginPadding Padding
{
set => base.Padding = value;
}
public new MarginPadding Padding { set => base.Padding = value; } private Drawable marker;
private EquilateralTriangle marker;
private readonly int[] availableDivisors; private readonly int[] availableDivisors;
private readonly float tickSpacing;
public TickContainer(BindableBeatDivisor beatDivisor, params int[] divisors) public TickSliderBar(params int[] divisors)
{ {
this.beatDivisor.BindTo(beatDivisor);
availableDivisors = divisors; availableDivisors = divisors;
tickSpacing = 1f / (availableDivisors.Length + 1);
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load()
{ {
InternalChild = marker = new EquilateralTriangle InternalChild = marker = new Marker();
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomCentre,
RelativePositionAxes = Axes.X,
Height = 7,
EdgeSmoothness = new Vector2(1),
Colour = colours.Gray4,
};
for (int i = 0; i < availableDivisors.Length; i++) foreach (var t in availableDivisors)
{ {
AddInternal(new Tick(availableDivisors[i]) AddInternal(new Tick(t)
{ {
Anchor = Anchor.TopLeft, Anchor = Anchor.TopLeft,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
RelativePositionAxes = Axes.X, RelativePositionAxes = Axes.X,
X = getTickPosition(i) X = getTickPosition(t)
}); });
} }
CurrentNumber.ValueChanged += v => marker.MoveToX(getTickPosition(v), 100, Easing.OutQuint);
} }
protected override void LoadComplete() protected override void UpdateValue(float value)
{ {
base.LoadComplete();
beatDivisor.ValueChanged += v => updatePosition();
updatePosition();
} }
private void updatePosition() => marker.MoveToX(getTickPosition(Array.IndexOf(availableDivisors, beatDivisor.Value)), 100, Easing.OutQuint); private float getTickPosition(float divisor) => (divisor - 1) / availableDivisors.Last();
private float getTickPosition(int index) => (index + 1) * tickSpacing;
private class Tick : Box private class Tick : Box
{ {
@ -249,7 +222,6 @@ namespace osu.Game.Screens.Edit.Screens.Compose
public Tick(int divisor) public Tick(int divisor)
{ {
this.divisor = divisor; this.divisor = divisor;
Size = new Vector2(2, 10); Size = new Vector2(2, 10);
} }
@ -264,6 +236,44 @@ namespace osu.Game.Screens.Edit.Screens.Compose
Colour = colours.Gray4; Colour = colours.Gray4;
} }
} }
private class Marker : CompositeDrawable
{
private const float size = 7;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Colour = colours.Gray4;
Anchor = Anchor.TopLeft;
Origin = Anchor.TopCentre;
Width = size;
RelativeSizeAxes = Axes.Y;
RelativePositionAxes = Axes.X;
InternalChildren = new Drawable[]
{
new Box
{
Width = 1,
RelativeSizeAxes = Axes.Y,
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
Colour = Color4.White,
},
new EquilateralTriangle
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
Height = size,
EdgeSmoothness = new Vector2(1),
Colour = Color4.White,
}
};
}
}
} }
} }
} }