1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-22 05:23:05 +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,7 +55,9 @@ 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)
{
// Post processing step to transform mania hit objects with the same start time into strong hits
converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x => converted.HitObjects = converted.HitObjects.GroupBy(t => t.StartTime).Select(x =>
{ {
TaikoHitObject first = x.First(); TaikoHitObject first = x.First();
@ -63,6 +65,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
first.IsStrong = true; first.IsStrong = true;
return first; return first;
}).ToList(); }).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,26 +77,60 @@ 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)
{
if (newState == MenuItemState.Selected)
background.Expand();
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()
{
NormalText.TextSize = BoldText.TextSize = 14;
NormalText.Margin = BoldText.Margin = new MarginPadding { Horizontal = 10, Vertical = MARGIN_VERTICAL };
}
}
private class BackgroundBox : CompositeDrawable
{
private readonly Container innerBackground;
public BackgroundBox()
{
RelativeSizeAxes = Axes.Both;
Masking = true;
InternalChild = innerBackground = new Container
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Masking = true, Masking = true,
Child = new Container
{
RelativeSizeAxes = Axes.Both,
Height = 2,
Masking = true,
CornerRadius = 4, CornerRadius = 4,
Child = new Box { RelativeSizeAxes = Axes.Both } 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
{ {
public SubMenu() public SubMenu()

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,13 +12,20 @@ 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,
Child = new EditorMenuBar
{
RelativeSizeAxes = Axes.Both,
Items = new[] Items = new[]
{ {
new EditorMenuBarItem("File") new EditorMenuBarItem("File")
@ -78,6 +88,7 @@ namespace osu.Game.Tests.Visual
} }
}, },
} }
}
}); });
} }
} }

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" />