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

Merge remote-tracking branch 'upstream/master' into smoogipoo-legacy-custom-banks

This commit is contained in:
Dean Herbert 2018-07-05 14:53:31 +09:00
commit d11ba2df0e
55 changed files with 498 additions and 396 deletions

View File

@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
{ {
public class CatchBeatmapProcessor : BeatmapProcessor public class CatchBeatmapProcessor : BeatmapProcessor
{ {
public const int RNG_SEED = 1337;
public CatchBeatmapProcessor(IBeatmap beatmap) public CatchBeatmapProcessor(IBeatmap beatmap)
: base(beatmap) : base(beatmap)
{ {
@ -22,12 +24,12 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
public override void PostProcess() public override void PostProcess()
{ {
base.PostProcess();
applyPositionOffsets(); applyPositionOffsets();
initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects); initialiseHyperDash((List<CatchHitObject>)Beatmap.HitObjects);
base.PostProcess();
int index = 0; int index = 0;
foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>()) foreach (var obj in Beatmap.HitObjects.OfType<CatchHitObject>())
{ {
@ -37,8 +39,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
} }
} }
public const int RNG_SEED = 1337;
private void applyPositionOffsets() private void applyPositionOffsets()
{ {
var rng = new FastRandom(RNG_SEED); var rng = new FastRandom(RNG_SEED);

View File

@ -69,7 +69,7 @@ namespace osu.Game.Rulesets.Mania.Tests
var obj = new Note { Column = i, StartTime = Time.Current + 2000 }; var obj = new Note { Column = i, StartTime = Time.Current + 2000 };
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
columns[i].Add(new DrawableNote(obj, columns[i].Action)); columns[i].Add(new DrawableNote(obj));
} }
} }
@ -80,7 +80,7 @@ namespace osu.Game.Rulesets.Mania.Tests
var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 }; var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 };
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
columns[i].Add(new DrawableHoldNote(obj, columns[i].Action)); columns[i].Add(new DrawableHoldNote(obj));
} }
} }
@ -92,7 +92,7 @@ namespace osu.Game.Rulesets.Mania.Tests
Origin = Anchor.Centre, Origin = Anchor.Centre,
Height = 0.85f, Height = 0.85f,
AccentColour = Color4.OrangeRed, AccentColour = Color4.OrangeRed,
Action = action, Action = { Value = action },
VisibleTimeRange = { Value = 2000 } VisibleTimeRange = { Value = 2000 }
}; };

View File

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration;
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.Containers;
@ -63,7 +64,7 @@ namespace osu.Game.Rulesets.Mania.Tests
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}") Child = new NoteContainer(direction, $"note, scrolling {direction.ToString().ToLower()}")
{ {
Child = new DrawableNote(note, ManiaAction.Key1) { AccentColour = Color4.OrangeRed } Child = new DrawableNote(note) { AccentColour = Color4.OrangeRed }
} }
}; };
} }
@ -78,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.Tests
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}") Child = new NoteContainer(direction, $"hold note, scrolling {direction.ToString().ToLower()}")
{ {
Child = new DrawableHoldNote(note, ManiaAction.Key1) Child = new DrawableHoldNote(note)
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
AccentColour = Color4.OrangeRed, AccentColour = Color4.OrangeRed,
@ -136,6 +137,13 @@ namespace osu.Game.Rulesets.Mania.Tests
}; };
} }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs<IBindable<ManiaAction>>(new Bindable<ManiaAction>());
return dependencies;
}
protected override void Update() protected override void Update()
{ {
base.Update(); base.Update();
@ -145,9 +153,6 @@ namespace osu.Game.Rulesets.Mania.Tests
if (!(obj.HitObject is IHasEndTime endTime)) if (!(obj.HitObject is IHasEndTime endTime))
continue; continue;
if (!obj.HasNestedHitObjects)
continue;
foreach (var nested in obj.NestedHitObjects) foreach (var nested in obj.NestedHitObjects)
{ {
double finalPosition = (nested.HitObject.StartTime - obj.HitObject.StartTime) / endTime.Duration; double finalPosition = (nested.HitObject.StartTime - obj.HitObject.StartTime) / endTime.Duration;

View File

@ -65,7 +65,7 @@ namespace osu.Game.Rulesets.Mania.Tests
var obj = new Note { Column = i, StartTime = Time.Current + 2000 }; var obj = new Note { Column = i, StartTime = Time.Current + 2000 };
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
stage.Add(new DrawableNote(obj, stage.Columns[i].Action)); stage.Add(new DrawableNote(obj));
} }
} }
} }
@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Mania.Tests
var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 }; var obj = new HoldNote { Column = i, StartTime = Time.Current + 2000, Duration = 500 };
obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); obj.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
stage.Add(new DrawableHoldNote(obj, stage.Columns[i].Action)); stage.Add(new DrawableHoldNote(obj));
} }
} }
} }

View File

@ -38,8 +38,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
private readonly Container<DrawableHoldNoteTick> tickContainer; private readonly Container<DrawableHoldNoteTick> tickContainer;
public DrawableHoldNote(HoldNote hitObject, ManiaAction action) public DrawableHoldNote(HoldNote hitObject)
: base(hitObject, action) : base(hitObject)
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
@ -57,12 +57,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
HoldStartTime = () => holdStartTime HoldStartTime = () => holdStartTime
}) })
}, },
head = new DrawableHeadNote(this, action) head = new DrawableHeadNote(this)
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre Origin = Anchor.TopCentre
}, },
tail = new DrawableTailNote(this, action) tail = new DrawableTailNote(this)
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre Origin = Anchor.TopCentre
@ -118,7 +118,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime) if (Time.Current < HitObject.StartTime || Time.Current > HitObject.EndTime)
return false; return false;
if (action != Action) if (action != Action.Value)
return false; return false;
// The user has pressed during the body of the hold note, after the head note and its hit windows have passed // The user has pressed during the body of the hold note, after the head note and its hit windows have passed
@ -135,7 +135,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (!holdStartTime.HasValue) if (!holdStartTime.HasValue)
return false; return false;
if (action != Action) if (action != Action.Value)
return false; return false;
holdStartTime = null; holdStartTime = null;
@ -154,8 +154,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
private readonly DrawableHoldNote holdNote; private readonly DrawableHoldNote holdNote;
public DrawableHeadNote(DrawableHoldNote holdNote, ManiaAction action) public DrawableHeadNote(DrawableHoldNote holdNote)
: base(holdNote.HitObject.Head, action) : base(holdNote.HitObject.Head)
{ {
this.holdNote = holdNote; this.holdNote = holdNote;
} }
@ -191,8 +191,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
private readonly DrawableHoldNote holdNote; private readonly DrawableHoldNote holdNote;
public DrawableTailNote(DrawableHoldNote holdNote, ManiaAction action) public DrawableTailNote(DrawableHoldNote holdNote)
: base(holdNote.HitObject.Tail, action) : base(holdNote.HitObject.Tail)
{ {
this.holdNote = holdNote; this.holdNote = holdNote;
} }
@ -235,7 +235,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (!holdNote.holdStartTime.HasValue) if (!holdNote.holdStartTime.HasValue)
return false; return false;
if (action != Action) if (action != Action.Value)
return false; return false;
UpdateJudgement(true); UpdateJudgement(true);

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using JetBrains.Annotations;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -10,30 +11,26 @@ using osu.Game.Rulesets.UI.Scrolling;
namespace osu.Game.Rulesets.Mania.Objects.Drawables namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
public abstract class DrawableManiaHitObject<TObject> : DrawableHitObject<ManiaHitObject> public abstract class DrawableManiaHitObject : DrawableHitObject<ManiaHitObject>
where TObject : ManiaHitObject
{ {
/// <summary> /// <summary>
/// The key that will trigger input for this hit object. /// The <see cref="ManiaAction"/> which causes this <see cref="DrawableManiaHitObject{TObject}"/> to be hit.
/// </summary> /// </summary>
protected ManiaAction Action { get; } protected readonly IBindable<ManiaAction> Action = new Bindable<ManiaAction>();
public new TObject HitObject;
protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>(); protected readonly IBindable<ScrollingDirection> Direction = new Bindable<ScrollingDirection>();
protected DrawableManiaHitObject(TObject hitObject, ManiaAction? action = null) protected DrawableManiaHitObject(ManiaHitObject hitObject)
: base(hitObject) : base(hitObject)
{ {
HitObject = hitObject;
if (action != null)
Action = action.Value;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader(true)]
private void load(IScrollingInfo scrollingInfo) private void load([CanBeNull] IBindable<ManiaAction> action, [NotNull] IScrollingInfo scrollingInfo)
{ {
if (action != null)
Action.BindTo(action);
Direction.BindTo(scrollingInfo.Direction); Direction.BindTo(scrollingInfo.Direction);
Direction.BindValueChanged(OnDirectionChanged, true); Direction.BindValueChanged(OnDirectionChanged, true);
} }
@ -42,6 +39,18 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
Anchor = Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre; Anchor = Origin = direction == ScrollingDirection.Up ? Anchor.TopCentre : Anchor.BottomCentre;
} }
}
public abstract class DrawableManiaHitObject<TObject> : DrawableManiaHitObject
where TObject : ManiaHitObject
{
public new readonly TObject HitObject;
protected DrawableManiaHitObject(TObject hitObject)
: base(hitObject)
{
HitObject = hitObject;
}
protected override void UpdateState(ArmedState state) protected override void UpdateState(ArmedState state)
{ {

View File

@ -20,8 +20,8 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
{ {
private readonly NotePiece headPiece; private readonly NotePiece headPiece;
public DrawableNote(Note hitObject, ManiaAction action) public DrawableNote(Note hitObject)
: base(hitObject, action) : base(hitObject)
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y; AutoSizeAxes = Axes.Y;
@ -74,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
public virtual bool OnPressed(ManiaAction action) public virtual bool OnPressed(ManiaAction action)
{ {
if (action != Action) if (action != Action.Value)
return false; return false;
return UpdateJudgement(true); return UpdateJudgement(true);

View File

@ -7,6 +7,8 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using System.Linq; using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.UI.Components; using osu.Game.Rulesets.Mania.UI.Components;
@ -19,21 +21,7 @@ namespace osu.Game.Rulesets.Mania.UI
private const float column_width = 45; private const float column_width = 45;
private const float special_column_width = 70; private const float special_column_width = 70;
private ManiaAction action; public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
public ManiaAction Action
{
get => action;
set
{
if (action == value)
return;
action = value;
background.Action = value;
keyArea.Action = value;
}
}
private readonly ColumnBackground background; private readonly ColumnBackground background;
private readonly ColumnKeyArea keyArea; private readonly ColumnKeyArea keyArea;
@ -130,6 +118,13 @@ namespace osu.Game.Rulesets.Mania.UI
} }
} }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
{
var dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
dependencies.CacheAs<IBindable<ManiaAction>>(Action);
return dependencies;
}
/// <summary> /// <summary>
/// Adds a DrawableHitObject to this Playfield. /// Adds a DrawableHitObject to this Playfield.
/// </summary> /// </summary>

View File

@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Mania.UI.Components
{ {
public class ColumnBackground : CompositeDrawable, IKeyBindingHandler<ManiaAction>, IHasAccentColour public class ColumnBackground : CompositeDrawable, IKeyBindingHandler<ManiaAction>, IHasAccentColour
{ {
public ManiaAction Action; private readonly IBindable<ManiaAction> action = new Bindable<ManiaAction>();
private Box background; private Box background;
private Box backgroundOverlay; private Box backgroundOverlay;
@ -25,8 +25,10 @@ namespace osu.Game.Rulesets.Mania.UI.Components
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(IScrollingInfo scrollingInfo) private void load(IBindable<ManiaAction> action, IScrollingInfo scrollingInfo)
{ {
this.action.BindTo(action);
InternalChildren = new[] InternalChildren = new[]
{ {
background = new Box background = new Box
@ -91,14 +93,14 @@ namespace osu.Game.Rulesets.Mania.UI.Components
public bool OnPressed(ManiaAction action) public bool OnPressed(ManiaAction action)
{ {
if (action == Action) if (action == this.action.Value)
backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint); backgroundOverlay.FadeTo(1, 50, Easing.OutQuint).Then().FadeTo(0.5f, 250, Easing.OutQuint);
return false; return false;
} }
public bool OnReleased(ManiaAction action) public bool OnReleased(ManiaAction action)
{ {
if (action == Action) if (action == this.action.Value)
backgroundOverlay.FadeTo(0, 250, Easing.OutQuint); backgroundOverlay.FadeTo(0, 250, Easing.OutQuint);
return false; return false;
} }

View File

@ -21,15 +21,16 @@ namespace osu.Game.Rulesets.Mania.UI.Components
private const float key_icon_size = 10; private const float key_icon_size = 10;
private const float key_icon_corner_radius = 3; private const float key_icon_corner_radius = 3;
public ManiaAction Action; private readonly IBindable<ManiaAction> action = new Bindable<ManiaAction>();
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>(); private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
private Container keyIcon; private Container keyIcon;
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(IScrollingInfo scrollingInfo) private void load(IBindable<ManiaAction> action, IScrollingInfo scrollingInfo)
{ {
this.action.BindTo(action);
Drawable gradient; Drawable gradient;
InternalChildren = new[] InternalChildren = new[]
@ -107,14 +108,14 @@ namespace osu.Game.Rulesets.Mania.UI.Components
public bool OnPressed(ManiaAction action) public bool OnPressed(ManiaAction action)
{ {
if (action == Action) if (action == this.action.Value)
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint); keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint).Then().ScaleTo(1.3f, 250, Easing.OutQuint);
return false; return false;
} }
public bool OnReleased(ManiaAction action) public bool OnReleased(ManiaAction action)
{ {
if (action == Action) if (action == this.action.Value)
keyIcon.ScaleTo(1f, 125, Easing.OutQuint); keyIcon.ScaleTo(1f, 125, Easing.OutQuint);
return false; return false;
} }

View File

@ -101,17 +101,15 @@ namespace osu.Game.Rulesets.Mania.UI
protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h) protected override DrawableHitObject<ManiaHitObject> GetVisualRepresentation(ManiaHitObject h)
{ {
ManiaAction action = Playfield.Columns.ElementAt(h.Column).Action; switch (h)
{
var holdNote = h as HoldNote; case HoldNote holdNote:
if (holdNote != null) return new DrawableHoldNote(holdNote);
return new DrawableHoldNote(holdNote, action); case Note note:
return new DrawableNote(note);
var note = h as Note; default:
if (note != null) return null;
return new DrawableNote(note, action); }
return null;
} }
protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f); protected override Vector2 PlayfieldArea => new Vector2(1, 0.8f);

View File

@ -127,7 +127,7 @@ namespace osu.Game.Rulesets.Mania.UI
var column = new Column(direction) var column = new Column(direction)
{ {
IsSpecial = isSpecial, IsSpecial = isSpecial,
Action = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ Action = { Value = isSpecial ? specialColumnStartAction++ : normalColumnStartAction++ }
}; };
AddColumn(column); AddColumn(column);

View File

@ -15,10 +15,10 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
{ {
} }
public override void PostProcess() public override void PreProcess()
{ {
base.PreProcess();
applyStacking((Beatmap<OsuHitObject>)Beatmap); applyStacking((Beatmap<OsuHitObject>)Beatmap);
base.PostProcess();
} }
private void applyStacking(Beatmap<OsuHitObject> beatmap) private void applyStacking(Beatmap<OsuHitObject> beatmap)
@ -44,7 +44,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
continue; continue;
double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime; double endTime = (stackBaseObject as IHasEndTime)?.EndTime ?? stackBaseObject.StartTime;
double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f; double stackThreshold = objectN.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
if (objectN.StartTime - endTime > stackThreshold) if (objectN.StartTime - endTime > stackThreshold)
//We are no longer within stacking range of the next object. //We are no longer within stacking range of the next object.
@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Beatmaps
OsuHitObject objectI = beatmap.HitObjects[i]; OsuHitObject objectI = beatmap.HitObjects[i];
if (objectI.StackHeight != 0 || objectI is Spinner) continue; if (objectI.StackHeight != 0 || objectI is Spinner) continue;
double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo?.StackLeniency ?? 0.7f; double stackThreshold = objectI.TimePreempt * beatmap.BeatmapInfo.StackLeniency;
/* If this object is a hitcircle, then we enter this "special" case. /* If this object is a hitcircle, then we enter this "special" case.
* It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider. * It either ends with a stack of hitcircles only, or a stack of hitcircles that are underneath a slider.

View File

@ -93,9 +93,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
base.AccentColour = value; base.AccentColour = value;
Body.AccentColour = AccentColour; Body.AccentColour = AccentColour;
Ball.AccentColour = AccentColour; Ball.AccentColour = AccentColour;
if (HasNestedHitObjects)
foreach (var drawableHitObject in NestedHitObjects) foreach (var drawableHitObject in NestedHitObjects)
drawableHitObject.AccentColour = AccentColour; drawableHitObject.AccentColour = AccentColour;
} }
} }
@ -136,7 +136,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{ {
if (!userTriggered && Time.Current >= slider.EndTime) if (!userTriggered && Time.Current >= slider.EndTime)
{ {
var judgementsCount = NestedHitObjects.Count; var judgementsCount = NestedHitObjects.Count();
var judgementsHit = NestedHitObjects.Count(h => h.IsHit); var judgementsHit = NestedHitObjects.Count(h => h.IsHit);
var hitFraction = (double)judgementsHit / judgementsCount; var hitFraction = (double)judgementsHit / judgementsCount;

View File

@ -37,7 +37,7 @@ namespace osu.Game.Rulesets.Taiko.UI
private void loadBarLines() private void loadBarLines()
{ {
TaikoHitObject lastObject = Beatmap.HitObjects[Beatmap.HitObjects.Count - 1]; TaikoHitObject lastObject = Beatmap.HitObjects[Beatmap.HitObjects.Count - 1];
double lastHitTime = 1 + (lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime; double lastHitTime = 1 + ((lastObject as IHasEndTime)?.EndTime ?? lastObject.StartTime);
var timingPoints = Beatmap.ControlPointInfo.TimingPoints.ToList(); var timingPoints = Beatmap.ControlPointInfo.TimingPoints.ToList();

View File

@ -65,17 +65,19 @@ namespace osu.Game.Tests.Visual
foreach (var rulesetInfo in rulesets.AvailableRulesets) foreach (var rulesetInfo in rulesets.AvailableRulesets)
{ {
var ruleset = rulesetInfo.CreateInstance(); var instance = rulesetInfo.CreateInstance();
var testBeatmap = createTestBeatmap(rulesetInfo); var testBeatmap = createTestBeatmap(rulesetInfo);
beatmaps.Add(testBeatmap); beatmaps.Add(testBeatmap);
AddStep("set ruleset", () => Ruleset.Value = rulesetInfo);
selectBeatmap(testBeatmap); selectBeatmap(testBeatmap);
testBeatmapLabels(ruleset); testBeatmapLabels(instance);
// TODO: adjust cases once more info is shown for other gamemodes // TODO: adjust cases once more info is shown for other gamemodes
switch (ruleset) switch (instance)
{ {
case OsuRuleset _: case OsuRuleset _:
testInfoLabels(5); testInfoLabels(5);

View File

@ -77,7 +77,7 @@ namespace osu.Game.Tests.Visual
foreach (var rulesetInfo in rulesets.AvailableRulesets) foreach (var rulesetInfo in rulesets.AvailableRulesets)
{ {
Ruleset ruleset = rulesetInfo.CreateInstance(); Ruleset ruleset = rulesetInfo.CreateInstance();
AddStep($"switch to {ruleset.Description}", () => modSelect.Ruleset.Value = rulesetInfo); AddStep($"switch to {ruleset.Description}", () => Ruleset.Value = rulesetInfo);
switch (ruleset) switch (ruleset)
{ {

View File

@ -6,23 +6,9 @@ using osu.Game.Rulesets.Objects.Types;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
public interface IBeatmapProcessor
{
IBeatmap Beatmap { get; }
/// <summary>
/// Post-processes <see cref="Beatmap"/> to add mode-specific components that aren't added during conversion.
/// <para>
/// An example of such a usage is for combo colours.
/// </para>
/// </summary>
void PostProcess();
}
/// <summary> /// <summary>
/// Processes a post-converted Beatmap. /// Provides functionality to alter a <see cref="IBeatmap"/> after it has been converted.
/// </summary> /// </summary>
/// <typeparam name="TObject">The type of HitObject contained in the Beatmap.</typeparam>
public class BeatmapProcessor : IBeatmapProcessor public class BeatmapProcessor : IBeatmapProcessor
{ {
public IBeatmap Beatmap { get; } public IBeatmap Beatmap { get; }
@ -32,13 +18,7 @@ namespace osu.Game.Beatmaps
Beatmap = beatmap; Beatmap = beatmap;
} }
/// <summary> public virtual void PreProcess()
/// Post-processes a Beatmap to add mode-specific components that aren't added during conversion.
/// <para>
/// An example of such a usage is for combo colours.
/// </para>
/// </summary>
public virtual void PostProcess()
{ {
IHasComboInformation lastObj = null; IHasComboInformation lastObj = null;
@ -62,5 +42,9 @@ namespace osu.Game.Beatmaps
lastObj = obj; lastObj = obj;
} }
} }
public virtual void PostProcess()
{
}
} }
} }

View File

@ -7,6 +7,9 @@ using osu.Game.Rulesets.Objects;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
/// <summary>
/// Provides functionality to convert a <see cref="IBeatmap"/> for a <see cref="Ruleset"/>.
/// </summary>
public interface IBeatmapConverter public interface IBeatmapConverter
{ {
/// <summary> /// <summary>

View File

@ -0,0 +1,40 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
namespace osu.Game.Beatmaps
{
/// <summary>
/// Provides functionality to alter a <see cref="IBeatmap"/> after it has been converted.
/// </summary>
public interface IBeatmapProcessor
{
/// <summary>
/// The <see cref="IBeatmap"/> to process. This should already be converted to the applicable <see cref="Ruleset"/>.
/// </summary>
IBeatmap Beatmap { get; }
/// <summary>
/// Processes the converted <see cref="Beatmap"/> prior to <see cref="HitObject.ApplyDefaults"/> being invoked.
/// <para>
/// Nested <see cref="HitObject"/>s generated during <see cref="HitObject.ApplyDefaults"/> will not be present by this point,
/// and no mods will have been applied to the <see cref="HitObject"/>s.
/// </para>
/// </summary>
/// <remarks>
/// This can only be used to add alterations to <see cref="HitObject"/>s generated directly through the conversion process.
/// </remarks>
void PreProcess();
/// <summary>
/// Processes the converted <see cref="Beatmap"/> after <see cref="HitObject.ApplyDefaults"/> has been invoked.
/// <para>
/// Nested <see cref="HitObject"/>s generated during <see cref="HitObject.ApplyDefaults"/> will be present by this point,
/// and mods will have been applied to all <see cref="HitObject"/>s.
/// </para>
/// </summary>
/// <remarks>
/// This should be used to add alterations to <see cref="HitObject"/>s while they are in their most playable state.
/// </remarks>
void PostProcess();
}
}

View File

@ -116,6 +116,10 @@ namespace osu.Game.Beatmaps
mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty); mod.ApplyToDifficulty(converted.BeatmapInfo.BaseDifficulty);
} }
IBeatmapProcessor processor = rulesetInstance.CreateBeatmapProcessor(converted);
processor?.PreProcess();
// Compute default values for hitobjects, including creating nested hitobjects in-case they're needed // Compute default values for hitobjects, including creating nested hitobjects in-case they're needed
foreach (var obj in converted.HitObjects) foreach (var obj in converted.HitObjects)
obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty); obj.ApplyDefaults(converted.ControlPointInfo, converted.BeatmapInfo.BaseDifficulty);
@ -124,8 +128,7 @@ namespace osu.Game.Beatmaps
foreach (var obj in converted.HitObjects) foreach (var obj in converted.HitObjects)
mod.ApplyToHitObject(obj); mod.ApplyToHitObject(obj);
// Post-process processor?.PostProcess();
rulesetInstance.CreateBeatmapProcessor(converted)?.PostProcess();
return converted; return converted;
} }

View File

@ -8,12 +8,14 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Input; using osu.Framework.Input;
using OpenTK; using OpenTK;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Input.Bindings;
using osu.Game.Audio; using osu.Game.Audio;
using osu.Game.Input.Bindings;
using osu.Game.Overlays; using osu.Game.Overlays;
namespace osu.Game.Graphics.Containers namespace osu.Game.Graphics.Containers
{ {
public class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner public class OsuFocusedOverlayContainer : FocusedOverlayContainer, IPreviewTrackOwner, IKeyBindingHandler<GlobalAction>
{ {
private SampleChannel samplePopIn; private SampleChannel samplePopIn;
private SampleChannel samplePopOut; private SampleChannel samplePopOut;
@ -65,6 +67,19 @@ namespace osu.Game.Graphics.Containers
return base.OnClick(state); return base.OnClick(state);
} }
public bool OnPressed(GlobalAction action)
{
if (action == GlobalAction.Back)
{
State = Visibility.Hidden;
return true;
}
return false;
}
public bool OnReleased(GlobalAction action) => false;
private void onStateChanged(Visibility visibility) private void onStateChanged(Visibility visibility)
{ {
switch (visibility) switch (visibility)

View File

@ -11,9 +11,9 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Game.Configuration; using osu.Game.Configuration;
using System; using System;
using System.Diagnostics;
using JetBrains.Annotations; using JetBrains.Annotations;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using OpenTK.Input;
namespace osu.Game.Graphics.Cursor namespace osu.Game.Graphics.Cursor
{ {
@ -25,9 +25,8 @@ namespace osu.Game.Graphics.Cursor
protected override Drawable CreateCursor() => new Cursor(); protected override Drawable CreateCursor() => new Cursor();
private Bindable<bool> cursorRotate; private Bindable<bool> cursorRotate;
private bool dragging; private DragRotationState dragRotationState;
private Vector2 positionMouseDown;
private bool startRotation;
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load([NotNull] OsuConfigManager config, [CanBeNull] ScreenshotManager screenshotManager) private void load([NotNull] OsuConfigManager config, [CanBeNull] ScreenshotManager screenshotManager)
@ -40,18 +39,18 @@ namespace osu.Game.Graphics.Cursor
protected override bool OnMouseMove(InputState state) protected override bool OnMouseMove(InputState state)
{ {
if (cursorRotate && dragging) if (dragRotationState != DragRotationState.NotDragging)
{ {
Debug.Assert(state.Mouse.PositionMouseDown != null); var position = state.Mouse.Position;
var distance = Vector2Extensions.Distance(position, positionMouseDown);
// don't start rotating until we're moved a minimum distance away from the mouse down location, // don't start rotating until we're moved a minimum distance away from the mouse down location,
// else it can have an annoying effect. // else it can have an annoying effect.
// ReSharper disable once PossibleInvalidOperationException if (dragRotationState == DragRotationState.DragStarted && distance > 30)
startRotation |= Vector2Extensions.Distance(state.Mouse.Position, state.Mouse.PositionMouseDown.Value) > 30; dragRotationState = DragRotationState.Rotating;
// don't rotate when distance is zero to avoid NaN
if (startRotation) if (dragRotationState == DragRotationState.Rotating && distance > 0)
{ {
Vector2 offset = state.Mouse.Position - state.Mouse.PositionMouseDown.Value; Vector2 offset = state.Mouse.Position - positionMouseDown;
float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f; float degrees = (float)MathHelper.RadiansToDegrees(Math.Atan2(-offset.X, offset.Y)) + 24.3f;
// Always rotate in the direction of least distance // Always rotate in the direction of least distance
@ -67,12 +66,6 @@ namespace osu.Game.Graphics.Cursor
return base.OnMouseMove(state); return base.OnMouseMove(state);
} }
protected override bool OnDragStart(InputState state)
{
dragging = true;
return base.OnDragStart(state);
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{ {
ActiveCursor.Scale = new Vector2(1); ActiveCursor.Scale = new Vector2(1);
@ -80,6 +73,12 @@ namespace osu.Game.Graphics.Cursor
((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0; ((Cursor)ActiveCursor).AdditiveLayer.Alpha = 0;
((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, Easing.OutQuint); ((Cursor)ActiveCursor).AdditiveLayer.FadeInFromZero(800, Easing.OutQuint);
if (args.Button == MouseButton.Left && cursorRotate)
{
dragRotationState = DragRotationState.DragStarted;
positionMouseDown = state.Mouse.Position;
}
return base.OnMouseDown(state, args); return base.OnMouseDown(state, args);
} }
@ -87,14 +86,16 @@ namespace osu.Game.Graphics.Cursor
{ {
if (!state.Mouse.HasMainButtonPressed) if (!state.Mouse.HasMainButtonPressed)
{ {
dragging = false;
startRotation = false;
((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint); ((Cursor)ActiveCursor).AdditiveLayer.FadeOut(500, Easing.OutQuint);
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);
ActiveCursor.ScaleTo(1, 500, Easing.OutElastic); ActiveCursor.ScaleTo(1, 500, Easing.OutElastic);
} }
if (args.Button == MouseButton.Left)
{
if (dragRotationState == DragRotationState.Rotating)
ActiveCursor.RotateTo(0, 600 * (1 + Math.Abs(ActiveCursor.Rotation / 720)), Easing.OutElasticHalf);
dragRotationState = DragRotationState.NotDragging;
}
return base.OnMouseUp(state, args); return base.OnMouseUp(state, args);
} }
@ -160,5 +161,12 @@ namespace osu.Game.Graphics.Cursor
cursorScale.TriggerChange(); cursorScale.TriggerChange();
} }
} }
private enum DragRotationState
{
NotDragging,
DragStarted,
Rotating,
}
} }
} }

View File

@ -2,9 +2,10 @@
// 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.Graphics; using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Input; using osu.Framework.Input;
using System; using System;
using osu.Game.Input.Bindings;
using OpenTK.Input;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {
@ -19,6 +20,7 @@ namespace osu.Game.Graphics.UserInterface
public Action Exit; public Action Exit;
private bool focus; private bool focus;
public bool HoldFocus public bool HoldFocus
{ {
get { return focus; } get { return focus; }
@ -26,7 +28,7 @@ namespace osu.Game.Graphics.UserInterface
{ {
focus = value; focus = value;
if (!focus && HasFocus) if (!focus && HasFocus)
GetContainingInputManager().ChangeFocus(null); base.KillFocus();
} }
} }
@ -41,18 +43,34 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{ {
if (!args.Repeat && args.Key == Key.Escape) if (!HasFocus) return false;
{
if (Text.Length > 0) if (args.Key == Key.Escape)
Text = string.Empty; return false; // disable the framework-level handling of escape key for confority (we use GlobalAction.Back).
else
Exit?.Invoke();
return true;
}
return base.OnKeyDown(state, args); return base.OnKeyDown(state, args);
} }
public override bool OnPressed(GlobalAction action)
{
if (action == GlobalAction.Back)
{
if (Text.Length > 0)
{
Text = string.Empty;
return true;
}
}
return base.OnPressed(action);
}
protected override void KillFocus()
{
base.KillFocus();
Exit?.Invoke();
}
public override bool RequestsFocus => HoldFocus; public override bool RequestsFocus => HoldFocus;
} }
} }

View File

@ -18,7 +18,7 @@ namespace osu.Game.Graphics.UserInterface
{ {
protected override Drawable GetDrawableCharacter(char c) => new PasswordMaskChar(CalculatedTextSize); protected override Drawable GetDrawableCharacter(char c) => new PasswordMaskChar(CalculatedTextSize);
public override bool AllowClipboardExport => false; protected override bool AllowClipboardExport => false;
private readonly CapsWarning warning; private readonly CapsWarning warning;

View File

@ -9,10 +9,12 @@ using osu.Framework.Input;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {
public class OsuTextBox : TextBox public class OsuTextBox : TextBox, IKeyBindingHandler<GlobalAction>
{ {
protected override Color4 BackgroundUnfocused => Color4.Black.Opacity(0.5f); protected override Color4 BackgroundUnfocused => Color4.Black.Opacity(0.5f);
protected override Color4 BackgroundFocused => OsuColour.Gray(0.3f).Opacity(0.8f); protected override Color4 BackgroundFocused => OsuColour.Gray(0.3f).Opacity(0.8f);
@ -33,10 +35,7 @@ namespace osu.Game.Graphics.UserInterface
TextContainer.Height = 0.5f; TextContainer.Height = 0.5f;
CornerRadius = 5; CornerRadius = 5;
Current.DisabledChanged += disabled => Current.DisabledChanged += disabled => { Alpha = disabled ? 0.3f : 1; };
{
Alpha = disabled ? 0.3f : 1;
};
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -59,5 +58,18 @@ namespace osu.Game.Graphics.UserInterface
} }
protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), TextSize = CalculatedTextSize }; protected override Drawable GetDrawableCharacter(char c) => new OsuSpriteText { Text = c.ToString(), TextSize = CalculatedTextSize };
public virtual bool OnPressed(GlobalAction action)
{
if (action == GlobalAction.Back)
{
KillFocus();
return true;
}
return false;
}
public bool OnReleased(GlobalAction action) => false;
} }
} }

View File

@ -34,8 +34,6 @@ namespace osu.Game.Graphics.UserInterface
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{ {
if (HandlePendingText(state)) return true;
if (!state.Keyboard.ControlPressed && !state.Keyboard.ShiftPressed) if (!state.Keyboard.ControlPressed && !state.Keyboard.ShiftPressed)
{ {
switch (args.Key) switch (args.Key)

View File

@ -45,7 +45,9 @@ namespace osu.Game.Input.Bindings
public IEnumerable<KeyBinding> InGameKeyBindings => new[] public IEnumerable<KeyBinding> InGameKeyBindings => new[]
{ {
new KeyBinding(InputKey.Space, GlobalAction.SkipCutscene), new KeyBinding(InputKey.Space, GlobalAction.SkipCutscene),
new KeyBinding(InputKey.Tilde, GlobalAction.QuickRetry) new KeyBinding(InputKey.Tilde, GlobalAction.QuickRetry),
new KeyBinding(new[] { InputKey.Control, InputKey.Plus }, GlobalAction.IncreaseScrollSpeed),
new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed),
}; };
protected override IEnumerable<Drawable> KeyBindingInputQueue => protected override IEnumerable<Drawable> KeyBindingInputQueue =>
@ -85,6 +87,12 @@ namespace osu.Game.Input.Bindings
ToggleGameplayMouseButtons, ToggleGameplayMouseButtons,
[Description("Go back")] [Description("Go back")]
Back Back,
[Description("Increase scroll speed")]
IncreaseScrollSpeed,
[Description("Decrease scroll speed")]
DecreaseScrollSpeed,
} }
} }

View File

@ -49,7 +49,7 @@ namespace osu.Game.Online.API.Requests.Responses
private DateTimeOffset submitted { get; set; } private DateTimeOffset submitted { get; set; }
[JsonProperty(@"ranked_date")] [JsonProperty(@"ranked_date")]
private DateTimeOffset ranked { get; set; } private DateTimeOffset? ranked { get; set; }
[JsonProperty(@"last_updated")] [JsonProperty(@"last_updated")]
private DateTimeOffset lastUpdated { get; set; } private DateTimeOffset lastUpdated { get; set; }

View File

@ -6,16 +6,16 @@ using System.Linq;
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.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input; using OpenTK.Input;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays.Dialog namespace osu.Game.Overlays.Dialog
{ {
@ -23,6 +23,9 @@ namespace osu.Game.Overlays.Dialog
{ {
public static readonly float ENTER_DURATION = 500; public static readonly float ENTER_DURATION = 500;
public static readonly float EXIT_DURATION = 200; public static readonly float EXIT_DURATION = 200;
protected override bool BlockPassThroughMouse => false;
private readonly Vector2 ringSize = new Vector2(100f); private readonly Vector2 ringSize = new Vector2(100f);
private readonly Vector2 ringMinifiedSize = new Vector2(20f); private readonly Vector2 ringMinifiedSize = new Vector2(20f);
private readonly Vector2 buttonsEnterSpacing = new Vector2(0f, 50f); private readonly Vector2 buttonsEnterSpacing = new Vector2(0f, 50f);
@ -34,26 +37,28 @@ namespace osu.Game.Overlays.Dialog
private readonly SpriteText header; private readonly SpriteText header;
private readonly TextFlowContainer body; private readonly TextFlowContainer body;
private bool actionInvoked;
public FontAwesome Icon public FontAwesome Icon
{ {
get { return icon.Icon; } get => icon.Icon;
set { icon.Icon = value; } set => icon.Icon = value;
} }
public string HeaderText public string HeaderText
{ {
get { return header.Text; } get => header.Text;
set { header.Text = value; } set => header.Text = value;
} }
public string BodyText public string BodyText
{ {
set { body.Text = value; } set => body.Text = value;
} }
public IEnumerable<PopupDialogButton> Buttons public IEnumerable<PopupDialogButton> Buttons
{ {
get { return buttonsContainer.Children; } get => buttonsContainer.Children;
set set
{ {
buttonsContainer.ChildrenEnumerable = value; buttonsContainer.ChildrenEnumerable = value;
@ -62,71 +67,17 @@ namespace osu.Game.Overlays.Dialog
var action = b.Action; var action = b.Action;
b.Action = () => b.Action = () =>
{ {
Hide(); if (actionInvoked) return;
actionInvoked = true;
action?.Invoke(); action?.Invoke();
Hide();
}; };
} }
} }
} }
private void pressButtonAtIndex(int index)
{
if (index < Buttons.Count())
Buttons.Skip(index).First().TriggerOnClick();
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Repeat) return false;
if (args.Key == Key.Enter || args.Key == Key.KeypadEnter)
{
Buttons.OfType<PopupDialogOkButton>().FirstOrDefault()?.TriggerOnClick();
return true;
}
// press button at number if 1-9 on number row or keypad are pressed
var k = args.Key;
if (k >= Key.Number1 && k <= Key.Number9)
{
pressButtonAtIndex(k - Key.Number1);
return true;
}
if (k >= Key.Keypad1 && k <= Key.Keypad9)
{
pressButtonAtIndex(k - Key.Keypad1);
return true;
}
return base.OnKeyDown(state, args);
}
protected override void PopIn()
{
base.PopIn();
// Reset various animations but only if the dialog animation fully completed
if (content.Alpha == 0)
{
buttonsContainer.TransformSpacingTo(buttonsEnterSpacing);
buttonsContainer.MoveToY(buttonsEnterSpacing.Y);
ring.ResizeTo(ringMinifiedSize);
}
content.FadeIn(ENTER_DURATION, Easing.OutQuint);
ring.ResizeTo(ringSize, ENTER_DURATION, Easing.OutQuint);
buttonsContainer.TransformSpacingTo(Vector2.Zero, ENTER_DURATION, Easing.OutQuint);
buttonsContainer.MoveToY(0, ENTER_DURATION, Easing.OutQuint);
}
protected override void PopOut()
{
base.PopOut();
content.FadeOut(EXIT_DURATION, Easing.InSine);
}
public PopupDialog() public PopupDialog()
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
@ -136,9 +87,6 @@ namespace osu.Game.Overlays.Dialog
content = new Container content = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Anchor = Anchor.BottomCentre,
Origin = Anchor.BottomCentre,
Width = 0.4f,
Alpha = 0f, Alpha = 0f,
Children = new Drawable[] Children = new Drawable[]
{ {
@ -243,5 +191,69 @@ namespace osu.Game.Overlays.Dialog
}, },
}; };
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Repeat) return false;
if (args.Key == Key.Enter || args.Key == Key.KeypadEnter)
{
Buttons.OfType<PopupDialogOkButton>().FirstOrDefault()?.TriggerOnClick();
return true;
}
// press button at number if 1-9 on number row or keypad are pressed
var k = args.Key;
if (k >= Key.Number1 && k <= Key.Number9)
{
pressButtonAtIndex(k - Key.Number1);
return true;
}
if (k >= Key.Keypad1 && k <= Key.Keypad9)
{
pressButtonAtIndex(k - Key.Keypad1);
return true;
}
return base.OnKeyDown(state, args);
}
protected override void PopIn()
{
base.PopIn();
actionInvoked = false;
// Reset various animations but only if the dialog animation fully completed
if (content.Alpha == 0)
{
buttonsContainer.TransformSpacingTo(buttonsEnterSpacing);
buttonsContainer.MoveToY(buttonsEnterSpacing.Y);
ring.ResizeTo(ringMinifiedSize);
}
content.FadeIn(ENTER_DURATION, Easing.OutQuint);
ring.ResizeTo(ringSize, ENTER_DURATION, Easing.OutQuint);
buttonsContainer.TransformSpacingTo(Vector2.Zero, ENTER_DURATION, Easing.OutQuint);
buttonsContainer.MoveToY(0, ENTER_DURATION, Easing.OutQuint);
}
protected override void PopOut()
{
if (!actionInvoked)
// In the case a user did not choose an action before a hide was triggered, press the last button.
// This is presumed to always be a sane default "cancel" action.
buttonsContainer.Last().TriggerOnClick();
base.PopOut();
content.FadeOut(EXIT_DURATION, Easing.InSine);
}
private void pressButtonAtIndex(int index)
{
if (index < Buttons.Count())
Buttons.Skip(index).First().TriggerOnClick();
}
} }
} }

View File

@ -1,12 +1,9 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Overlays.Dialog; using osu.Game.Overlays.Dialog;
using OpenTK.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays namespace osu.Game.Overlays
@ -16,6 +13,20 @@ namespace osu.Game.Overlays
private readonly Container dialogContainer; private readonly Container dialogContainer;
private PopupDialog currentDialog; private PopupDialog currentDialog;
public DialogOverlay()
{
RelativeSizeAxes = Axes.Both;
Child = dialogContainer = new Container
{
RelativeSizeAxes = Axes.Both,
};
Width = 0.4f;
Anchor = Anchor.BottomCentre;
Origin = Anchor.BottomCentre;
}
public void Push(PopupDialog dialog) public void Push(PopupDialog dialog)
{ {
if (dialog == currentDialog) return; if (dialog == currentDialog) return;
@ -32,6 +43,8 @@ namespace osu.Game.Overlays
protected override bool PlaySamplesOnStateChange => false; protected override bool PlaySamplesOnStateChange => false;
protected override bool BlockPassThroughKeyboard => true;
private void onDialogOnStateChanged(VisibilityContainer dialog, Visibility v) private void onDialogOnStateChanged(VisibilityContainer dialog, Visibility v)
{ {
if (v != Visibility.Hidden) return; if (v != Visibility.Hidden) return;
@ -52,32 +65,14 @@ namespace osu.Game.Overlays
protected override void PopOut() protected override void PopOut()
{ {
base.PopOut(); base.PopOut();
this.FadeOut(PopupDialog.EXIT_DURATION, Easing.InSine);
}
public DialogOverlay() if (currentDialog?.State == Visibility.Visible)
{
RelativeSizeAxes = Axes.Both;
Children = new Drawable[]
{ {
new Container currentDialog.Hide();
{ return;
RelativeSizeAxes = Axes.Both, }
Children = new Drawable[]
{ this.FadeOut(PopupDialog.EXIT_DURATION, Easing.InSine);
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black.Opacity(0.5f),
},
},
},
dialogContainer = new Container
{
RelativeSizeAxes = Axes.Both,
},
};
} }
} }
} }

View File

@ -202,9 +202,6 @@ namespace osu.Game.Overlays.KeyBinding
switch (args.Key) switch (args.Key)
{ {
case Key.Escape:
finalise();
return true;
case Key.Delete: case Key.Delete:
{ {
if (state.Keyboard.ShiftPressed) if (state.Keyboard.ShiftPressed)

View File

@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Mods
public readonly Bindable<IEnumerable<Mod>> SelectedMods = new Bindable<IEnumerable<Mod>>(); public readonly Bindable<IEnumerable<Mod>> SelectedMods = new Bindable<IEnumerable<Mod>>();
public readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>(); public readonly IBindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
private void rulesetChanged(RulesetInfo newRuleset) private void rulesetChanged(RulesetInfo newRuleset)
{ {
@ -51,8 +51,8 @@ namespace osu.Game.Overlays.Mods
refreshSelectedMods(); refreshSelectedMods();
} }
[BackgroundDependencyLoader(permitNulls: true)] [BackgroundDependencyLoader]
private void load(OsuColour colours, Bindable<RulesetInfo> ruleset, RulesetStore rulesets, AudioManager audio) private void load(OsuColour colours, IBindable<RulesetInfo> ruleset, AudioManager audio)
{ {
SelectedMods.ValueChanged += selectedModsChanged; SelectedMods.ValueChanged += selectedModsChanged;
@ -60,13 +60,8 @@ namespace osu.Game.Overlays.Mods
HighMultiplierColour = colours.Green; HighMultiplierColour = colours.Green;
UnrankedLabel.Colour = colours.Blue; UnrankedLabel.Colour = colours.Blue;
if (ruleset != null) Ruleset.BindTo(ruleset);
Ruleset.BindTo(ruleset); Ruleset.BindValueChanged(rulesetChanged, true);
else
Ruleset.Value = rulesets.AvailableRulesets.First();
Ruleset.ValueChanged += rulesetChanged;
Ruleset.TriggerChange();
sampleOn = audio.Sample.Get(@"UI/check-on"); sampleOn = audio.Sample.Get(@"UI/check-on");
sampleOff = audio.Sample.Get(@"UI/check-off"); sampleOff = audio.Sample.Get(@"UI/check-off");

View File

@ -56,7 +56,13 @@ namespace osu.Game.Overlays.Settings.Sections
reloadSkins(); reloadSkins();
skinDropdown.Bindable = config.GetBindable<int>(OsuSetting.Skin); var skinBindable = config.GetBindable<int>(OsuSetting.Skin);
// Todo: This should not be necessary when OsuConfigManager is databased
if (skinDropdown.Items.All(s => s.Value != skinBindable.Value))
skinBindable.Value = 0;
skinDropdown.Bindable = skinBindable;
} }
private void reloadSkins() => skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair<string, int>(s.ToString(), s.ID)); private void reloadSkins() => skinDropdown.Items = skins.GetAllUsableSkins().Select(s => new KeyValuePair<string, int>(s.ToString(), s.ID));

View File

@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Toolbar
}; };
} }
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader]
private void load(RulesetStore rulesets, Bindable<RulesetInfo> parentRuleset) private void load(RulesetStore rulesets, Bindable<RulesetInfo> parentRuleset)
{ {
this.rulesets = rulesets; this.rulesets = rulesets;
@ -82,11 +82,7 @@ namespace osu.Game.Overlays.Toolbar
ruleset.ValueChanged += rulesetChanged; ruleset.ValueChanged += rulesetChanged;
ruleset.DisabledChanged += disabledChanged; ruleset.DisabledChanged += disabledChanged;
ruleset.BindTo(parentRuleset);
if (parentRuleset != null)
ruleset.BindTo(parentRuleset);
else
ruleset.Value = rulesets.AvailableRulesets.FirstOrDefault();
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)

View File

@ -33,8 +33,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
protected virtual IEnumerable<SampleInfo> GetSamples() => HitObject.Samples; protected virtual IEnumerable<SampleInfo> GetSamples() => HitObject.Samples;
private readonly Lazy<List<DrawableHitObject>> nestedHitObjects = new Lazy<List<DrawableHitObject>>(); private readonly Lazy<List<DrawableHitObject>> nestedHitObjects = new Lazy<List<DrawableHitObject>>();
public bool HasNestedHitObjects => nestedHitObjects.IsValueCreated; public IEnumerable<DrawableHitObject> NestedHitObjects => nestedHitObjects.IsValueCreated ? nestedHitObjects.Value : Enumerable.Empty<DrawableHitObject>();
public IReadOnlyList<DrawableHitObject> NestedHitObjects => nestedHitObjects.Value;
public event Action<DrawableHitObject, Judgement> OnJudgement; public event Action<DrawableHitObject, Judgement> OnJudgement;
public event Action<DrawableHitObject, Judgement> OnJudgementRemoved; public event Action<DrawableHitObject, Judgement> OnJudgementRemoved;
@ -50,12 +49,12 @@ namespace osu.Game.Rulesets.Objects.Drawables
/// <summary> /// <summary>
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been hit. /// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been hit.
/// </summary> /// </summary>
public bool IsHit => Judgements.Any(j => j.Final && j.IsHit) && (!HasNestedHitObjects || NestedHitObjects.All(n => n.IsHit)); public bool IsHit => Judgements.Any(j => j.Final && j.IsHit) && NestedHitObjects.All(n => n.IsHit);
/// <summary> /// <summary>
/// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been judged. /// Whether this <see cref="DrawableHitObject"/> and all of its nested <see cref="DrawableHitObject"/>s have been judged.
/// </summary> /// </summary>
public bool AllJudged => (!ProvidesJudgement || judgementFinalized) && (!HasNestedHitObjects || NestedHitObjects.All(h => h.AllJudged)); public bool AllJudged => (!ProvidesJudgement || judgementFinalized) && NestedHitObjects.All(h => h.AllJudged);
/// <summary> /// <summary>
/// Whether this <see cref="DrawableHitObject"/> can be judged. /// Whether this <see cref="DrawableHitObject"/> can be judged.
@ -205,9 +204,8 @@ namespace osu.Game.Rulesets.Objects.Drawables
if (AllJudged) if (AllJudged)
return false; return false;
if (HasNestedHitObjects) foreach (var d in NestedHitObjects)
foreach (var d in NestedHitObjects) judgementOccurred |= d.UpdateJudgement(userTriggered);
judgementOccurred |= d.UpdateJudgement(userTriggered);
if (!ProvidesJudgement || judgementFinalized || judgementOccurred) if (!ProvidesJudgement || judgementFinalized || judgementOccurred)
return judgementOccurred; return judgementOccurred;

View File

@ -57,8 +57,18 @@ namespace osu.Game.Rulesets
/// <returns></returns> /// <returns></returns>
public abstract RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap); public abstract RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap);
/// <summary>
/// Creates a <see cref="IBeatmapConverter"/> to convert a <see cref="IBeatmap"/> to one that is applicable for this <see cref="Ruleset"/>.
/// </summary>
/// <param name="beatmap">The <see cref="IBeatmap"/> to be converted.</param>
/// <returns>The <see cref="IBeatmapConverter"/>.</returns>
public abstract IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap); public abstract IBeatmapConverter CreateBeatmapConverter(IBeatmap beatmap);
/// <summary>
/// Optionally creates a <see cref="IBeatmapProcessor"/> to alter a <see cref="IBeatmap"/> after it has been converted.
/// </summary>
/// <param name="beatmap">The <see cref="IBeatmap"/> to be processed.</param>
/// <returns>The <see cref="IBeatmapProcessor"/>.</returns>
public virtual IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => null; public virtual IBeatmapProcessor CreateBeatmapProcessor(IBeatmap beatmap) => null;
public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap); public abstract DifficultyCalculator CreateDifficultyCalculator(WorkingBeatmap beatmap);

View File

@ -4,30 +4,33 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input; using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using OpenTK.Input;
namespace osu.Game.Rulesets.UI.Scrolling namespace osu.Game.Rulesets.UI.Scrolling
{ {
/// <summary> /// <summary>
/// A type of <see cref="Playfield"/> specialized towards scrolling <see cref="DrawableHitObject"/>s. /// A type of <see cref="Playfield"/> specialized towards scrolling <see cref="DrawableHitObject"/>s.
/// </summary> /// </summary>
public abstract class ScrollingPlayfield : Playfield public abstract class ScrollingPlayfield : Playfield, IKeyBindingHandler<GlobalAction>
{ {
/// <summary> /// <summary>
/// The default span of time visible by the length of the scrolling axes. /// The default span of time visible by the length of the scrolling axes.
/// This is clamped between <see cref="time_span_min"/> and <see cref="time_span_max"/>. /// This is clamped between <see cref="time_span_min"/> and <see cref="time_span_max"/>.
/// </summary> /// </summary>
private const double time_span_default = 1500; private const double time_span_default = 1500;
/// <summary> /// <summary>
/// The minimum span of time that may be visible by the length of the scrolling axes. /// The minimum span of time that may be visible by the length of the scrolling axes.
/// </summary> /// </summary>
private const double time_span_min = 50; private const double time_span_min = 50;
/// <summary> /// <summary>
/// The maximum span of time that may be visible by the length of the scrolling axes. /// The maximum span of time that may be visible by the length of the scrolling axes.
/// </summary> /// </summary>
private const double time_span_max = 10000; private const double time_span_max = 10000;
/// <summary> /// <summary>
/// The step increase/decrease of the span of time visible by the length of the scrolling axes. /// The step increase/decrease of the span of time visible by the length of the scrolling axes.
/// </summary> /// </summary>
@ -78,27 +81,26 @@ namespace osu.Game.Rulesets.UI.Scrolling
HitObjects.TimeRange.BindTo(VisibleTimeRange); HitObjects.TimeRange.BindTo(VisibleTimeRange);
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) public bool OnPressed(GlobalAction action)
{ {
if (!UserScrollSpeedAdjustment) if (!UserScrollSpeedAdjustment)
return false; return false;
if (state.Keyboard.ControlPressed) switch (action)
{ {
switch (args.Key) case GlobalAction.IncreaseScrollSpeed:
{ this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange - time_span_step, 200, Easing.OutQuint);
case Key.Minus: return true;
this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange + time_span_step, 600, Easing.OutQuint); case GlobalAction.DecreaseScrollSpeed:
break; this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange + time_span_step, 200, Easing.OutQuint);
case Key.Plus: return true;
this.TransformBindableTo(VisibleTimeRange, VisibleTimeRange - time_span_step, 600, Easing.OutQuint);
break;
}
} }
return false; return false;
} }
public bool OnReleased(GlobalAction action) => false;
protected sealed override HitObjectContainer CreateHitObjectContainer() protected sealed override HitObjectContainer CreateHitObjectContainer()
{ {
var container = new ScrollingHitObjectContainer(); var container = new ScrollingHitObjectContainer();

View File

@ -47,13 +47,10 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
} }
} }
if (obj.HasNestedHitObjects) ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
{
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
// Nested hitobjects don't need to scroll, but they do need accurate positions // Nested hitobjects don't need to scroll, but they do need accurate positions
UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length); UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
}
} }
} }

View File

@ -48,13 +48,10 @@ namespace osu.Game.Rulesets.UI.Scrolling.Visualisers
} }
} }
if (obj.HasNestedHitObjects) ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
{
ComputeInitialStates(obj.NestedHitObjects, direction, timeRange, length);
// Nested hitobjects don't need to scroll, but they do need accurate positions // Nested hitobjects don't need to scroll, but they do need accurate positions
UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length); UpdatePositions(obj.NestedHitObjects, direction, obj.HitObject.StartTime, timeRange, length);
}
} }
} }

View File

@ -40,7 +40,14 @@ namespace osu.Game.Screens
while (screen.LoadState < LoadState.Ready) while (screen.LoadState < LoadState.Ready)
Thread.Sleep(1); Thread.Sleep(1);
base.Push(screen); try
{
base.Push(screen);
}
catch (ScreenAlreadyExitedException)
{
// screen may have exited before the push was successful.
}
} }
protected override void Update() protected override void Update()

View File

@ -148,8 +148,6 @@ namespace osu.Game.Screens.Menu
case Key.Space: case Key.Space:
logo?.TriggerOnClick(state); logo?.TriggerOnClick(state);
return true; return true;
case Key.Escape:
return goBack();
} }
return false; return false;
@ -181,16 +179,7 @@ namespace osu.Game.Screens.Menu
} }
} }
public bool OnReleased(GlobalAction action) public bool OnReleased(GlobalAction action) => false;
{
switch (action)
{
case GlobalAction.Back:
return true;
default:
return false;
}
}
private void onPlay() private void onPlay()
{ {

View File

@ -1,34 +1,34 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input; using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
using osu.Game.Overlays; using osu.Game.Overlays;
using OpenTK.Input;
namespace osu.Game.Screens.Menu namespace osu.Game.Screens.Menu
{ {
public class ExitConfirmOverlay : HoldToConfirmOverlay public class ExitConfirmOverlay : HoldToConfirmOverlay, IKeyBindingHandler<GlobalAction>
{ {
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) public bool OnPressed(GlobalAction action)
{ {
if (args.Key == Key.Escape && !args.Repeat) if (action == GlobalAction.Back)
{ {
BeginConfirm(); BeginConfirm();
return true; return true;
} }
return base.OnKeyDown(state, args); return false;
} }
protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) public bool OnReleased(GlobalAction action)
{ {
if (args.Key == Key.Escape) if (action == GlobalAction.Back)
{ {
AbortConfirm(); AbortConfirm();
return true; return true;
} }
return base.OnKeyUp(state, args); return false;
} }
} }
} }

View File

@ -8,7 +8,6 @@ using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Input.Bindings; using osu.Framework.Input.Bindings;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
@ -17,7 +16,6 @@ using osu.Game.Input.Bindings;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
using OpenTK; using OpenTK;
using OpenTK.Input;
using osu.Game.Overlays; using osu.Game.Overlays;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -84,11 +82,8 @@ namespace osu.Game.Screens
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load(BindableBeatmap beatmap, OsuGame osu, AudioManager audio, Bindable<RulesetInfo> ruleset) private void load(BindableBeatmap beatmap, OsuGame osu, AudioManager audio, Bindable<RulesetInfo> ruleset)
{ {
if (beatmap != null) Beatmap.BindTo(beatmap);
Beatmap.BindTo(beatmap); Ruleset.BindTo(ruleset);
if (ruleset != null)
Ruleset.BindTo(ruleset);
if (osu != null) if (osu != null)
{ {
@ -108,6 +103,8 @@ namespace osu.Game.Screens
public bool OnPressed(GlobalAction action) public bool OnPressed(GlobalAction action)
{ {
if (!IsCurrentScreen) return false;
if (action == GlobalAction.Back && AllowBackButton) if (action == GlobalAction.Back && AllowBackButton)
{ {
Exit(); Exit();
@ -119,20 +116,6 @@ namespace osu.Game.Screens
public bool OnReleased(GlobalAction action) => action == GlobalAction.Back && AllowBackButton; public bool OnReleased(GlobalAction action) => action == GlobalAction.Back && AllowBackButton;
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Repeat || !IsCurrentScreen) return false;
switch (args.Key)
{
case Key.Escape:
Exit();
return true;
}
return base.OnKeyDown(state, args);
}
protected override void OnResuming(Screen last) protected override void OnResuming(Screen last)
{ {
sampleExit?.Play(); sampleExit?.Play();
@ -197,11 +180,10 @@ namespace osu.Game.Screens
if (Background != null && !Background.Equals(nextOsu?.Background)) if (Background != null && !Background.Equals(nextOsu?.Background))
{ {
if (nextOsu != null) Background.Exit();
//We need to use MakeCurrent in case we are jumping up multiple game screens.
nextOsu.Background?.MakeCurrent(); //We need to use MakeCurrent in case we are jumping up multiple game screens.
else nextOsu?.Background?.MakeCurrent();
Background.Exit();
} }
if (base.OnExiting(next)) if (base.OnExiting(next))

View File

@ -1,12 +1,9 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input;
using OpenTK.Input;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using System.Linq;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
{ {
@ -21,16 +18,5 @@ namespace osu.Game.Screens.Play
AddButton("Retry", colours.YellowDark, () => OnRetry?.Invoke()); AddButton("Retry", colours.YellowDark, () => OnRetry?.Invoke());
AddButton("Quit", new Color4(170, 27, 39, 255), () => OnQuit?.Invoke()); AddButton("Quit", new Color4(170, 27, 39, 255), () => OnQuit?.Invoke());
} }
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (!args.Repeat && args.Key == Key.Escape)
{
InternalButtons.Children.Last().TriggerOnClick();
return true;
}
return base.OnKeyDown(state, args);
}
} }
} }

View File

@ -15,10 +15,13 @@ using osu.Game.Graphics.UserInterface;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using OpenTK.Input; using OpenTK.Input;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using osu.Framework.Input.Bindings;
using osu.Game.Input.Bindings;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
{ {
public abstract class GameplayMenuOverlay : OverlayContainer public abstract class GameplayMenuOverlay : OverlayContainer, IKeyBindingHandler<GlobalAction>
{ {
private const int transition_duration = 200; private const int transition_duration = 200;
private const int button_height = 70; private const int button_height = 70;
@ -31,6 +34,11 @@ namespace osu.Game.Screens.Play
public Action OnRetry; public Action OnRetry;
public Action OnQuit; public Action OnQuit;
/// <summary>
/// Action that is invoked when <see cref="GlobalAction.Back"/> is triggered.
/// </summary>
protected virtual Action BackAction => () => InternalButtons.Children.Last().TriggerOnClick();
public abstract string Header { get; } public abstract string Header { get; }
public abstract string Description { get; } public abstract string Description { get; }
@ -219,6 +227,19 @@ namespace osu.Game.Screens.Play
return base.OnKeyDown(state, args); return base.OnKeyDown(state, args);
} }
public bool OnPressed(GlobalAction action)
{
if (action == GlobalAction.Back)
{
BackAction.Invoke();
return true;
}
return false;
}
public bool OnReleased(GlobalAction action) => action == GlobalAction.Back;
private void buttonSelectionChanged(DialogButton button, bool isSelected) private void buttonSelectionChanged(DialogButton button, bool isSelected)
{ {
if (!isSelected) if (!isSelected)

View File

@ -6,11 +6,9 @@ using System.Linq;
using osu.Framework.Allocation; 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.Input;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK.Graphics; using OpenTK.Graphics;
using OpenTK.Input;
namespace osu.Game.Screens.Play namespace osu.Game.Screens.Play
{ {
@ -138,16 +136,7 @@ namespace osu.Game.Screens.Play
public override string Header => "paused"; public override string Header => "paused";
public override string Description => "you're not going to do what i think you're going to do, are ya?"; public override string Description => "you're not going to do what i think you're going to do, are ya?";
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) protected override Action BackAction => () => InternalButtons.Children.First().TriggerOnClick();
{
if (!args.Repeat && args.Key == Key.Escape)
{
InternalButtons.Children.First().TriggerOnClick();
return true;
}
return base.OnKeyDown(state, args);
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)

View File

@ -49,8 +49,6 @@ namespace osu.Game.Screens.Play
public bool AllowLeadIn { get; set; } = true; public bool AllowLeadIn { get; set; } = true;
public bool AllowResults { get; set; } = true; public bool AllowResults { get; set; } = true;
protected override bool AllowBackButton => false;
private Bindable<bool> mouseWheelDisabled; private Bindable<bool> mouseWheelDisabled;
private Bindable<double> userAudioOffset; private Bindable<double> userAudioOffset;

View File

@ -55,8 +55,7 @@ namespace osu.Game.Screens.Select
[BackgroundDependencyLoader(true)] [BackgroundDependencyLoader(true)]
private void load([CanBeNull] Bindable<RulesetInfo> parentRuleset) private void load([CanBeNull] Bindable<RulesetInfo> parentRuleset)
{ {
if (parentRuleset != null) ruleset.BindTo(parentRuleset);
ruleset.BindTo(parentRuleset);
ruleset.ValueChanged += _ => updateDisplay(); ruleset.ValueChanged += _ => updateDisplay();
} }

View File

@ -29,6 +29,7 @@ namespace osu.Game.Screens.Select
private readonly TabControl<GroupMode> groupTabs; private readonly TabControl<GroupMode> groupTabs;
private SortMode sort = SortMode.Title; private SortMode sort = SortMode.Title;
public SortMode Sort public SortMode Sort
{ {
get { return sort; } get { return sort; }
@ -43,6 +44,7 @@ namespace osu.Game.Screens.Select
} }
private GroupMode group = GroupMode.All; private GroupMode group = GroupMode.All;
public GroupMode Group public GroupMode Group
{ {
get { return group; } get { return group; }
@ -69,7 +71,8 @@ namespace osu.Game.Screens.Select
private readonly SearchTextBox searchTextBox; private readonly SearchTextBox searchTextBox;
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => base.ReceiveMouseInputAt(screenSpacePos) || groupTabs.ReceiveMouseInputAt(screenSpacePos) || sortTabs.ReceiveMouseInputAt(screenSpacePos); public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) =>
base.ReceiveMouseInputAt(screenSpacePos) || groupTabs.ReceiveMouseInputAt(screenSpacePos) || sortTabs.ReceiveMouseInputAt(screenSpacePos);
public FilterControl() public FilterControl()
{ {
@ -177,8 +180,7 @@ namespace osu.Game.Screens.Select
showConverted = config.GetBindable<bool>(OsuSetting.ShowConvertedBeatmaps); showConverted = config.GetBindable<bool>(OsuSetting.ShowConvertedBeatmaps);
showConverted.ValueChanged += val => updateCriteria(); showConverted.ValueChanged += val => updateCriteria();
if (parentRuleset != null) ruleset.BindTo(parentRuleset);
ruleset.BindTo(parentRuleset);
ruleset.BindValueChanged(val => updateCriteria(), true); ruleset.BindValueChanged(val => updateCriteria(), true);
} }

View File

@ -55,6 +55,8 @@ namespace osu.Game.Screens.Select
private readonly Box box; private readonly Box box;
private readonly Box light; private readonly Box light;
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => box.ReceiveMouseInputAt(screenSpacePos);
public FooterButton() public FooterButton()
{ {
Children = new Drawable[] Children = new Drawable[]

View File

@ -40,7 +40,10 @@ namespace osu.Game.Screens.Select.Leaderboards
private ScheduledDelegate showScoresDelegate; private ScheduledDelegate showScoresDelegate;
private bool scoresLoadedOnce;
private IEnumerable<Score> scores; private IEnumerable<Score> scores;
public IEnumerable<Score> Scores public IEnumerable<Score> Scores
{ {
get { return scores; } get { return scores; }
@ -48,6 +51,8 @@ namespace osu.Game.Screens.Select.Leaderboards
{ {
scores = value; scores = value;
scoresLoadedOnce = true;
scrollFlow?.FadeOut(fade_duration, Easing.OutQuint).Expire(); scrollFlow?.FadeOut(fade_duration, Easing.OutQuint).Expire();
scrollFlow = null; scrollFlow = null;
@ -196,9 +201,7 @@ namespace osu.Game.Screens.Select.Leaderboards
{ {
this.api = api; this.api = api;
if (parentRuleset != null) ruleset.BindTo(parentRuleset);
ruleset.BindTo(parentRuleset);
ruleset.ValueChanged += _ => updateScores(); ruleset.ValueChanged += _ => updateScores();
if (api != null) if (api != null)
@ -227,6 +230,10 @@ namespace osu.Game.Screens.Select.Leaderboards
private void updateScores() private void updateScores()
{ {
// don't display any scores or placeholder until the first Scores_Set has been called.
// this avoids scope changes flickering a "no scores" placeholder before initialisation of song select is finished.
if (!scoresLoadedOnce) return;
getScoresRequest?.Cancel(); getScoresRequest?.Cancel();
getScoresRequest = null; getScoresRequest = null;

View File

@ -1,10 +1,13 @@
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Configuration;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets;
namespace osu.Game.Tests.Visual namespace osu.Game.Tests.Visual
{ {
@ -13,6 +16,8 @@ namespace osu.Game.Tests.Visual
private readonly OsuTestBeatmap beatmap = new OsuTestBeatmap(new DummyWorkingBeatmap()); private readonly OsuTestBeatmap beatmap = new OsuTestBeatmap(new DummyWorkingBeatmap());
protected BindableBeatmap Beatmap => beatmap; protected BindableBeatmap Beatmap => beatmap;
protected readonly Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
protected DependencyContainer Dependencies { get; private set; } protected DependencyContainer Dependencies { get; private set; }
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent)
@ -22,13 +27,18 @@ namespace osu.Game.Tests.Visual
Dependencies.CacheAs<BindableBeatmap>(beatmap); Dependencies.CacheAs<BindableBeatmap>(beatmap);
Dependencies.CacheAs<IBindableBeatmap>(beatmap); Dependencies.CacheAs<IBindableBeatmap>(beatmap);
Dependencies.CacheAs(Ruleset);
Dependencies.CacheAs<IBindable<RulesetInfo>>(Ruleset);
return Dependencies; return Dependencies;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(AudioManager audioManager) private void load(AudioManager audioManager, RulesetStore rulesets)
{ {
beatmap.SetAudioManager(audioManager); beatmap.SetAudioManager(audioManager);
Ruleset.Value = rulesets.AvailableRulesets.First();
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)

View File

@ -86,7 +86,11 @@ namespace osu.Game.Tests.Visual
private readonly WeakList<WorkingBeatmap> workingWeakReferences = new WeakList<WorkingBeatmap>(); private readonly WeakList<WorkingBeatmap> workingWeakReferences = new WeakList<WorkingBeatmap>();
private readonly WeakList<Player> playerWeakReferences = new WeakList<Player>(); private readonly WeakList<Player> playerWeakReferences = new WeakList<Player>();
private Player loadPlayerFor(RulesetInfo ri) => loadPlayerFor(ri.CreateInstance()); private Player loadPlayerFor(RulesetInfo ri)
{
Ruleset.Value = ri;
return loadPlayerFor(ri.CreateInstance());
}
private Player loadPlayerFor(Ruleset r) private Player loadPlayerFor(Ruleset r)
{ {

View File

@ -18,7 +18,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.1.1" />
<PackageReference Include="Newtonsoft.Json" Version="11.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="11.0.2" />
<PackageReference Include="ppy.osu.Framework" Version="2018.626.0" /> <PackageReference Include="ppy.osu.Framework" Version="2018.629.0" />
<PackageReference Include="SharpCompress" Version="0.17.1" /> <PackageReference Include="SharpCompress" Version="0.17.1" />
<PackageReference Include="NUnit" Version="3.10.1" /> <PackageReference Include="NUnit" Version="3.10.1" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" /> <PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />