From 189988236b91f63b5e374f9289025ac938cebf4d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 15:23:17 +0900 Subject: [PATCH 01/35] Move PlayerInputManager logic inside RulesetInputManager --- osu.Game/Rulesets/UI/RulesetContainer.cs | 20 +-- osu.Game/Rulesets/UI/RulesetInputManager.cs | 163 +++++++++++++++++++- osu.Game/Screens/Play/PlayerInputManager.cs | 140 ----------------- osu.Game/osu.Game.csproj | 1 - 4 files changed, 169 insertions(+), 155 deletions(-) delete mode 100644 osu.Game/Screens/Play/PlayerInputManager.cs diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 84cadeb2a1..0a16335c77 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -9,7 +9,6 @@ using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; -using osu.Game.Screens.Play; using System; using System.Collections.Generic; using System.Diagnostics; @@ -43,7 +42,7 @@ namespace osu.Game.Rulesets.UI /// /// The input manager for this RulesetContainer. /// - internal readonly PlayerInputManager InputManager = new PlayerInputManager(); + internal IHasReplayHandler ReplayInputManager => (IHasReplayHandler)KeyBindingInputManager; /// /// The key conversion input manager for this RulesetContainer. @@ -58,7 +57,7 @@ namespace osu.Game.Rulesets.UI /// /// Whether we have a replay loaded currently. /// - public bool HasReplayLoaded => InputManager.ReplayInputHandler != null; + public bool HasReplayLoaded => ReplayInputManager.ReplayInputHandler != null; public abstract IEnumerable Objects { get; } @@ -76,11 +75,7 @@ namespace osu.Game.Rulesets.UI internal RulesetContainer(Ruleset ruleset) { Ruleset = ruleset; - } - [BackgroundDependencyLoader] - private void load() - { KeyBindingInputManager = CreateInputManager(); KeyBindingInputManager.RelativeSizeAxes = Axes.Both; } @@ -113,7 +108,7 @@ namespace osu.Game.Rulesets.UI public virtual void SetReplay(Replay replay) { Replay = replay; - InputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null; + ReplayInputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null; } } @@ -267,13 +262,12 @@ namespace osu.Game.Rulesets.UI [BackgroundDependencyLoader] private void load() { - InputManager.Add(content = new Container + KeyBindingInputManager.Add(content = new Container { RelativeSizeAxes = Axes.Both, - Children = new[] { KeyBindingInputManager } }); - AddInternal(InputManager); + AddInternal(KeyBindingInputManager); KeyBindingInputManager.Add(Playfield = CreatePlayfield()); loadObjects(); @@ -283,8 +277,8 @@ namespace osu.Game.Rulesets.UI { base.SetReplay(replay); - if (InputManager?.ReplayInputHandler != null) - InputManager.ReplayInputHandler.ToScreenSpace = Playfield.ScaledContent.ToScreenSpace; + if (ReplayInputManager?.ReplayInputHandler != null) + ReplayInputManager.ReplayInputHandler.ToScreenSpace = input => Playfield.ScaledContent.ToScreenSpace(input); } /// diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 6d22b2e91e..bd7e51e937 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -1,20 +1,176 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System.Collections.Generic; using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Configuration; +using osu.Framework.Input; using osu.Framework.Input.Bindings; +using osu.Framework.Timing; +using osu.Game.Configuration; using osu.Game.Input.Bindings; +using osu.Game.Input.Handlers; using osu.Game.Screens.Play; +using OpenTK.Input; namespace osu.Game.Rulesets.UI { - public abstract class RulesetInputManager : DatabasedKeyBindingInputManager, ICanAttachKeyCounter + public abstract class RulesetInputManager : DatabasedKeyBindingInputManager, ICanAttachKeyCounter, IHasReplayHandler where T : struct { protected RulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique) { } + private List lastPressedActions = new List(); + + protected override void HandleNewState(InputState state) + { + base.HandleNewState(state); + + var replayState = state as ReplayInputHandler.ReplayState; + + if (replayState == null) return; + + // Here we handle states specifically coming from a replay source. + // These have extra action information rather than keyboard keys or mouse buttons. + + List newActions = replayState.PressedActions; + + foreach (var released in lastPressedActions.Except(newActions)) + PropagateReleased(KeyBindingInputQueue, released); + + foreach (var pressed in newActions.Except(lastPressedActions)) + PropagatePressed(KeyBindingInputQueue, pressed); + + lastPressedActions = newActions; + } + + private ManualClock clock; + private IFrameBasedClock parentClock; + + private ReplayInputHandler replayInputHandler; + public ReplayInputHandler ReplayInputHandler + { + get + { + return replayInputHandler; + } + set + { + if (replayInputHandler != null) RemoveHandler(replayInputHandler); + + replayInputHandler = value; + UseParentState = replayInputHandler == null; + + if (replayInputHandler != null) + AddHandler(replayInputHandler); + } + } + + private Bindable mouseDisabled; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + mouseDisabled = config.GetBindable(OsuSetting.MouseDisableButtons); + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + //our clock will now be our parent's clock, but we want to replace this to allow manual control. + parentClock = Clock; + + Clock = new FramedClock(clock = new ManualClock + { + CurrentTime = parentClock.CurrentTime, + Rate = parentClock.Rate, + }); + } + + /// + /// Whether we running up-to-date with our parent clock. + /// If not, we will need to keep processing children until we catch up. + /// + private bool requireMoreUpdateLoops; + + /// + /// Whether we in a valid state (ie. should we keep processing children frames). + /// This should be set to false when the replay is, for instance, waiting for future frames to arrive. + /// + private bool validState; + + protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState; + + private bool isAttached => replayInputHandler != null && !UseParentState; + + private const int max_catch_up_updates_per_frame = 50; + + public override bool UpdateSubTree() + { + requireMoreUpdateLoops = true; + validState = true; + + int loops = 0; + + while (validState && requireMoreUpdateLoops && loops++ < max_catch_up_updates_per_frame) + if (!base.UpdateSubTree()) + return false; + + return true; + } + + protected override void Update() + { + if (parentClock == null) return; + + clock.Rate = parentClock.Rate; + clock.IsRunning = parentClock.IsRunning; + + if (!isAttached) + { + clock.CurrentTime = parentClock.CurrentTime; + } + else + { + double? newTime = replayInputHandler.SetFrameFromTime(parentClock.CurrentTime); + + if (newTime == null) + { + // we shouldn't execute for this time value. probably waiting on more replay data. + validState = false; + return; + } + + clock.CurrentTime = newTime.Value; + } + + requireMoreUpdateLoops = clock.CurrentTime != parentClock.CurrentTime; + base.Update(); + } + + protected override void TransformState(InputState state) + { + base.TransformState(state); + + // we don't want to transform the state if a replay is present (for now, at least). + if (replayInputHandler != null) return; + + var mouse = state.Mouse as Framework.Input.MouseState; + + if (mouse != null) + { + if (mouseDisabled.Value) + { + mouse.SetPressed(MouseButton.Left, false); + mouse.SetPressed(MouseButton.Right, false); + } + } + } + public void Attach(KeyCounterCollection keyCounter) { var receptor = new ActionReceptor(keyCounter); @@ -37,6 +193,11 @@ namespace osu.Game.Rulesets.UI } } + public interface IHasReplayHandler + { + ReplayInputHandler ReplayInputHandler { get; set; } + } + public interface ICanAttachKeyCounter { void Attach(KeyCounterCollection keyCounter); diff --git a/osu.Game/Screens/Play/PlayerInputManager.cs b/osu.Game/Screens/Play/PlayerInputManager.cs deleted file mode 100644 index f5e57f9e9d..0000000000 --- a/osu.Game/Screens/Play/PlayerInputManager.cs +++ /dev/null @@ -1,140 +0,0 @@ -// Copyright (c) 2007-2017 ppy Pty Ltd . -// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE - -using OpenTK.Input; -using osu.Framework.Allocation; -using osu.Framework.Configuration; -using osu.Framework.Input; -using osu.Framework.Timing; -using osu.Game.Configuration; -using osu.Game.Input.Handlers; - -namespace osu.Game.Screens.Play -{ - public class PlayerInputManager : PassThroughInputManager - { - private ManualClock clock; - private IFrameBasedClock parentClock; - - private ReplayInputHandler replayInputHandler; - public ReplayInputHandler ReplayInputHandler - { - get - { - return replayInputHandler; - } - set - { - if (replayInputHandler != null) RemoveHandler(replayInputHandler); - - replayInputHandler = value; - UseParentState = replayInputHandler == null; - - if (replayInputHandler != null) - AddHandler(replayInputHandler); - } - } - - private Bindable mouseDisabled; - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - mouseDisabled = config.GetBindable(OsuSetting.MouseDisableButtons); - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - //our clock will now be our parent's clock, but we want to replace this to allow manual control. - parentClock = Clock; - - Clock = new FramedClock(clock = new ManualClock - { - CurrentTime = parentClock.CurrentTime, - Rate = parentClock.Rate, - }); - } - - /// - /// Whether we running up-to-date with our parent clock. - /// If not, we will need to keep processing children until we catch up. - /// - private bool requireMoreUpdateLoops; - - /// - /// Whether we in a valid state (ie. should we keep processing children frames). - /// This should be set to false when the replay is, for instance, waiting for future frames to arrive. - /// - private bool validState; - - protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState; - - private bool isAttached => replayInputHandler != null && !UseParentState; - - private const int max_catch_up_updates_per_frame = 50; - - public override bool UpdateSubTree() - { - requireMoreUpdateLoops = true; - validState = true; - - int loops = 0; - - while (validState && requireMoreUpdateLoops && loops++ < max_catch_up_updates_per_frame) - if (!base.UpdateSubTree()) - return false; - - return true; - } - - protected override void Update() - { - if (parentClock == null) return; - - clock.Rate = parentClock.Rate; - clock.IsRunning = parentClock.IsRunning; - - if (!isAttached) - { - clock.CurrentTime = parentClock.CurrentTime; - } - else - { - double? newTime = replayInputHandler.SetFrameFromTime(parentClock.CurrentTime); - - if (newTime == null) - { - // we shouldn't execute for this time value. probably waiting on more replay data. - validState = false; - return; - } - - clock.CurrentTime = newTime.Value; - } - - requireMoreUpdateLoops = clock.CurrentTime != parentClock.CurrentTime; - base.Update(); - } - - protected override void TransformState(InputState state) - { - base.TransformState(state); - - // we don't want to transform the state if a replay is present (for now, at least). - if (replayInputHandler != null) return; - - var mouse = state.Mouse as Framework.Input.MouseState; - - if (mouse != null) - { - if (mouseDisabled.Value) - { - mouse.SetPressed(MouseButton.Left, false); - mouse.SetPressed(MouseButton.Right, false); - } - } - } - } -} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 32a8df6357..4e9e769cb7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -321,7 +321,6 @@ - From a7a7e0323f8ff199d10b3ccb11d6c3c9539348b8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 15:36:42 +0900 Subject: [PATCH 02/35] Update autoplay and replay handling to result in actions, not keys --- .../Replays/OsuReplayInputHandler.cs | 32 +++++++++++++++++++ .../UI/OsuRulesetContainer.cs | 4 +++ .../osu.Game.Rulesets.Osu.csproj | 1 + .../Replays/TaikoFramedReplayInputHandler.cs | 16 ++++------ osu.Game/Input/Handlers/ReplayInputHandler.cs | 15 +++++++++ .../Replays/FramedReplayInputHandler.cs | 28 +++------------- osu.Game/Rulesets/UI/RulesetContainer.cs | 2 +- 7 files changed, 64 insertions(+), 34 deletions(-) create mode 100644 osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs diff --git a/osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs b/osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs new file mode 100644 index 0000000000..a54679b8cc --- /dev/null +++ b/osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using osu.Framework.Input; +using osu.Game.Rulesets.Replays; +using OpenTK; + +namespace osu.Game.Rulesets.Osu.Replays +{ + public class OsuReplayInputHandler : FramedReplayInputHandler + { + public OsuReplayInputHandler(Replay replay) + : base(replay) + { + } + + public override List GetPendingStates() + { + List actions = new List(); + + if (CurrentFrame?.MouseLeft ?? false) actions.Add(OsuAction.LeftButton); + if (CurrentFrame?.MouseRight ?? false) actions.Add(OsuAction.RightButton); + + return new List + { + new ReplayState + { + Mouse = new ReplayMouseState(ToScreenSpace(Position ?? Vector2.Zero)), + PressedActions = actions + } + }; + } + } +} diff --git a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs index 083f11945c..0b87bf7346 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuRulesetContainer.cs @@ -10,9 +10,11 @@ using osu.Game.Rulesets.Osu.Beatmaps; using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; +using osu.Game.Rulesets.Osu.Replays; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.UI; +using osu.Game.Rulesets.Replays; namespace osu.Game.Rulesets.Osu.UI { @@ -49,6 +51,8 @@ namespace osu.Game.Rulesets.Osu.UI return null; } + protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new OsuReplayInputHandler(replay); + protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f); } } diff --git a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj index 1422ded407..0c9e53cf69 100644 --- a/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj +++ b/osu.Game.Rulesets.Osu/osu.Game.Rulesets.Osu.csproj @@ -78,6 +78,7 @@ + diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs index f6425dd66f..89093ae05e 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs @@ -4,7 +4,6 @@ using osu.Game.Rulesets.Replays; using System.Collections.Generic; using osu.Framework.Input; -using OpenTK.Input; namespace osu.Game.Rulesets.Taiko.Replays { @@ -17,21 +16,18 @@ namespace osu.Game.Rulesets.Taiko.Replays public override List GetPendingStates() { - var keys = new List(); + var keys = new List(); if (CurrentFrame?.MouseRight1 == true) - keys.Add(Key.F); + keys.Add(TaikoAction.LeftCentre); if (CurrentFrame?.MouseRight2 == true) - keys.Add(Key.J); + keys.Add(TaikoAction.RightCentre); if (CurrentFrame?.MouseLeft1 == true) - keys.Add(Key.D); + keys.Add(TaikoAction.LeftRim); if (CurrentFrame?.MouseLeft2 == true) - keys.Add(Key.K); + keys.Add(TaikoAction.RightRim); - return new List - { - new InputState { Keyboard = new ReplayKeyboardState(keys) } - }; + return new List { new ReplayState { PressedActions = keys } }; } } } diff --git a/osu.Game/Input/Handlers/ReplayInputHandler.cs b/osu.Game/Input/Handlers/ReplayInputHandler.cs index 76e038048c..5f86495580 100644 --- a/osu.Game/Input/Handlers/ReplayInputHandler.cs +++ b/osu.Game/Input/Handlers/ReplayInputHandler.cs @@ -2,6 +2,8 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; +using System.Collections.Generic; +using osu.Framework.Input; using osu.Framework.Input.Handlers; using osu.Framework.Platform; using OpenTK; @@ -29,5 +31,18 @@ namespace osu.Game.Input.Handlers public override bool IsActive => true; public override int Priority => 0; + + public class ReplayState : InputState + where T : struct + { + public List PressedActions; + + public override InputState Clone() + { + var clone = (ReplayState)base.Clone(); + clone.PressedActions = new List(PressedActions); + return clone; + } + } } } \ No newline at end of file diff --git a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs index 60da35fd91..f0d68c0467 100644 --- a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs +++ b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Input; using osu.Framework.MathUtils; using osu.Game.Input.Handlers; @@ -18,7 +17,7 @@ namespace osu.Game.Rulesets.Replays /// The ReplayHandler will take a replay and handle the propagation of updates to the input stack. /// It handles logic of any frames which *must* be executed. /// - public class FramedReplayInputHandler : ReplayInputHandler + public abstract class FramedReplayInputHandler : ReplayInputHandler { private readonly Replay replay; @@ -31,7 +30,7 @@ namespace osu.Game.Rulesets.Replays private int nextFrameIndex => MathHelper.Clamp(currentFrameIndex + (currentDirection > 0 ? 1 : -1), 0, Frames.Count - 1); - public FramedReplayInputHandler(Replay replay) + protected FramedReplayInputHandler(Replay replay) { this.replay = replay; } @@ -51,7 +50,7 @@ namespace osu.Game.Rulesets.Replays { } - private Vector2? position + protected Vector2? Position { get { @@ -62,23 +61,7 @@ namespace osu.Game.Rulesets.Replays } } - public override List GetPendingStates() - { - var buttons = new HashSet(); - if (CurrentFrame?.MouseLeft ?? false) - buttons.Add(MouseButton.Left); - if (CurrentFrame?.MouseRight ?? false) - buttons.Add(MouseButton.Right); - - return new List - { - new InputState - { - Mouse = new ReplayMouseState(ToScreenSpace(position ?? Vector2.Zero), buttons), - Keyboard = new ReplayKeyboardState(new List()) - } - }; - } + public override List GetPendingStates() => new List(); public bool AtLastFrame => currentFrameIndex == Frames.Count - 1; public bool AtFirstFrame => currentFrameIndex == 0; @@ -133,10 +116,9 @@ namespace osu.Game.Rulesets.Replays protected class ReplayMouseState : MouseState { - public ReplayMouseState(Vector2 position, IEnumerable list) + public ReplayMouseState(Vector2 position) { Position = position; - list.ForEach(b => SetPressed(b, true)); } } diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 0a16335c77..17417856a1 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -97,7 +97,7 @@ namespace osu.Game.Rulesets.UI /// The input manager. public abstract PassThroughInputManager CreateInputManager(); - protected virtual FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new FramedReplayInputHandler(replay); + protected virtual FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => null; public Replay Replay { get; private set; } From f0635af40deeae8f3c44bcd328a9a39a6c9c7583 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 15:48:40 +0900 Subject: [PATCH 03/35] Add documentation and regions to RulesetInputManager --- osu.Game/Rulesets/UI/RulesetInputManager.cs | 43 +++++++++++++++++---- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index bd7e51e937..75e273adea 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -23,6 +23,8 @@ namespace osu.Game.Rulesets.UI { } + #region Action mapping (for replays) + private List lastPressedActions = new List(); protected override void HandleNewState(InputState state) @@ -47,8 +49,9 @@ namespace osu.Game.Rulesets.UI lastPressedActions = newActions; } - private ManualClock clock; - private IFrameBasedClock parentClock; + #endregion + + #region IHasReplayHandler private ReplayInputHandler replayInputHandler; public ReplayInputHandler ReplayInputHandler @@ -69,13 +72,12 @@ namespace osu.Game.Rulesets.UI } } - private Bindable mouseDisabled; + #endregion - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - mouseDisabled = config.GetBindable(OsuSetting.MouseDisableButtons); - } + #region Clock control + + private ManualClock clock; + private IFrameBasedClock parentClock; protected override void LoadComplete() { @@ -152,6 +154,18 @@ namespace osu.Game.Rulesets.UI base.Update(); } + #endregion + + #region Setting application (disables etc.) + + private Bindable mouseDisabled; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + mouseDisabled = config.GetBindable(OsuSetting.MouseDisableButtons); + } + protected override void TransformState(InputState state) { base.TransformState(state); @@ -171,6 +185,10 @@ namespace osu.Game.Rulesets.UI } } + #endregion + + #region Key Counter Attachment + public void Attach(KeyCounterCollection keyCounter) { var receptor = new ActionReceptor(keyCounter); @@ -191,13 +209,22 @@ namespace osu.Game.Rulesets.UI public bool OnReleased(T action) => Target.Children.OfType>().Any(c => c.OnReleased(action)); } + + #endregion } + /// + /// Expose the in a capable . + /// public interface IHasReplayHandler { ReplayInputHandler ReplayInputHandler { get; set; } } + /// + /// Supports attaching a . + /// Keys will be populated automatically and a receptor will be injected inside. + /// public interface ICanAttachKeyCounter { void Attach(KeyCounterCollection keyCounter); From 76a95495d36e8069159775cc82a008317c47abc0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 17:30:10 +0900 Subject: [PATCH 04/35] Move shared code to base class --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 11 ----------- osu.Game/Overlays/Direct/DirectListPanel.cs | 15 --------------- osu.Game/Overlays/Direct/DirectPanel.cs | 17 +++++++++++++++++ 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 98ab5e88f8..822edd02df 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -26,22 +26,11 @@ namespace osu.Game.Overlays.Direct { Height = 140 + vertical_padding; //full height of all the elements plus vertical padding (autosize uses the image) CornerRadius = 4; - Masking = true; - - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0f, 1f), - Radius = 3f, - Colour = Color4.Black.Opacity(0.25f), - }; } protected override void LoadComplete() { base.LoadComplete(); - - this.FadeInFromZero(200, Easing.Out); bottomPanel.LayoutDuration = 200; bottomPanel.LayoutEasing = Easing.Out; bottomPanel.Origin = Anchor.BottomLeft; diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index 5b45fc7725..0821fbea3a 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -29,21 +29,6 @@ namespace osu.Game.Overlays.Direct RelativeSizeAxes = Axes.X; Height = height; CornerRadius = 5; - Masking = true; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0f, 1f), - Radius = 3f, - Colour = Color4.Black.Opacity(0.25f), - }; - } - - protected override void LoadComplete() - { - base.LoadComplete(); - - this.FadeInFromZero(200, Easing.Out); } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 2f048b0e3d..9395e6817d 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -2,6 +2,7 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using osu.Framework.Extensions.Color4Extensions; using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -10,6 +11,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using OpenTK.Graphics; namespace osu.Game.Overlays.Direct { @@ -20,6 +22,21 @@ namespace osu.Game.Overlays.Direct protected DirectPanel(BeatmapSetInfo setInfo) { SetInfo = setInfo; + + Masking = true; + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0f, 1f), + Radius = 3f, + Colour = Color4.Black.Opacity(0.25f), + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + this.FadeInFromZero(200, Easing.Out); } protected List GetDifficultyIcons() From 4e1cf329c88628cfaa537dd81c420c3350534e6d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 17:39:39 +0900 Subject: [PATCH 05/35] Move background logic to base class; reduce overdraw after set fades in --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 10 ++------- osu.Game/Overlays/Direct/DirectPanel.cs | 25 ++++++++++++++++++++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 822edd02df..5b648633c1 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -39,14 +39,8 @@ namespace osu.Game.Overlays.Direct [BackgroundDependencyLoader] private void load(OsuColour colours, LocalisationEngine localisation) { - Children = new[] + AddRange(new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - CreateBackground(), new Box { RelativeSizeAxes = Axes.Both, @@ -174,7 +168,7 @@ namespace osu.Game.Overlays.Direct new Statistic(FontAwesome.fa_heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0), }, }, - }; + }); } } } diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 9395e6817d..a56c15b532 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -2,10 +2,12 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; +using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; @@ -19,6 +21,8 @@ namespace osu.Game.Overlays.Direct { protected readonly BeatmapSetInfo SetInfo; + protected Box BlackBackground; + protected DirectPanel(BeatmapSetInfo setInfo) { SetInfo = setInfo; @@ -33,6 +37,21 @@ namespace osu.Game.Overlays.Direct }; } + [BackgroundDependencyLoader] + private void load() + { + AddRange(new[] + { + // temporary blackness until the actual background loads. + BlackBackground = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + CreateBackground(), + }); + } + protected override void LoadComplete() { base.LoadComplete(); @@ -55,7 +74,11 @@ namespace osu.Game.Overlays.Direct Origin = Anchor.Centre, RelativeSizeAxes = Axes.Both, FillMode = FillMode.Fill, - OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out), + OnLoadComplete = d => + { + d.FadeInFromZero(400, Easing.Out); + BlackBackground.Delay(400).FadeOut(); + }, }) { RelativeSizeAxes = Axes.Both, From a2549157ca578f548a4342e7f6d7a3ba0ffcbf90 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 18:18:03 +0900 Subject: [PATCH 06/35] Add hover effects --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 3 +- osu.Game/Overlays/Direct/DirectListPanel.cs | 13 +--- osu.Game/Overlays/Direct/DirectPanel.cs | 85 +++++++++++++++++---- 3 files changed, 76 insertions(+), 25 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 5b648633c1..0cc1c18d8d 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -25,7 +25,6 @@ namespace osu.Game.Overlays.Direct public DirectGridPanel(BeatmapSetInfo beatmap) : base(beatmap) { Height = 140 + vertical_padding; //full height of all the elements plus vertical padding (autosize uses the image) - CornerRadius = 4; } protected override void LoadComplete() @@ -39,6 +38,8 @@ namespace osu.Game.Overlays.Direct [BackgroundDependencyLoader] private void load(OsuColour colours, LocalisationEngine localisation) { + Content.CornerRadius = 4; + AddRange(new Drawable[] { new Box diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index 0821fbea3a..d284c50bc4 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -28,20 +28,15 @@ namespace osu.Game.Overlays.Direct { RelativeSizeAxes = Axes.X; Height = height; - CornerRadius = 5; } [BackgroundDependencyLoader] private void load(LocalisationEngine localisation) { - Children = new[] + Content.CornerRadius = 5; + + AddRange(new Drawable[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - }, - CreateBackground(), new Box { RelativeSizeAxes = Axes.Both, @@ -132,7 +127,7 @@ namespace osu.Game.Overlays.Direct }, }, }, - }; + }); } private class DownloadButton : OsuClickableContainer diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index a56c15b532..7e95c1674b 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -9,11 +9,14 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transforms; using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using OpenTK.Graphics; +using osu.Framework.Input; +using osu.Framework.MathUtils; namespace osu.Game.Overlays.Direct { @@ -23,35 +26,62 @@ namespace osu.Game.Overlays.Direct protected Box BlackBackground; + private const double hover_transition_time = 400; + + private Container content; + + protected override Container Content => content; + protected DirectPanel(BeatmapSetInfo setInfo) { SetInfo = setInfo; - - Masking = true; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0f, 1f), - Radius = 3f, - Colour = Color4.Black.Opacity(0.25f), - }; } [BackgroundDependencyLoader] private void load() { - AddRange(new[] + AddInternal(content = new Container { - // temporary blackness until the actual background loads. - BlackBackground = new Box + RelativeSizeAxes = Axes.Both, + Masking = true, + EdgeEffect = new EdgeEffectParameters { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0f, 1f), + Radius = 2f, + Colour = Color4.Black.Opacity(0.25f), }, - CreateBackground(), + Children = new[] + { + // temporary blackness until the actual background loads. + BlackBackground = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + CreateBackground(), + } }); } + protected override bool OnHover(InputState state) + { + content.FadeEdgeEffectTo(1f, hover_transition_time, Easing.OutQuint); + content.TransformTo(content.PopulateTransform(new TransformEdgeEffectRadius(), 14, hover_transition_time, Easing.OutQuint)); + content.MoveToY(-4, hover_transition_time, Easing.OutQuint); + + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + content.FadeEdgeEffectTo(0.25f, hover_transition_time, Easing.OutQuint); + content.TransformTo(content.PopulateTransform(new TransformEdgeEffectRadius(), 2, hover_transition_time, Easing.OutQuint)); + content.MoveToY(0, hover_transition_time, Easing.OutQuint); + + base.OnHoverLost(state); + } + protected override void LoadComplete() { base.LoadComplete(); @@ -127,5 +157,30 @@ namespace osu.Game.Overlays.Direct Value = value; } } + + private class TransformEdgeEffectRadius : Transform + { + /// + /// Current value of the transformed colour in linear colour space. + /// + private float valueAt(double time) + { + if (time < StartTime) return StartValue; + if (time >= EndTime) return EndValue; + + return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing); + } + + public override string TargetMember => "EdgeEffect.Colour"; + + protected override void Apply(Container c, double time) + { + EdgeEffectParameters e = c.EdgeEffect; + e.Radius = valueAt(time); + c.EdgeEffect = e; + } + + protected override void ReadIntoStartValue(Container d) => StartValue = d.EdgeEffect.Radius; + } } } From 36629f52074162d881c245d2293f139e889b39da Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 18:51:34 +0900 Subject: [PATCH 07/35] Make ProgressBar usable in more places than just MusicController --- .../Graphics/UserInterface/ProgressBar.cs | 67 +++++++++++++++++++ osu.Game/Overlays/MusicController.cs | 45 ------------- osu.Game/osu.Game.csproj | 1 + 3 files changed, 68 insertions(+), 45 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/ProgressBar.cs diff --git a/osu.Game/Graphics/UserInterface/ProgressBar.cs b/osu.Game/Graphics/UserInterface/ProgressBar.cs new file mode 100644 index 0000000000..f22983a6e6 --- /dev/null +++ b/osu.Game/Graphics/UserInterface/ProgressBar.cs @@ -0,0 +1,67 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using OpenTK.Graphics; + +namespace osu.Game.Graphics.UserInterface +{ + public class ProgressBar : SliderBar + { + public Action OnSeek; + + private readonly Box fill; + private readonly Box background; + + public Color4 FillColour + { + set { fill.Colour = value; } + } + + public Color4 BackgroundColour + { + set + { + background.Alpha = 1; + background.Colour = value; + } + } + + public double EndTime + { + set { CurrentNumber.MaxValue = value; } + } + + public double CurrentTime + { + set { CurrentNumber.Value = value; } + } + + public ProgressBar() + { + CurrentNumber.MinValue = 0; + CurrentNumber.MaxValue = 1; + RelativeSizeAxes = Axes.X; + + Children = new Drawable[] + { + background = new Box + { + Alpha = 0, + RelativeSizeAxes = Axes.Both + }, + fill = new Box { RelativeSizeAxes = Axes.Y } + }; + } + + protected override void UpdateValue(float value) + { + fill.Width = value * UsableWidth; + } + + protected override void OnUserChange() => OnSeek?.Invoke(Current); + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index d970089942..f2c90f009a 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -15,7 +15,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; -using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.Localisation; using osu.Framework.Threading; @@ -434,49 +433,5 @@ namespace osu.Game.Overlays sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4"); } } - - private class ProgressBar : SliderBar - { - public Action OnSeek; - - private readonly Box fill; - - public Color4 FillColour - { - set { fill.Colour = value; } - } - - public double EndTime - { - set { CurrentNumber.MaxValue = value; } - } - - public double CurrentTime - { - set { CurrentNumber.Value = value; } - } - - public ProgressBar() - { - CurrentNumber.MinValue = 0; - CurrentNumber.MaxValue = 1; - RelativeSizeAxes = Axes.X; - - Children = new Drawable[] - { - fill = new Box - { - RelativeSizeAxes = Axes.Y - } - }; - } - - protected override void UpdateValue(float value) - { - fill.Width = value * UsableWidth; - } - - protected override void OnUserChange() => OnSeek?.Invoke(Current); - } } } diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 32a8df6357..f361c141f1 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -116,6 +116,7 @@ + From cacf256aade865ecc9748219827b56a06510125e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 18:51:50 +0900 Subject: [PATCH 08/35] Add placeholder download method with progress bar --- osu.Game/Overlays/Direct/DirectGridPanel.cs | 7 +++++ osu.Game/Overlays/Direct/DirectListPanel.cs | 1 + osu.Game/Overlays/Direct/DirectPanel.cs | 29 ++++++++++++++++++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/DirectGridPanel.cs b/osu.Game/Overlays/Direct/DirectGridPanel.cs index 0cc1c18d8d..3a9e75bd38 100644 --- a/osu.Game/Overlays/Direct/DirectGridPanel.cs +++ b/osu.Game/Overlays/Direct/DirectGridPanel.cs @@ -12,6 +12,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; +using osu.Framework.Input; namespace osu.Game.Overlays.Direct { @@ -171,5 +172,11 @@ namespace osu.Game.Overlays.Direct }, }); } + + protected override bool OnClick(InputState state) + { + StartDownload(); + return true; + } } } diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index d284c50bc4..b3502b0827 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -124,6 +124,7 @@ namespace osu.Game.Overlays.Direct Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Size = new Vector2(height - vertical_padding * 2), + Action = StartDownload }, }, }, diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 7e95c1674b..8738d8ea90 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -17,6 +17,8 @@ using osu.Game.Graphics.Sprites; using OpenTK.Graphics; using osu.Framework.Input; using osu.Framework.MathUtils; +using osu.Game.Graphics.UserInterface; +using osu.Game.Online.API; namespace osu.Game.Overlays.Direct { @@ -30,6 +32,9 @@ namespace osu.Game.Overlays.Direct private Container content; + private APIAccess api; + private ProgressBar progressBar; + protected override Container Content => content; protected DirectPanel(BeatmapSetInfo setInfo) @@ -38,8 +43,10 @@ namespace osu.Game.Overlays.Direct } [BackgroundDependencyLoader] - private void load() + private void load(APIAccess api, OsuColour colours) { + this.api = api; + AddInternal(content = new Container { RelativeSizeAxes = Axes.Both, @@ -60,6 +67,16 @@ namespace osu.Game.Overlays.Direct Colour = Color4.Black, }, CreateBackground(), + progressBar = new ProgressBar + { + Anchor = Anchor.BottomLeft, + Origin = Anchor.BottomLeft, + Height = 0, + Alpha = 0, + BackgroundColour = Color4.Black.Opacity(0.7f), + FillColour = colours.Blue, + Depth = -1, + }, } }); } @@ -82,6 +99,16 @@ namespace osu.Game.Overlays.Direct base.OnHoverLost(state); } + protected void StartDownload() + { + progressBar.FadeIn(400, Easing.OutQuint); + progressBar.ResizeHeightTo(4, 400, Easing.OutQuint); + + progressBar.Current.Value = 0.5f; + + api.Queue(new APIRequest()); + } + protected override void LoadComplete() { base.LoadComplete(); From dac54c362a4050107ac11135ecf1445aff8af809 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 15:39:35 +0900 Subject: [PATCH 09/35] Update framework --- osu-framework | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu-framework b/osu-framework index 1ba1e8ef1e..da5fbf8c58 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 1ba1e8ef1e5ec0466632be02492023a081cb85ab +Subproject commit da5fbf8c580b079671298f6da54be10a00bf434c From 314108146a9ae75bcdb82b7413bd998794febc94 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 20:14:17 +0900 Subject: [PATCH 10/35] Add a download API request --- osu.Game/Online/API/APIRequest.cs | 43 +++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/API/APIRequest.cs b/osu.Game/Online/API/APIRequest.cs index 23268a9ca9..307afb2d2b 100644 --- a/osu.Game/Online/API/APIRequest.cs +++ b/osu.Game/Online/API/APIRequest.cs @@ -11,11 +11,11 @@ namespace osu.Game.Online.API /// An API request with a well-defined response type. /// /// Type of the response (used for deserialisation). - public class APIRequest : APIRequest + public abstract class APIRequest : APIRequest { protected override WebRequest CreateWebRequest() => new JsonWebRequest(Uri); - public APIRequest() + protected APIRequest() { base.Success += onSuccess; } @@ -28,10 +28,36 @@ namespace osu.Game.Online.API public new event APISuccessHandler Success; } + public abstract class APIDownloadRequest : APIRequest + { + protected override WebRequest CreateWebRequest() + { + var request = new WebRequest(Uri); + request.DownloadProgress += request_Progress; + return request; + } + + private void request_Progress(WebRequest request, long current, long total) => API.Scheduler.Add(delegate { Progress?.Invoke(current, total); }); + + protected APIDownloadRequest() + { + base.Success += onSuccess; + } + + private void onSuccess() + { + Success?.Invoke(WebRequest.ResponseData); + } + + public event APIProgressHandler Progress; + + public new event APISuccessHandler Success; + } + /// /// AN API request with no specified response type. /// - public class APIRequest + public abstract class APIRequest { /// /// The maximum amount of time before this request will fail. @@ -42,7 +68,7 @@ namespace osu.Game.Online.API protected virtual WebRequest CreateWebRequest() => new WebRequest(Uri); - protected virtual string Uri => $@"{api.Endpoint}/api/v2/{Target}"; + protected virtual string Uri => $@"{API.Endpoint}/api/v2/{Target}"; private double remainingTime => Math.Max(0, Timeout - (DateTime.Now.TotalMilliseconds() - (startTime ?? 0))); @@ -52,7 +78,7 @@ namespace osu.Game.Online.API public double StartTime => startTime ?? -1; - private APIAccess api; + protected APIAccess API; protected WebRequest WebRequest; public event APISuccessHandler Success; @@ -64,7 +90,7 @@ namespace osu.Game.Online.API public void Perform(APIAccess api) { - this.api = api; + API = api; if (checkAndProcessFailure()) return; @@ -109,9 +135,9 @@ namespace osu.Game.Online.API /// Whether we are in a failed or cancelled state. private bool checkAndProcessFailure() { - if (api == null || pendingFailure == null) return cancelled; + if (API == null || pendingFailure == null) return cancelled; - api.Scheduler.Add(pendingFailure); + API.Scheduler.Add(pendingFailure); pendingFailure = null; return true; } @@ -119,5 +145,6 @@ namespace osu.Game.Online.API public delegate void APIFailureHandler(Exception e); public delegate void APISuccessHandler(); + public delegate void APIProgressHandler(long current, long total); public delegate void APISuccessHandler(T content); } From 3c10b2d3d9b44e06bf95f88a8c26371d976634b5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 20:14:35 +0900 Subject: [PATCH 11/35] Populate set IDs in GetBeatmapSetsResponse --- osu.Game/Online/API/Requests/GetBeatmapSetsRequest.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Online/API/Requests/GetBeatmapSetsRequest.cs b/osu.Game/Online/API/Requests/GetBeatmapSetsRequest.cs index ca984d3511..e4763f73ee 100644 --- a/osu.Game/Online/API/Requests/GetBeatmapSetsRequest.cs +++ b/osu.Game/Online/API/Requests/GetBeatmapSetsRequest.cs @@ -46,6 +46,9 @@ namespace osu.Game.Online.API.Requests [JsonProperty(@"favourite_count")] private int favouriteCount { get; set; } + [JsonProperty(@"id")] + private int onlineId { get; set; } + [JsonProperty(@"beatmaps")] private IEnumerable beatmaps { get; set; } @@ -53,6 +56,7 @@ namespace osu.Game.Online.API.Requests { return new BeatmapSetInfo { + OnlineBeatmapSetID = onlineId, Metadata = this, OnlineInfo = new BeatmapSetOnlineInfo { From 9c82593c9e82a23ebc9f435674f1b6172a1351e6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 20:15:45 +0900 Subject: [PATCH 12/35] Add cancel event to ProgressNotification --- osu.Game/Overlays/Notifications/ProgressNotification.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs index f42b4b6cb3..a31291e1b8 100644 --- a/osu.Game/Overlays/Notifications/ProgressNotification.cs +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -152,11 +152,14 @@ namespace osu.Game.Overlays.Notifications break; case ProgressNotificationState.Active: case ProgressNotificationState.Queued: - State = ProgressNotificationState.Cancelled; + if (CancelRequested?.Invoke() != false) + State = ProgressNotificationState.Cancelled; break; } } + public Func CancelRequested { get; set; } + /// /// The function to post completion notifications back to. /// From 32a23c7fe41fd2c4f978385fdb6f32f576d9e0dc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 20:16:03 +0900 Subject: [PATCH 13/35] Add initial osu!direct beatmap download and import process --- osu.Game/Overlays/Direct/DirectPanel.cs | 82 ++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 8738d8ea90..b44a100d3c 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -4,6 +4,8 @@ using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; +using System.IO; +using System.Threading.Tasks; using OpenTK; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -19,6 +21,9 @@ using osu.Framework.Input; using osu.Framework.MathUtils; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; +using osu.Framework.Logging; +using osu.Game.Beatmaps.IO; +using osu.Game.Overlays.Notifications; namespace osu.Game.Overlays.Direct { @@ -34,6 +39,8 @@ namespace osu.Game.Overlays.Direct private APIAccess api; private ProgressBar progressBar; + private BeatmapManager beatmaps; + private NotificationOverlay notifications; protected override Container Content => content; @@ -43,9 +50,11 @@ namespace osu.Game.Overlays.Direct } [BackgroundDependencyLoader] - private void load(APIAccess api, OsuColour colours) + private void load(APIAccess api, BeatmapManager beatmaps, OsuColour colours, NotificationOverlay notifications) { this.api = api; + this.beatmaps = beatmaps; + this.notifications = notifications; AddInternal(content = new Container { @@ -101,12 +110,79 @@ namespace osu.Game.Overlays.Direct protected void StartDownload() { + if (!api.LocalUser.Value.IsSupporter) + { + notifications.Post(new SimpleNotification + { + Icon = FontAwesome.fa_superpowers, + Text = "You gotta be a supporter to download for now 'yo" + }); + return; + } + progressBar.FadeIn(400, Easing.OutQuint); progressBar.ResizeHeightTo(4, 400, Easing.OutQuint); - progressBar.Current.Value = 0.5f; + progressBar.Current.Value = 0; - api.Queue(new APIRequest()); + ProgressNotification downloadNotification = new ProgressNotification + { + Text = $"Downloading {SetInfo.Metadata.Artist} - {SetInfo.Metadata.Title}", + }; + + var request = new DownloadBeatmapSetRequest(SetInfo); + request.Failure += e => + { + progressBar.Current.Value = 0; + progressBar.FadeOut(500); + downloadNotification.State = ProgressNotificationState.Completed; + Logger.Error(e, "Failed to get beatmap download information"); + }; + + request.Progress += (current, total) => + { + float progress = (float)current / total; + + progressBar.Current.Value = progress; + + downloadNotification.State = ProgressNotificationState.Active; + downloadNotification.Progress = progress; + }; + + request.Success += data => + { + progressBar.Current.Value = 1; + progressBar.FadeOut(500); + + downloadNotification.State = ProgressNotificationState.Completed; + + using (var stream = new MemoryStream(data)) + using (var archive = new OszArchiveReader(stream)) + beatmaps.Import(archive); + }; + + downloadNotification.CancelRequested += () => + { + request.Cancel(); + return true; + }; + + notifications.Post(downloadNotification); + + // don't run in the main api queue as this is a long-running task. + Task.Run(() => request.Perform(api)); + } + + public class DownloadBeatmapSetRequest : APIDownloadRequest + { + private readonly BeatmapSetInfo beatmapSet; + + public DownloadBeatmapSetRequest(BeatmapSetInfo beatmapSet) + { + this.beatmapSet = beatmapSet; + } + + protected override string Target => $@"beatmapsets/{beatmapSet.OnlineBeatmapSetID}/download"; } protected override void LoadComplete() From 9adff5f697221b0d7f8ab9460315c681345a6a3f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 20:18:47 +0900 Subject: [PATCH 14/35] Add osu!direct toggle to toolbar --- osu.Game/OsuGame.cs | 1 + osu.Game/Overlays/Toolbar/Toolbar.cs | 1 + .../Overlays/Toolbar/ToolbarDirectButton.cs | 19 +++++++++++++++++++ osu.Game/osu.Game.csproj | 1 + 4 files changed, 22 insertions(+) create mode 100644 osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 8c82071c23..43e3731166 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -219,6 +219,7 @@ namespace osu.Game dependencies.Cache(settings); dependencies.Cache(social); + dependencies.Cache(direct); dependencies.Cache(chat); dependencies.Cache(userProfile); dependencies.Cache(musicController); diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 32344ca7eb..e36db1f9da 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -58,6 +58,7 @@ namespace osu.Game.Overlays.Toolbar AutoSizeAxes = Axes.X, Children = new Drawable[] { + new ToolbarDirectButton(), new ToolbarChatButton(), new ToolbarSocialButton(), new ToolbarMusicButton(), diff --git a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs new file mode 100644 index 0000000000..484b079d23 --- /dev/null +++ b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs @@ -0,0 +1,19 @@ +using osu.Framework.Allocation; +using osu.Game.Graphics; + +namespace osu.Game.Overlays.Toolbar +{ + internal class ToolbarDirectButton : ToolbarOverlayToggleButton + { + public ToolbarDirectButton() + { + SetIcon(FontAwesome.fa_download); + } + + [BackgroundDependencyLoader] + private void load(DirectOverlay direct) + { + StateContainer = direct; + } + } +} \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index f361c141f1..15c400b21e 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -130,6 +130,7 @@ + From 0082640548d3e6cab5cdfbfe0ed2cb442511ccda Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 20:25:18 +0900 Subject: [PATCH 15/35] Add missing licence header --- osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs index 484b079d23..32e149b31a 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs @@ -1,3 +1,6 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + using osu.Framework.Allocation; using osu.Game.Graphics; From a7e6efd34fc83ceb33cf7c8a31200d3d709e1dad Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 20:30:18 +0900 Subject: [PATCH 16/35] Rename keys -> actions --- .../Replays/TaikoFramedReplayInputHandler.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs index 89093ae05e..fce0179721 100644 --- a/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs +++ b/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs @@ -16,18 +16,18 @@ namespace osu.Game.Rulesets.Taiko.Replays public override List GetPendingStates() { - var keys = new List(); + var actions = new List(); if (CurrentFrame?.MouseRight1 == true) - keys.Add(TaikoAction.LeftCentre); + actions.Add(TaikoAction.LeftCentre); if (CurrentFrame?.MouseRight2 == true) - keys.Add(TaikoAction.RightCentre); + actions.Add(TaikoAction.RightCentre); if (CurrentFrame?.MouseLeft1 == true) - keys.Add(TaikoAction.LeftRim); + actions.Add(TaikoAction.LeftRim); if (CurrentFrame?.MouseLeft2 == true) - keys.Add(TaikoAction.RightRim); + actions.Add(TaikoAction.RightRim); - return new List { new ReplayState { PressedActions = keys } }; + return new List { new ReplayState { PressedActions = actions } }; } } } From c9f90efb8ac418d52949628a0018f31bf605b0a1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 20:31:57 +0900 Subject: [PATCH 17/35] Add more checks and remove direct cast --- osu.Game/Rulesets/UI/RulesetContainer.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetContainer.cs b/osu.Game/Rulesets/UI/RulesetContainer.cs index 17417856a1..a7472f4dbc 100644 --- a/osu.Game/Rulesets/UI/RulesetContainer.cs +++ b/osu.Game/Rulesets/UI/RulesetContainer.cs @@ -42,7 +42,7 @@ namespace osu.Game.Rulesets.UI /// /// The input manager for this RulesetContainer. /// - internal IHasReplayHandler ReplayInputManager => (IHasReplayHandler)KeyBindingInputManager; + internal IHasReplayHandler ReplayInputManager => KeyBindingInputManager as IHasReplayHandler; /// /// The key conversion input manager for this RulesetContainer. @@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.UI /// /// Whether we have a replay loaded currently. /// - public bool HasReplayLoaded => ReplayInputManager.ReplayInputHandler != null; + public bool HasReplayLoaded => ReplayInputManager?.ReplayInputHandler != null; public abstract IEnumerable Objects { get; } @@ -107,6 +107,9 @@ namespace osu.Game.Rulesets.UI /// The replay, null for local input. public virtual void SetReplay(Replay replay) { + if (ReplayInputManager == null) + throw new InvalidOperationException($"A {nameof(KeyBindingInputManager)} which supports replay loading is not available"); + Replay = replay; ReplayInputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null; } From 2b667cf789a57ac5c73a5c274dbceef2ba544086 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 20:32:55 +0900 Subject: [PATCH 18/35] Fix typos --- osu.Game/Rulesets/UI/RulesetInputManager.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Rulesets/UI/RulesetInputManager.cs b/osu.Game/Rulesets/UI/RulesetInputManager.cs index 75e273adea..0419070b42 100644 --- a/osu.Game/Rulesets/UI/RulesetInputManager.cs +++ b/osu.Game/Rulesets/UI/RulesetInputManager.cs @@ -94,13 +94,13 @@ namespace osu.Game.Rulesets.UI } /// - /// Whether we running up-to-date with our parent clock. + /// Whether we are running up-to-date with our parent clock. /// If not, we will need to keep processing children until we catch up. /// private bool requireMoreUpdateLoops; /// - /// Whether we in a valid state (ie. should we keep processing children frames). + /// Whether we are in a valid state (ie. should we keep processing children frames). /// This should be set to false when the replay is, for instance, waiting for future frames to arrive. /// private bool validState; @@ -229,4 +229,4 @@ namespace osu.Game.Rulesets.UI { void Attach(KeyCounterCollection keyCounter); } -} \ No newline at end of file +} From 1b0a1dd4108285dbec840ad8cf9a9ef1b014d066 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 20:37:03 +0900 Subject: [PATCH 19/35] Add missing licence header --- osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs b/osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs index a54679b8cc..0811a68392 100644 --- a/osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs +++ b/osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; using osu.Framework.Input; using osu.Game.Rulesets.Replays; using OpenTK; From febf0348be646d1af5aeda1ae1ee8dcf5206a298 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 24 Aug 2017 21:26:50 +0900 Subject: [PATCH 20/35] Permit nulls to allow test cases to run successfully --- osu.Game/Overlays/Direct/DirectPanel.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index b44a100d3c..bc30fb83f5 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -49,7 +49,7 @@ namespace osu.Game.Overlays.Direct SetInfo = setInfo; } - [BackgroundDependencyLoader] + [BackgroundDependencyLoader(permitNulls: true)] private void load(APIAccess api, BeatmapManager beatmaps, OsuColour colours, NotificationOverlay notifications) { this.api = api; @@ -110,6 +110,8 @@ namespace osu.Game.Overlays.Direct protected void StartDownload() { + if (api == null) return; + if (!api.LocalUser.Value.IsSupporter) { notifications.Post(new SimpleNotification From 7f617e2c3659ab1dad686c6971e056be0e169884 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Aug 2017 11:53:41 +0900 Subject: [PATCH 21/35] Remove downloaded beatmap panels from osu!direct --- osu.Game/Overlays/DirectOverlay.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index b1c7dab778..f270aec43e 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -161,11 +161,19 @@ namespace osu.Game.Overlays } [BackgroundDependencyLoader] - private void load(OsuColour colours, APIAccess api, RulesetStore rulesets) + private void load(OsuColour colours, APIAccess api, RulesetStore rulesets, BeatmapManager beatmaps) { this.api = api; this.rulesets = rulesets; resultCountsContainer.Colour = colours.Yellow; + + beatmaps.BeatmapSetAdded += setAdded; + } + + private void setAdded(BeatmapSetInfo set) + { + // if a new map was imported, we should remove it from search results (download completed etc.) + panels?.FirstOrDefault(p => p.SetInfo.OnlineBeatmapSetID == set.OnlineBeatmapSetID)?.FadeOut(400).Expire(); } private void updateResultCounts() From ca0d1b79b2b772e2c789be0b78c2a0dd7d50aa33 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Aug 2017 11:54:18 +0900 Subject: [PATCH 22/35] Disallow multiple download requests for the same panel --- osu.Game/Overlays/Direct/DirectPanel.cs | 30 +++++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index bc30fb83f5..4f02ce1bf6 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -29,7 +29,7 @@ namespace osu.Game.Overlays.Direct { public abstract class DirectPanel : Container { - protected readonly BeatmapSetInfo SetInfo; + public readonly BeatmapSetInfo SetInfo; protected Box BlackBackground; @@ -108,10 +108,23 @@ namespace osu.Game.Overlays.Direct base.OnHoverLost(state); } + // this should eventually be moved to a more central place, like BeatmapManager. + private DownloadBeatmapSetRequest downloadRequest; + protected void StartDownload() { if (api == null) return; + // we already have an active download running. + if (downloadRequest != null) + { + content.MoveToX(-5, 50, Easing.OutSine).Then() + .MoveToX(5, 100, Easing.InOutSine).Then() + .MoveToX(-5, 100, Easing.InOutSine).Then() + .MoveToX(0, 50, Easing.InSine).Then(); + return; + } + if (!api.LocalUser.Value.IsSupporter) { notifications.Post(new SimpleNotification @@ -132,16 +145,18 @@ namespace osu.Game.Overlays.Direct Text = $"Downloading {SetInfo.Metadata.Artist} - {SetInfo.Metadata.Title}", }; - var request = new DownloadBeatmapSetRequest(SetInfo); - request.Failure += e => + downloadRequest = new DownloadBeatmapSetRequest(SetInfo); + downloadRequest.Failure += e => { progressBar.Current.Value = 0; progressBar.FadeOut(500); downloadNotification.State = ProgressNotificationState.Completed; Logger.Error(e, "Failed to get beatmap download information"); + + downloadRequest = null; }; - request.Progress += (current, total) => + downloadRequest.Progress += (current, total) => { float progress = (float)current / total; @@ -151,7 +166,7 @@ namespace osu.Game.Overlays.Direct downloadNotification.Progress = progress; }; - request.Success += data => + downloadRequest.Success += data => { progressBar.Current.Value = 1; progressBar.FadeOut(500); @@ -165,14 +180,15 @@ namespace osu.Game.Overlays.Direct downloadNotification.CancelRequested += () => { - request.Cancel(); + downloadRequest.Cancel(); + downloadRequest = null; return true; }; notifications.Post(downloadNotification); // don't run in the main api queue as this is a long-running task. - Task.Run(() => request.Perform(api)); + Task.Run(() => downloadRequest.Perform(api)); } public class DownloadBeatmapSetRequest : APIDownloadRequest From 7055cb581d71a9d7fe438f7ec9e6beeba26824e4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Aug 2017 11:54:35 +0900 Subject: [PATCH 23/35] Load direct panels more asynchronously to avoid stutter --- osu.Game/Overlays/DirectOverlay.cs | 60 +++++++++++++++--------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs index f270aec43e..f734e43826 100644 --- a/osu.Game/Overlays/DirectOverlay.cs +++ b/osu.Game/Overlays/DirectOverlay.cs @@ -30,7 +30,7 @@ namespace osu.Game.Overlays private readonly FillFlowContainer resultCountsContainer; private readonly OsuSpriteText resultCountsText; - private readonly FillFlowContainer panels; + private FillFlowContainer panels; protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74"); protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71"); @@ -48,17 +48,6 @@ namespace osu.Game.Overlays if (beatmapSets?.Equals(value) ?? false) return; beatmapSets = value; - if (BeatmapSets == null) - { - foreach (var p in panels.Children) - { - p.FadeOut(200); - p.Expire(); - } - - return; - } - recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value); } } @@ -108,13 +97,6 @@ namespace osu.Game.Overlays }, } }, - panels = new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Spacing = new Vector2(panel_padding), - Margin = new MarginPadding { Top = 10 }, - }, }; Filter.Search.Current.ValueChanged += text => { if (text != string.Empty) Header.Tabs.Current.Value = DirectTab.Search; }; @@ -193,18 +175,38 @@ namespace osu.Game.Overlays private void recreatePanels(PanelDisplayStyle displayStyle) { + if (panels != null) + { + panels.FadeOut(200); + panels.Expire(); + panels = null; + } + if (BeatmapSets == null) return; - panels.ChildrenEnumerable = BeatmapSets.Select(b => - { - switch (displayStyle) - { - case PanelDisplayStyle.Grid: - return new DirectGridPanel(b) { Width = 400 }; - default: - return new DirectListPanel(b); - } - }); + var newPanels = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Spacing = new Vector2(panel_padding), + Margin = new MarginPadding { Top = 10 }, + ChildrenEnumerable = BeatmapSets.Select(b => + { + switch (displayStyle) + { + case PanelDisplayStyle.Grid: + return new DirectGridPanel(b) { Width = 400 }; + default: + return new DirectListPanel(b); + } + }) + }; + + LoadComponentAsync(newPanels, p => + { + if (panels != null) ScrollFlow.Remove(panels); + ScrollFlow.Add(panels = newPanels); + }); } private GetBeatmapSetsRequest getSetsRequest; From 86bde4b6b253e87fd92ae8026878a4a5128f35cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Aug 2017 13:03:34 +0900 Subject: [PATCH 24/35] Use the correct icon for osu!direct in the toolbar --- osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs index 32e149b31a..dacb6d67b8 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs @@ -10,7 +10,7 @@ namespace osu.Game.Overlays.Toolbar { public ToolbarDirectButton() { - SetIcon(FontAwesome.fa_download); + SetIcon(FontAwesome.fa_osu_chevron_down_o); } [BackgroundDependencyLoader] From 06c392d6f2690a4f34d895b775c61f2326dde344 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 25 Aug 2017 15:09:07 +0900 Subject: [PATCH 25/35] Update OsuMenu in line with framework. --- osu-framework | 2 +- osu.Game/Graphics/UserInterface/OsuMenu.cs | 23 ++++++++++++++++------ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/osu-framework b/osu-framework index da5fbf8c58..5a189d1050 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit da5fbf8c580b079671298f6da54be10a00bf434c +Subproject commit 5a189d1050579b217bfe6b6c17c3ee6d6ef9c839 diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index e597bc44b5..79519e26a0 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -5,28 +5,39 @@ using OpenTK; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterface { - public class OsuMenu : Menu + public class OsuMenu : Menu + where TItem : MenuItem { public OsuMenu() { CornerRadius = 4; - Background.Colour = Color4.Black.Opacity(0.5f); - - ItemsContainer.Padding = new MarginPadding(5); + BackgroundColour = Color4.Black.Opacity(0.5f); } protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint); - protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint); - protected override void UpdateContentHeight() + protected override void UpdateMenuHeight() { var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight; this.ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, Easing.OutQuint); } + + protected override FlowContainer CreateItemsFlow() + { + var flow = base.CreateItemsFlow(); + flow.Padding = new MarginPadding(5); + + return flow; + } + } + + public class OsuMenu : OsuMenu + { } } From 7467d24d35849fa9dbfe9b69530f5ca7a91d6447 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 25 Aug 2017 15:10:12 +0900 Subject: [PATCH 26/35] Update OsuContextMenu in line with framework. --- .../Graphics/UserInterface/OsuContextMenu.cs | 149 +++++++++++++++--- .../UserInterface/OsuContextMenuItem.cs | 107 ++----------- 2 files changed, 133 insertions(+), 123 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs index d4882cce1e..ddb91d42a1 100644 --- a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs @@ -1,52 +1,151 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; using OpenTK.Graphics; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Audio.Sample; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; +using osu.Framework.Input; +using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { - public class OsuContextMenu : ContextMenu - where TItem : ContextMenuItem + public class OsuContextMenu : OsuMenu + where TItem : OsuContextMenuItem { - protected override Menu CreateMenu() => new CustomMenu(); + private const int fade_duration = 250; - public class CustomMenu : Menu + public OsuContextMenu() { - private const int fade_duration = 250; - - public CustomMenu() + CornerRadius = 5; + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.1f), + Radius = 4, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.ContextMenuGray; + } + + protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint); + protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint); + + protected override FlowContainer CreateItemsFlow() + { + var flow = base.CreateItemsFlow(); + flow.Padding = new MarginPadding { Vertical = OsuContextMenuItemRepresentation.MARGIN_VERTICAL }; + + return flow; + } + + protected override MenuItemRepresentation CreateMenuItemRepresentation(TItem model) => new OsuContextMenuItemRepresentation(this, model); + + #region OsuContextMenuItemRepresentation + private class OsuContextMenuItemRepresentation : MenuItemRepresentation + { + private const int margin_horizontal = 17; + private const int text_size = 17; + private const int transition_length = 80; + public const int MARGIN_VERTICAL = 4; + + private SampleChannel sampleClick; + private SampleChannel sampleHover; + + private OsuSpriteText text; + private OsuSpriteText textBold; + + public OsuContextMenuItemRepresentation(Menu menu, TItem model) + : base(menu, model) { - CornerRadius = 5; - ItemsContainer.Padding = new MarginPadding { Vertical = OsuContextMenuItem.MARGIN_VERTICAL }; - Masking = true; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(0.1f), - Radius = 4, - }; } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(AudioManager audio) { - Background.Colour = colours.ContextMenuGray; + sampleHover = audio.Sample.Get(@"UI/generic-hover"); + sampleClick = audio.Sample.Get(@"UI/generic-click"); + + BackgroundColour = Color4.Transparent; + BackgroundColourHover = OsuColour.FromHex(@"172023"); + + updateTextColour(); } - protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint); - protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint); - - protected override void UpdateContentHeight() + private void updateTextColour() { - var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight; - this.ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, Easing.OutQuint); + switch (Model.Type) + { + case MenuItemType.Standard: + textBold.Colour = text.Colour = Color4.White; + break; + case MenuItemType.Destructive: + textBold.Colour = text.Colour = Color4.Red; + break; + case MenuItemType.Highlighted: + textBold.Colour = text.Colour = OsuColour.FromHex(@"ffcc22"); + break; + } } + + protected override bool OnHover(InputState state) + { + sampleHover.Play(); + textBold.FadeIn(transition_length, Easing.OutQuint); + text.FadeOut(transition_length, Easing.OutQuint); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + textBold.FadeOut(transition_length, Easing.OutQuint); + text.FadeIn(transition_length, Easing.OutQuint); + base.OnHoverLost(state); + } + + protected override bool OnClick(InputState state) + { + sampleClick.Play(); + return base.OnClick(state); + } + + protected override Drawable CreateText(string title) => new Container + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Children = new Drawable[] + { + text = new OsuSpriteText + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + TextSize = text_size, + Text = title, + Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, + }, + textBold = new OsuSpriteText + { + AlwaysPresent = true, + Alpha = 0, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + TextSize = text_size, + Text = title, + Font = @"Exo2.0-Bold", + Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, + } + } + }; } + #endregion } } \ No newline at end of file diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenuItem.cs b/osu.Game/Graphics/UserInterface/OsuContextMenuItem.cs index 196e905bdc..bf00208b88 100644 --- a/osu.Game/Graphics/UserInterface/OsuContextMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/OsuContextMenuItem.cs @@ -1,114 +1,25 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK.Graphics; -using osu.Framework.Allocation; -using osu.Framework.Audio; -using osu.Framework.Audio.Sample; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; +using System; using osu.Framework.Graphics.UserInterface; -using osu.Framework.Input; -using osu.Game.Graphics.Sprites; namespace osu.Game.Graphics.UserInterface { - public class OsuContextMenuItem : ContextMenuItem + public class OsuContextMenuItem : MenuItem { - private const int transition_length = 80; - private const int margin_horizontal = 17; - public const int MARGIN_VERTICAL = 4; - private const int text_size = 17; + public readonly MenuItemType Type; - private OsuSpriteText text; - private OsuSpriteText textBold; - - private SampleChannel sampleClick; - private SampleChannel sampleHover; - - private readonly MenuItemType type; - - protected override Container CreateTextContainer(string title) => new Container + public OsuContextMenuItem(string text, MenuItemType type = MenuItemType.Standard) + : base(text) { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Children = new Drawable[] - { - text = new OsuSpriteText - { - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - TextSize = text_size, - Text = title, - Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, - }, - textBold = new OsuSpriteText - { - AlwaysPresent = true, - Alpha = 0, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - TextSize = text_size, - Text = title, - Font = @"Exo2.0-Bold", - Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, - } - } - }; - - public OsuContextMenuItem(string title, MenuItemType type = MenuItemType.Standard) : base(title) - { - this.type = type; + Type = type; } - [BackgroundDependencyLoader] - private void load(AudioManager audio) + public OsuContextMenuItem(string text, MenuItemType type, Action action) + : base(text, action) { - sampleHover = audio.Sample.Get(@"UI/generic-hover"); - sampleClick = audio.Sample.Get(@"UI/generic-click"); - - BackgroundColour = Color4.Transparent; - BackgroundColourHover = OsuColour.FromHex(@"172023"); - - updateTextColour(); - } - - private void updateTextColour() - { - switch (type) - { - case MenuItemType.Standard: - textBold.Colour = text.Colour = Color4.White; - break; - case MenuItemType.Destructive: - textBold.Colour = text.Colour = Color4.Red; - break; - case MenuItemType.Highlighted: - textBold.Colour = text.Colour = OsuColour.FromHex(@"ffcc22"); - break; - } - } - - protected override bool OnHover(InputState state) - { - sampleHover.Play(); - textBold.FadeIn(transition_length, Easing.OutQuint); - text.FadeOut(transition_length, Easing.OutQuint); - return base.OnHover(state); - } - - protected override void OnHoverLost(InputState state) - { - textBold.FadeOut(transition_length, Easing.OutQuint); - text.FadeIn(transition_length, Easing.OutQuint); - base.OnHoverLost(state); - } - - protected override bool OnClick(InputState state) - { - sampleClick.Play(); - return base.OnClick(state); + Type = type; } } } \ No newline at end of file From 4fb95706184c4b5310daf96b3c6c76bfeb28dfbc Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 25 Aug 2017 15:10:29 +0900 Subject: [PATCH 27/35] Create IHasOsuContextMenu and update OsuContextMenuContainer in line with framework. --- .../Visual/TestCaseContextMenu.cs | 19 +++++++++---------- .../Graphics/Cursor/IHasOsuContextMenu.cs | 9 +++++++++ .../Cursor/OsuContextMenuContainer.cs | 4 ++-- osu.Game/osu.Game.csproj | 1 + 4 files changed, 21 insertions(+), 12 deletions(-) create mode 100644 osu.Game/Graphics/Cursor/IHasOsuContextMenu.cs diff --git a/osu.Desktop.Tests/Visual/TestCaseContextMenu.cs b/osu.Desktop.Tests/Visual/TestCaseContextMenu.cs index f0894f794a..2ac3a28bd4 100644 --- a/osu.Desktop.Tests/Visual/TestCaseContextMenu.cs +++ b/osu.Desktop.Tests/Visual/TestCaseContextMenu.cs @@ -3,9 +3,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Shapes; -using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using OpenTK; using OpenTK.Graphics; @@ -67,9 +66,9 @@ namespace osu.Desktop.Tests.Visual ); } - private class MyContextMenuContainer : Container, IHasContextMenu + private class MyContextMenuContainer : Container, IHasOsuContextMenu { - public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[] + public OsuContextMenuItem[] ContextMenuItems => new[] { new OsuContextMenuItem(@"Some option"), new OsuContextMenuItem(@"Highlighted option", MenuItemType.Highlighted), @@ -81,16 +80,16 @@ namespace osu.Desktop.Tests.Visual }; } - private class AnotherContextMenuContainer : Container, IHasContextMenu + private class AnotherContextMenuContainer : Container, IHasOsuContextMenu { - public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[] + public OsuContextMenuItem[] ContextMenuItems => new[] { new OsuContextMenuItem(@"Simple option"), new OsuContextMenuItem(@"Simple very very long option"), - new OsuContextMenuItem(@"Change width", MenuItemType.Highlighted) { Action = () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint) }, - new OsuContextMenuItem(@"Change height", MenuItemType.Highlighted) { Action = () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint) }, - new OsuContextMenuItem(@"Change width back", MenuItemType.Destructive) { Action = () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint) }, - new OsuContextMenuItem(@"Change height back", MenuItemType.Destructive) { Action = () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint) }, + new OsuContextMenuItem(@"Change width", MenuItemType.Highlighted, () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint)), + new OsuContextMenuItem(@"Change height", MenuItemType.Highlighted, () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint)), + new OsuContextMenuItem(@"Change width back", MenuItemType.Destructive, () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint)), + new OsuContextMenuItem(@"Change height back", MenuItemType.Destructive, () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint)), }; } } diff --git a/osu.Game/Graphics/Cursor/IHasOsuContextMenu.cs b/osu.Game/Graphics/Cursor/IHasOsuContextMenu.cs new file mode 100644 index 0000000000..6fb1a3d31f --- /dev/null +++ b/osu.Game/Graphics/Cursor/IHasOsuContextMenu.cs @@ -0,0 +1,9 @@ +using osu.Framework.Graphics.Cursor; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Graphics.Cursor +{ + public interface IHasOsuContextMenu : IHasContextMenu + { + } +} diff --git a/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs b/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs index 9162fd6893..4ee3e31707 100644 --- a/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs +++ b/osu.Game/Graphics/Cursor/OsuContextMenuContainer.cs @@ -7,8 +7,8 @@ using osu.Game.Graphics.UserInterface; namespace osu.Game.Graphics.Cursor { - public class OsuContextMenuContainer : ContextMenuContainer + public class OsuContextMenuContainer : ContextMenuContainer { - protected override ContextMenu CreateContextMenu() => new OsuContextMenu(); + protected override Menu CreateMenu() => new OsuContextMenu(); } } \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 97cf1db803..0c710fd242 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -84,6 +84,7 @@ + From b42c9d21fe6922c5733366d43aec415f9a0206ff Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 25 Aug 2017 15:57:43 +0900 Subject: [PATCH 28/35] Update LoginSettings in line with framework. --- osu-framework | 2 +- .../Sections/General/LoginSettings.cs | 90 ++++++++++++------- 2 files changed, 57 insertions(+), 35 deletions(-) diff --git a/osu-framework b/osu-framework index 5a189d1050..2f0674792a 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 5a189d1050579b217bfe6b6c17c3ee6d6ef9c839 +Subproject commit 2f0674792adaf123dcf44ea0099c5707df4a6d60 diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 7ae45159d9..111dba7151 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -257,9 +257,15 @@ namespace osu.Game.Overlays.Settings.Sections.General private class UserDropdown : OsuEnumDropdown { - protected override DropdownHeader CreateHeader() => new UserDropdownHeader { AccentColour = AccentColour }; - protected override Menu CreateMenu() => new UserDropdownMenu(); - protected override DropdownMenuItem CreateMenuItem(string text, UserAction value) => new UserDropdownMenuItem(text, value) { AccentColour = AccentColour }; + protected override DropdownHeader CreateHeader() + { + var newHeader = new UserDropdownHeader(); + newHeader.AccentColour.BindTo(AccentColour); + + return newHeader; + } + + protected override DropdownMenu CreateMenu() => new UserDropdownMenu(); public Color4 StatusColour { @@ -274,7 +280,52 @@ namespace osu.Game.Overlays.Settings.Sections.General [BackgroundDependencyLoader] private void load(OsuColour colours) { - AccentColour = colours.Gray5; + AccentColour.Value = colours.Gray5; + } + + private class UserDropdownMenu : OsuDropdownMenu + { + public UserDropdownMenu() + { + Masking = true; + CornerRadius = 5; + + Margin = new MarginPadding { Bottom = 5 }; + + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.25f), + Radius = 4, + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.Gray3; + } + + protected override FlowContainer CreateItemsFlow() + { + var flow = base.CreateItemsFlow(); + flow.Padding = new MarginPadding(0); + + return flow; + } + + protected override MenuItemRepresentation CreateMenuItemRepresentation(DropdownMenuItem model) => new UserDropdownMenuItem(this, model); + + private class UserDropdownMenuItem : OsuDropdownMenuItemRepresentation + { + public UserDropdownMenuItem(Menu> menu, DropdownMenuItem model) + : base(menu, model) + { + Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 }; + Label.Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 }; + CornerRadius = 5; + } + } } private class UserDropdownHeader : OsuDropdownHeader @@ -324,38 +375,9 @@ namespace osu.Game.Overlays.Settings.Sections.General } } - private class UserDropdownMenu : OsuMenu - { - public UserDropdownMenu() - { - Margin = new MarginPadding { Bottom = 5 }; - CornerRadius = 5; - ItemsContainer.Padding = new MarginPadding(0); - Masking = true; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(0.25f), - Radius = 4, - }; - } - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Background.Colour = colours.Gray3; - } - } - private class UserDropdownMenuItem : OsuDropdownMenuItem - { - public UserDropdownMenuItem(string text, UserAction current) : base(text, current) - { - Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 }; - Label.Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 }; - CornerRadius = 5; - } - } + } private enum UserAction From 923ffae42c3cbd6403380756474f78cccc2c4e34 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 25 Aug 2017 15:57:55 +0900 Subject: [PATCH 29/35] Update SlimEnumDropdown in line with framework --- .../Overlays/SearchableList/SlimEnumDropdown.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/SearchableList/SlimEnumDropdown.cs b/osu.Game/Overlays/SearchableList/SlimEnumDropdown.cs index 38e3e44911..e68cddb293 100644 --- a/osu.Game/Overlays/SearchableList/SlimEnumDropdown.cs +++ b/osu.Game/Overlays/SearchableList/SlimEnumDropdown.cs @@ -12,8 +12,15 @@ namespace osu.Game.Overlays.SearchableList { public class SlimEnumDropdown : OsuEnumDropdown { - protected override DropdownHeader CreateHeader() => new SlimDropdownHeader { AccentColour = AccentColour }; - protected override Menu CreateMenu() => new SlimMenu(); + protected override DropdownHeader CreateHeader() + { + var newHeader = new SlimDropdownHeader(); + newHeader.AccentColour.BindTo(AccentColour); + + return newHeader; + } + + protected override DropdownMenu CreateMenu() => new SlimMenu(); private class SlimDropdownHeader : OsuDropdownHeader { @@ -31,11 +38,11 @@ namespace osu.Game.Overlays.SearchableList } } - private class SlimMenu : OsuMenu + private class SlimMenu : OsuDropdownMenu { public SlimMenu() { - Background.Colour = Color4.Black.Opacity(0.7f); + BackgroundColour = Color4.Black.Opacity(0.7f); } } } From e83a554ffc311f03d73a53551b752395957d47a5 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 25 Aug 2017 15:58:09 +0900 Subject: [PATCH 30/35] Update CollectionsDropdown in line with framework --- .../Overlays/Music/CollectionsDropdown.cs | 57 +++++++++++-------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/osu.Game/Overlays/Music/CollectionsDropdown.cs b/osu.Game/Overlays/Music/CollectionsDropdown.cs index 0c0a636be8..be72d4481a 100644 --- a/osu.Game/Overlays/Music/CollectionsDropdown.cs +++ b/osu.Game/Overlays/Music/CollectionsDropdown.cs @@ -15,13 +15,41 @@ namespace osu.Game.Overlays.Music { public class CollectionsDropdown : OsuDropdown { - protected override DropdownHeader CreateHeader() => new CollectionsHeader { AccentColour = AccentColour }; - protected override Menu CreateMenu() => new CollectionsMenu(); - [BackgroundDependencyLoader] private void load(OsuColour colours) { - AccentColour = colours.Gray6; + AccentColour.Value = colours.Gray6; + } + + protected override DropdownHeader CreateHeader() + { + var newHeader = new CollectionsHeader(); + newHeader.AccentColour.BindTo(AccentColour); + + return newHeader; + } + + protected override DropdownMenu CreateMenu() => new CollectionsMenu(); + + private class CollectionsMenu : OsuDropdownMenu + { + public CollectionsMenu() + { + CornerRadius = 5; + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(0.3f), + Radius = 3, + Offset = new Vector2(0f, 1f), + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.Gray4; + } } private class CollectionsHeader : OsuDropdownHeader @@ -48,26 +76,5 @@ namespace osu.Game.Overlays.Music }; } } - - private class CollectionsMenu : OsuMenu - { - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - Background.Colour = colours.Gray4; - } - - public CollectionsMenu() - { - CornerRadius = 5; - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Colour = Color4.Black.Opacity(0.3f), - Radius = 3, - Offset = new Vector2(0f, 1f), - }; - } - } } } From a3a5a89636d4cf93b3c8872d62d9cb9d2aa674ca Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 25 Aug 2017 15:58:21 +0900 Subject: [PATCH 31/35] Update OsuDropdown in line with framework --- .../Graphics/UserInterface/OsuDropdown.cs | 165 ++++++++++-------- 1 file changed, 89 insertions(+), 76 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index f5a4219707..d556c58bdd 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -1,9 +1,9 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using System.Linq; using OpenTK.Graphics; using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -16,52 +16,96 @@ namespace osu.Game.Graphics.UserInterface { public class OsuDropdown : Dropdown { - protected override DropdownHeader CreateHeader() => new OsuDropdownHeader { AccentColour = AccentColour }; - - protected override Menu CreateMenu() => new OsuMenu(); - - private Color4? accentColour; - public virtual Color4 AccentColour - { - get { return accentColour.GetValueOrDefault(); } - set - { - accentColour = value; - if (Header != null) - ((OsuDropdownHeader)Header).AccentColour = value; - foreach (var item in MenuItems.OfType()) - item.AccentColour = value; - } - } + public readonly Bindable AccentColour = new Bindable(); [BackgroundDependencyLoader] private void load(OsuColour colours) { - if (accentColour == null) - AccentColour = colours.PinkDarker; + if (AccentColour.Value == null) + AccentColour.Value = colours.PinkDarker; } - protected override DropdownMenuItem CreateMenuItem(string text, T value) => new OsuDropdownMenuItem(text, value) { AccentColour = AccentColour }; - - public class OsuDropdownMenuItem : DropdownMenuItem + protected override DropdownHeader CreateHeader() { - public OsuDropdownMenuItem(string text, T current) : base(text, current) + var newHeader = new OsuDropdownHeader(); + newHeader.AccentColour.BindTo(AccentColour); + + return newHeader; + } + + protected override DropdownMenu CreateMenu() + { + var newMenu = new OsuDropdownMenu(); + newMenu.AccentColour.BindTo(AccentColour); + + return newMenu; + } + + #region OsuDropdownMenu + protected class OsuDropdownMenu : DropdownMenu + { + public readonly Bindable AccentColour = new Bindable(); + + protected override MenuItemRepresentation CreateMenuItemRepresentation(DropdownMenuItem model) { - Foreground.Padding = new MarginPadding(2); + var newItem = new OsuDropdownMenuItemRepresentation(this, model); + newItem.AccentColour.BindTo(AccentColour); - Masking = true; - CornerRadius = 6; + return newItem; + } - Children = new[] + #region OsuDropdownMenuItemRepresentation + protected class OsuDropdownMenuItemRepresentation : DropdownMenuItemRepresentation + { + public readonly Bindable AccentColour = new Bindable(); + + private SpriteIcon chevron; + protected OsuSpriteText Label; + + private Color4 nonAccentHoverColour; + private Color4 nonAccentSelectedColour; + + public OsuDropdownMenuItemRepresentation(Menu> menu, DropdownMenuItem model) + : base(menu, model) { - new FillFlowContainer + Foreground.Padding = new MarginPadding(2); + + Masking = true; + CornerRadius = 6; + + AccentColour.ValueChanged += updateAccent; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = Color4.Transparent; + nonAccentHoverColour = colours.PinkDarker; + nonAccentSelectedColour = Color4.Black.Opacity(0.5f); + } + + private void updateAccent(Color4? newValue) + { + BackgroundColourHover = newValue ?? nonAccentHoverColour; + BackgroundColourSelected = newValue ?? nonAccentSelectedColour; + AnimateBackground(IsHovered); + AnimateForeground(IsHovered); + } + + protected override void AnimateForeground(bool hover) + { + base.AnimateForeground(hover); + chevron.Alpha = hover ? 1 : 0; + } + + protected override Drawable CreateText(string title) => new FillFlowContainer { Direction = FillDirection.Horizontal, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Children = new Drawable[] { - Chevron = new SpriteIcon + chevron = new SpriteIcon { AlwaysPresent = true, Icon = FontAwesome.fa_chevron_right, @@ -72,47 +116,18 @@ namespace osu.Game.Graphics.UserInterface Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, }, - Label = new OsuSpriteText { - Text = text, + Label = new OsuSpriteText + { + Text = title, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, } } - } - }; - } - - private Color4? accentColour; - - protected readonly SpriteIcon Chevron; - protected readonly OsuSpriteText Label; - - protected override void FormatForeground(bool hover = false) - { - base.FormatForeground(hover); - Chevron.Alpha = hover ? 1 : 0; - } - - public Color4 AccentColour - { - get { return accentColour.GetValueOrDefault(); } - set - { - accentColour = value; - BackgroundColourHover = BackgroundColourSelected = value; - FormatBackground(); - FormatForeground(); - } - } - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - BackgroundColour = Color4.Transparent; - BackgroundColourHover = accentColour ?? colours.PinkDarker; - BackgroundColourSelected = Color4.Black.Opacity(0.5f); + }; } + #endregion } + #endregion public class OsuDropdownHeader : DropdownHeader { @@ -125,16 +140,7 @@ namespace osu.Game.Graphics.UserInterface protected readonly SpriteIcon Icon; - private Color4? accentColour; - public virtual Color4 AccentColour - { - get { return accentColour.GetValueOrDefault(); } - set - { - accentColour = value; - BackgroundColourHover = value; - } - } + public readonly Bindable AccentColour = new Bindable(); public OsuDropdownHeader() { @@ -161,13 +167,20 @@ namespace osu.Game.Graphics.UserInterface Size = new Vector2(20), } }; + + AccentColour.ValueChanged += accentColourChanged; } [BackgroundDependencyLoader] private void load(OsuColour colours) { BackgroundColour = Color4.Black.Opacity(0.5f); - BackgroundColourHover = accentColour ?? colours.PinkDarker; + BackgroundColourHover = AccentColour?.Value ?? colours.PinkDarker; + } + + private void accentColourChanged(Color4? newValue) + { + BackgroundColourHover = newValue ?? Color4.White; } } } From ce644138b9f117de9094ffab9cada87a1ebd3df0 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 25 Aug 2017 15:58:30 +0900 Subject: [PATCH 32/35] Update OsuTabControl in line with framework --- .../Graphics/UserInterface/OsuTabControl.cs | 101 ++++++++++-------- 1 file changed, 59 insertions(+), 42 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index 5ad412965c..bc673a7af6 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -50,7 +50,7 @@ namespace osu.Game.Graphics.UserInterface accentColour = value; var dropDown = Dropdown as OsuTabDropdown; if (dropDown != null) - dropDown.AccentColour = value; + dropDown.AccentColour.Value = value; foreach (var item in TabContainer.Children.OfType()) item.AccentColour = value; } @@ -142,55 +142,53 @@ namespace osu.Game.Graphics.UserInterface private class OsuTabDropdown : OsuDropdown { - protected override DropdownHeader CreateHeader() => new OsuTabDropdownHeader - { - AccentColour = AccentColour, - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - }; - - protected override DropdownMenuItem CreateMenuItem(string text, T value) - { - var item = base.CreateMenuItem(text, value); - item.ForegroundColourHover = Color4.Black; - return item; - } - public OsuTabDropdown() { - DropdownMenu.Anchor = Anchor.TopRight; - DropdownMenu.Origin = Anchor.TopRight; - RelativeSizeAxes = Axes.X; - DropdownMenu.Background.Colour = Color4.Black.Opacity(0.7f); - DropdownMenu.MaxHeight = 400; + + } + + protected override DropdownMenu CreateMenu() => new OsuTabDropdownMenu(); + + protected override DropdownHeader CreateHeader() + { + var newHeader = new OsuTabDropdownHeader + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight + }; + + newHeader.AccentColour.BindTo(AccentColour); + + return newHeader; + } + + private class OsuTabDropdownMenu : OsuDropdownMenu + { + public OsuTabDropdownMenu() + { + Anchor = Anchor.TopRight; + Origin = Anchor.TopRight; + + BackgroundColour = Color4.Black.Opacity(0.7f); + MaxHeight = 400; + } + + protected override MenuItemRepresentation CreateMenuItemRepresentation(DropdownMenuItem model) => new OsuTabDropdownMenuItemRepresentation(this, model); + + private class OsuTabDropdownMenuItemRepresentation : OsuDropdownMenuItemRepresentation + { + public OsuTabDropdownMenuItemRepresentation(Menu> menu, DropdownMenuItem model) + : base(menu, model) + { + ForegroundColourHover = Color4.Black; + } + } } protected class OsuTabDropdownHeader : OsuDropdownHeader { - public override Color4 AccentColour - { - get { return base.AccentColour; } - set - { - base.AccentColour = value; - Foreground.Colour = value; - } - } - - protected override bool OnHover(InputState state) - { - Foreground.Colour = BackgroundColour; - return base.OnHover(state); - } - - protected override void OnHoverLost(InputState state) - { - Foreground.Colour = BackgroundColourHover; - base.OnHoverLost(state); - } - public OsuTabDropdownHeader() { RelativeSizeAxes = Axes.None; @@ -219,6 +217,25 @@ namespace osu.Game.Graphics.UserInterface }; Padding = new MarginPadding { Left = 5, Right = 5 }; + + AccentColour.ValueChanged += accentColourChanged; + } + + private void accentColourChanged(Color4? newValue) + { + Foreground.Colour = newValue ?? Color4.White; + } + + protected override bool OnHover(InputState state) + { + Foreground.Colour = BackgroundColour; + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + Foreground.Colour = BackgroundColourHover; + base.OnHoverLost(state); } } } From 9f02000174808c0f99f4d97035305e94a1aaa6d2 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 25 Aug 2017 15:58:42 +0900 Subject: [PATCH 33/35] Update FilterControl using new AccentColour definition --- osu.Game/Overlays/Direct/FilterControl.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Direct/FilterControl.cs b/osu.Game/Overlays/Direct/FilterControl.cs index 28d26d0641..ca9e8667e6 100644 --- a/osu.Game/Overlays/Direct/FilterControl.cs +++ b/osu.Game/Overlays/Direct/FilterControl.cs @@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Direct [BackgroundDependencyLoader(true)] private void load(OsuGame game, RulesetStore rulesets, OsuColour colours) { - DisplayStyleControl.Dropdown.AccentColour = colours.BlueDark; + DisplayStyleControl.Dropdown.AccentColour.Value = colours.BlueDark; Ruleset.BindTo(game?.Ruleset ?? new Bindable { Value = rulesets.GetRuleset(0) }); foreach (var r in rulesets.AllRulesets) From 3ffc46770472e1d91f2a160350f46e521f0147f7 Mon Sep 17 00:00:00 2001 From: smoogipooo Date: Fri, 25 Aug 2017 16:27:01 +0900 Subject: [PATCH 34/35] Fix crappy resizing. --- osu-framework | 2 +- osu.Game/Graphics/UserInterface/OsuMenu.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu-framework b/osu-framework index 2f0674792a..56ce220e7f 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 2f0674792adaf123dcf44ea0099c5707df4a6d60 +Subproject commit 56ce220e7f631ce2890597e505d073cdfc0233a1 diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index 79519e26a0..45bee216ad 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -25,7 +25,7 @@ namespace osu.Game.Graphics.UserInterface protected override void UpdateMenuHeight() { var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight; - this.ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, Easing.OutQuint); + this.ResizeHeightTo(State == MenuState.Opened ? actualHeight : 0, 300, Easing.OutQuint); } protected override FlowContainer CreateItemsFlow() From ee85515d951846d1cdd5241c89ec47a77a5efa10 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 25 Aug 2017 18:41:12 +0900 Subject: [PATCH 35/35] Changes in line with framework changes --- osu-framework | 2 +- .../Graphics/UserInterface/OsuContextMenu.cs | 26 ++++------ .../Graphics/UserInterface/OsuDropdown.cs | 48 ++++++++++++++----- osu.Game/Graphics/UserInterface/OsuMenu.cs | 14 +----- .../Graphics/UserInterface/OsuTabControl.cs | 32 ++++++++----- .../Sections/General/LoginSettings.cs | 20 +++----- 6 files changed, 75 insertions(+), 67 deletions(-) diff --git a/osu-framework b/osu-framework index 56ce220e7f..926d7c971d 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 56ce220e7f631ce2890597e505d073cdfc0233a1 +Subproject commit 926d7c971d059c7aeb3ccfb09d06910c46aa3a40 diff --git a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs index ddb91d42a1..ad4cd1edbc 100644 --- a/osu.Game/Graphics/UserInterface/OsuContextMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuContextMenu.cs @@ -39,18 +39,12 @@ namespace osu.Game.Graphics.UserInterface protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint); protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint); - protected override FlowContainer CreateItemsFlow() - { - var flow = base.CreateItemsFlow(); - flow.Padding = new MarginPadding { Vertical = OsuContextMenuItemRepresentation.MARGIN_VERTICAL }; + protected override MarginPadding ItemFlowContainerPadding => new MarginPadding { Vertical = DrawableOsuContextMenuItem.MARGIN_VERTICAL }; - return flow; - } + protected override DrawableMenuItem CreateDrawableMenuItem(TItem item) => new DrawableOsuContextMenuItem(this, item); - protected override MenuItemRepresentation CreateMenuItemRepresentation(TItem model) => new OsuContextMenuItemRepresentation(this, model); - - #region OsuContextMenuItemRepresentation - private class OsuContextMenuItemRepresentation : MenuItemRepresentation + #region DrawableOsuContextMenuItem + private class DrawableOsuContextMenuItem : DrawableMenuItem { private const int margin_horizontal = 17; private const int text_size = 17; @@ -63,8 +57,8 @@ namespace osu.Game.Graphics.UserInterface private OsuSpriteText text; private OsuSpriteText textBold; - public OsuContextMenuItemRepresentation(Menu menu, TItem model) - : base(menu, model) + public DrawableOsuContextMenuItem(Menu menu, TItem item) + : base(item) { } @@ -82,7 +76,7 @@ namespace osu.Game.Graphics.UserInterface private void updateTextColour() { - switch (Model.Type) + switch (Item.Type) { case MenuItemType.Standard: textBold.Colour = text.Colour = Color4.White; @@ -117,7 +111,7 @@ namespace osu.Game.Graphics.UserInterface return base.OnClick(state); } - protected override Drawable CreateText(string title) => new Container + protected override Drawable CreateContent() => new Container { AutoSizeAxes = Axes.Both, Anchor = Anchor.CentreLeft, @@ -129,7 +123,7 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, TextSize = text_size, - Text = title, + Text = Item.Text, Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, }, textBold = new OsuSpriteText @@ -139,7 +133,7 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, TextSize = text_size, - Text = title, + Text = Item.Text, Font = @"Exo2.0-Bold", Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL }, } diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index d556c58bdd..2c691b7763 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -44,18 +44,40 @@ namespace osu.Game.Graphics.UserInterface #region OsuDropdownMenu protected class OsuDropdownMenu : DropdownMenu { + // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring + public OsuDropdownMenu() + { + CornerRadius = 4; + BackgroundColour = Color4.Black.Opacity(0.5f); + } + + // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring + protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint); + protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint); + + // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring + protected override MarginPadding ItemFlowContainerPadding => new MarginPadding(5); + + // todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring + protected override void UpdateMenuHeight() + { + var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight; + this.ResizeHeightTo(State == MenuState.Opened ? actualHeight : 0, 300, Easing.OutQuint); + } + public readonly Bindable AccentColour = new Bindable(); - protected override MenuItemRepresentation CreateMenuItemRepresentation(DropdownMenuItem model) + + protected override DrawableMenuItem CreateDrawableMenuItem(DropdownMenuItem item) { - var newItem = new OsuDropdownMenuItemRepresentation(this, model); + var newItem = new DrawableOsuDropdownMenuItem(item); newItem.AccentColour.BindTo(AccentColour); return newItem; } - #region OsuDropdownMenuItemRepresentation - protected class OsuDropdownMenuItemRepresentation : DropdownMenuItemRepresentation + #region DrawableOsuDropdownMenuItem + protected class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem { public readonly Bindable AccentColour = new Bindable(); @@ -65,8 +87,8 @@ namespace osu.Game.Graphics.UserInterface private Color4 nonAccentHoverColour; private Color4 nonAccentSelectedColour; - public OsuDropdownMenuItemRepresentation(Menu> menu, DropdownMenuItem model) - : base(menu, model) + public DrawableOsuDropdownMenuItem(DropdownMenuItem item) + : base(item) { Foreground.Padding = new MarginPadding(2); @@ -88,17 +110,17 @@ namespace osu.Game.Graphics.UserInterface { BackgroundColourHover = newValue ?? nonAccentHoverColour; BackgroundColourSelected = newValue ?? nonAccentSelectedColour; - AnimateBackground(IsHovered); - AnimateForeground(IsHovered); + UpdateBackgroundColour(); + UpdateForegroundColour(); } - protected override void AnimateForeground(bool hover) + protected override void UpdateForegroundColour() { - base.AnimateForeground(hover); - chevron.Alpha = hover ? 1 : 0; + base.UpdateForegroundColour(); + chevron.Alpha = IsHovered ? 1 : 0; } - protected override Drawable CreateText(string title) => new FillFlowContainer + protected override Drawable CreateContent() => new FillFlowContainer { Direction = FillDirection.Horizontal, RelativeSizeAxes = Axes.X, @@ -118,7 +140,7 @@ namespace osu.Game.Graphics.UserInterface }, Label = new OsuSpriteText { - Text = title, + Text = Item.Text, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, } diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs index 45bee216ad..0c5bfa2947 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenu.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs @@ -1,11 +1,9 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; using OpenTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterface @@ -28,16 +26,6 @@ namespace osu.Game.Graphics.UserInterface this.ResizeHeightTo(State == MenuState.Opened ? actualHeight : 0, 300, Easing.OutQuint); } - protected override FlowContainer CreateItemsFlow() - { - var flow = base.CreateItemsFlow(); - flow.Padding = new MarginPadding(5); - - return flow; - } - } - - public class OsuMenu : OsuMenu - { + protected override MarginPadding ItemFlowContainerPadding => new MarginPadding(5); } } diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index bc673a7af6..58d853d97e 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -48,9 +48,9 @@ namespace osu.Game.Graphics.UserInterface set { accentColour = value; - var dropDown = Dropdown as OsuTabDropdown; - if (dropDown != null) - dropDown.AccentColour.Value = value; + var dropdown = Dropdown as OsuTabDropdown; + if (dropdown != null) + dropdown.AccentColour.Value = value; foreach (var item in TabContainer.Children.OfType()) item.AccentColour = value; } @@ -140,16 +140,20 @@ namespace osu.Game.Graphics.UserInterface protected override void OnDeactivated() => fadeInactive(); } + // todo: this needs to go private class OsuTabDropdown : OsuDropdown { public OsuTabDropdown() { RelativeSizeAxes = Axes.X; - - } - protected override DropdownMenu CreateMenu() => new OsuTabDropdownMenu(); + protected override DropdownMenu CreateMenu() + { + var menu = new OsuTabDropdownMenu(); + menu.AccentColour.BindTo(AccentColour); + return menu; + } protected override DropdownHeader CreateHeader() { @@ -175,18 +179,24 @@ namespace osu.Game.Graphics.UserInterface MaxHeight = 400; } - protected override MenuItemRepresentation CreateMenuItemRepresentation(DropdownMenuItem model) => new OsuTabDropdownMenuItemRepresentation(this, model); - - private class OsuTabDropdownMenuItemRepresentation : OsuDropdownMenuItemRepresentation + protected override DrawableMenuItem CreateDrawableMenuItem(DropdownMenuItem item) { - public OsuTabDropdownMenuItemRepresentation(Menu> menu, DropdownMenuItem model) - : base(menu, model) + var poop = new DrawableOsuTabDropdownMenuItem(this, item); + poop.AccentColour.BindTo(AccentColour); + return poop; + } + + private class DrawableOsuTabDropdownMenuItem : DrawableOsuDropdownMenuItem + { + public DrawableOsuTabDropdownMenuItem(Menu> menu, DropdownMenuItem item) + : base(item) { ForegroundColourHover = Color4.Black; } } } + protected class OsuTabDropdownHeader : OsuDropdownHeader { public OsuTabDropdownHeader() diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 111dba7151..ad7c7cf092 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -306,20 +306,14 @@ namespace osu.Game.Overlays.Settings.Sections.General BackgroundColour = colours.Gray3; } - protected override FlowContainer CreateItemsFlow() + protected override MarginPadding ItemFlowContainerPadding => new MarginPadding(); + + protected override DrawableMenuItem CreateDrawableMenuItem(DropdownMenuItem item) => new DrawableUserDropdownMenuItem(this, item); + + private class DrawableUserDropdownMenuItem : DrawableOsuDropdownMenuItem { - var flow = base.CreateItemsFlow(); - flow.Padding = new MarginPadding(0); - - return flow; - } - - protected override MenuItemRepresentation CreateMenuItemRepresentation(DropdownMenuItem model) => new UserDropdownMenuItem(this, model); - - private class UserDropdownMenuItem : OsuDropdownMenuItemRepresentation - { - public UserDropdownMenuItem(Menu> menu, DropdownMenuItem model) - : base(menu, model) + public DrawableUserDropdownMenuItem(Menu> menu, DropdownMenuItem item) + : base(item) { Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 }; Label.Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 };