1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-21 03:02:54 +08:00

Merge remote-tracking branch 'refs/remotes/ppy/master' into clickable_users

This commit is contained in:
EVAST9919 2017-10-03 01:51:10 +03:00
commit d61e72b5a3
17 changed files with 511 additions and 344 deletions

@ -1 +1 @@
Subproject commit cdb031c3a8ef693cd71458c5e19c68127ab72938 Subproject commit 9d142a8e009794dfee828392e36025d08577131d

View File

@ -10,6 +10,10 @@ namespace osu.Game.Rulesets.Catch.Tests
[TestFixture] [TestFixture]
public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer public class TestCaseCatchPlayer : Game.Tests.Visual.TestCasePlayer
{ {
public TestCaseCatchPlayer() : base(typeof(CatchRuleset))
{
}
protected override Beatmap CreateBeatmap() protected override Beatmap CreateBeatmap()
{ {
var beatmap = new Beatmap(); var beatmap = new Beatmap();

View File

@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.Catch.Tests
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] public override IReadOnlyList<Type> RequiredTypes => new[]
{ {
typeof(CatcherArea), typeof(Catcher),
}; };
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Catch.Tests
new CatchInputManager(rulesets.GetRuleset(2)) new CatchInputManager(rulesets.GetRuleset(2))
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Child = new CatcherArea Child = new Catcher
{ {
RelativePositionAxes = Axes.Both, RelativePositionAxes = Axes.Both,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,

View File

@ -1,10 +1,12 @@
// 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 osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using OpenTK; using OpenTK;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.Objects.Drawable; using osu.Game.Rulesets.Catch.Objects.Drawable;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
@ -15,11 +17,15 @@ namespace osu.Game.Rulesets.Catch.UI
{ {
protected override Container<Drawable> Content => content; protected override Container<Drawable> Content => content;
private readonly Container<Drawable> content; private readonly Container<Drawable> content;
private readonly CatcherArea catcherArea;
private readonly Container catcherContainer;
private readonly Catcher catcher;
public CatchPlayfield() public CatchPlayfield()
: base(Axes.Y) : base(Axes.Y)
{ {
Container explodingFruitContainer;
Reversed.Value = true; Reversed.Value = true;
Size = new Vector2(1); Size = new Vector2(1);
@ -33,16 +39,35 @@ namespace osu.Game.Rulesets.Catch.UI
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}, },
catcherArea = new CatcherArea explodingFruitContainer = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
},
catcherContainer = new Container
{
RelativeSizeAxes = Axes.X,
Anchor = Anchor.BottomLeft, Anchor = Anchor.BottomLeft,
Origin = Anchor.TopLeft, Origin = Anchor.TopLeft,
Height = 0.3f Height = 180,
Child = catcher = new Catcher
{
ExplodingFruitTarget = explodingFruitContainer,
RelativePositionAxes = Axes.Both,
Origin = Anchor.TopCentre,
X = 0.5f,
}
} }
}; };
} }
protected override void Update()
{
base.Update();
catcher.Size = new Vector2(catcherContainer.DrawSize.Y);
}
public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2;
public override void Add(DrawableHitObject h) public override void Add(DrawableHitObject h)
{ {
h.Depth = (float)h.HitObject.StartTime; h.Depth = (float)h.HitObject.StartTime;
@ -50,7 +75,7 @@ namespace osu.Game.Rulesets.Catch.UI
base.Add(h); base.Add(h);
var fruit = (DrawableFruit)h; var fruit = (DrawableFruit)h;
fruit.CheckPosition = catcherArea.CheckIfWeCanCatch; fruit.CheckPosition = CheckIfWeCanCatch;
} }
public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement) public override void OnJudgement(DrawableHitObject judgedObject, Judgement judgement)
@ -59,7 +84,7 @@ namespace osu.Game.Rulesets.Catch.UI
{ {
Vector2 screenPosition = judgedObject.ScreenSpaceDrawQuad.Centre; Vector2 screenPosition = judgedObject.ScreenSpaceDrawQuad.Centre;
Remove(judgedObject); Remove(judgedObject);
catcherArea.Add(judgedObject, screenPosition); catcher.Add(judgedObject, screenPosition);
} }
} }
} }

View File

@ -0,0 +1,193 @@
// 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.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.MathUtils;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
namespace osu.Game.Rulesets.Catch.UI
{
public class Catcher : Container, IKeyBindingHandler<CatchAction>
{
private Texture texture;
private Container<DrawableHitObject> caughtFruit;
public Container ExplodingFruitTarget;
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
Children = new Drawable[]
{
createCatcherSprite(),
caughtFruit = new Container<DrawableHitObject>
{
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
}
};
}
private int currentDirection;
private bool dashing;
protected bool Dashing
{
get { return dashing; }
set
{
if (value == dashing) return;
dashing = value;
if (dashing)
Schedule(addAdditiveSprite);
}
}
private void addAdditiveSprite()
{
if (!dashing) return;
var additive = createCatcherSprite();
additive.RelativePositionAxes = Axes.Both;
additive.Blending = BlendingMode.Additive;
additive.Position = Position;
additive.Scale = Scale;
((Container)Parent).Add(additive);
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire();
Scheduler.AddDelayed(addAdditiveSprite, 50);
}
private Sprite createCatcherSprite() => new Sprite
{
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit,
Texture = texture,
OriginPosition = new Vector2(DrawWidth / 2, 10) //temporary until the sprite is aligned correctly.
};
public bool OnPressed(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection--;
return true;
case CatchAction.MoveRight:
currentDirection++;
return true;
case CatchAction.Dash:
Dashing = true;
return true;
}
return false;
}
public bool OnReleased(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection++;
return true;
case CatchAction.MoveRight:
currentDirection--;
return true;
case CatchAction.Dash:
Dashing = false;
return true;
}
return false;
}
/// <summary>
/// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable.
/// </summary>
private const double base_speed = 1.0 / 512;
protected override void Update()
{
base.Update();
if (currentDirection == 0) return;
double dashModifier = Dashing ? 1 : 0.5;
Scale = new Vector2(Math.Sign(currentDirection), 1);
X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * base_speed * dashModifier, 0, 1);
}
public void Add(DrawableHitObject fruit, Vector2 absolutePosition)
{
fruit.RelativePositionAxes = Axes.None;
fruit.Position = new Vector2(ToLocalSpace(absolutePosition).X - DrawSize.X / 2, 0);
fruit.Anchor = Anchor.TopCentre;
fruit.Origin = Anchor.BottomCentre;
fruit.Scale *= 0.7f;
fruit.LifetimeEnd = double.MaxValue;
float distance = fruit.DrawSize.X / 2 * fruit.Scale.X;
while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance))
{
fruit.X += RNG.Next(-5, 5);
fruit.Y -= RNG.Next(0, 5);
}
caughtFruit.Add(fruit);
if (((CatchBaseHit)fruit.HitObject).LastInCombo)
explode();
}
private void explode()
{
var fruit = caughtFruit.ToArray();
foreach (var f in fruit)
{
var originalX = f.X * Scale.X;
if (ExplodingFruitTarget != null)
{
f.Anchor = Anchor.TopLeft;
f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget);
caughtFruit.Remove(f);
ExplodingFruitTarget.Add(f);
}
f.MoveToY(f.Y - 50, 250, Easing.OutSine)
.Then()
.MoveToY(f.Y + 50, 500, Easing.InSine);
f.MoveToX(f.X + originalX * 6, 1000);
f.FadeOut(750);
f.Expire();
}
}
}
}

View File

@ -1,229 +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.Linq;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Bindings;
using osu.Framework.MathUtils;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using OpenTK;
namespace osu.Game.Rulesets.Catch.UI
{
public class CatcherArea : Container
{
private Catcher catcher;
private Container explodingFruitContainer;
public void Add(DrawableHitObject fruit, Vector2 screenPosition) => catcher.AddToStack(fruit, screenPosition);
public bool CheckIfWeCanCatch(CatchBaseHit obj) => Math.Abs(catcher.Position.X - obj.X) < catcher.DrawSize.X / DrawSize.X / 2;
[BackgroundDependencyLoader]
private void load()
{
Children = new Drawable[]
{
explodingFruitContainer = new Container
{
RelativeSizeAxes = Axes.Both,
},
catcher = new Catcher
{
RelativePositionAxes = Axes.Both,
ExplodingFruitTarget = explodingFruitContainer,
Origin = Anchor.TopCentre,
X = 0.5f,
}
};
}
protected override void Update()
{
base.Update();
catcher.Size = new Vector2(DrawSize.Y);
}
private class Catcher : Container, IKeyBindingHandler<CatchAction>
{
private Texture texture;
private Container<DrawableHitObject> caughtFruit;
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
Children = new Drawable[]
{
createCatcherSprite(),
caughtFruit = new Container<DrawableHitObject>
{
Anchor = Anchor.TopCentre,
Origin = Anchor.BottomCentre,
}
};
}
private int currentDirection;
private bool dashing;
public Container ExplodingFruitTarget;
protected bool Dashing
{
get { return dashing; }
set
{
if (value == dashing) return;
dashing = value;
if (dashing)
Schedule(addAdditiveSprite);
}
}
private void addAdditiveSprite()
{
if (!dashing) return;
var additive = createCatcherSprite();
additive.RelativePositionAxes = Axes.Both;
additive.Blending = BlendingMode.Additive;
additive.Position = Position;
additive.Scale = Scale;
((CatcherArea)Parent).Add(additive);
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint).Expire();
Scheduler.AddDelayed(addAdditiveSprite, 50);
}
private Sprite createCatcherSprite() => new Sprite
{
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit,
Texture = texture,
OriginPosition = new Vector2(DrawWidth / 2, 10) //temporary until the sprite is aligned correctly.
};
public bool OnPressed(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection--;
return true;
case CatchAction.MoveRight:
currentDirection++;
return true;
case CatchAction.Dash:
Dashing = true;
return true;
}
return false;
}
public bool OnReleased(CatchAction action)
{
switch (action)
{
case CatchAction.MoveLeft:
currentDirection++;
return true;
case CatchAction.MoveRight:
currentDirection--;
return true;
case CatchAction.Dash:
Dashing = false;
return true;
}
return false;
}
/// <summary>
/// The relative space to cover in 1 millisecond. based on 1 game pixel per millisecond as in osu-stable.
/// </summary>
private const double base_speed = 1.0 / 512;
protected override void Update()
{
base.Update();
if (currentDirection == 0) return;
double dashModifier = Dashing ? 1 : 0.5;
Scale = new Vector2(Math.Sign(currentDirection), 1);
X = (float)MathHelper.Clamp(X + Math.Sign(currentDirection) * Clock.ElapsedFrameTime * base_speed * dashModifier, 0, 1);
}
public void AddToStack(DrawableHitObject fruit, Vector2 absolutePosition)
{
fruit.RelativePositionAxes = Axes.None;
fruit.Position = new Vector2(ToLocalSpace(absolutePosition).X - DrawSize.X / 2, 0);
fruit.Anchor = Anchor.TopCentre;
fruit.Origin = Anchor.BottomCentre;
fruit.Scale *= 0.7f;
fruit.LifetimeEnd = double.MaxValue;
float distance = fruit.DrawSize.X / 2 * fruit.Scale.X;
while (caughtFruit.Any(f => f.LifetimeEnd == double.MaxValue && Vector2Extensions.DistanceSquared(f.Position, fruit.Position) < distance * distance))
{
fruit.X += RNG.Next(-5, 5);
fruit.Y -= RNG.Next(0, 5);
}
caughtFruit.Add(fruit);
if (((CatchBaseHit)fruit.HitObject).LastInCombo)
explode();
}
private void explode()
{
var fruit = caughtFruit.ToArray();
foreach (var f in fruit)
{
var originalX = f.X * Scale.X;
if (ExplodingFruitTarget != null)
{
f.Anchor = Anchor.TopLeft;
f.Position = caughtFruit.ToSpaceOfOtherDrawable(f.DrawPosition, ExplodingFruitTarget);
caughtFruit.Remove(f);
ExplodingFruitTarget.Add(f);
}
f.MoveToY(f.Y - 50, 250, Easing.OutSine)
.Then()
.MoveToY(f.Y + 50, 500, Easing.InSine);
f.MoveToX(f.X + originalX * 6, 1000);
f.FadeOut(750);
f.Expire();
}
}
}
}
}

View File

@ -59,7 +59,7 @@
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Tests\TestCaseCatcher.cs" /> <Compile Include="Tests\TestCaseCatcher.cs" />
<Compile Include="Tests\TestCaseCatchPlayer.cs" /> <Compile Include="Tests\TestCaseCatchPlayer.cs" />
<Compile Include="UI\CatcherArea.cs" /> <Compile Include="UI\Catcher.cs" />
<Compile Include="UI\CatchRulesetContainer.cs" /> <Compile Include="UI\CatchRulesetContainer.cs" />
<Compile Include="UI\CatchPlayfield.cs" /> <Compile Include="UI\CatchPlayfield.cs" />
<Compile Include="CatchRuleset.cs" /> <Compile Include="CatchRuleset.cs" />

View File

@ -55,14 +55,17 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original); Beatmap<TaikoHitObject> converted = base.ConvertBeatmap(original);
// Post processing step to transform hit objects with the same start time into strong hits if (original.BeatmapInfo.RulesetID == 3)
converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>
{ {
TaikoHitObject first = x.First(); // Post processing step to transform mania hit objects with the same start time into strong hits
if (x.Skip(1).Any()) converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>
first.IsStrong = true; {
return first; TaikoHitObject first = x.First();
}).ToList(); if (x.Skip(1).Any())
first.IsStrong = true;
return first;
}).ToList();
}
return converted; return converted;
} }

View File

@ -58,6 +58,23 @@ namespace osu.Game.Beatmaps
ComboColors = original?.ComboColors ?? ComboColors; ComboColors = original?.ComboColors ?? ComboColors;
HitObjects = original?.HitObjects ?? HitObjects; HitObjects = original?.HitObjects ?? HitObjects;
Storyboard = original?.Storyboard ?? Storyboard; Storyboard = original?.Storyboard ?? Storyboard;
if (original == null && Metadata == null)
{
// we may have no metadata in cases we weren't sourced from the database.
// let's fill it (and other related fields) so we don't need to null-check it in future usages.
BeatmapInfo = new BeatmapInfo
{
Metadata = new BeatmapMetadata
{
Artist = @"Unknown",
Title = @"Unknown",
Author = @"Unknown Creator",
},
Version = @"Normal",
Difficulty = new BeatmapDifficulty()
};
}
} }
} }

View File

@ -59,7 +59,7 @@ namespace osu.Game.Graphics.UserInterface
public class OsuTabItem : TabItem<T>, IHasAccentColour public class OsuTabItem : TabItem<T>, IHasAccentColour
{ {
protected readonly SpriteText Text; protected readonly SpriteText Text;
private readonly Box box; protected readonly Box Bar;
private Color4 accentColour; private Color4 accentColour;
public Color4 AccentColour public Color4 AccentColour
@ -77,13 +77,13 @@ namespace osu.Game.Graphics.UserInterface
private void fadeActive() private void fadeActive()
{ {
box.FadeIn(transition_length, Easing.OutQuint); Bar.FadeIn(transition_length, Easing.OutQuint);
Text.FadeColour(Color4.White, transition_length, Easing.OutQuint); Text.FadeColour(Color4.White, transition_length, Easing.OutQuint);
} }
private void fadeInactive() private void fadeInactive()
{ {
box.FadeOut(transition_length, Easing.OutQuint); Bar.FadeOut(transition_length, Easing.OutQuint);
Text.FadeColour(AccentColour, transition_length, Easing.OutQuint); Text.FadeColour(AccentColour, transition_length, Easing.OutQuint);
} }
@ -123,7 +123,7 @@ namespace osu.Game.Graphics.UserInterface
TextSize = 14, TextSize = 14,
Font = @"Exo2.0-Bold", // Font should only turn bold when active? Font = @"Exo2.0-Bold", // Font should only turn bold when active?
}, },
box = new Box Bar = new Box
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = 1, Height = 1,

View File

@ -38,7 +38,6 @@ namespace osu.Game.Rulesets
protected override void Prepare(bool reset = false) protected override void Prepare(bool reset = false)
{ {
Connection.CreateTable<RulesetInfo>(); Connection.CreateTable<RulesetInfo>();
if (reset) if (reset)

View File

@ -32,16 +32,11 @@ namespace osu.Game.Screens.Edit
Height = 40, Height = 40,
Children = new Drawable[] Children = new Drawable[]
{ {
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex("111")
},
new EditorMenuBar new EditorMenuBar
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
X = 100, RelativeSizeAxes = Axes.Both,
Items = new[] Items = new[]
{ {
new EditorMenuBarItem("File") new EditorMenuBarItem("File")

View File

@ -19,8 +19,20 @@ namespace osu.Game.Screens.Edit.Menus
public EditorMenuBar() public EditorMenuBar()
: base(Direction.Horizontal, true) : base(Direction.Horizontal, true)
{ {
ItemsContainer.Padding = new MarginPadding(0); RelativeSizeAxes = Axes.X;
BackgroundColour = Color4.Transparent;
ItemsContainer.Padding = new MarginPadding { Left = 100 };
BackgroundColour = OsuColour.FromHex("111");
AddRangeInternal(new Drawable[]
{
new ScreenSelectionTabControl
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
X = -15
}
});
} }
protected override Framework.Graphics.UserInterface.Menu CreateSubMenu() => new SubMenu(); protected override Framework.Graphics.UserInterface.Menu CreateSubMenu() => new SubMenu();
@ -29,27 +41,35 @@ namespace osu.Game.Screens.Edit.Menus
private class DrawableEditorBarMenuItem : DrawableOsuMenuItem private class DrawableEditorBarMenuItem : DrawableOsuMenuItem
{ {
private Color4 openedForegroundColour; private BackgroundBox background;
private Color4 openedBackgroundColour;
public DrawableEditorBarMenuItem(MenuItem item) public DrawableEditorBarMenuItem(MenuItem item)
: base(item) : base(item)
{ {
Anchor = Anchor.CentreLeft;
Origin = Anchor.CentreLeft;
StateChanged += stateChanged;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
ForegroundColour = ForegroundColourHover = colours.BlueLight; ForegroundColour = colours.BlueLight;
BackgroundColour = BackgroundColourHover = Color4.Transparent; BackgroundColour = Color4.Transparent;
openedForegroundColour = Color4.White; ForegroundColourHover = Color4.White;
openedBackgroundColour = colours.Gray3; BackgroundColourHover = colours.Gray3;
}
public override void SetFlowDirection(Direction direction)
{
AutoSizeAxes = Axes.Both;
} }
protected override void UpdateBackgroundColour() protected override void UpdateBackgroundColour()
{ {
if (State == MenuItemState.Selected) if (State == MenuItemState.Selected)
Background.FadeColour(openedBackgroundColour); Background.FadeColour(BackgroundColourHover);
else else
base.UpdateBackgroundColour(); base.UpdateBackgroundColour();
} }
@ -57,24 +77,58 @@ namespace osu.Game.Screens.Edit.Menus
protected override void UpdateForegroundColour() protected override void UpdateForegroundColour()
{ {
if (State == MenuItemState.Selected) if (State == MenuItemState.Selected)
Foreground.FadeColour(openedForegroundColour); Foreground.FadeColour(ForegroundColourHover);
else else
base.UpdateForegroundColour(); base.UpdateForegroundColour();
} }
protected override Drawable CreateBackground() => new Container private void stateChanged(MenuItemState newState)
{ {
RelativeSizeAxes = Axes.Both, if (newState == MenuItemState.Selected)
Masking = true, background.Expand();
Child = new Container else
background.Contract();
}
protected override Drawable CreateBackground() => background = new BackgroundBox();
protected override DrawableOsuMenuItem.TextContainer CreateTextContainer() => new TextContainer();
private new class TextContainer : DrawableOsuMenuItem.TextContainer
{
public TextContainer()
{ {
RelativeSizeAxes = Axes.Both, NormalText.TextSize = BoldText.TextSize = 14;
Height = 2, NormalText.Margin = BoldText.Margin = new MarginPadding { Horizontal = 10, Vertical = MARGIN_VERTICAL };
Masking = true,
CornerRadius = 4,
Child = new Box { RelativeSizeAxes = Axes.Both }
} }
}; }
private class BackgroundBox : CompositeDrawable
{
private readonly Container innerBackground;
public BackgroundBox()
{
RelativeSizeAxes = Axes.Both;
Masking = true;
InternalChild = innerBackground = new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
CornerRadius = 4,
Child = new Box { RelativeSizeAxes = Axes.Both }
};
}
/// <summary>
/// Expands the background such that it doesn't show the bottom corners.
/// </summary>
public void Expand() => innerBackground.Height = 2;
/// <summary>
/// Contracts the background such that it shows the bottom corners.
/// </summary>
public void Contract() => innerBackground.Height = 1;
}
} }
private class SubMenu : OsuMenu private class SubMenu : OsuMenu

View File

@ -0,0 +1,85 @@
// 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.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using OpenTK;
using System.ComponentModel;
namespace osu.Game.Screens.Edit.Menus
{
public class ScreenSelectionTabControl : OsuTabControl<EditorScreenMode>
{
public ScreenSelectionTabControl()
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
TabContainer.RelativeSizeAxes &= ~Axes.X;
TabContainer.AutoSizeAxes = Axes.X;
TabContainer.Padding = new MarginPadding();
Add(new Box
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
Height = 1,
Colour = Color4.White.Opacity(0.2f),
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AccentColour = colours.Yellow;
}
protected override Dropdown<EditorScreenMode> CreateDropdown() => null;
protected override TabItem<EditorScreenMode> CreateTabItem(EditorScreenMode value) => new TabItem(value);
private class TabItem : OsuTabItem
{
private const float transition_length = 250;
public TabItem(EditorScreenMode value)
: base(value)
{
Text.Margin = new MarginPadding();
Text.Anchor = Anchor.CentreLeft;
Text.Origin = Anchor.CentreLeft;
}
protected override void OnActivated()
{
base.OnActivated();
Bar.ScaleTo(new Vector2(1, 5), transition_length, Easing.OutQuint);
}
protected override void OnDeactivated()
{
base.OnDeactivated();
Bar.ScaleTo(Vector2.One, transition_length, Easing.OutQuint);
}
}
}
public enum EditorScreenMode
{
[Description("compose")]
Compose,
[Description("design")]
Design,
[Description("timing")]
Timing,
[Description("song")]
SongSetup
}
}

View File

@ -1,7 +1,10 @@
// 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.Collections.Generic;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Edit.Menus; using osu.Game.Screens.Edit.Menus;
@ -9,74 +12,82 @@ namespace osu.Game.Tests.Visual
{ {
public class TestCaseEditorMenuBar : OsuTestCase public class TestCaseEditorMenuBar : OsuTestCase
{ {
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(EditorMenuBar), typeof(ScreenSelectionTabControl) };
public TestCaseEditorMenuBar() public TestCaseEditorMenuBar()
{ {
Add(new EditorMenuBar Add(new Container
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
Height = 50,
Y = 50, Y = 50,
Items = new[] Child = new EditorMenuBar
{ {
new EditorMenuBarItem("File") RelativeSizeAxes = Axes.Both,
Items = new[]
{ {
Items = new[] new EditorMenuBarItem("File")
{ {
new EditorMenuItem("Clear All Notes"), Items = new[]
new EditorMenuItem("Open Difficulty..."), {
new EditorMenuItem("Save"), new EditorMenuItem("Clear All Notes"),
new EditorMenuItem("Create a new Difficulty..."), new EditorMenuItem("Open Difficulty..."),
new EditorMenuItemSpacer(), new EditorMenuItem("Save"),
new EditorMenuItem("Revert to Saved"), new EditorMenuItem("Create a new Difficulty..."),
new EditorMenuItem("Revert to Saved (Full)"), new EditorMenuItemSpacer(),
new EditorMenuItemSpacer(), new EditorMenuItem("Revert to Saved"),
new EditorMenuItem("Test Beatmap"), new EditorMenuItem("Revert to Saved (Full)"),
new EditorMenuItem("Open AiMod"), new EditorMenuItemSpacer(),
new EditorMenuItemSpacer(), new EditorMenuItem("Test Beatmap"),
new EditorMenuItem("Upload Beatmap..."), new EditorMenuItem("Open AiMod"),
new EditorMenuItem("Export Package"), new EditorMenuItemSpacer(),
new EditorMenuItem("Export Map Package"), new EditorMenuItem("Upload Beatmap..."),
new EditorMenuItem("Import from..."), new EditorMenuItem("Export Package"),
new EditorMenuItemSpacer(), new EditorMenuItem("Export Map Package"),
new EditorMenuItem("Open Song Folder"), new EditorMenuItem("Import from..."),
new EditorMenuItem("Open .osu in Notepad"), new EditorMenuItemSpacer(),
new EditorMenuItem("Open .osb in Notepad"), new EditorMenuItem("Open Song Folder"),
new EditorMenuItemSpacer(), new EditorMenuItem("Open .osu in Notepad"),
new EditorMenuItem("Exit"), new EditorMenuItem("Open .osb in Notepad"),
} new EditorMenuItemSpacer(),
}, new EditorMenuItem("Exit"),
new EditorMenuBarItem("Timing") }
{ },
Items = new[] new EditorMenuBarItem("Timing")
{ {
new EditorMenuItem("Time Signature"), Items = new[]
new EditorMenuItem("Metronome Clicks"), {
new EditorMenuItemSpacer(), new EditorMenuItem("Time Signature"),
new EditorMenuItem("Add Timing Section"), new EditorMenuItem("Metronome Clicks"),
new EditorMenuItem("Add Inheriting Section"), new EditorMenuItemSpacer(),
new EditorMenuItem("Reset Current Section"), new EditorMenuItem("Add Timing Section"),
new EditorMenuItem("Delete Timing Section"), new EditorMenuItem("Add Inheriting Section"),
new EditorMenuItem("Resnap Current Section"), new EditorMenuItem("Reset Current Section"),
new EditorMenuItemSpacer(), new EditorMenuItem("Delete Timing Section"),
new EditorMenuItem("Timing Setup"), new EditorMenuItem("Resnap Current Section"),
new EditorMenuItemSpacer(), new EditorMenuItemSpacer(),
new EditorMenuItem("Resnap All Notes", MenuItemType.Destructive), new EditorMenuItem("Timing Setup"),
new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive), new EditorMenuItemSpacer(),
new EditorMenuItem("Recalculate Slider Lengths", MenuItemType.Destructive), new EditorMenuItem("Resnap All Notes", MenuItemType.Destructive),
new EditorMenuItem("Delete All Timing Sections", MenuItemType.Destructive), new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive),
new EditorMenuItemSpacer(), new EditorMenuItem("Recalculate Slider Lengths", MenuItemType.Destructive),
new EditorMenuItem("Set Current Position as Preview Point"), new EditorMenuItem("Delete All Timing Sections", MenuItemType.Destructive),
} new EditorMenuItemSpacer(),
}, new EditorMenuItem("Set Current Position as Preview Point"),
new EditorMenuBarItem("Testing") }
{ },
Items = new[] new EditorMenuBarItem("Testing")
{ {
new EditorMenuItem("Item 1"), Items = new[]
new EditorMenuItem("Item 2"), {
new EditorMenuItem("Item 3"), new EditorMenuItem("Item 1"),
} new EditorMenuItem("Item 2"),
}, new EditorMenuItem("Item 3"),
}
},
}
} }
}); });
} }

View File

@ -1,6 +1,7 @@
// 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.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@ -18,31 +19,39 @@ namespace osu.Game.Tests.Visual
{ {
public class TestCasePlayer : OsuTestCase public class TestCasePlayer : OsuTestCase
{ {
private readonly Type ruleset;
protected Player Player; protected Player Player;
private RulesetStore rulesets;
public override string Description => @"Showing everything to play the game."; public override string Description => @"Showing everything to play the game.";
/// <summary>
/// Create a TestCase which runs through the Player screen.
/// </summary>
/// <param name="ruleset">An optional ruleset type which we want to target. If not provided we'll allow all rulesets to be tested.</param>
protected TestCasePlayer(Type ruleset)
{
this.ruleset = ruleset;
}
public TestCasePlayer()
{
}
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(RulesetStore rulesets) private void load(RulesetStore rulesets)
{ {
this.rulesets = rulesets;
}
protected override void LoadComplete()
{
base.LoadComplete();
Add(new Box Add(new Box
{ {
RelativeSizeAxes = Framework.Graphics.Axes.Both, RelativeSizeAxes = Framework.Graphics.Axes.Both,
Colour = Color4.Black, Colour = Color4.Black,
}); });
foreach (var r in rulesets.Query<RulesetInfo>()) string instantiation = ruleset?.AssemblyQualifiedName;
AddStep(r.Name, () => loadPlayerFor(r));
loadPlayerFor(rulesets.Query<RulesetInfo>().First()); foreach (var r in rulesets.Query<RulesetInfo>(rs => rs.Available && (instantiation == null || rs.InstantiationInfo == instantiation)))
AddStep(r.Name, () => loadPlayerFor(r));
} }
protected virtual Beatmap CreateBeatmap() protected virtual Beatmap CreateBeatmap()

View File

@ -617,6 +617,7 @@
<Compile Include="Screens\Edit\Menus\EditorMenuBarItem.cs" /> <Compile Include="Screens\Edit\Menus\EditorMenuBarItem.cs" />
<Compile Include="Screens\Edit\Menus\EditorMenuItem.cs" /> <Compile Include="Screens\Edit\Menus\EditorMenuItem.cs" />
<Compile Include="Screens\Edit\Menus\EditorMenuItemSpacer.cs" /> <Compile Include="Screens\Edit\Menus\EditorMenuItemSpacer.cs" />
<Compile Include="Screens\Edit\Menus\ScreenSelectionTabControl.cs" />
<Compile Include="Screens\Loader.cs" /> <Compile Include="Screens\Loader.cs" />
<Compile Include="Screens\Menu\Button.cs" /> <Compile Include="Screens\Menu\Button.cs" />
<Compile Include="Screens\Menu\ButtonSystem.cs" /> <Compile Include="Screens\Menu\ButtonSystem.cs" />