1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-15 14:12:54 +08:00

Merge branch 'master' into fix-track-not-resetting

This commit is contained in:
Dean Herbert 2017-08-18 17:24:22 +09:00 committed by GitHub
commit ffc8f763e5
74 changed files with 1448 additions and 682 deletions

@ -1 +1 @@
Subproject commit 67d89a36016f98c0ede576b859a2ccafe114fce8 Subproject commit 5c22092e590d589927962b8d0173dae5f9b1405c

View File

@ -2,60 +2,38 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Rulesets.Osu.Objects.Drawables;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using osu.Game.Rulesets.Osu;
using osu.Framework.Allocation;
using osu.Game.Rulesets;
namespace osu.Desktop.Tests.Visual namespace osu.Desktop.Tests.Visual
{ {
internal class TestCaseHitObjects : OsuTestCase internal class TestCaseHitObjects : OsuTestCase
{ {
private readonly FramedClock framedClock; private FramedClock framedClock;
private bool auto; private bool auto;
public TestCaseHitObjects() [BackgroundDependencyLoader]
private void load(RulesetStore rulesets)
{ {
var rateAdjustClock = new StopwatchClock(true); var rateAdjustClock = new StopwatchClock(true);
framedClock = new FramedClock(rateAdjustClock); framedClock = new FramedClock(rateAdjustClock);
playbackSpeed.ValueChanged += delegate { rateAdjustClock.Rate = playbackSpeed.Value; };
playbackSpeed.TriggerChange();
AddStep(@"circles", () => loadHitobjects(HitObjectType.Circle)); AddStep(@"circles", () => loadHitobjects(HitObjectType.Circle));
AddStep(@"slider", () => loadHitobjects(HitObjectType.Slider)); AddStep(@"slider", () => loadHitobjects(HitObjectType.Slider));
AddStep(@"spinner", () => loadHitobjects(HitObjectType.Spinner)); AddStep(@"spinner", () => loadHitobjects(HitObjectType.Spinner));
AddToggleStep(@"auto", state => { auto = state; loadHitobjects(mode); }); AddToggleStep("Auto", state => { auto = state; loadHitobjects(mode); });
AddSliderStep("Playback speed", 0.0, 2.0, 0.5, v => rateAdjustClock.Rate = v);
BasicSliderBar<double> sliderBar;
Add(new Container
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new SpriteText { Text = "Playback Speed" },
sliderBar = new BasicSliderBar<double>
{
Width = 150,
Height = 10,
SelectionColor = Color4.Orange,
}
}
});
sliderBar.Current.BindTo(playbackSpeed);
framedClock.ProcessFrame(); framedClock.ProcessFrame();
@ -65,7 +43,7 @@ namespace osu.Desktop.Tests.Visual
Clock = framedClock, Clock = framedClock,
Children = new[] Children = new[]
{ {
playfieldContainer = new Container { RelativeSizeAxes = Axes.Both }, playfieldContainer = new OsuInputManager(rulesets.GetRuleset(0)) { RelativeSizeAxes = Axes.Both },
approachContainer = new Container { RelativeSizeAxes = Axes.Both } approachContainer = new Container { RelativeSizeAxes = Axes.Both }
} }
}; };
@ -75,9 +53,8 @@ namespace osu.Desktop.Tests.Visual
private HitObjectType mode = HitObjectType.Slider; private HitObjectType mode = HitObjectType.Slider;
private readonly BindableNumber<double> playbackSpeed = new BindableDouble(0.5) { MinValue = 0, MaxValue = 1 }; private Container playfieldContainer;
private readonly Container playfieldContainer; private Container approachContainer;
private readonly Container approachContainer;
private void loadHitobjects(HitObjectType mode) private void loadHitobjects(HitObjectType mode)
{ {

View File

@ -0,0 +1,25 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Overlays;
namespace osu.Desktop.Tests.Visual
{
public class TestCaseKeyConfiguration : OsuTestCase
{
private readonly KeyBindingOverlay overlay;
public override string Description => @"Key configuration";
public TestCaseKeyConfiguration()
{
Child = overlay = new KeyBindingOverlay();
}
protected override void LoadComplete()
{
base.LoadComplete();
overlay.Show();
}
}
}

View File

@ -1,11 +1,8 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
@ -34,34 +31,13 @@ namespace osu.Desktop.Tests.Visual
new KeyCounterMouse(MouseButton.Right), new KeyCounterMouse(MouseButton.Right),
}, },
}; };
BindableInt bindable = new BindableInt { MinValue = 0, MaxValue = 200, Default = 50 };
bindable.ValueChanged += delegate { kc.FadeTime = bindable.Value; }; AddStep("Add random", () =>
AddStep("Add Random", () =>
{ {
Key key = (Key)((int)Key.A + RNG.Next(26)); Key key = (Key)((int)Key.A + RNG.Next(26));
kc.Add(new KeyCounterKeyboard(key)); kc.Add(new KeyCounterKeyboard(key));
}); });
AddSliderStep("Fade time", 0, 200, 50, v => kc.FadeTime = v);
TestSliderBar<int> sliderBar;
Add(new Container
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Children = new Drawable[]
{
new SpriteText { Text = "FadeTime" },
sliderBar = new TestSliderBar<int>
{
Width = 150,
Height = 10,
SelectionColor = Color4.Orange,
}
}
});
sliderBar.Current.BindTo(bindable);
Add(kc); Add(kc);
} }

View File

@ -68,7 +68,7 @@ namespace osu.Desktop.Tests.Visual
while (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3) while (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3)
{ {
var p = progressingNotifications.FirstOrDefault(n => n.IsLoaded && n.State == ProgressNotificationState.Queued); var p = progressingNotifications.FirstOrDefault(n => n.IsAlive && n.State == ProgressNotificationState.Queued);
if (p == null) if (p == null)
break; break;

View File

@ -13,7 +13,7 @@ namespace osu.Desktop.Tests.Visual
public TestCaseSettings() public TestCaseSettings()
{ {
Children = new[] { settings = new SettingsOverlay() }; Children = new[] { settings = new MainSettings() };
} }
protected override void LoadComplete() protected override void LoadComplete()

View File

@ -81,6 +81,7 @@
<Compile Include="Visual\TestCaseGamefield.cs" /> <Compile Include="Visual\TestCaseGamefield.cs" />
<Compile Include="Visual\TestCaseGraph.cs" /> <Compile Include="Visual\TestCaseGraph.cs" />
<Compile Include="Visual\TestCaseHitObjects.cs" /> <Compile Include="Visual\TestCaseHitObjects.cs" />
<Compile Include="Visual\TestCaseKeyConfiguration.cs" />
<Compile Include="Visual\TestCaseKeyCounter.cs" /> <Compile Include="Visual\TestCaseKeyCounter.cs" />
<Compile Include="Visual\TestCaseLeaderboard.cs" /> <Compile Include="Visual\TestCaseLeaderboard.cs" />
<Compile Include="Visual\TestCaseManiaHitObjects.cs" /> <Compile Include="Visual\TestCaseManiaHitObjects.cs" />

View File

@ -27,8 +27,6 @@ namespace osu.Desktop.Overlays
private UpdateManager updateManager; private UpdateManager updateManager;
private NotificationOverlay notificationOverlay; private NotificationOverlay notificationOverlay;
protected override bool HideOnEscape => false;
public override bool HandleInput => false; public override bool HandleInput => false;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -1,32 +1,27 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic; using System.ComponentModel;
using osu.Game.Input; using osu.Framework.Input.Bindings;
using OpenTK.Input; using osu.Game.Input.Bindings;
namespace osu.Game.Rulesets.Catch namespace osu.Game.Rulesets.Catch
{ {
public class CatchInputManager : ActionMappingInputManager<CatchAction> public class CatchInputManager : DatabasedKeyBindingInputManager<CatchAction>
{ {
public CatchInputManager(RulesetInfo ruleset) : base(ruleset) public CatchInputManager(RulesetInfo ruleset)
: base(ruleset, 0, SimultaneousBindingMode.Unique)
{ {
Mappings = new Dictionary<Key, CatchAction>
{
{ Key.Z, CatchAction.MoveLeft },
{ Key.Left, CatchAction.MoveLeft },
{ Key.X, CatchAction.MoveRight },
{ Key.Right, CatchAction.MoveRight },
{ Key.LShift, CatchAction.Dash },
{ Key.RShift, CatchAction.Dash },
};
} }
} }
public enum CatchAction public enum CatchAction
{ {
[Description("Move left")]
MoveLeft, MoveLeft,
[Description("Move right")]
MoveRight, MoveRight,
[Description("Engage dash")]
Dash Dash
} }
} }

View File

@ -13,6 +13,7 @@ using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Scoring; using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Framework.Input.Bindings;
namespace osu.Game.Rulesets.Catch namespace osu.Game.Rulesets.Catch
{ {
@ -20,6 +21,16 @@ namespace osu.Game.Rulesets.Catch
{ {
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new CatchRulesetContainer(this, beatmap, isForCurrentRuleset); public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new CatchRulesetContainer(this, beatmap, isForCurrentRuleset);
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
{
new KeyBinding(Key.Z, CatchAction.MoveLeft),
new KeyBinding(Key.Left, CatchAction.MoveLeft),
new KeyBinding(Key.X, CatchAction.MoveRight),
new KeyBinding(Key.Right, CatchAction.MoveRight),
new KeyBinding(Key.LShift, CatchAction.Dash),
new KeyBinding(Key.RShift, CatchAction.Dash),
};
public override IEnumerable<Mod> GetModsFor(ModType type) public override IEnumerable<Mod> GetModsFor(ModType type)
{ {
switch (type) switch (type)

View File

@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.UI
protected override Playfield<CatchBaseHit, CatchJudgement> CreatePlayfield() => new CatchPlayfield(); protected override Playfield<CatchBaseHit, CatchJudgement> CreatePlayfield() => new CatchPlayfield();
protected override PassThroughInputManager CreateActionMappingInputManager() => new CatchInputManager(Ruleset.RulesetInfo); public override PassThroughInputManager CreateKeyBindingInputManager() => new CatchInputManager(Ruleset?.RulesetInfo);
protected override DrawableHitObject<CatchBaseHit, CatchJudgement> GetVisualRepresentation(CatchBaseHit h) protected override DrawableHitObject<CatchBaseHit, CatchJudgement> GetVisualRepresentation(CatchBaseHit h)
{ {

View File

@ -8,7 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Framework.Input; using osu.Framework.Input.Bindings;
using osu.Framework.MathUtils; using osu.Framework.MathUtils;
using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.Catch.UI
catcher.Size = new Vector2(DrawSize.Y); catcher.Size = new Vector2(DrawSize.Y);
} }
private class Catcher : Container private class Catcher : Container, IKeyBindingHandler<CatchAction>
{ {
private Texture texture; private Texture texture;
@ -104,13 +104,9 @@ namespace osu.Game.Rulesets.Catch.UI
OriginPosition = new Vector2(DrawWidth / 2, 10) //temporary until the sprite is aligned correctly. OriginPosition = new Vector2(DrawWidth / 2, 10) //temporary until the sprite is aligned correctly.
}; };
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) public bool OnPressed(CatchAction action)
{ {
if (args.Repeat) return true; switch (action)
if (state.Data is CatchAction)
{
switch ((CatchAction)state.Data)
{ {
case CatchAction.MoveLeft: case CatchAction.MoveLeft:
currentDirection--; currentDirection--;
@ -122,16 +118,13 @@ namespace osu.Game.Rulesets.Catch.UI
Dashing = true; Dashing = true;
return true; return true;
} }
return false;
} }
return base.OnKeyDown(state, args); public bool OnReleased(CatchAction action)
}
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
{ {
if (state.Data is CatchAction) switch (action)
{
switch ((CatchAction)state.Data)
{ {
case CatchAction.MoveLeft: case CatchAction.MoveLeft:
currentDirection++; currentDirection++;
@ -143,9 +136,8 @@ namespace osu.Game.Rulesets.Catch.UI
Dashing = false; Dashing = false;
return true; return true;
} }
}
return base.OnKeyUp(state, args); return false;
} }
protected override void Update() protected override void Update()

View File

@ -7,12 +7,12 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Framework.Input; using osu.Framework.Input.Bindings;
using OpenTK; using OpenTK;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{ {
public class CirclePiece : Container public class CirclePiece : Container, IKeyBindingHandler<OsuAction>
{ {
private readonly Sprite disc; private readonly Sprite disc;
@ -49,9 +49,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
disc.Texture = textures.Get(@"Play/osu/disc"); disc.Texture = textures.Get(@"Play/osu/disc");
} }
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) public bool OnPressed(OsuAction action)
{ {
return Hit?.Invoke() ?? false; switch (action)
{
case OsuAction.LeftButton:
case OsuAction.RightButton:
return IsHovered && (Hit?.Invoke() ?? false);
} }
return false;
}
public bool OnReleased(OsuAction action) => false;
} }
} }

View File

@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
return; return;
accentColour = value; accentColour = value;
if (LoadState == LoadState.Loaded) if (LoadState == LoadState.Ready)
Schedule(reloadTexture); Schedule(reloadTexture);
} }
} }

View File

@ -0,0 +1,45 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.ComponentModel;
using System.Linq;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
using OpenTK.Input;
using KeyboardState = osu.Framework.Input.KeyboardState;
using MouseState = osu.Framework.Input.MouseState;
namespace osu.Game.Rulesets.Osu
{
public class OsuInputManager : DatabasedKeyBindingInputManager<OsuAction>
{
public OsuInputManager(RulesetInfo ruleset) : base(ruleset, 0, SimultaneousBindingMode.Unique)
{
}
protected override void TransformState(InputState state)
{
base.TransformState(state);
var mouse = state.Mouse as MouseState;
var keyboard = state.Keyboard as KeyboardState;
if (mouse != null && keyboard != null)
{
if (mouse.IsPressed(MouseButton.Left))
keyboard.Keys = keyboard.Keys.Concat(new[] { Key.LastKey + 1 });
if (mouse.IsPressed(MouseButton.Right))
keyboard.Keys = keyboard.Keys.Concat(new[] { Key.LastKey + 2 });
}
}
}
public enum OsuAction
{
[Description("Left Button")]
LeftButton,
[Description("Right Button")]
RightButton
}
}

View File

@ -1,39 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Input;
using OpenTK.Input;
using KeyboardState = osu.Framework.Input.KeyboardState;
using MouseState = osu.Framework.Input.MouseState;
namespace osu.Game.Rulesets.Osu
{
public class OsuKeyConversionInputManager : PassThroughInputManager
{
private bool leftViaKeyboard;
private bool rightViaKeyboard;
protected override void TransformState(InputState state)
{
base.TransformState(state);
var mouse = state.Mouse as MouseState;
var keyboard = state.Keyboard as KeyboardState;
if (keyboard != null)
{
leftViaKeyboard = keyboard.Keys.Contains(Key.Z);
rightViaKeyboard = keyboard.Keys.Contains(Key.X);
}
if (mouse != null)
{
if (leftViaKeyboard)
mouse.SetPressed(MouseButton.Left, true);
if (rightViaKeyboard)
mouse.SetPressed(MouseButton.Right, true);
}
}
}
}

View File

@ -17,6 +17,7 @@ using osu.Framework.Graphics;
using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings;
using osu.Framework.Input.Bindings;
namespace osu.Game.Rulesets.Osu namespace osu.Game.Rulesets.Osu
{ {
@ -24,6 +25,14 @@ namespace osu.Game.Rulesets.Osu
{ {
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new OsuRulesetContainer(this, beatmap, isForCurrentRuleset); public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset) => new OsuRulesetContainer(this, beatmap, isForCurrentRuleset);
public override IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new[]
{
new KeyBinding(Key.Z, OsuAction.LeftButton),
new KeyBinding(Key.X, OsuAction.RightButton),
new KeyBinding(Key.LastKey + 1, OsuAction.LeftButton),
new KeyBinding(Key.LastKey + 2, OsuAction.RightButton),
};
public override IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap) => new[] public override IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap) => new[]
{ {
new BeatmapStatistic new BeatmapStatistic

View File

@ -1,22 +1,22 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Diagnostics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.OpenGL.Buffers;
using osu.Framework.Graphics.OpenGL.Vertices;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Shaders; using osu.Framework.Graphics.Shaders;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Framework.Input; using osu.Framework.Input;
using OpenTK;
using System;
using osu.Framework.Graphics.OpenGL.Buffers;
using OpenTK.Graphics.ES30;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Colour;
using osu.Framework.Timing; using osu.Framework.Timing;
using System.Diagnostics; using OpenTK;
using osu.Framework.Graphics.OpenGL.Vertices; using OpenTK.Graphics.ES30;
namespace osu.Game.Graphics.Cursor namespace osu.Game.Rulesets.Osu.UI.Cursor
{ {
internal class CursorTrail : Drawable internal class CursorTrail : Drawable
{ {

View File

@ -1,8 +1,6 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
@ -10,13 +8,15 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input; using osu.Framework.Input.Bindings;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Configuration; using osu.Game.Configuration;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Graphics.Cursor namespace osu.Game.Rulesets.Osu.UI.Cursor
{ {
public class GameplayCursor : CursorContainer public class GameplayCursor : CursorContainer, IKeyBindingHandler<OsuAction>
{ {
protected override Drawable CreateCursor() => new OsuCursor(); protected override Drawable CreateCursor() => new OsuCursor();
@ -25,19 +25,7 @@ namespace osu.Game.Graphics.Cursor
Add(new CursorTrail { Depth = 1 }); Add(new CursorTrail { Depth = 1 });
} }
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) private int downCount;
{
ActiveCursor.Scale = new Vector2(1);
ActiveCursor.ScaleTo(1.2f, 100, Easing.OutQuad);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
if (!state.Mouse.HasMainButtonPressed)
ActiveCursor.ScaleTo(1, 200, Easing.OutQuad);
return base.OnMouseUp(state, args);
}
public class OsuCursor : Container public class OsuCursor : Container
{ {
@ -143,5 +131,33 @@ namespace osu.Game.Graphics.Cursor
cursorContainer.Scale = new Vector2(scale); cursorContainer.Scale = new Vector2(scale);
} }
} }
public bool OnPressed(OsuAction action)
{
switch (action)
{
case OsuAction.LeftButton:
case OsuAction.RightButton:
downCount++;
ActiveCursor.ScaleTo(1).ScaleTo(1.2f, 100, Easing.OutQuad);
break;
}
return false;
}
public bool OnReleased(OsuAction action)
{
switch (action)
{
case OsuAction.LeftButton:
case OsuAction.RightButton:
if (--downCount == 0)
ActiveCursor.ScaleTo(1, 200, Easing.OutQuad);
break;
}
return false;
}
} }
} }

View File

@ -10,8 +10,8 @@ using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Connections; using osu.Game.Rulesets.Osu.Objects.Drawables.Connections;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using System.Linq; using System.Linq;
using osu.Game.Graphics.Cursor;
using osu.Game.Rulesets.Osu.Judgements; using osu.Game.Rulesets.Osu.Judgements;
using osu.Game.Rulesets.Osu.UI.Cursor;
namespace osu.Game.Rulesets.Osu.UI namespace osu.Game.Rulesets.Osu.UI
{ {

View File

@ -31,7 +31,7 @@ namespace osu.Game.Rulesets.Osu.UI
protected override Playfield<OsuHitObject, OsuJudgement> CreatePlayfield() => new OsuPlayfield(); protected override Playfield<OsuHitObject, OsuJudgement> CreatePlayfield() => new OsuPlayfield();
protected override PassThroughInputManager CreateActionMappingInputManager() => new OsuKeyConversionInputManager(); public override PassThroughInputManager CreateKeyBindingInputManager() => new OsuInputManager(Ruleset?.RulesetInfo);
protected override DrawableHitObject<OsuHitObject, OsuJudgement> GetVisualRepresentation(OsuHitObject h) protected override DrawableHitObject<OsuHitObject, OsuJudgement> GetVisualRepresentation(OsuHitObject h)
{ {

View File

@ -77,7 +77,9 @@
<Compile Include="OsuDifficulty\Skills\Skill.cs" /> <Compile Include="OsuDifficulty\Skills\Skill.cs" />
<Compile Include="OsuDifficulty\Skills\Speed.cs" /> <Compile Include="OsuDifficulty\Skills\Speed.cs" />
<Compile Include="OsuDifficulty\Utils\History.cs" /> <Compile Include="OsuDifficulty\Utils\History.cs" />
<Compile Include="OsuKeyConversionInputManager.cs" /> <Compile Include="OsuInputManager.cs" />
<Compile Include="UI\Cursor\CursorTrail.cs" />
<Compile Include="UI\Cursor\GameplayCursor.cs" />
<Compile Include="UI\OsuSettings.cs" /> <Compile Include="UI\OsuSettings.cs" />
<Compile Include="Scoring\OsuScoreProcessor.cs" /> <Compile Include="Scoring\OsuScoreProcessor.cs" />
<Compile Include="UI\OsuRulesetContainer.cs" /> <Compile Include="UI\OsuRulesetContainer.cs" />

View File

@ -307,6 +307,11 @@ namespace osu.Game.Beatmaps
/// <returns>The imported beatmap, or an existing instance if it is already present.</returns> /// <returns>The imported beatmap, or an existing instance if it is already present.</returns>
private BeatmapSetInfo importToStorage(ArchiveReader reader) private BeatmapSetInfo importToStorage(ArchiveReader reader)
{ {
// let's make sure there are actually .osu files to import.
string mapName = reader.Filenames.FirstOrDefault(f => f.EndsWith(".osu"));
if (string.IsNullOrEmpty(mapName))
throw new InvalidOperationException("No beatmap files found in the map folder.");
// for now, concatenate all .osu files in the set to create a unique hash. // for now, concatenate all .osu files in the set to create a unique hash.
MemoryStream hashable = new MemoryStream(); MemoryStream hashable = new MemoryStream();
foreach (string file in reader.Filenames.Where(f => f.EndsWith(".osu"))) foreach (string file in reader.Filenames.Where(f => f.EndsWith(".osu")))
@ -339,7 +344,7 @@ namespace osu.Game.Beatmaps
BeatmapMetadata metadata; BeatmapMetadata metadata;
using (var stream = new StreamReader(reader.GetStream(reader.Filenames.First(f => f.EndsWith(".osu"))))) using (var stream = new StreamReader(reader.GetStream(mapName)))
metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata; metadata = BeatmapDecoder.GetDecoder(stream).Decode(stream).Metadata;
beatmapSet = new BeatmapSetInfo beatmapSet = new BeatmapSetInfo

View File

@ -19,7 +19,9 @@ namespace osu.Game.Beatmaps.Formats
public static BeatmapDecoder GetDecoder(StreamReader stream) public static BeatmapDecoder GetDecoder(StreamReader stream)
{ {
string line = stream.ReadLine()?.Trim(); string line;
do { line = stream.ReadLine()?.Trim(); }
while (line != null && line.Length == 0);
if (line == null || !decoders.ContainsKey(line)) if (line == null || !decoders.ContainsKey(line))
throw new IOException(@"Unknown file format"); throw new IOException(@"Unknown file format");

View File

@ -27,7 +27,9 @@ namespace osu.Game.Beatmaps.Formats
AddDecoder<OsuLegacyDecoder>(@"osu file format v7"); AddDecoder<OsuLegacyDecoder>(@"osu file format v7");
AddDecoder<OsuLegacyDecoder>(@"osu file format v6"); AddDecoder<OsuLegacyDecoder>(@"osu file format v6");
AddDecoder<OsuLegacyDecoder>(@"osu file format v5"); AddDecoder<OsuLegacyDecoder>(@"osu file format v5");
// TODO: Not sure how far back to go, or differences between versions AddDecoder<OsuLegacyDecoder>(@"osu file format v4");
AddDecoder<OsuLegacyDecoder>(@"osu file format v3");
// TODO: differences between versions
} }
private ConvertHitObjectParser parser; private ConvertHitObjectParser parser;
@ -222,6 +224,7 @@ namespace osu.Game.Beatmaps.Formats
{ {
while (line.IndexOf('$') >= 0) while (line.IndexOf('$') >= 0)
{ {
string origLine = line;
string[] split = line.Split(','); string[] split = line.Split(',');
for (int i = 0; i < split.Length; i++) for (int i = 0; i < split.Length; i++)
{ {
@ -231,6 +234,7 @@ namespace osu.Game.Beatmaps.Formats
} }
line = string.Join(",", split); line = string.Join(",", split);
if (line == origLine) break;
} }
} }
@ -327,6 +331,7 @@ namespace osu.Game.Beatmaps.Formats
if (speedMultiplier != difficultyPoint.SpeedMultiplier) if (speedMultiplier != difficultyPoint.SpeedMultiplier)
{ {
beatmap.ControlPointInfo.DifficultyPoints.RemoveAll(x => x.Time == time);
beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint beatmap.ControlPointInfo.DifficultyPoints.Add(new DifficultyControlPoint
{ {
Time = time, Time = time,

View File

@ -34,9 +34,8 @@ namespace osu.Game.Graphics.Containers
protected override Container<Drawable> Content => content; protected override Container<Drawable> Content => content;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(UserInputManager input, OsuConfigManager config) private void load(OsuConfigManager config)
{ {
this.input = input;
parallaxEnabled = config.GetBindable<bool>(OsuSetting.MenuParallax); parallaxEnabled = config.GetBindable<bool>(OsuSetting.MenuParallax);
parallaxEnabled.ValueChanged += delegate parallaxEnabled.ValueChanged += delegate
{ {
@ -48,6 +47,12 @@ namespace osu.Game.Graphics.Containers
}; };
} }
protected override void LoadComplete()
{
base.LoadComplete();
input = GetContainingInputManager();
}
private bool firstUpdate = true; private bool firstUpdate = true;
protected override void Update() protected override void Update()

View File

@ -3,10 +3,8 @@
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input; using OpenTK.Input;
using osu.Framework.Allocation;
using osu.Framework.Input; using osu.Framework.Input;
using System; using System;
using System.Linq;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {
@ -28,34 +26,28 @@ namespace osu.Game.Graphics.UserInterface
{ {
focus = value; focus = value;
if (!focus && HasFocus) if (!focus && HasFocus)
inputManager.ChangeFocus(null); GetContainingInputManager().ChangeFocus(null);
} }
} }
private InputManager inputManager;
[BackgroundDependencyLoader]
private void load(UserInputManager inputManager)
{
this.inputManager = inputManager;
}
protected override void OnFocus(InputState state) protected override void OnFocus(InputState state)
{ {
base.OnFocus(state); base.OnFocus(state);
BorderThickness = 0; BorderThickness = 0;
} }
protected override void OnFocusLost(InputState state) protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{ {
if (state.Keyboard.Keys.Any(key => key == Key.Escape)) if (args.Key == Key.Escape)
{ {
if (Text.Length > 0) if (Text.Length > 0)
Text = string.Empty; Text = string.Empty;
else else
Exit?.Invoke(); Exit?.Invoke();
return true;
} }
base.OnFocusLost(state);
return base.OnKeyDown(state, args);
} }
public override bool RequestsFocus => HoldFocus; public override bool RequestsFocus => HoldFocus;

View File

@ -7,6 +7,7 @@ using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
@ -16,7 +17,7 @@ using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {
public class OsuButton : Button public class OsuButton : Button, IFilterable
{ {
private Box hover; private Box hover;
@ -108,5 +109,15 @@ namespace osu.Game.Graphics.UserInterface
Content.ScaleTo(1, 1000, Easing.OutElastic); Content.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args); return base.OnMouseUp(state, args);
} }
public string[] FilterTerms => new[] { Text };
public bool MatchingFilter
{
set
{
this.FadeTo(value ? 1 : 0);
}
}
} }
} }

View File

@ -15,8 +15,6 @@ namespace osu.Game.Graphics.UserInterface.Volume
{ {
private readonly VolumeMeter volumeMeterMaster; private readonly VolumeMeter volumeMeterMaster;
protected override bool HideOnEscape => false;
private void volumeChanged(double newVolume) private void volumeChanged(double newVolume)
{ {
Show(); Show();

View File

@ -1,74 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Input;
using osu.Game.Rulesets;
using OpenTK.Input;
namespace osu.Game.Input
{
/// <summary>
/// Maps custom action data of type <see cref="T"/> and stores to <see cref="InputState.Data"/>.
/// </summary>
/// <typeparam name="T">The type of the custom action.</typeparam>
public class ActionMappingInputManager<T> : PassThroughInputManager
where T : struct
{
private readonly RulesetInfo ruleset;
private readonly int? variant;
/// <summary>
/// Create a new instance.
/// </summary>
/// <param name="ruleset">A reference to identify the current <see cref="Ruleset"/>. Used to lookup mappings. Null for global mappings.</param>
/// <param name="variant">An optional variant for the specified <see cref="Ruleset"/>. Used when a ruleset has more than one possible keyboard layouts.</param>
protected ActionMappingInputManager(RulesetInfo ruleset = null, int? variant = null)
{
this.ruleset = ruleset;
this.variant = variant;
}
protected IDictionary<Key, T> Mappings { get; set; }
[BackgroundDependencyLoader]
private void load(BindingStore bindings)
{
var rulesetId = ruleset?.ID;
foreach (var b in bindings.Query<Binding>(b => b.RulesetID == rulesetId && b.Variant == variant))
Mappings[b.Key] = (T)(object)b.Action;
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
mapKey(state, args.Key);
return base.OnKeyDown(state, args);
}
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
{
mapKey(state, args.Key);
return base.OnKeyUp(state, args);
}
private void mapKey(InputState state, Key key)
{
T mappedData;
if (Mappings.TryGetValue(key, out mappedData))
state.Data = mappedData;
}
private T parseStringRepresentation(string str)
{
T res;
if (Enum.TryParse(str, out res))
return res;
return default(T);
}
}
}

View File

@ -1,23 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Rulesets;
using OpenTK.Input;
using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes;
namespace osu.Game.Input
{
public class Binding
{
[ForeignKey(typeof(RulesetInfo))]
public int? RulesetID { get; set; }
[Indexed]
public int? Variant { get; set; }
public Key Key { get; set; }
public int Action { get; set; }
}
}

View File

@ -1,29 +0,0 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Platform;
using osu.Game.Database;
using SQLite.Net;
namespace osu.Game.Input
{
public class BindingStore : DatabaseBackedStore
{
public BindingStore(SQLiteConnection connection, Storage storage = null)
: base(connection, storage)
{
}
protected override void Prepare(bool reset = false)
{
Connection.CreateTable<Binding>();
}
protected override Type[] ValidTypes => new[]
{
typeof(Binding)
};
}
}

View File

@ -0,0 +1,38 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets;
using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes;
namespace osu.Game.Input.Bindings
{
[Table("KeyBinding")]
public class DatabasedKeyBinding : KeyBinding
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
[ForeignKey(typeof(RulesetInfo))]
public int? RulesetID { get; set; }
[Indexed]
public int? Variant { get; set; }
[Column("Keys")]
public string KeysString
{
get { return KeyCombination.ToString(); }
private set { KeyCombination = value; }
}
[Indexed]
[Column("Action")]
public int IntAction
{
get { return (int)Action; }
set { Action = value; }
}
}
}

View File

@ -0,0 +1,54 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets;
namespace osu.Game.Input.Bindings
{
/// <summary>
/// A KeyBindingInputManager with a database backing for custom overrides.
/// </summary>
/// <typeparam name="T">The type of the custom action.</typeparam>
public abstract class DatabasedKeyBindingInputManager<T> : KeyBindingInputManager<T>
where T : struct
{
private readonly RulesetInfo ruleset;
private readonly int? variant;
private KeyBindingStore store;
public override IEnumerable<KeyBinding> DefaultKeyBindings => ruleset.CreateInstance().GetDefaultKeyBindings();
/// <summary>
/// Create a new instance.
/// </summary>
/// <param name="ruleset">A reference to identify the current <see cref="Ruleset"/>. Used to lookup mappings. Null for global mappings.</param>
/// <param name="variant">An optional variant for the specified <see cref="Ruleset"/>. Used when a ruleset has more than one possible keyboard layouts.</param>
/// <param name="simultaneousMode">Specify how to deal with multiple matches of <see cref="KeyCombination"/>s and <see cref="T"/>s.</param>
protected DatabasedKeyBindingInputManager(RulesetInfo ruleset = null, int? variant = null, SimultaneousBindingMode simultaneousMode = SimultaneousBindingMode.None)
: base(simultaneousMode)
{
this.ruleset = ruleset;
this.variant = variant;
if (ruleset != null && variant == null)
throw new InvalidOperationException($"{nameof(variant)} can not be null when a non-null {nameof(ruleset)} is provided.");
}
[BackgroundDependencyLoader]
private void load(KeyBindingStore keyBindings)
{
store = keyBindings;
}
protected override void ReloadMappings()
{
KeyBindings = store.Query(ruleset?.ID, variant);
}
}
}

View File

@ -0,0 +1,52 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Input;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Input.Bindings;
namespace osu.Game.Input.Bindings
{
public class GlobalKeyBindingInputManager : DatabasedKeyBindingInputManager<GlobalAction>
{
private readonly Drawable handler;
public GlobalKeyBindingInputManager(OsuGameBase game)
{
if (game is IKeyBindingHandler<GlobalAction>)
handler = game;
}
public override IEnumerable<KeyBinding> DefaultKeyBindings => new[]
{
new KeyBinding(Key.F8, GlobalAction.ToggleChat),
new KeyBinding(Key.F9, GlobalAction.ToggleSocial),
new KeyBinding(new[] { Key.LControl, Key.LAlt, Key.R }, GlobalAction.ResetInputSettings),
new KeyBinding(new[] { Key.LControl, Key.T }, GlobalAction.ToggleToolbar),
new KeyBinding(new[] { Key.LControl, Key.O }, GlobalAction.ToggleSettings),
new KeyBinding(new[] { Key.LControl, Key.D }, GlobalAction.ToggleDirect),
};
protected override IEnumerable<Drawable> GetKeyboardInputQueue() =>
handler == null ? base.GetKeyboardInputQueue() : new[] { handler }.Concat(base.GetKeyboardInputQueue());
}
public enum GlobalAction
{
[Description("Toggle chat overlay")]
ToggleChat,
[Description("Toggle social overlay")]
ToggleSocial,
[Description("Reset input settings")]
ResetInputSettings,
[Description("Toggle toolbar")]
ToggleToolbar,
[Description("Toggle settings")]
ToggleSettings,
[Description("Toggle osu!direct")]
ToggleDirect,
}
}

View File

@ -0,0 +1,93 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Input.Bindings;
using osu.Framework.Platform;
using osu.Game.Database;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets;
using SQLite.Net;
namespace osu.Game.Input
{
public class KeyBindingStore : DatabaseBackedStore
{
public KeyBindingStore(SQLiteConnection connection, RulesetStore rulesets, Storage storage = null)
: base(connection, storage)
{
foreach (var info in rulesets.Query<RulesetInfo>())
{
var ruleset = info.CreateInstance();
foreach (var variant in ruleset.AvailableVariants)
insertDefaults(ruleset.GetDefaultKeyBindings(), info.ID, variant);
}
}
public void Register(KeyBindingInputManager manager) => insertDefaults(manager.DefaultKeyBindings);
protected override int StoreVersion => 3;
protected override void PerformMigration(int currentVersion, int targetVersion)
{
base.PerformMigration(currentVersion, targetVersion);
while (currentVersion++ < targetVersion)
{
switch (currentVersion)
{
case 1:
case 2:
case 3:
// cannot migrate; breaking underlying changes.
Reset();
break;
}
}
}
protected override void Prepare(bool reset = false)
{
if (reset)
Connection.DropTable<DatabasedKeyBinding>();
Connection.CreateTable<DatabasedKeyBinding>();
}
private void insertDefaults(IEnumerable<KeyBinding> defaults, int? rulesetId = null, int? variant = null)
{
var query = Query(rulesetId, variant);
// compare counts in database vs defaults
foreach (var group in defaults.GroupBy(k => k.Action))
{
int count;
while (group.Count() > (count = query.Count(k => (int)k.Action == (int)group.Key)))
{
var insertable = group.Skip(count).First();
// insert any defaults which are missing.
Connection.Insert(new DatabasedKeyBinding
{
KeyCombination = insertable.KeyCombination,
Action = insertable.Action,
RulesetID = rulesetId,
Variant = variant
});
}
}
}
protected override Type[] ValidTypes => new[]
{
typeof(DatabasedKeyBinding)
};
public IEnumerable<KeyBinding> Query(int? rulesetId = null, int? variant = null) =>
Query<DatabasedKeyBinding>(b => b.RulesetID == rulesetId && b.Variant == variant);
public void Update(KeyBinding keyBinding) => Connection.Update(keyBinding);
}
}

View File

@ -9,17 +9,16 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Framework.Input; using osu.Framework.Input;
using OpenTK.Input;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Game.Graphics.UserInterface.Volume; using osu.Game.Graphics.UserInterface.Volume;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Timing;
using osu.Game.Overlays.Toolbar; using osu.Game.Overlays.Toolbar;
using osu.Game.Screens; using osu.Game.Screens;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using OpenTK; using OpenTK;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using osu.Framework.Input.Bindings;
using osu.Framework.Platform; using osu.Framework.Platform;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -27,10 +26,11 @@ using osu.Game.Rulesets.Scoring;
using osu.Game.Overlays.Notifications; using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Input.Bindings;
namespace osu.Game namespace osu.Game
{ {
public class OsuGame : OsuGameBase public class OsuGame : OsuGameBase, IKeyBindingHandler<GlobalAction>
{ {
public Toolbar Toolbar; public Toolbar Toolbar;
@ -169,10 +169,6 @@ namespace osu.Game
volume = new VolumeControl(), volume = new VolumeControl(),
overlayContent = new Container { RelativeSizeAxes = Axes.Both }, overlayContent = new Container { RelativeSizeAxes = Axes.Both },
new OnScreenDisplay(), new OnScreenDisplay(),
new GlobalHotkeys //exists because UserInputManager is at a level below us.
{
Handler = globalHotkeyPressed
}
}); });
LoadComponentAsync(screenStack = new Loader(), d => LoadComponentAsync(screenStack = new Loader(), d =>
@ -186,7 +182,11 @@ namespace osu.Game
LoadComponentAsync(direct = new DirectOverlay { Depth = -1 }, mainContent.Add); LoadComponentAsync(direct = new DirectOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(social = new SocialOverlay { Depth = -1 }, mainContent.Add); LoadComponentAsync(social = new SocialOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(chat = new ChatOverlay { Depth = -1 }, mainContent.Add); LoadComponentAsync(chat = new ChatOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(settings = new SettingsOverlay { Depth = -1 }, overlayContent.Add); LoadComponentAsync(settings = new MainSettings
{
GetToolbarHeight = () => ToolbarOffset,
Depth = -1
}, overlayContent.Add);
LoadComponentAsync(userProfile = new UserProfileOverlay { Depth = -2 }, mainContent.Add); LoadComponentAsync(userProfile = new UserProfileOverlay { Depth = -2 }, mainContent.Add);
LoadComponentAsync(musicController = new MusicController LoadComponentAsync(musicController = new MusicController
{ {
@ -252,35 +252,19 @@ namespace osu.Game
Cursor.State = Visibility.Hidden; Cursor.State = Visibility.Hidden;
} }
private bool globalHotkeyPressed(InputState state, KeyDownEventArgs args) public bool OnPressed(GlobalAction action)
{ {
if (args.Repeat || intro == null) return false; if (intro == null) return false;
switch (args.Key) switch (action)
{ {
case Key.F8: case GlobalAction.ToggleChat:
chat.ToggleVisibility(); chat.ToggleVisibility();
return true; return true;
case Key.F9: case GlobalAction.ToggleSocial:
social.ToggleVisibility(); social.ToggleVisibility();
return true; return true;
case Key.PageUp: case GlobalAction.ResetInputSettings:
case Key.PageDown:
var swClock = (Clock as ThrottledFrameClock)?.Source as StopwatchClock;
if (swClock == null) return false;
swClock.Rate *= args.Key == Key.PageUp ? 1.1f : 0.9f;
Logger.Log($@"Adjusting game clock to {swClock.Rate}", LoggingTarget.Debug);
return true;
}
if (state.Keyboard.ControlPressed)
{
switch (args.Key)
{
case Key.R:
if (state.Keyboard.AltPressed)
{
var sensitivity = frameworkConfig.GetBindable<double>(FrameworkSetting.CursorSensitivity); var sensitivity = frameworkConfig.GetBindable<double>(FrameworkSetting.CursorSensitivity);
sensitivity.Disabled = false; sensitivity.Disabled = false;
@ -289,26 +273,22 @@ namespace osu.Game
frameworkConfig.Set(FrameworkSetting.ActiveInputHandlers, string.Empty); frameworkConfig.Set(FrameworkSetting.ActiveInputHandlers, string.Empty);
return true; return true;
} case GlobalAction.ToggleToolbar:
break;
case Key.T:
Toolbar.ToggleVisibility(); Toolbar.ToggleVisibility();
return true; return true;
case Key.O: case GlobalAction.ToggleSettings:
settings.ToggleVisibility(); settings.ToggleVisibility();
return true; return true;
case Key.D: case GlobalAction.ToggleDirect:
if (state.Keyboard.ShiftPressed || state.Keyboard.AltPressed)
return false;
direct.ToggleVisibility(); direct.ToggleVisibility();
return true; return true;
} }
}
return false; return false;
} }
public bool OnReleased(GlobalAction action) => false;
public event Action<Screen> ScreenChanged; public event Action<Screen> ScreenChanged;
private Container mainContent; private Container mainContent;

View File

@ -20,6 +20,7 @@ using SQLite.Net;
using osu.Framework.Graphics.Performance; using osu.Framework.Graphics.Performance;
using osu.Game.Database; using osu.Game.Database;
using osu.Game.Input; using osu.Game.Input;
using osu.Game.Input.Bindings;
using osu.Game.IO; using osu.Game.IO;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -38,7 +39,7 @@ namespace osu.Game
protected ScoreStore ScoreStore; protected ScoreStore ScoreStore;
protected BindingStore BindingStore; protected KeyBindingStore KeyBindingStore;
protected override string MainResourceFile => @"osu.Game.Resources.dll"; protected override string MainResourceFile => @"osu.Game.Resources.dll";
@ -107,7 +108,7 @@ namespace osu.Game
dependencies.Cache(FileStore = new FileStore(connection, Host.Storage)); dependencies.Cache(FileStore = new FileStore(connection, Host.Storage));
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, connection, RulesetStore, Host)); dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, connection, RulesetStore, Host));
dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, connection, Host, BeatmapManager)); dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, connection, Host, BeatmapManager));
dependencies.Cache(BindingStore = new BindingStore(connection)); dependencies.Cache(KeyBindingStore = new KeyBindingStore(connection, RulesetStore));
dependencies.Cache(new OsuColour()); dependencies.Cache(new OsuColour());
//this completely overrides the framework default. will need to change once we make a proper FontStore. //this completely overrides the framework default. will need to change once we make a proper FontStore.
@ -182,22 +183,28 @@ namespace osu.Game
{ {
base.LoadComplete(); base.LoadComplete();
GlobalKeyBindingInputManager globalBinding;
base.Content.Add(new RatioAdjust base.Content.Add(new RatioAdjust
{ {
Children = new Drawable[] Children = new Drawable[]
{ {
Cursor = new MenuCursor(), Cursor = new MenuCursor(),
new OsuTooltipContainer(Cursor) globalBinding = new GlobalKeyBindingInputManager(this)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = content = new OsuContextMenuContainer Child = new OsuTooltipContainer(Cursor)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}, Child = content = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both },
}
} }
} }
}); });
KeyBindingStore.Register(globalBinding);
dependencies.Cache(globalBinding);
// TODO: This is temporary until we reimplement the local FPS display. // TODO: This is temporary until we reimplement the local FPS display.
// It's just to allow end-users to access the framework FPS display without knowing the shortcut key. // It's just to allow end-users to access the framework FPS display without knowing the shortcut key.
fpsDisplayVisible = LocalConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay); fpsDisplayVisible = LocalConfig.GetBindable<bool>(OsuSetting.ShowFpsDisplay);

View File

@ -152,7 +152,7 @@ namespace osu.Game.Overlays.Chat
protected override void OnFocus(InputState state) protected override void OnFocus(InputState state)
{ {
InputManager.ChangeFocus(search); GetContainingInputManager().ChangeFocus(search);
base.OnFocus(state); base.OnFocus(state);
} }

View File

@ -243,7 +243,7 @@ namespace osu.Game.Overlays
protected override void OnFocus(InputState state) protected override void OnFocus(InputState state)
{ {
//this is necessary as inputTextBox is masked away and therefore can't get focus :( //this is necessary as inputTextBox is masked away and therefore can't get focus :(
InputManager.ChangeFocus(inputTextBox); GetContainingInputManager().ChangeFocus(inputTextBox);
base.OnFocus(state); base.OnFocus(state);
} }

View File

@ -0,0 +1,23 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input.Bindings;
using osu.Game.Graphics;
namespace osu.Game.Overlays.KeyBinding
{
public class GlobalKeyBindingsSection : KeyBindingsSection
{
private readonly string name;
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nofail;
public override string Header => name;
public GlobalKeyBindingsSection(KeyBindingInputManager manager, string name)
{
this.name = name;
Defaults = manager.DefaultKeyBindings;
}
}
}

View File

@ -0,0 +1,306 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Input;
using OpenTK.Graphics;
using OpenTK.Input;
namespace osu.Game.Overlays.KeyBinding
{
internal class KeyBindingRow : Container, IFilterable
{
private readonly Enum action;
private readonly IEnumerable<Framework.Input.Bindings.KeyBinding> bindings;
private const float transition_time = 150;
private const float height = 20;
private const float padding = 5;
private bool matchingFilter;
public bool MatchingFilter
{
get { return matchingFilter; }
set
{
matchingFilter = value;
this.FadeTo(!matchingFilter ? 0 : 1);
}
}
private OsuSpriteText text;
private OsuSpriteText pressAKey;
private FillFlowContainer<KeyButton> buttons;
public string[] FilterTerms => new[] { text.Text }.Concat(bindings.Select(b => b.KeyCombination.ReadableString())).ToArray();
public KeyBindingRow(Enum action, IEnumerable<Framework.Input.Bindings.KeyBinding> bindings)
{
this.action = action;
this.bindings = bindings;
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Masking = true;
CornerRadius = padding;
}
private KeyBindingStore store;
[BackgroundDependencyLoader]
private void load(OsuColour colours, KeyBindingStore store)
{
this.store = store;
EdgeEffect = new EdgeEffectParameters
{
Radius = 2,
Colour = colours.YellowDark.Opacity(0),
Type = EdgeEffectType.Shadow,
Hollow = true,
};
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = 0.6f,
},
text = new OsuSpriteText
{
Text = action.GetDescription(),
Margin = new MarginPadding(padding),
},
buttons = new FillFlowContainer<KeyButton>
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight
},
pressAKey = new OsuSpriteText
{
Text = "Press a key to change binding, DEL to delete, ESC to cancel.",
Y = height,
Margin = new MarginPadding(padding),
Alpha = 0,
Colour = colours.YellowDark
}
};
foreach (var b in bindings)
buttons.Add(new KeyButton(b));
}
protected override bool OnHover(InputState state)
{
this.FadeEdgeEffectTo<Container>(1, transition_time, Easing.OutQuint);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
this.FadeEdgeEffectTo<Container>(0, transition_time, Easing.OutQuint);
base.OnHoverLost(state);
}
public override bool AcceptsFocus => true;
private KeyButton bindTarget;
protected override void OnFocus(InputState state)
{
AutoSizeDuration = 500;
AutoSizeEasing = Easing.OutQuint;
pressAKey.FadeIn(300, Easing.OutQuint);
pressAKey.Padding = new MarginPadding();
base.OnFocus(state);
}
private bool isModifier(Key k) => k < Key.F1;
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
switch (args.Key)
{
case Key.Escape:
GetContainingInputManager().ChangeFocus(null);
return true;
case Key.Delete:
bindTarget.UpdateKeyCombination(Key.Unknown);
store.Update(bindTarget.KeyBinding);
GetContainingInputManager().ChangeFocus(null);
return true;
}
if (HasFocus)
{
bindTarget.UpdateKeyCombination(state.Keyboard.Keys.ToArray());
if (!isModifier(args.Key))
finalise();
return true;
}
return base.OnKeyDown(state, args);
}
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args)
{
if (HasFocus)
{
finalise();
return true;
}
return base.OnKeyUp(state, args);
}
private void finalise()
{
store.Update(bindTarget.KeyBinding);
GetContainingInputManager().ChangeFocus(null);
}
protected override void OnFocusLost(InputState state)
{
bindTarget.IsBinding = false;
bindTarget = null;
pressAKey.FadeOut(300, Easing.OutQuint);
pressAKey.Padding = new MarginPadding { Bottom = -pressAKey.DrawHeight };
base.OnFocusLost(state);
}
protected override bool OnClick(InputState state)
{
if (bindTarget != null) bindTarget.IsBinding = false;
bindTarget = buttons.FirstOrDefault(b => b.IsHovered) ?? buttons.FirstOrDefault();
if (bindTarget != null) bindTarget.IsBinding = true;
return bindTarget != null;
}
private class KeyButton : Container
{
public readonly Framework.Input.Bindings.KeyBinding KeyBinding;
private readonly Box box;
public readonly OsuSpriteText Text;
private Color4 hoverColour;
private bool isBinding;
public bool IsBinding
{
get { return isBinding; }
set
{
if (value == isBinding) return;
isBinding = value;
updateHoverState();
}
}
public KeyButton(Framework.Input.Bindings.KeyBinding keyBinding)
{
KeyBinding = keyBinding;
Margin = new MarginPadding(padding);
// todo: use this in a meaningful way
// var isDefault = keyBinding.Action is Enum;
Masking = true;
CornerRadius = padding;
Height = height;
AutoSizeAxes = Axes.X;
Children = new Drawable[]
{
new Container
{
AlwaysPresent = true,
Width = 80,
Height = height,
},
box = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black
},
Text = new OsuSpriteText
{
Font = "Venera",
TextSize = 10,
Margin = new MarginPadding(5),
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = keyBinding.KeyCombination.ReadableString(),
},
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
hoverColour = colours.YellowDark;
}
protected override bool OnHover(InputState state)
{
updateHoverState();
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
updateHoverState();
base.OnHoverLost(state);
}
private void updateHoverState()
{
if (isBinding)
{
box.FadeColour(Color4.White, transition_time, Easing.OutQuint);
Text.FadeColour(Color4.Black, transition_time, Easing.OutQuint);
}
else
{
box.FadeColour(IsHovered ? hoverColour : Color4.Black, transition_time, Easing.OutQuint);
Text.FadeColour(IsHovered ? Color4.Black : Color4.White, transition_time, Easing.OutQuint);
}
}
public void UpdateKeyCombination(params Key[] newCombination)
{
KeyBinding.KeyCombination = newCombination;
Text.Text = KeyBinding.KeyCombination.ReadableString();
}
}
}
}

View File

@ -0,0 +1,46 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Game.Input;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets;
using OpenTK;
namespace osu.Game.Overlays.KeyBinding
{
public abstract class KeyBindingsSection : SettingsSection
{
protected IEnumerable<Framework.Input.Bindings.KeyBinding> Defaults;
protected RulesetInfo Ruleset;
protected KeyBindingsSection()
{
FlowContent.Spacing = new Vector2(0, 1);
}
[BackgroundDependencyLoader]
private void load(KeyBindingStore store)
{
var enumType = Defaults?.FirstOrDefault()?.Action?.GetType();
if (enumType == null) return;
// for now let's just assume a variant of zero.
// this will need to be implemented in a better way in the future.
int? variant = null;
if (Ruleset != null)
variant = 0;
var bindings = store.Query(Ruleset?.ID, variant);
foreach (Enum v in Enum.GetValues(enumType))
// one row per valid action.
Add(new KeyBindingRow(v, bindings.Where(b => b.Action.Equals((int)(object)v))));
}
}
}

View File

@ -0,0 +1,21 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Graphics;
using osu.Game.Rulesets;
namespace osu.Game.Overlays.KeyBinding
{
public class RulesetBindingsSection : KeyBindingsSection
{
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nofail;
public override string Header => Ruleset.Name;
public RulesetBindingsSection(RulesetInfo ruleset)
{
Ruleset = ruleset;
Defaults = ruleset.CreateInstance().GetDefaultKeyBindings();
}
}
}

View File

@ -0,0 +1,31 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Game.Input.Bindings;
using osu.Game.Overlays.KeyBinding;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets;
namespace osu.Game.Overlays
{
public class KeyBindingOverlay : SettingsOverlay
{
protected override Drawable CreateHeader() => new SettingsHeader("key configuration", "Customise your keys!");
[BackgroundDependencyLoader(permitNulls: true)]
private void load(RulesetStore rulesets, GlobalKeyBindingInputManager global)
{
AddSection(new GlobalKeyBindingsSection(global, "Global"));
foreach (var ruleset in rulesets.Query<RulesetInfo>())
AddSection(new RulesetBindingsSection(ruleset));
}
public KeyBindingOverlay()
: base(false)
{
}
}
}

View File

@ -69,7 +69,7 @@ namespace osu.Game.Overlays
settingsSection.Bounding = true; settingsSection.Bounding = true;
this.FadeIn(transition_time, Easing.OutQuint); this.FadeIn(transition_time, Easing.OutQuint);
InputManager.ChangeFocus(settingsSection); GetContainingInputManager().ChangeFocus(settingsSection);
} }
protected override void PopOut() protected override void PopOut()

View File

@ -0,0 +1,151 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays.Settings;
using osu.Game.Overlays.Settings.Sections;
using osu.Game.Screens.Ranking;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Overlays
{
public class MainSettings : SettingsOverlay
{
private readonly KeyBindingOverlay keyBindingOverlay;
private BackButton backButton;
protected override IEnumerable<SettingsSection> CreateSections() => new SettingsSection[]
{
new GeneralSection(),
new GraphicsSection(),
new GameplaySection(),
new AudioSection(),
new SkinSection(),
new InputSection(keyBindingOverlay),
new OnlineSection(),
new MaintenanceSection(),
new DebugSection(),
};
protected override Drawable CreateHeader() => new SettingsHeader("settings", "Change the way osu! behaves");
protected override Drawable CreateFooter() => new SettingsFooter();
public MainSettings()
: base(true)
{
keyBindingOverlay = new KeyBindingOverlay
{
Depth = 1,
Anchor = Anchor.TopRight,
};
keyBindingOverlay.StateChanged += keyBindingOverlay_StateChanged;
}
public override bool AcceptsFocus => keyBindingOverlay.State != Visibility.Visible;
private const float hidden_width = 120;
private void keyBindingOverlay_StateChanged(VisibilityContainer container, Visibility visibility)
{
switch (visibility)
{
case Visibility.Visible:
Background.FadeTo(0.9f, 300, Easing.OutQuint);
Sidebar?.FadeColour(Color4.DarkGray, 300, Easing.OutQuint);
SectionsContainer.FadeOut(300, Easing.OutQuint);
ContentContainer.MoveToX(hidden_width - WIDTH, 500, Easing.OutQuint);
backButton.Delay(100).FadeIn(100);
break;
case Visibility.Hidden:
Background.FadeTo(0.6f, 500, Easing.OutQuint);
Sidebar?.FadeColour(Color4.White, 300, Easing.OutQuint);
SectionsContainer.FadeIn(500, Easing.OutQuint);
ContentContainer.MoveToX(0, 500, Easing.OutQuint);
backButton.FadeOut(100);
break;
}
}
protected override float ExpandedPosition => keyBindingOverlay.State == Visibility.Visible ? hidden_width - WIDTH : base.ExpandedPosition;
[BackgroundDependencyLoader]
private void load()
{
ContentContainer.Add(keyBindingOverlay);
ContentContainer.Add(backButton = new BackButton
{
Alpha = 0,
Width = hidden_width,
RelativeSizeAxes = Axes.Y,
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Action = () => keyBindingOverlay.Hide()
});
}
private class BackButton : OsuClickableContainer
{
private AspectContainer aspect;
[BackgroundDependencyLoader]
private void load()
{
Children = new Drawable[]
{
aspect = new AspectContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Children = new Drawable[]
{
new SpriteIcon
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Y = -15,
Size = new Vector2(15),
Shadow = true,
Icon = FontAwesome.fa_chevron_left
},
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Y = 15,
TextSize = 12,
Font = @"Exo2.0-Bold",
Text = @"back",
},
}
}
};
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
aspect.ScaleTo(0.75f, 2000, Easing.OutQuint);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
aspect.ScaleTo(1, 1000, Easing.OutElastic);
return base.OnMouseUp(state, args);
}
}
}
}

View File

@ -6,7 +6,6 @@ using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Input;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -31,12 +30,10 @@ namespace osu.Game.Overlays.Music
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>(); private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
public IEnumerable<BeatmapSetInfo> BeatmapSets; public IEnumerable<BeatmapSetInfo> BeatmapSets;
private InputManager inputManager;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuGameBase game, BeatmapManager beatmaps, OsuColour colours, UserInputManager inputManager) private void load(OsuGameBase game, BeatmapManager beatmaps, OsuColour colours)
{ {
this.inputManager = inputManager;
this.beatmaps = beatmaps; this.beatmaps = beatmaps;
Children = new Drawable[] Children = new Drawable[]
@ -102,7 +99,7 @@ namespace osu.Game.Overlays.Music
protected override void PopIn() protected override void PopIn()
{ {
filter.Search.HoldFocus = true; filter.Search.HoldFocus = true;
Schedule(() => inputManager.ChangeFocus(filter.Search)); Schedule(() => GetContainingInputManager().ChangeFocus(filter.Search));
this.ResizeTo(new Vector2(1, playlist_height), transition_duration, Easing.OutQuint); this.ResizeTo(new Vector2(1, playlist_height), transition_duration, Easing.OutQuint);
this.FadeIn(transition_duration, Easing.OutQuint); this.FadeIn(transition_duration, Easing.OutQuint);

View File

@ -258,7 +258,10 @@ namespace osu.Game.Overlays
Type = EdgeEffectType.Glow, Type = EdgeEffectType.Glow,
Radius = 8, Radius = 8,
}; };
}
protected override void LoadComplete()
{
updateGlow(); updateGlow();
FinishTransforms(true); FinishTransforms(true);
} }

View File

@ -103,7 +103,7 @@ namespace osu.Game.Overlays.SearchableList
protected override void OnFocus(InputState state) protected override void OnFocus(InputState state)
{ {
InputManager.ChangeFocus(Filter.Search); GetContainingInputManager().ChangeFocus(Filter.Search);
} }
protected override void PopIn() protected override void PopIn()

View File

@ -26,9 +26,12 @@ namespace osu.Game.Overlays.Settings.Sections.Audio
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
if (audio != null)
{
audio.OnNewDevice -= onDeviceChanged; audio.OnNewDevice -= onDeviceChanged;
audio.OnLostDevice -= onDeviceChanged; audio.OnLostDevice -= onDeviceChanged;
} }
}
private void updateItems() private void updateItems()
{ {

View File

@ -57,12 +57,9 @@ namespace osu.Game.Overlays.Settings.Sections.General
Spacing = new Vector2(0f, 5f); Spacing = new Vector2(0f, 5f);
} }
private InputManager inputManager;
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours, APIAccess api, UserInputManager inputManager) private void load(OsuColour colours, APIAccess api)
{ {
this.inputManager = inputManager;
this.colours = colours; this.colours = colours;
api?.Register(this); api?.Register(this);
@ -174,7 +171,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
break; break;
} }
if (form != null) inputManager.ChangeFocus(form); if (form != null) GetContainingInputManager()?.ChangeFocus(form);
} }
public override bool AcceptsFocus => true; public override bool AcceptsFocus => true;
@ -183,7 +180,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
protected override void OnFocus(InputState state) protected override void OnFocus(InputState state)
{ {
if (form != null) inputManager.ChangeFocus(form); if (form != null) GetContainingInputManager().ChangeFocus(form);
base.OnFocus(state); base.OnFocus(state);
} }
@ -192,7 +189,6 @@ namespace osu.Game.Overlays.Settings.Sections.General
private TextBox username; private TextBox username;
private TextBox password; private TextBox password;
private APIAccess api; private APIAccess api;
private InputManager inputManager;
private void performLogin() private void performLogin()
{ {
@ -201,9 +197,8 @@ namespace osu.Game.Overlays.Settings.Sections.General
} }
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(APIAccess api, OsuConfigManager config, UserInputManager inputManager) private void load(APIAccess api, OsuConfigManager config)
{ {
this.inputManager = inputManager;
this.api = api; this.api = api;
Direction = FillDirection.Vertical; Direction = FillDirection.Vertical;
Spacing = new Vector2(0, 5); Spacing = new Vector2(0, 5);
@ -256,7 +251,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
protected override void OnFocus(InputState state) protected override void OnFocus(InputState state)
{ {
Schedule(() => { inputManager.ChangeFocus(string.IsNullOrEmpty(username.Text) ? username : password); }); Schedule(() => { GetContainingInputManager().ChangeFocus(string.IsNullOrEmpty(username.Text) ? username : password); });
} }
} }

View File

@ -10,14 +10,15 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{ {
protected override string Header => "Keyboard"; protected override string Header => "Keyboard";
public KeyboardSettings() public KeyboardSettings(KeyBindingOverlay keyConfig)
{ {
Children = new Drawable[] Children = new Drawable[]
{ {
new OsuButton new OsuButton
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Text = "Key Configuration" Text = "Key Configuration",
Action = () => keyConfig.ToggleVisibility()
}, },
}; };
} }

View File

@ -12,12 +12,12 @@ namespace osu.Game.Overlays.Settings.Sections
public override string Header => "Input"; public override string Header => "Input";
public override FontAwesome Icon => FontAwesome.fa_keyboard_o; public override FontAwesome Icon => FontAwesome.fa_keyboard_o;
public InputSection() public InputSection(KeyBindingOverlay keyConfig)
{ {
Children = new Drawable[] Children = new Drawable[]
{ {
new MouseSettings(), new MouseSettings(),
new KeyboardSettings(), new KeyboardSettings(keyConfig),
}; };
} }
} }

View File

@ -11,6 +11,15 @@ namespace osu.Game.Overlays.Settings
{ {
public class SettingsHeader : Container public class SettingsHeader : Container
{ {
private readonly string heading;
private readonly string subheading;
public SettingsHeader(string heading, string subheading)
{
this.heading = heading;
this.subheading = subheading;
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
@ -28,7 +37,7 @@ namespace osu.Game.Overlays.Settings
{ {
new OsuSpriteText new OsuSpriteText
{ {
Text = "settings", Text = heading,
TextSize = 40, TextSize = 40,
Margin = new MarginPadding Margin = new MarginPadding
{ {
@ -39,7 +48,7 @@ namespace osu.Game.Overlays.Settings
new OsuSpriteText new OsuSpriteText
{ {
Colour = colours.Pink, Colour = colours.Pink,
Text = "Change the way osu! behaves", Text = subheading,
TextSize = 18, TextSize = 18,
Margin = new MarginPadding Margin = new MarginPadding
{ {

View File

@ -7,7 +7,6 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using System.Collections.Generic; using System.Collections.Generic;
@ -25,15 +24,15 @@ namespace osu.Game.Overlays.Settings
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>(); public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
public string[] FilterTerms => new[] { Header }; public string[] FilterTerms => new[] { Header };
private const int header_size = 26;
private const int header_margin = 25;
private const int border_size = 2;
public bool MatchingFilter public bool MatchingFilter
{ {
set set { this.FadeTo(value ? 1 : 0); }
{
this.FadeTo(value ? 1 : 0);
} }
}
private readonly SpriteText headerLabel;
protected SettingsSection() protected SettingsSection()
{ {
@ -41,9 +40,22 @@ namespace osu.Game.Overlays.Settings
AutoSizeAxes = Axes.Y; AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
const int header_size = 26; FlowContent = new FillFlowContainer
const int header_margin = 25; {
const int border_size = 2; Margin = new MarginPadding
{
Top = header_size + header_margin
},
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 30),
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AddRangeInternal(new Drawable[] AddRangeInternal(new Drawable[]
{ {
new Box new Box
@ -65,28 +77,16 @@ namespace osu.Game.Overlays.Settings
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Children = new[] Children = new[]
{ {
headerLabel = new OsuSpriteText new OsuSpriteText
{ {
TextSize = header_size, TextSize = header_size,
Text = Header, Text = Header,
Colour = colours.Yellow
}, },
FlowContent = new FillFlowContainer FlowContent
{
Margin = new MarginPadding { Top = header_size + header_margin },
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 30),
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
},
} }
}, },
}); });
} }
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
headerLabel.Colour = colours.Yellow;
}
} }
} }

View File

@ -14,12 +14,12 @@ using osu.Game.Overlays.Toolbar;
namespace osu.Game.Overlays.Settings namespace osu.Game.Overlays.Settings
{ {
public class Sidebar : Container, IStateful<ExpandedState> public class Sidebar : Container<SidebarButton>, IStateful<ExpandedState>
{ {
private readonly FillFlowContainer content; private readonly FillFlowContainer<SidebarButton> content;
internal const float DEFAULT_WIDTH = ToolbarButton.WIDTH; internal const float DEFAULT_WIDTH = ToolbarButton.WIDTH;
internal const int EXPANDED_WIDTH = 200; internal const int EXPANDED_WIDTH = 200;
protected override Container<Drawable> Content => content; protected override Container<SidebarButton> Content => content;
public Sidebar() public Sidebar()
{ {
@ -35,7 +35,7 @@ namespace osu.Game.Overlays.Settings
{ {
Children = new[] Children = new[]
{ {
content = new FillFlowContainer content = new FillFlowContainer<SidebarButton>
{ {
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
@ -87,6 +87,8 @@ namespace osu.Game.Overlays.Settings
get { return state; } get { return state; }
set set
{ {
expandEvent?.Cancel();
if (state == value) return; if (state == value) return;
state = value; state = value;

View File

@ -2,9 +2,12 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -12,11 +15,10 @@ using osu.Framework.Input;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings;
using osu.Game.Overlays.Settings.Sections;
namespace osu.Game.Overlays namespace osu.Game.Overlays
{ {
public class SettingsOverlay : OsuFocusedOverlayContainer public abstract class SettingsOverlay : OsuFocusedOverlayContainer
{ {
internal const float CONTENT_MARGINS = 10; internal const float CONTENT_MARGINS = 10;
@ -24,55 +26,61 @@ namespace osu.Game.Overlays
public const float SIDEBAR_WIDTH = Sidebar.DEFAULT_WIDTH; public const float SIDEBAR_WIDTH = Sidebar.DEFAULT_WIDTH;
private const float width = 400; protected const float WIDTH = 400;
private const float sidebar_padding = 10; private const float sidebar_padding = 10;
private Sidebar sidebar; protected Container<Drawable> ContentContainer;
private SidebarButton[] sidebarButtons;
protected override Container<Drawable> Content => ContentContainer;
protected Sidebar Sidebar;
private SidebarButton selectedSidebarButton; private SidebarButton selectedSidebarButton;
private SettingsSectionsContainer sectionsContainer; protected SettingsSectionsContainer SectionsContainer;
private SearchTextBox searchTextBox; private SearchTextBox searchTextBox;
private Func<float> getToolbarHeight; /// <summary>
/// Provide a source for the toolbar height.
/// </summary>
public Func<float> GetToolbarHeight;
public SettingsOverlay() private readonly bool showSidebar;
protected Box Background;
protected SettingsOverlay(bool showSidebar)
{ {
this.showSidebar = showSidebar;
RelativeSizeAxes = Axes.Y; RelativeSizeAxes = Axes.Y;
AutoSizeAxes = Axes.X; AutoSizeAxes = Axes.X;
} }
[BackgroundDependencyLoader(permitNulls: true)] protected virtual IEnumerable<SettingsSection> CreateSections() => null;
private void load(OsuGame game)
[BackgroundDependencyLoader]
private void load()
{ {
var sections = new SettingsSection[] InternalChild = ContentContainer = new Container
{ {
new GeneralSection(), Width = WIDTH,
new GraphicsSection(), RelativeSizeAxes = Axes.Y,
new GameplaySection(),
new AudioSection(),
new SkinSection(),
new InputSection(),
new OnlineSection(),
new MaintenanceSection(),
new DebugSection(),
};
Children = new Drawable[] Children = new Drawable[]
{ {
new Box Background = new Box
{ {
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Scale = new Vector2(2, 1), // over-extend to the left for transitions
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.Black, Colour = Color4.Black,
Alpha = 0.6f, Alpha = 0.6f,
}, },
sectionsContainer = new SettingsSectionsContainer SectionsContainer = new SettingsSectionsContainer
{ {
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Both,
Width = width, ExpandableHeader = CreateHeader(),
Margin = new MarginPadding { Left = SIDEBAR_WIDTH },
ExpandableHeader = new SettingsHeader(),
FixedHeader = searchTextBox = new SearchTextBox FixedHeader = searchTextBox = new SearchTextBox
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
@ -86,63 +94,84 @@ namespace osu.Game.Overlays
}, },
Exit = Hide, Exit = Hide,
}, },
Children = sections, Footer = CreateFooter()
Footer = new SettingsFooter()
}, },
sidebar = new Sidebar }
};
if (showSidebar)
{ {
Width = SIDEBAR_WIDTH, AddInternal(Sidebar = new Sidebar { Width = SIDEBAR_WIDTH });
Children = sidebarButtons = sections.Select(section =>
new SidebarButton SectionsContainer.SelectedSection.ValueChanged += section =>
{
selectedSidebarButton.Selected = false;
selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section);
selectedSidebarButton.Selected = true;
};
}
searchTextBox.Current.ValueChanged += newValue => SectionsContainer.SearchContainer.SearchTerm = newValue;
CreateSections()?.ForEach(AddSection);
}
protected void AddSection(SettingsSection section)
{
SectionsContainer.Add(section);
if (Sidebar != null)
{
var button = new SidebarButton
{ {
Section = section, Section = section,
Action = s => Action = s =>
{ {
sectionsContainer.ScrollTo(s); SectionsContainer.ScrollTo(s);
sidebar.State = ExpandedState.Contracted; Sidebar.State = ExpandedState.Contracted;
}, },
}
).ToArray()
}
}; };
selectedSidebarButton = sidebarButtons[0]; Sidebar.Add(button);
selectedSidebarButton.Selected = true;
sectionsContainer.SelectedSection.ValueChanged += section => if (selectedSidebarButton == null)
{ {
selectedSidebarButton.Selected = false; selectedSidebarButton = Sidebar.Children.First();
selectedSidebarButton = sidebarButtons.Single(b => b.Section == section);
selectedSidebarButton.Selected = true; selectedSidebarButton.Selected = true;
};
searchTextBox.Current.ValueChanged += newValue => sectionsContainer.SearchContainer.SearchTerm = newValue;
getToolbarHeight = () => game?.ToolbarOffset ?? 0;
} }
}
}
protected virtual Drawable CreateHeader() => new Container();
protected virtual Drawable CreateFooter() => new Container();
protected override void PopIn() protected override void PopIn()
{ {
base.PopIn(); base.PopIn();
sectionsContainer.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint); ContentContainer.MoveToX(ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint);
sidebar.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint);
this.FadeTo(1, TRANSITION_LENGTH / 2); Sidebar?.MoveToX(0, TRANSITION_LENGTH, Easing.OutQuint);
this.FadeTo(1, TRANSITION_LENGTH, Easing.OutQuint);
searchTextBox.HoldFocus = true; searchTextBox.HoldFocus = true;
} }
protected virtual float ExpandedPosition => 0;
protected override void PopOut() protected override void PopOut()
{ {
base.PopOut(); base.PopOut();
sectionsContainer.MoveToX(-width, TRANSITION_LENGTH, Easing.OutQuint); ContentContainer.MoveToX(-WIDTH, TRANSITION_LENGTH, Easing.OutQuint);
sidebar.MoveToX(-SIDEBAR_WIDTH, TRANSITION_LENGTH, Easing.OutQuint);
this.FadeTo(0, TRANSITION_LENGTH / 2); Sidebar?.MoveToX(-SIDEBAR_WIDTH, TRANSITION_LENGTH, Easing.OutQuint);
this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint);
searchTextBox.HoldFocus = false; searchTextBox.HoldFocus = false;
if (searchTextBox.HasFocus) if (searchTextBox.HasFocus)
InputManager.ChangeFocus(null); GetContainingInputManager().ChangeFocus(null);
} }
public override bool AcceptsFocus => true; public override bool AcceptsFocus => true;
@ -151,7 +180,7 @@ namespace osu.Game.Overlays
protected override void OnFocus(InputState state) protected override void OnFocus(InputState state)
{ {
InputManager.ChangeFocus(searchTextBox); GetContainingInputManager().ChangeFocus(searchTextBox);
base.OnFocus(state); base.OnFocus(state);
} }
@ -159,11 +188,11 @@ namespace osu.Game.Overlays
{ {
base.UpdateAfterChildren(); base.UpdateAfterChildren();
sectionsContainer.Margin = new MarginPadding { Left = sidebar.DrawWidth }; ContentContainer.Margin = new MarginPadding { Left = Sidebar?.DrawWidth ?? 0 };
sectionsContainer.Padding = new MarginPadding { Top = getToolbarHeight() }; ContentContainer.Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
} }
private class SettingsSectionsContainer : SectionsContainer<SettingsSection> protected class SettingsSectionsContainer : SectionsContainer<SettingsSection>
{ {
public SearchContainer<SettingsSection> SearchContainer; public SearchContainer<SettingsSection> SearchContainer;

View File

@ -22,8 +22,6 @@ namespace osu.Game.Overlays.Toolbar
private readonly ToolbarUserArea userArea; private readonly ToolbarUserArea userArea;
protected override bool HideOnEscape => false;
protected override bool BlockPassThroughMouse => false; protected override bool BlockPassThroughMouse => false;
private const double transition_time = 500; private const double transition_time = 500;
@ -60,8 +58,8 @@ namespace osu.Game.Overlays.Toolbar
AutoSizeAxes = Axes.X, AutoSizeAxes = Axes.X,
Children = new Drawable[] Children = new Drawable[]
{ {
new ToolbarSocialButton(),
new ToolbarChatButton(), new ToolbarChatButton(),
new ToolbarSocialButton(),
new ToolbarMusicButton(), new ToolbarMusicButton(),
new ToolbarButton new ToolbarButton
{ {

View File

@ -18,8 +18,11 @@ namespace osu.Game.Rulesets.Objects.Legacy
internal abstract class ConvertHitObjectParser : HitObjectParser internal abstract class ConvertHitObjectParser : HitObjectParser
{ {
public override HitObject Parse(string text) public override HitObject Parse(string text)
{
try
{ {
string[] split = text.Split(','); string[] split = text.Split(',');
ConvertHitObjectType type = (ConvertHitObjectType)int.Parse(split[3]) & ~ConvertHitObjectType.ColourHax; ConvertHitObjectType type = (ConvertHitObjectType)int.Parse(split[3]) & ~ConvertHitObjectType.ColourHax;
bool combo = type.HasFlag(ConvertHitObjectType.NewCombo); bool combo = type.HasFlag(ConvertHitObjectType.NewCombo);
type &= ~ConvertHitObjectType.NewCombo; type &= ~ConvertHitObjectType.NewCombo;
@ -161,6 +164,11 @@ namespace osu.Game.Rulesets.Objects.Legacy
return result; return result;
} }
catch (FormatException)
{
throw new FormatException("One or more hit objects were malformed.");
}
}
private void readCustomSampleBanks(string str, SampleBankInfo bankInfo) private void readCustomSampleBanks(string str, SampleBankInfo bankInfo)
{ {

View File

@ -8,6 +8,7 @@ using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings;
@ -53,5 +54,17 @@ namespace osu.Game.Rulesets
/// Do not override this unless you are a legacy mode. /// Do not override this unless you are a legacy mode.
/// </summary> /// </summary>
public virtual int LegacyID => -1; public virtual int LegacyID => -1;
/// <summary>
/// A list of available variant ids.
/// </summary>
public virtual IEnumerable<int> AvailableVariants => new[] { 0 };
/// <summary>
/// Get a list of default keys for the specified variant.
/// </summary>
/// <param name="variant">A variant.</param>
/// <returns>A list of valid <see cref="KeyBinding"/>s.</returns>
public virtual IEnumerable<KeyBinding> GetDefaultKeyBindings(int variant = 0) => new KeyBinding[] { };
} }
} }

View File

@ -6,7 +6,7 @@ using SQLite.Net.Attributes;
namespace osu.Game.Rulesets namespace osu.Game.Rulesets
{ {
public class RulesetInfo public class RulesetInfo : IEquatable<RulesetInfo>
{ {
[PrimaryKey, AutoIncrement] [PrimaryKey, AutoIncrement]
public int? ID { get; set; } public int? ID { get; set; }
@ -21,5 +21,7 @@ namespace osu.Game.Rulesets
public bool Available { get; set; } public bool Available { get; set; }
public virtual Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo), this); public virtual Ruleset CreateInstance() => (Ruleset)Activator.CreateInstance(Type.GetType(InstantiationInfo), this);
public bool Equals(RulesetInfo other) => other != null && ID == other.ID && Available == other.Available && Name == other.Name && InstantiationInfo == other.InstantiationInfo;
} }
} }

View File

@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.UI
internal RulesetContainer(Ruleset ruleset) internal RulesetContainer(Ruleset ruleset)
{ {
Ruleset = ruleset; Ruleset = ruleset;
KeyConversionInputManager = CreateActionMappingInputManager(); KeyConversionInputManager = CreateKeyBindingInputManager();
KeyConversionInputManager.RelativeSizeAxes = Axes.Both; KeyConversionInputManager.RelativeSizeAxes = Axes.Both;
} }
@ -95,7 +95,7 @@ namespace osu.Game.Rulesets.UI
/// Creates a key conversion input manager. /// Creates a key conversion input manager.
/// </summary> /// </summary>
/// <returns>The input manager.</returns> /// <returns>The input manager.</returns>
protected virtual PassThroughInputManager CreateActionMappingInputManager() => new PassThroughInputManager(); public virtual PassThroughInputManager CreateKeyBindingInputManager() => new PassThroughInputManager();
protected virtual FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new FramedReplayInputHandler(replay); protected virtual FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new FramedReplayInputHandler(replay);

View File

@ -37,7 +37,7 @@ namespace osu.Game.Screens
} }
// Make sure the in-progress loading is complete before pushing the screen. // Make sure the in-progress loading is complete before pushing the screen.
while (screen.LoadState < LoadState.Loaded) while (screen.LoadState < LoadState.Ready)
Thread.Sleep(1); Thread.Sleep(1);
base.Push(screen); base.Push(screen);

View File

@ -108,7 +108,7 @@ namespace osu.Game.Screens.Play
} }
} }
public override bool HandleInput => receptor?.IsAlive != true; public override bool HandleInput => receptor == null;
private Receptor receptor; private Receptor receptor;

View File

@ -22,8 +22,6 @@ namespace osu.Game.Screens.Play
private const int button_height = 70; private const int button_height = 70;
private const float background_alpha = 0.75f; private const float background_alpha = 0.75f;
protected override bool HideOnEscape => false;
protected override bool BlockPassThroughKeyboard => true; protected override bool BlockPassThroughKeyboard => true;
public Action OnRetry; public Action OnRetry;
@ -95,7 +93,8 @@ namespace osu.Game.Screens.Play
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Height = button_height, Height = button_height,
Action = delegate { Action = delegate
{
action?.Invoke(); action?.Invoke();
Hide(); Hide();
} }

View File

@ -227,9 +227,9 @@ namespace osu.Game.Screens.Play
Direction = FillDirection.Horizontal, Direction = FillDirection.Horizontal,
Children = new[] Children = new[]
{ {
new SpriteIcon { Icon = FontAwesome.fa_chevron_right }, new SpriteIcon { Size = new Vector2(15), Shadow = true, Icon = FontAwesome.fa_chevron_right },
new SpriteIcon { Icon = FontAwesome.fa_chevron_right }, new SpriteIcon { Size = new Vector2(15), Shadow = true, Icon = FontAwesome.fa_chevron_right },
new SpriteIcon { Icon = FontAwesome.fa_chevron_right }, new SpriteIcon { Size = new Vector2(15), Shadow = true, Icon = FontAwesome.fa_chevron_right },
} }
}, },
new OsuSpriteText new OsuSpriteText

View File

@ -18,8 +18,6 @@ namespace osu.Game.Screens.Play
{ {
private const int bottom_bar_height = 5; private const int bottom_bar_height = 5;
protected override bool HideOnEscape => false;
private static readonly Vector2 handle_size = new Vector2(14, 25); private static readonly Vector2 handle_size = new Vector2(14, 25);
private const float transition_duration = 200; private const float transition_duration = 200;

View File

@ -50,8 +50,6 @@ namespace osu.Game.Screens.Select
AlwaysPresent = true; AlwaysPresent = true;
} }
protected override bool HideOnEscape => false;
protected override bool BlockPassThroughMouse => false; protected override bool BlockPassThroughMouse => false;
protected override void PopIn() protected override void PopIn()

View File

@ -153,7 +153,7 @@ namespace osu.Game.Screens.Select
{ {
searchTextBox.HoldFocus = false; searchTextBox.HoldFocus = false;
if (searchTextBox.HasFocus) if (searchTextBox.HasFocus)
inputManager.ChangeFocus(searchTextBox); GetContainingInputManager().ChangeFocus(searchTextBox);
} }
public void Activate() public void Activate()
@ -163,13 +163,9 @@ namespace osu.Game.Screens.Select
private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>(); private readonly Bindable<RulesetInfo> ruleset = new Bindable<RulesetInfo>();
private InputManager inputManager;
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(OsuColour colours, OsuGame osu, UserInputManager inputManager) private void load(OsuColour colours, OsuGame osu)
{ {
this.inputManager = inputManager;
sortTabs.AccentColour = colours.GreenLight; sortTabs.AccentColour = colours.GreenLight;
if (osu != null) if (osu != null)

View File

@ -373,6 +373,7 @@ namespace osu.Game.Screens.Select.Leaderboards
Icon = FontAwesome.fa_square, Icon = FontAwesome.fa_square,
Colour = OsuColour.FromHex(@"3087ac"), Colour = OsuColour.FromHex(@"3087ac"),
Rotation = 45, Rotation = 45,
Size = new Vector2(20),
Shadow = true, Shadow = true,
}, },
new SpriteIcon new SpriteIcon
@ -380,7 +381,7 @@ namespace osu.Game.Screens.Select.Leaderboards
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = icon, Icon = icon,
Colour = OsuColour.FromHex(@"a4edff"), Colour = OsuColour.FromHex(@"a4edff"),
Scale = new Vector2(0.8f), Size = new Vector2(14),
}, },
new GlowingSpriteText(value, @"Exo2.0-Bold", 17, Color4.White, OsuColour.FromHex(@"83ccfa")) new GlowingSpriteText(value, @"Exo2.0-Bold", 17, Color4.White, OsuColour.FromHex(@"83ccfa"))
{ {

View File

@ -86,7 +86,7 @@ namespace osu.Game.Screens.Select.Options
/// <param name="colour">Colour of the button.</param> /// <param name="colour">Colour of the button.</param>
/// <param name="icon">Icon of the button.</param> /// <param name="icon">Icon of the button.</param>
/// <param name="hotkey">Hotkey of the button.</param> /// <param name="hotkey">Hotkey of the button.</param>
/// <param name="action">Action the button does.</param> /// <param name="action">Binding the button does.</param>
/// <param name="depth"> /// <param name="depth">
/// <para>Lower depth to be put on the left, and higher to be put on the right.</para> /// <para>Lower depth to be put on the left, and higher to be put on the right.</para>
/// <para>Notice this is different to <see cref="Footer"/>!</para> /// <para>Notice this is different to <see cref="Footer"/>!</para>

View File

@ -156,11 +156,11 @@ namespace osu.Game.Screens.Select
} }
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader(permitNulls: true)]
private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours, UserInputManager input) private void load(BeatmapManager beatmaps, AudioManager audio, DialogOverlay dialog, OsuGame osu, OsuColour colours)
{ {
if (Footer != null) if (Footer != null)
{ {
Footer.AddButton(@"random", colours.Green, () => triggerRandom(input), Key.F2); Footer.AddButton(@"random", colours.Green, triggerRandom, Key.F2);
Footer.AddButton(@"options", colours.Blue, BeatmapOptions.ToggleVisibility, Key.F3); Footer.AddButton(@"options", colours.Blue, BeatmapOptions.ToggleVisibility, Key.F3);
BeatmapOptions.AddButton(@"Delete", @"Beatmap", FontAwesome.fa_trash, colours.Pink, promptDelete, Key.Number4, float.MaxValue); BeatmapOptions.AddButton(@"Delete", @"Beatmap", FontAwesome.fa_trash, colours.Pink, promptDelete, Key.Number4, float.MaxValue);
@ -253,8 +253,6 @@ namespace osu.Game.Screens.Select
} }
else else
{ {
Ruleset.Value = beatmap.Ruleset;
if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID) if (beatmap.BeatmapSetInfoID == beatmapNoDebounce?.BeatmapSetInfoID)
sampleChangeDifficulty.Play(); sampleChangeDifficulty.Play();
else else
@ -267,9 +265,9 @@ namespace osu.Game.Screens.Select
} }
} }
private void triggerRandom(UserInputManager input) private void triggerRandom()
{ {
if (input.CurrentState.Keyboard.ShiftPressed) if (GetContainingInputManager().CurrentState.Keyboard.ShiftPressed)
carousel.SelectPreviousRandom(); carousel.SelectPreviousRandom();
else else
carousel.SelectNextRandom(); carousel.SelectNextRandom();

View File

@ -92,14 +92,22 @@
<Compile Include="Graphics\UserInterface\MenuItemType.cs" /> <Compile Include="Graphics\UserInterface\MenuItemType.cs" />
<Compile Include="Graphics\UserInterface\OsuContextMenu.cs" /> <Compile Include="Graphics\UserInterface\OsuContextMenu.cs" />
<Compile Include="Graphics\UserInterface\OsuContextMenuItem.cs" /> <Compile Include="Graphics\UserInterface\OsuContextMenuItem.cs" />
<Compile Include="Input\Binding.cs" /> <Compile Include="Input\Bindings\DatabasedKeyBinding.cs" />
<Compile Include="Input\BindingStore.cs" /> <Compile Include="Input\Bindings\DatabasedKeyBindingInputManager.cs" />
<Compile Include="Input\KeyBindingStore.cs" />
<Compile Include="Input\Bindings\GlobalKeyBindingInputManager.cs" />
<Compile Include="IO\FileStore.cs" /> <Compile Include="IO\FileStore.cs" />
<Compile Include="IO\FileInfo.cs" /> <Compile Include="IO\FileInfo.cs" />
<Compile Include="Online\API\Requests\GetUsersRequest.cs" /> <Compile Include="Online\API\Requests\GetUsersRequest.cs" />
<Compile Include="Online\API\Requests\PostMessageRequest.cs" /> <Compile Include="Online\API\Requests\PostMessageRequest.cs" />
<Compile Include="Online\Chat\ErrorMessage.cs" /> <Compile Include="Online\Chat\ErrorMessage.cs" />
<Compile Include="Overlays\Chat\ChatTabControl.cs" /> <Compile Include="Overlays\Chat\ChatTabControl.cs" />
<Compile Include="Overlays\KeyBinding\GlobalKeyBindingsSection.cs" />
<Compile Include="Overlays\KeyBinding\KeyBindingRow.cs" />
<Compile Include="Overlays\KeyBinding\KeyBindingsSection.cs" />
<Compile Include="Overlays\KeyBindingOverlay.cs" />
<Compile Include="Overlays\KeyBinding\RulesetBindingsSection.cs" />
<Compile Include="Overlays\MainSettings.cs" />
<Compile Include="Overlays\Music\CollectionsDropdown.cs" /> <Compile Include="Overlays\Music\CollectionsDropdown.cs" />
<Compile Include="Overlays\Music\FilterControl.cs" /> <Compile Include="Overlays\Music\FilterControl.cs" />
<Compile Include="Overlays\Music\PlaylistItem.cs" /> <Compile Include="Overlays\Music\PlaylistItem.cs" />
@ -120,7 +128,6 @@
<Compile Include="Overlays\Profile\Sections\RecentSection.cs" /> <Compile Include="Overlays\Profile\Sections\RecentSection.cs" />
<Compile Include="Graphics\Containers\ConstrainedIconContainer.cs" /> <Compile Include="Graphics\Containers\ConstrainedIconContainer.cs" />
<Compile Include="Rulesets\Mods\IApplicableToDifficulty.cs" /> <Compile Include="Rulesets\Mods\IApplicableToDifficulty.cs" />
<Compile Include="Input\ActionMappingInputManager.cs" />
<Compile Include="Users\UserCoverBackground.cs" /> <Compile Include="Users\UserCoverBackground.cs" />
<Compile Include="Overlays\UserProfileOverlay.cs" /> <Compile Include="Overlays\UserProfileOverlay.cs" />
<Compile Include="Overlays\Profile\ProfileHeader.cs" /> <Compile Include="Overlays\Profile\ProfileHeader.cs" />
@ -142,8 +149,6 @@
<Compile Include="Rulesets\RulesetInfo.cs" /> <Compile Include="Rulesets\RulesetInfo.cs" />
<Compile Include="Rulesets\Scoring\ScoreStore.cs" /> <Compile Include="Rulesets\Scoring\ScoreStore.cs" />
<Compile Include="Graphics\Backgrounds\Triangles.cs" /> <Compile Include="Graphics\Backgrounds\Triangles.cs" />
<Compile Include="Graphics\Cursor\CursorTrail.cs" />
<Compile Include="Graphics\Cursor\GameplayCursor.cs" />
<Compile Include="Graphics\IHasAccentColour.cs" /> <Compile Include="Graphics\IHasAccentColour.cs" />
<Compile Include="Graphics\Sprites\OsuSpriteText.cs" /> <Compile Include="Graphics\Sprites\OsuSpriteText.cs" />
<Compile Include="Graphics\UserInterface\BackButton.cs" /> <Compile Include="Graphics\UserInterface\BackButton.cs" />