Merge branch 'master' into non-concurrent-sample-playback

This commit is contained in:
smoogipoo
2021-02-12 17:22:15 +09:00
295 changed files with 7478 additions and 2398 deletions

View File

@ -38,7 +38,12 @@ namespace osu.Game.Graphics.Containers
foreach (var link in links)
{
AddText(text[previousLinkEnd..link.Index]);
AddLink(text.Substring(link.Index, link.Length), link.Action, link.Argument ?? link.Url);
string displayText = text.Substring(link.Index, link.Length);
string linkArgument = link.Argument ?? link.Url;
string tooltip = displayText == link.Url ? null : link.Url;
AddLink(displayText, link.Action, linkArgument, tooltip);
previousLinkEnd = link.Index + link.Length;
}
@ -52,7 +57,7 @@ namespace osu.Game.Graphics.Containers
=> createLink(AddText(text, creationParameters), new LinkDetails(LinkAction.Custom, null), tooltipText, action);
public void AddLink(string text, LinkAction action, string argument, string tooltipText = null, Action<SpriteText> creationParameters = null)
=> createLink(AddText(text, creationParameters), new LinkDetails(action, argument), null);
=> createLink(AddText(text, creationParameters), new LinkDetails(action, argument), tooltipText);
public void AddLink(IEnumerable<SpriteText> text, LinkAction action = LinkAction.External, string linkArgument = null, string tooltipText = null)
{

View File

@ -20,6 +20,8 @@ namespace osu.Game.Graphics.Containers
{
private Sample samplePopIn;
private Sample samplePopOut;
protected virtual string PopInSampleName => "UI/overlay-pop-in";
protected virtual string PopOutSampleName => "UI/overlay-pop-out";
protected override bool BlockNonPositionalInput => true;
@ -40,8 +42,8 @@ namespace osu.Game.Graphics.Containers
[BackgroundDependencyLoader(true)]
private void load(AudioManager audio)
{
samplePopIn = audio.Samples.Get(@"UI/overlay-pop-in");
samplePopOut = audio.Samples.Get(@"UI/overlay-pop-out");
samplePopIn = audio.Samples.Get(PopInSampleName);
samplePopOut = audio.Samples.Get(PopOutSampleName);
}
protected override void LoadComplete()

View File

@ -24,6 +24,10 @@ namespace osu.Game.Graphics.Containers
private Bindable<bool> parallaxEnabled;
private const float parallax_duration = 100;
private bool firstUpdate = true;
public ParallaxContainer()
{
RelativeSizeAxes = Axes.Both;
@ -60,17 +64,27 @@ namespace osu.Game.Graphics.Containers
input = GetContainingInputManager();
}
private bool firstUpdate = true;
protected override void Update()
{
base.Update();
if (parallaxEnabled.Value)
{
Vector2 offset = (input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.Position) - DrawSize / 2) * ParallaxAmount;
Vector2 offset = Vector2.Zero;
const float parallax_duration = 100;
if (input.CurrentState.Mouse != null)
{
var sizeDiv2 = DrawSize / 2;
Vector2 relativeAmount = ToLocalSpace(input.CurrentState.Mouse.Position) - sizeDiv2;
const float base_factor = 0.999f;
relativeAmount.X = (float)(Math.Sign(relativeAmount.X) * Interpolation.Damp(0, 1, base_factor, Math.Abs(relativeAmount.X)));
relativeAmount.Y = (float)(Math.Sign(relativeAmount.Y) * Interpolation.Damp(0, 1, base_factor, Math.Abs(relativeAmount.Y)));
offset = relativeAmount * sizeDiv2 * ParallaxAmount;
}
double elapsed = Math.Clamp(Clock.ElapsedFrameTime, 0, parallax_duration);

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Allocation;
@ -9,6 +10,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Layout;
using osu.Framework.Utils;
namespace osu.Game.Graphics.Containers
{
@ -20,6 +22,7 @@ namespace osu.Game.Graphics.Containers
where T : Drawable
{
public Bindable<T> SelectedSection { get; } = new Bindable<T>();
private Drawable lastClickedSection;
public Drawable ExpandableHeader
{
@ -36,7 +39,7 @@ namespace osu.Game.Graphics.Containers
if (value == null) return;
AddInternal(expandableHeader);
lastKnownScroll = float.NaN;
lastKnownScroll = null;
}
}
@ -52,7 +55,7 @@ namespace osu.Game.Graphics.Containers
if (value == null) return;
AddInternal(fixedHeader);
lastKnownScroll = float.NaN;
lastKnownScroll = null;
}
}
@ -71,7 +74,7 @@ namespace osu.Game.Graphics.Containers
footer.Anchor |= Anchor.y2;
footer.Origin |= Anchor.y2;
scrollContainer.Add(footer);
lastKnownScroll = float.NaN;
lastKnownScroll = null;
}
}
@ -89,21 +92,26 @@ namespace osu.Game.Graphics.Containers
headerBackgroundContainer.Add(headerBackground);
lastKnownScroll = float.NaN;
lastKnownScroll = null;
}
}
protected override Container<T> Content => scrollContentContainer;
private readonly OsuScrollContainer scrollContainer;
private readonly UserTrackingScrollContainer scrollContainer;
private readonly Container headerBackgroundContainer;
private readonly MarginPadding originalSectionsMargin;
private Drawable expandableHeader, fixedHeader, footer, headerBackground;
private FlowContainer<T> scrollContentContainer;
private float headerHeight, footerHeight;
private float? headerHeight, footerHeight;
private float lastKnownScroll;
private float? lastKnownScroll;
/// <summary>
/// The percentage of the container to consider the centre-point for deciding the active section (and scrolling to a requested section).
/// </summary>
private const float scroll_y_centre = 0.1f;
public SectionsContainer()
{
@ -128,18 +136,24 @@ namespace osu.Game.Graphics.Containers
public override void Add(T drawable)
{
base.Add(drawable);
lastKnownScroll = float.NaN;
headerHeight = float.NaN;
footerHeight = float.NaN;
Debug.Assert(drawable != null);
lastKnownScroll = null;
headerHeight = null;
footerHeight = null;
}
public void ScrollTo(Drawable section) =>
scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(section) - (FixedHeader?.BoundingBox.Height ?? 0));
public void ScrollTo(Drawable section)
{
lastClickedSection = section;
scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(section) - scrollContainer.DisplayableContent * scroll_y_centre - (FixedHeader?.BoundingBox.Height ?? 0));
}
public void ScrollToTop() => scrollContainer.ScrollTo(0);
[NotNull]
protected virtual OsuScrollContainer CreateScrollContainer() => new OsuScrollContainer();
protected virtual UserTrackingScrollContainer CreateScrollContainer() => new UserTrackingScrollContainer();
[NotNull]
protected virtual FlowContainer<T> CreateScrollContentContainer() =>
@ -156,7 +170,7 @@ namespace osu.Game.Graphics.Containers
if (source == InvalidationSource.Child && (invalidation & Invalidation.DrawSize) != 0)
{
lastKnownScroll = -1;
lastKnownScroll = null;
result = true;
}
@ -167,7 +181,10 @@ namespace osu.Game.Graphics.Containers
{
base.UpdateAfterChildren();
float headerH = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0);
float fixedHeaderSize = FixedHeader?.LayoutSize.Y ?? 0;
float expandableHeaderSize = ExpandableHeader?.LayoutSize.Y ?? 0;
float headerH = expandableHeaderSize + fixedHeaderSize;
float footerH = Footer?.LayoutSize.Y ?? 0;
if (headerH != headerHeight || footerH != footerHeight)
@ -183,28 +200,39 @@ namespace osu.Game.Graphics.Containers
{
lastKnownScroll = currentScroll;
// reset last clicked section because user started scrolling themselves
if (scrollContainer.UserScrolling)
lastClickedSection = null;
if (ExpandableHeader != null && FixedHeader != null)
{
float offset = Math.Min(ExpandableHeader.LayoutSize.Y, currentScroll);
float offset = Math.Min(expandableHeaderSize, currentScroll);
ExpandableHeader.Y = -offset;
FixedHeader.Y = -offset + ExpandableHeader.LayoutSize.Y;
FixedHeader.Y = -offset + expandableHeaderSize;
}
headerBackgroundContainer.Height = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0);
headerBackgroundContainer.Height = expandableHeaderSize + fixedHeaderSize;
headerBackgroundContainer.Y = ExpandableHeader?.Y ?? 0;
float scrollOffset = FixedHeader?.LayoutSize.Y ?? 0;
Func<T, float> diff = section => scrollContainer.GetChildPosInContent(section) - currentScroll - scrollOffset;
var smallestSectionHeight = Children.Count > 0 ? Children.Min(d => d.Height) : 0;
if (scrollContainer.IsScrolledToEnd())
{
SelectedSection.Value = Children.LastOrDefault();
}
// scroll offset is our fixed header height if we have it plus 10% of content height
// plus 5% to fix floating point errors and to not have a section instantly unselect when scrolling upwards
// but the 5% can't be bigger than our smallest section height, otherwise it won't get selected correctly
float selectionLenienceAboveSection = Math.Min(smallestSectionHeight / 2.0f, scrollContainer.DisplayableContent * 0.05f);
float scrollCentre = fixedHeaderSize + scrollContainer.DisplayableContent * scroll_y_centre + selectionLenienceAboveSection;
if (Precision.AlmostBigger(0, scrollContainer.Current))
SelectedSection.Value = lastClickedSection as T ?? Children.FirstOrDefault();
else if (Precision.AlmostBigger(scrollContainer.Current, scrollContainer.ScrollableExtent))
SelectedSection.Value = lastClickedSection as T ?? Children.LastOrDefault();
else
{
SelectedSection.Value = Children.TakeWhile(section => diff(section) <= 0).LastOrDefault()
?? Children.FirstOrDefault();
SelectedSection.Value = Children
.TakeWhile(section => scrollContainer.GetChildPosInContent(section) - currentScroll - scrollCentre <= 0)
.LastOrDefault() ?? Children.FirstOrDefault();
}
}
}
@ -214,8 +242,9 @@ namespace osu.Game.Graphics.Containers
if (!Children.Any()) return;
var newMargin = originalSectionsMargin;
newMargin.Top += headerHeight;
newMargin.Bottom += footerHeight;
newMargin.Top += (headerHeight ?? 0);
newMargin.Bottom += (footerHeight ?? 0);
scrollContentContainer.Margin = newMargin;
}

View File

@ -0,0 +1,57 @@
// 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.Graphics;
namespace osu.Game.Graphics.Containers
{
public class UserTrackingScrollContainer : UserTrackingScrollContainer<Drawable>
{
public UserTrackingScrollContainer()
{
}
public UserTrackingScrollContainer(Direction direction)
: base(direction)
{
}
}
public class UserTrackingScrollContainer<T> : OsuScrollContainer<T>
where T : Drawable
{
/// <summary>
/// Whether the last scroll event was user triggered, directly on the scroll container.
/// </summary>
public bool UserScrolling { get; private set; }
public void CancelUserScroll() => UserScrolling = false;
public UserTrackingScrollContainer()
{
}
public UserTrackingScrollContainer(Direction direction)
: base(direction)
{
}
protected override void OnUserScroll(float value, bool animated = true, double? distanceDecay = default)
{
UserScrolling = true;
base.OnUserScroll(value, animated, distanceDecay);
}
public new void ScrollTo(float value, bool animated = true, double? distanceDecay = null)
{
UserScrolling = false;
base.ScrollTo(value, animated, distanceDecay);
}
public new void ScrollToEnd(bool animated = true, bool allowDuringDrag = false)
{
UserScrolling = false;
base.ScrollToEnd(animated, allowDuringDrag);
}
}
}

View File

@ -4,54 +4,38 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Online;
using osuTK;
namespace osu.Game.Graphics.UserInterface
{
public class DownloadButton : OsuAnimatedButton
public class DownloadButton : GrayButton
{
public readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
private readonly SpriteIcon icon;
private readonly SpriteIcon checkmark;
private readonly Box background;
[Resolved]
private OsuColour colours { get; set; }
public readonly Bindable<DownloadState> State = new Bindable<DownloadState>();
private SpriteIcon checkmark;
public DownloadButton()
: base(FontAwesome.Solid.Download)
{
Children = new Drawable[]
{
background = new Box
{
RelativeSizeAxes = Axes.Both,
Depth = float.MaxValue
},
icon = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(13),
Icon = FontAwesome.Solid.Download,
},
checkmark = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
X = 8,
Size = Vector2.Zero,
Icon = FontAwesome.Solid.Check,
}
};
}
[BackgroundDependencyLoader]
private void load()
{
AddInternal(checkmark = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
X = 8,
Size = Vector2.Zero,
Icon = FontAwesome.Solid.Check,
});
State.BindValueChanged(updateState, true);
}
@ -60,27 +44,27 @@ namespace osu.Game.Graphics.UserInterface
switch (state.NewValue)
{
case DownloadState.NotDownloaded:
background.FadeColour(colours.Gray4, 500, Easing.InOutExpo);
icon.MoveToX(0, 500, Easing.InOutExpo);
Background.FadeColour(colours.Gray4, 500, Easing.InOutExpo);
Icon.MoveToX(0, 500, Easing.InOutExpo);
checkmark.ScaleTo(Vector2.Zero, 500, Easing.InOutExpo);
TooltipText = "Download";
break;
case DownloadState.Downloading:
background.FadeColour(colours.Blue, 500, Easing.InOutExpo);
icon.MoveToX(0, 500, Easing.InOutExpo);
Background.FadeColour(colours.Blue, 500, Easing.InOutExpo);
Icon.MoveToX(0, 500, Easing.InOutExpo);
checkmark.ScaleTo(Vector2.Zero, 500, Easing.InOutExpo);
TooltipText = "Downloading...";
break;
case DownloadState.Importing:
background.FadeColour(colours.Yellow, 500, Easing.InOutExpo);
Background.FadeColour(colours.Yellow, 500, Easing.InOutExpo);
TooltipText = "Importing";
break;
case DownloadState.LocallyAvailable:
background.FadeColour(colours.Green, 500, Easing.InOutExpo);
icon.MoveToX(-8, 500, Easing.InOutExpo);
Background.FadeColour(colours.Green, 500, Easing.InOutExpo);
Icon.MoveToX(-8, 500, Easing.InOutExpo);
checkmark.ScaleTo(new Vector2(13), 500, Easing.InOutExpo);
break;
}

View File

@ -0,0 +1,48 @@
// 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.Shapes;
using osu.Framework.Graphics.Sprites;
using osuTK;
namespace osu.Game.Graphics.UserInterface
{
public class GrayButton : OsuAnimatedButton
{
protected SpriteIcon Icon { get; private set; }
protected Box Background { get; private set; }
private readonly IconUsage icon;
[Resolved]
private OsuColour colours { get; set; }
public GrayButton(IconUsage icon)
{
this.icon = icon;
}
[BackgroundDependencyLoader]
private void load()
{
Children = new Drawable[]
{
Background = new Box
{
Colour = colours.Gray4,
RelativeSizeAxes = Axes.Both,
Depth = float.MaxValue
},
Icon = new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(13),
Icon = icon,
},
};
}
}
}

View File

@ -0,0 +1,50 @@
// 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.Audio;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Game.Configuration;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// Handles debouncing hover sounds at a global level to ensure the effects are not overwhelming.
/// </summary>
public abstract class HoverSampleDebounceComponent : CompositeDrawable
{
/// <summary>
/// Length of debounce for hover sound playback, in milliseconds.
/// </summary>
public double HoverDebounceTime { get; } = 20;
private Bindable<double?> lastPlaybackTime;
[BackgroundDependencyLoader]
private void load(AudioManager audio, SessionStatics statics)
{
lastPlaybackTime = statics.GetBindable<double?>(Static.LastHoverSoundPlaybackTime);
}
protected override bool OnHover(HoverEvent e)
{
// hover sounds shouldn't be played during scroll operations.
if (e.HasAnyButtonPressed)
return false;
bool enoughTimePassedSinceLastPlayback = !lastPlaybackTime.Value.HasValue || Time.Current - lastPlaybackTime.Value >= HoverDebounceTime;
if (enoughTimePassedSinceLastPlayback)
{
PlayHoverSample();
lastPlaybackTime.Value = Time.Current;
}
return false;
}
public abstract void PlayHoverSample();
}
}

View File

@ -5,12 +5,10 @@ using System.ComponentModel;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input.Events;
using osu.Game.Configuration;
using osu.Framework.Utils;
namespace osu.Game.Graphics.UserInterface
{
@ -18,19 +16,12 @@ namespace osu.Game.Graphics.UserInterface
/// Adds hover sounds to a drawable.
/// Does not draw anything.
/// </summary>
public class HoverSounds : CompositeDrawable
public class HoverSounds : HoverSampleDebounceComponent
{
private Sample sampleHover;
/// <summary>
/// Length of debounce for hover sound playback, in milliseconds.
/// </summary>
public double HoverDebounceTime { get; } = 20;
protected readonly HoverSampleSet SampleSet;
private Bindable<double?> lastPlaybackTime;
public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal)
{
SampleSet = sampleSet;
@ -40,22 +31,13 @@ namespace osu.Game.Graphics.UserInterface
[BackgroundDependencyLoader]
private void load(AudioManager audio, SessionStatics statics)
{
lastPlaybackTime = statics.GetBindable<double?>(Static.LastHoverSoundPlaybackTime);
sampleHover = audio.Samples.Get($@"UI/generic-hover{SampleSet.GetDescription()}");
}
protected override bool OnHover(HoverEvent e)
public override void PlayHoverSample()
{
bool enoughTimePassedSinceLastPlayback = !lastPlaybackTime.Value.HasValue || Time.Current - lastPlaybackTime.Value >= HoverDebounceTime;
if (enoughTimePassedSinceLastPlayback)
{
sampleHover?.Play();
lastPlaybackTime.Value = Time.Current;
}
return base.OnHover(e);
sampleHover.Frequency.Value = 0.96 + RNG.NextDouble(0.08);
sampleHover.Play();
}
}
@ -68,6 +50,9 @@ namespace osu.Game.Graphics.UserInterface
Normal,
[Description("-softer")]
Soft
Soft,
[Description("-toolbar")]
Toolbar
}
}

View File

@ -42,13 +42,7 @@ namespace osu.Game.Graphics.UserInterface
},
};
Current.ValueChanged += filled =>
{
if (filled.NewValue)
fill.FadeIn(200, Easing.OutQuint);
else
fill.FadeTo(0.01f, 200, Easing.OutQuint); //todo: remove once we figure why containers aren't drawing at all times
};
Current.ValueChanged += filled => fill.FadeTo(filled.NewValue ? 1 : 0, 200, Easing.OutQuint);
}
[BackgroundDependencyLoader]

View File

@ -5,6 +5,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Graphics.Containers;
@ -18,6 +19,11 @@ namespace osu.Game.Graphics.UserInterface
public Color4 UncheckedColor { get; set; } = Color4.White;
public int FadeDuration { get; set; }
/// <summary>
/// Whether to play sounds when the state changes as a result of user interaction.
/// </summary>
protected virtual bool PlaySoundsOnUserChange => true;
public string LabelText
{
set
@ -43,7 +49,7 @@ namespace osu.Game.Graphics.UserInterface
private Sample sampleChecked;
private Sample sampleUnchecked;
public OsuCheckbox()
public OsuCheckbox(bool nubOnRight = true)
{
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X;
@ -52,26 +58,42 @@ namespace osu.Game.Graphics.UserInterface
Children = new Drawable[]
{
labelText = new OsuTextFlowContainer
labelText = new OsuTextFlowContainer(ApplyLabelParameters)
{
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Padding = new MarginPadding { Right = Nub.EXPANDED_SIZE + nub_padding }
},
Nub = new Nub
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Margin = new MarginPadding { Right = nub_padding },
},
new HoverClickSounds()
Nub = new Nub(),
new HoverSounds()
};
if (nubOnRight)
{
Nub.Anchor = Anchor.CentreRight;
Nub.Origin = Anchor.CentreRight;
Nub.Margin = new MarginPadding { Right = nub_padding };
labelText.Padding = new MarginPadding { Right = Nub.EXPANDED_SIZE + nub_padding * 2 };
}
else
{
Nub.Anchor = Anchor.CentreLeft;
Nub.Origin = Anchor.CentreLeft;
Nub.Margin = new MarginPadding { Left = nub_padding };
labelText.Padding = new MarginPadding { Left = Nub.EXPANDED_SIZE + nub_padding * 2 };
}
Nub.Current.BindTo(Current);
Current.DisabledChanged += disabled => labelText.Alpha = Nub.Alpha = disabled ? 0.3f : 1;
}
/// <summary>
/// A function which can be overridden to change the parameters of the label's text.
/// </summary>
protected virtual void ApplyLabelParameters(SpriteText text)
{
}
[BackgroundDependencyLoader]
private void load(AudioManager audio)
{
@ -96,10 +118,14 @@ namespace osu.Game.Graphics.UserInterface
protected override void OnUserChange(bool value)
{
base.OnUserChange(value);
if (value)
sampleChecked?.Play();
else
sampleUnchecked?.Play();
if (PlaySoundsOnUserChange)
{
if (value)
sampleChecked?.Play();
else
sampleUnchecked?.Play();
}
}
}
}

View File

@ -40,8 +40,19 @@ namespace osu.Game.Graphics.UserInterface
set => CurrentNumber.Value = value;
}
public ProgressBar()
private readonly bool allowSeek;
public override bool HandlePositionalInput => allowSeek;
public override bool HandleNonPositionalInput => allowSeek;
/// <summary>
/// Construct a new progress bar.
/// </summary>
/// <param name="allowSeek">Whether the user should be allowed to click/drag to adjust the value.</param>
public ProgressBar(bool allowSeek)
{
this.allowSeek = allowSeek;
CurrentNumber.MinValue = 0;
CurrentNumber.MaxValue = 1;
RelativeSizeAxes = Axes.X;