diff --git a/osu-framework b/osu-framework index 7ac3dbff36..bbfd0fc7a8 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 7ac3dbff3615fb410da1e330e6379b53a41292b6 +Subproject commit bbfd0fc7a8f5293a0f853f51040b40808abbb459 diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTabControl.cs b/osu.Desktop.VisualTests/Tests/TestCaseTabControl.cs index 2d3969b822..b72abd1992 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseTabControl.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseTabControl.cs @@ -36,7 +36,7 @@ namespace osu.Desktop.VisualTests.Tests filter.PinItem(GroupMode.All); filter.PinItem(GroupMode.RecentlyPlayed); - filter.SelectedItem.ValueChanged += newFilter => + filter.Current.ValueChanged += newFilter => { text.Text = "Currently Selected: " + newFilter.ToString(); }; diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index e150c7dc07..a5a4fab3e1 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -3,8 +3,8 @@ using OpenTK; using OpenTK.Graphics; -using osu.Framework; using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; @@ -12,18 +12,18 @@ using osu.Framework.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterface { - public class Nub : CircularContainer, IStateful + public class Nub : CircularContainer, IHasCurrentValue { public const float COLLAPSED_SIZE = 20; public const float EXPANDED_SIZE = 40; - private readonly Box fill; - private const float border_width = 3; private Color4 glowingColour, idleColour; public Nub() { + Box fill; + Size = new Vector2(COLLAPSED_SIZE, 12); BorderColour = Color4.White; @@ -40,6 +40,14 @@ namespace osu.Game.Graphics.UserInterface AlwaysPresent = true, }, }; + + Current.ValueChanged += newValue => + { + if (newValue) + fill.FadeIn(200, EasingTypes.OutQuint); + else + fill.FadeTo(0.01f, 200, EasingTypes.OutQuint); //todo: remove once we figure why containers aren't drawing at all times + }; } [BackgroundDependencyLoader] @@ -84,28 +92,12 @@ namespace osu.Game.Graphics.UserInterface } } - private CheckboxState state; + private readonly Bindable current = new Bindable(); - public CheckboxState State + public Bindable Current { - get - { - return state; - } - set - { - state = value; - - switch (state) - { - case CheckboxState.Checked: - fill.FadeIn(200, EasingTypes.OutQuint); - break; - case CheckboxState.Unchecked: - fill.FadeTo(0.01f, 200, EasingTypes.OutQuint); //todo: remove once we figure why containers aren't drawing at all times - break; - } - } + get { return current; } + set { current.BindTo(value); } } } } diff --git a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs index 6a5151b90c..5d4760fec6 100644 --- a/osu.Game/Graphics/UserInterface/OsuCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuCheckbox.cs @@ -23,16 +23,10 @@ namespace osu.Game.Graphics.UserInterface { set { - if (bindable != null) - bindable.ValueChanged -= bindableValueChanged; bindable = value; + if (bindable != null) - { - bool state = State == CheckboxState.Checked; - if (state != bindable.Value) - State = bindable.Value ? CheckboxState.Checked : CheckboxState.Unchecked; - bindable.ValueChanged += bindableValueChanged; - } + Current = bindable; if (bindable?.Disabled ?? true) Alpha = 0.3f; @@ -78,23 +72,20 @@ namespace osu.Game.Graphics.UserInterface labelSpriteText = new OsuSpriteText(), nub = new Nub { + Current = Current, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Margin = new MarginPadding { Right = 5 }, } }; - } - private void bindableValueChanged(bool isChecked) - { - State = isChecked ? CheckboxState.Checked : CheckboxState.Unchecked; - } - - protected override void Dispose(bool isDisposing) - { - if (bindable != null) - bindable.ValueChanged -= bindableValueChanged; - base.Dispose(isDisposing); + Current.ValueChanged += newValue => + { + if (newValue) + sampleChecked?.Play(); + else + sampleUnchecked?.Play(); + }; } protected override bool OnHover(InputState state) @@ -117,23 +108,5 @@ namespace osu.Game.Graphics.UserInterface sampleChecked = audio.Sample.Get(@"Checkbox/check-on"); sampleUnchecked = audio.Sample.Get(@"Checkbox/check-off"); } - - protected override void OnChecked() - { - sampleChecked?.Play(); - nub.State = CheckboxState.Checked; - - if (bindable != null) - bindable.Value = true; - } - - protected override void OnUnchecked() - { - sampleUnchecked?.Play(); - nub.State = CheckboxState.Unchecked; - - if (bindable != null) - bindable.Value = false; - } } } diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 3466fb1a60..9bb0d15545 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -45,7 +45,7 @@ namespace osu.Game.Graphics.UserInterface private class OsuDropdownMenuItem : DropdownMenuItem { - public OsuDropdownMenuItem(string text, T value) : base(text, value) + public OsuDropdownMenuItem(string text, T current) : base(text, current) { Foreground.Padding = new MarginPadding(2); diff --git a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs index 078c8564d7..91fb1c672a 100644 --- a/osu.Game/Graphics/UserInterface/OsuSliderBar.cs +++ b/osu.Game/Graphics/UserInterface/OsuSliderBar.cs @@ -50,7 +50,6 @@ namespace osu.Game.Graphics.UserInterface nub = new Nub { Origin = Anchor.TopCentre, - State = CheckboxState.Unchecked, Expanded = true, } }; @@ -94,13 +93,13 @@ namespace osu.Game.Graphics.UserInterface protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) { - nub.State = CheckboxState.Checked; + nub.Current.Value = true; return base.OnMouseDown(state, args); } protected override bool OnMouseUp(InputState state, MouseUpEventArgs args) { - nub.State = CheckboxState.Unchecked; + nub.Current.Value = false; return base.OnMouseUp(state, args); } diff --git a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs index 5914d0ba4c..f732916889 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs @@ -1,7 +1,6 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System; using OpenTK; using OpenTK.Graphics; using osu.Framework.Allocation; @@ -24,8 +23,6 @@ namespace osu.Game.Graphics.UserInterface private readonly SpriteText text; private readonly TextAwesome icon; - public event EventHandler Action; - private Color4? accentColour; public Color4 AccentColour { @@ -34,7 +31,7 @@ namespace osu.Game.Graphics.UserInterface { accentColour = value; - if (State != CheckboxState.Checked) + if (Current) { text.Colour = AccentColour; icon.Colour = AccentColour; @@ -48,20 +45,6 @@ namespace osu.Game.Graphics.UserInterface set { text.Text = value; } } - protected override void OnChecked() - { - fadeIn(); - icon.Icon = FontAwesome.fa_check_circle_o; - Action?.Invoke(this, State); - } - - protected override void OnUnchecked() - { - fadeOut(); - icon.Icon = FontAwesome.fa_circle_o; - Action?.Invoke(this, State); - } - private const float transition_length = 500; private void fadeIn() @@ -84,7 +67,7 @@ namespace osu.Game.Graphics.UserInterface protected override void OnHoverLost(InputState state) { - if (State == CheckboxState.Unchecked) + if (!Current) fadeOut(); base.OnHoverLost(state); @@ -134,6 +117,20 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.BottomLeft, } }; + + Current.ValueChanged += v => + { + if (v) + { + fadeIn(); + icon.Icon = FontAwesome.fa_check_circle_o; + } + else + { + fadeOut(); + icon.Icon = FontAwesome.fa_circle_o; + } + }; } } } diff --git a/osu.Game/Overlays/Options/OptionDropdown.cs b/osu.Game/Overlays/Options/OptionDropdown.cs index 9ae02a17d3..decf5896c2 100644 --- a/osu.Game/Overlays/Options/OptionDropdown.cs +++ b/osu.Game/Overlays/Options/OptionDropdown.cs @@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Options set { bindable = value; - dropdown.SelectedValue.BindTo(bindable); + dropdown.Current = bindable; if (bindable.Disabled) Alpha = 0.3f; } diff --git a/osu.Game/Overlays/Options/OptionTextBox.cs b/osu.Game/Overlays/Options/OptionTextBox.cs index 722f24d50d..346c9f88f5 100644 --- a/osu.Game/Overlays/Options/OptionTextBox.cs +++ b/osu.Game/Overlays/Options/OptionTextBox.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Configuration; -using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options @@ -15,38 +14,13 @@ namespace osu.Game.Overlays.Options { set { - if (bindable != null) - bindable.ValueChanged -= bindableValueChanged; bindable = value; - if (bindable != null) - { - Text = bindable.Value; - bindable.ValueChanged += bindableValueChanged; - } + + Current = bindable; if (bindable?.Disabled ?? true) Alpha = 0.3f; } } - - public OptionTextBox() - { - OnChange += onChange; - } - - private void onChange(TextBox sender, bool newText) - { - if (bindable != null) - bindable.Value = Text; - } - - private void bindableValueChanged(string newValue) => Text = newValue; - - protected override void Dispose(bool isDisposing) - { - if (bindable != null) - bindable.ValueChanged -= bindableValueChanged; - base.Dispose(isDisposing); - } } } \ No newline at end of file diff --git a/osu.Game/Screens/Play/HotkeyRetryOverlay.cs b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs new file mode 100644 index 0000000000..16062bebe5 --- /dev/null +++ b/osu.Game/Screens/Play/HotkeyRetryOverlay.cs @@ -0,0 +1,82 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Input; +using OpenTK.Input; +using osu.Framework.Allocation; +using osu.Framework.Audio.Sample; +using osu.Framework.Audio; +using System; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using OpenTK.Graphics; + +namespace osu.Game.Screens.Play +{ + public class HotkeyRetryOverlay : Container + { + public Action Action; + + private SampleChannel retrySample; + private Box overlay; + + private const int activate_delay = 400; + private const int fadeout_delay = 200; + + private bool fired; + + [BackgroundDependencyLoader] + private void load(AudioManager audio) + { + retrySample = audio.Sample.Get(@"Menu/menuback"); + RelativeSizeAxes = Axes.Both; + AlwaysPresent = true; + + Children = new Drawable[] + { + overlay = new Box + { + Alpha = 0, + Colour = Color4.Black, + RelativeSizeAxes = Axes.Both, + } + }; + } + + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + if (args.Repeat) return false; + + if (args.Key == Key.Tilde) + { + overlay.FadeIn(activate_delay, EasingTypes.Out); + return true; + } + + return base.OnKeyDown(state, args); + } + + protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) + { + if (args.Key == Key.Tilde && !fired) + { + overlay.FadeOut(fadeout_delay, EasingTypes.Out); + return true; + } + + return base.OnKeyUp(state, args); + } + + protected override void Update() + { + base.Update(); + if (!fired && overlay.Alpha == 1) + { + fired = true; + retrySample.Play(); + Action?.Invoke(); + } + } + } +} diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 36ab1ab946..a7108eda1b 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -157,6 +157,10 @@ namespace osu.Game.Screens.Play { OnRetry = Restart, OnQuit = Exit, + }, + new HotkeyRetryOverlay + { + Action = Restart, } }; } diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs index c52d0397ed..48a46f0b90 100644 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs +++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs @@ -8,7 +8,6 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; -using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; @@ -24,7 +23,7 @@ namespace osu.Game.Screens.Select private void invokeOnFilter() { - OnFilter?.Invoke(tabs.SelectedItem, modsCheckbox.State == CheckboxState.Checked); + OnFilter?.Invoke(tabs.Current, modsCheckbox.Current); } [BackgroundDependencyLoader] @@ -61,10 +60,10 @@ namespace osu.Game.Screens.Select }, }; - tabs.SelectedItem.ValueChanged += item => invokeOnFilter(); - modsCheckbox.Action += (sender, e) => invokeOnFilter(); + tabs.Current.ValueChanged += item => invokeOnFilter(); + modsCheckbox.Current.ValueChanged += item => invokeOnFilter(); - tabs.SelectedItem.Value = BeatmapDetailTab.Global; + tabs.Current.Value = BeatmapDetailTab.Global; } } diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index 6d92b35993..7596af1484 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -93,11 +93,6 @@ namespace osu.Game.Screens.Select searchTextBox = new SearchTextBox { RelativeSizeAxes = Axes.X, - OnChange = (sender, newText) => - { - if (newText) - FilterChanged?.Invoke(CreateCriteria()); - }, Exit = () => Exit?.Invoke(), }, new Box @@ -149,10 +144,12 @@ namespace osu.Game.Screens.Select } }; + searchTextBox.Current.ValueChanged += t => FilterChanged?.Invoke(CreateCriteria()); + groupTabs.PinItem(GroupMode.All); groupTabs.PinItem(GroupMode.RecentlyPlayed); - groupTabs.SelectedItem.ValueChanged += val => Group = val; - sortTabs.SelectedItem.ValueChanged += val => Sort = val; + groupTabs.Current.ValueChanged += val => Group = val; + sortTabs.Current.ValueChanged += val => Sort = val; } public void Deactivate() diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 6dd5ec3088..d90fdda41a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -180,6 +180,7 @@ +