mirror of
https://github.com/ppy/osu.git
synced 2024-11-13 22:07:25 +08:00
Merge branch 'master' into music-effect-arrow-keys-hover
This commit is contained in:
commit
c0b5153094
105
osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
Normal file
105
osu.Game.Rulesets.Catch.Tests/TestSceneCatcher.cs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
using osu.Framework.Audio.Sample;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Tests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneCatcher : OsuTestScene
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(CatcherSprite),
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly Container container;
|
||||||
|
|
||||||
|
public TestSceneCatcher()
|
||||||
|
{
|
||||||
|
Child = container = new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
AddStep("show default catcher implementation", () => { container.Child = new CatcherSprite(); });
|
||||||
|
|
||||||
|
AddStep("show custom catcher implementation", () =>
|
||||||
|
{
|
||||||
|
container.Child = new CatchCustomSkinSourceContainer
|
||||||
|
{
|
||||||
|
Child = new CatcherSprite()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CatcherCustomSkin : Container
|
||||||
|
{
|
||||||
|
public CatcherCustomSkin()
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.Blue
|
||||||
|
},
|
||||||
|
new SpriteText
|
||||||
|
{
|
||||||
|
Text = "custom"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Cached(typeof(ISkinSource))]
|
||||||
|
private class CatchCustomSkinSourceContainer : Container, ISkinSource
|
||||||
|
{
|
||||||
|
public event Action SourceChanged
|
||||||
|
{
|
||||||
|
add { }
|
||||||
|
remove { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public Drawable GetDrawableComponent(string componentName)
|
||||||
|
{
|
||||||
|
switch (componentName)
|
||||||
|
{
|
||||||
|
case "Play/Catch/fruit-catcher-idle":
|
||||||
|
return new CatcherCustomSkin();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SampleChannel GetSample(string sampleName) =>
|
||||||
|
throw new NotImplementedException();
|
||||||
|
|
||||||
|
public Texture GetTexture(string componentName) =>
|
||||||
|
throw new NotImplementedException();
|
||||||
|
|
||||||
|
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration =>
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,8 +6,6 @@ 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.Graphics.Sprites;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.MathUtils;
|
using osu.Framework.MathUtils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -141,7 +139,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
caughtFruit = new Container<DrawableHitObject>
|
caughtFruit = new Container<DrawableHitObject>
|
||||||
{
|
{
|
||||||
@ -212,7 +210,7 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
|
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Sprite createCatcherSprite() => new CatcherSprite();
|
private Drawable createCatcherSprite() => new CatcherSprite();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a caught fruit to the catcher's stack.
|
/// Add a caught fruit to the catcher's stack.
|
||||||
@ -444,23 +442,6 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
fruit.Expire();
|
fruit.Expire();
|
||||||
}
|
}
|
||||||
|
|
||||||
private class CatcherSprite : Sprite
|
|
||||||
{
|
|
||||||
public CatcherSprite()
|
|
||||||
{
|
|
||||||
Size = new Vector2(CATCHER_SIZE);
|
|
||||||
|
|
||||||
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
|
|
||||||
OriginPosition = new Vector2(-0.02f, 0.06f) * CATCHER_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(TextureStore textures)
|
|
||||||
{
|
|
||||||
Texture = textures.Get(@"Play/Catch/fruit-catcher-idle");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
33
osu.Game.Rulesets.Catch/UI/CatcherSprite.cs
Normal file
33
osu.Game.Rulesets.Catch/UI/CatcherSprite.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.UI
|
||||||
|
{
|
||||||
|
public class CatcherSprite : CompositeDrawable
|
||||||
|
{
|
||||||
|
public CatcherSprite()
|
||||||
|
{
|
||||||
|
Size = new Vector2(CatcherArea.CATCHER_SIZE);
|
||||||
|
|
||||||
|
// Sets the origin roughly to the centre of the catcher's plate to allow for correct scaling.
|
||||||
|
OriginPosition = new Vector2(-0.02f, 0.06f) * CatcherArea.CATCHER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
InternalChild = new SkinnableSprite(@"Play/Catch/fruit-catcher-idle")
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,6 @@
|
|||||||
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.Graphics.Sprites;
|
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
|
|
||||||
@ -25,7 +24,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures)
|
private void load(TextureStore textures)
|
||||||
{
|
{
|
||||||
Child = new SkinnableDrawable("Play/osu/approachcircle", name => new Sprite { Texture = textures.Get(name) });
|
Child = new SkinnableSprite("Play/osu/approachcircle");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
55
osu.Game.Tests/Visual/UserInterface/TestSceneNumberBox.cs
Normal file
55
osu.Game.Tests/Visual/UserInterface/TestSceneNumberBox.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.UserInterface
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneNumberBox : OsuTestScene
|
||||||
|
{
|
||||||
|
public override IReadOnlyList<Type> RequiredTypes => new[]
|
||||||
|
{
|
||||||
|
typeof(OsuNumberBox),
|
||||||
|
};
|
||||||
|
|
||||||
|
private OsuNumberBox numberBox;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Child = new Container
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Padding = new MarginPadding { Horizontal = 250 },
|
||||||
|
Child = numberBox = new OsuNumberBox
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
PlaceholderText = "Insert numbers here"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
clearInput();
|
||||||
|
AddStep("enter numbers", () => numberBox.Text = "987654321");
|
||||||
|
expectedValue("987654321");
|
||||||
|
clearInput();
|
||||||
|
AddStep("enter text + single number", () => numberBox.Text = "1 hello 2 world 3");
|
||||||
|
expectedValue("123");
|
||||||
|
clearInput();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearInput() => AddStep("clear input", () => numberBox.Text = null);
|
||||||
|
|
||||||
|
private void expectedValue(string value) => AddAssert("expect number", () => numberBox.Text == value);
|
||||||
|
}
|
||||||
|
}
|
@ -183,7 +183,7 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SettingsTextBox
|
new SettingsNumberBox
|
||||||
{
|
{
|
||||||
LabelText = "Beatmap ID",
|
LabelText = "Beatmap ID",
|
||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
|
@ -231,7 +231,7 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SettingsTextBox
|
new SettingsNumberBox
|
||||||
{
|
{
|
||||||
LabelText = "User ID",
|
LabelText = "User ID",
|
||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
|
10
osu.Game/Graphics/UserInterface/OsuNumberBox.cs
Normal file
10
osu.Game/Graphics/UserInterface/OsuNumberBox.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
namespace osu.Game.Graphics.UserInterface
|
||||||
|
{
|
||||||
|
public class OsuNumberBox : OsuTextBox
|
||||||
|
{
|
||||||
|
protected override bool CanAddCharacter(char character) => char.IsNumber(character);
|
||||||
|
}
|
||||||
|
}
|
@ -50,6 +50,7 @@ namespace osu.Game.Input.Bindings
|
|||||||
{
|
{
|
||||||
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.Tilde }, GlobalAction.QuickExit),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Plus }, GlobalAction.IncreaseScrollSpeed),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Plus }, GlobalAction.IncreaseScrollSpeed),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Minus }, GlobalAction.DecreaseScrollSpeed),
|
||||||
};
|
};
|
||||||
@ -94,6 +95,9 @@ namespace osu.Game.Input.Bindings
|
|||||||
[Description("Quick retry (hold)")]
|
[Description("Quick retry (hold)")]
|
||||||
QuickRetry,
|
QuickRetry,
|
||||||
|
|
||||||
|
[Description("Quick exit (Hold)")]
|
||||||
|
QuickExit,
|
||||||
|
|
||||||
[Description("Take screenshot")]
|
[Description("Take screenshot")]
|
||||||
TakeScreenshot,
|
TakeScreenshot,
|
||||||
|
|
||||||
|
@ -1,153 +1,23 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Graphics;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Game.Graphics;
|
|
||||||
using osu.Game.Graphics.Sprites;
|
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osuTK;
|
|
||||||
using osuTK.Graphics;
|
|
||||||
|
|
||||||
namespace osu.Game.Overlays
|
namespace osu.Game.Overlays
|
||||||
{
|
{
|
||||||
public class OverlayHeaderTabControl : TabControl<string>
|
public class OverlayHeaderTabControl : OverlayTabControl<string>
|
||||||
{
|
{
|
||||||
private readonly Box bar;
|
protected override TabItem<string> CreateTabItem(string value) => new OverlayHeaderTabItem(value)
|
||||||
|
|
||||||
private Color4 accentColour = Color4.White;
|
|
||||||
|
|
||||||
public Color4 AccentColour
|
|
||||||
{
|
{
|
||||||
get => accentColour;
|
AccentColour = AccentColour,
|
||||||
set
|
|
||||||
{
|
|
||||||
if (accentColour == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
accentColour = value;
|
|
||||||
bar.Colour = value;
|
|
||||||
|
|
||||||
foreach (TabItem<string> tabItem in TabContainer)
|
|
||||||
{
|
|
||||||
((HeaderTabItem)tabItem).AccentColour = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public new MarginPadding Padding
|
|
||||||
{
|
|
||||||
get => TabContainer.Padding;
|
|
||||||
set => TabContainer.Padding = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public OverlayHeaderTabControl()
|
|
||||||
{
|
|
||||||
TabContainer.Masking = false;
|
|
||||||
TabContainer.Spacing = new Vector2(15, 0);
|
|
||||||
|
|
||||||
AddInternal(bar = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 2,
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.CentreLeft
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Dropdown<string> CreateDropdown() => null;
|
|
||||||
|
|
||||||
protected override TabItem<string> CreateTabItem(string value) => new HeaderTabItem(value)
|
|
||||||
{
|
|
||||||
AccentColour = AccentColour
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private class HeaderTabItem : TabItem<string>
|
private class OverlayHeaderTabItem : OverlayTabItem<string>
|
||||||
{
|
{
|
||||||
private readonly OsuSpriteText text;
|
public OverlayHeaderTabItem(string value)
|
||||||
private readonly ExpandingBar bar;
|
|
||||||
|
|
||||||
private Color4 accentColour;
|
|
||||||
|
|
||||||
public Color4 AccentColour
|
|
||||||
{
|
|
||||||
get => accentColour;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (accentColour == value)
|
|
||||||
return;
|
|
||||||
|
|
||||||
accentColour = value;
|
|
||||||
bar.Colour = value;
|
|
||||||
|
|
||||||
updateState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public HeaderTabItem(string value)
|
|
||||||
: base(value)
|
: base(value)
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.X;
|
Text.Text = value;
|
||||||
RelativeSizeAxes = Axes.Y;
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
text = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Margin = new MarginPadding { Bottom = 10 },
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Text = value,
|
|
||||||
Font = OsuFont.GetFont()
|
|
||||||
},
|
|
||||||
bar = new ExpandingBar
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
ExpandedSize = 7.5f,
|
|
||||||
CollapsedSize = 0
|
|
||||||
},
|
|
||||||
new HoverClickSounds()
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e)
|
|
||||||
{
|
|
||||||
base.OnHover(e);
|
|
||||||
|
|
||||||
updateState();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnHoverLost(HoverLostEvent e)
|
|
||||||
{
|
|
||||||
base.OnHoverLost(e);
|
|
||||||
|
|
||||||
updateState();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnActivated() => updateState();
|
|
||||||
|
|
||||||
protected override void OnDeactivated() => updateState();
|
|
||||||
|
|
||||||
private void updateState()
|
|
||||||
{
|
|
||||||
if (Active.Value || IsHovered)
|
|
||||||
{
|
|
||||||
text.FadeColour(Color4.White, 120, Easing.InQuad);
|
|
||||||
bar.Expand();
|
|
||||||
|
|
||||||
if (Active.Value)
|
|
||||||
text.Font = text.Font.With(weight: FontWeight.Bold);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
text.FadeColour(AccentColour, 120, Easing.InQuad);
|
|
||||||
bar.Collapse();
|
|
||||||
text.Font = text.Font.With(weight: FontWeight.Medium);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
163
osu.Game/Overlays/OverlayTabControl.cs
Normal file
163
osu.Game/Overlays/OverlayTabControl.cs
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays
|
||||||
|
{
|
||||||
|
public abstract class OverlayTabControl<T> : TabControl<T>
|
||||||
|
{
|
||||||
|
private readonly Box bar;
|
||||||
|
|
||||||
|
private Color4 accentColour = Color4.White;
|
||||||
|
|
||||||
|
public Color4 AccentColour
|
||||||
|
{
|
||||||
|
get => accentColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (accentColour == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
accentColour = value;
|
||||||
|
bar.Colour = value;
|
||||||
|
|
||||||
|
foreach (TabItem<T> tabItem in TabContainer)
|
||||||
|
{
|
||||||
|
((OverlayTabItem<T>)tabItem).AccentColour = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public new MarginPadding Padding
|
||||||
|
{
|
||||||
|
get => TabContainer.Padding;
|
||||||
|
set => TabContainer.Padding = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected OverlayTabControl()
|
||||||
|
{
|
||||||
|
TabContainer.Masking = false;
|
||||||
|
TabContainer.Spacing = new Vector2(15, 0);
|
||||||
|
|
||||||
|
AddInternal(bar = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 2,
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.CentreLeft
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Dropdown<T> CreateDropdown() => null;
|
||||||
|
|
||||||
|
protected override TabItem<T> CreateTabItem(T value) => new OverlayTabItem<T>(value);
|
||||||
|
|
||||||
|
protected class OverlayTabItem<U> : TabItem<U>
|
||||||
|
{
|
||||||
|
private readonly ExpandingBar bar;
|
||||||
|
|
||||||
|
protected readonly OsuSpriteText Text;
|
||||||
|
|
||||||
|
private Color4 accentColour;
|
||||||
|
|
||||||
|
public Color4 AccentColour
|
||||||
|
{
|
||||||
|
get => accentColour;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (accentColour == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
accentColour = value;
|
||||||
|
bar.Colour = value;
|
||||||
|
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public OverlayTabItem(U value)
|
||||||
|
: base(value)
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.X;
|
||||||
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
Text = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding { Bottom = 10 },
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Font = OsuFont.GetFont(),
|
||||||
|
},
|
||||||
|
bar = new ExpandingBar
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
ExpandedSize = 7.5f,
|
||||||
|
CollapsedSize = 0
|
||||||
|
},
|
||||||
|
new HoverClickSounds()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
base.OnHover(e);
|
||||||
|
|
||||||
|
if (!Active.Value)
|
||||||
|
HoverAction();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
|
{
|
||||||
|
base.OnHoverLost(e);
|
||||||
|
|
||||||
|
if (!Active.Value)
|
||||||
|
UnhoverAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnActivated()
|
||||||
|
{
|
||||||
|
HoverAction();
|
||||||
|
Text.Font = Text.Font.With(weight: FontWeight.Bold);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnDeactivated()
|
||||||
|
{
|
||||||
|
UnhoverAction();
|
||||||
|
Text.Font = Text.Font.With(weight: FontWeight.Medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
if (Active.Value)
|
||||||
|
OnActivated();
|
||||||
|
else
|
||||||
|
OnDeactivated();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void HoverAction()
|
||||||
|
{
|
||||||
|
bar.Expand();
|
||||||
|
Text.FadeColour(Color4.White, 120, Easing.InQuad);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void UnhoverAction()
|
||||||
|
{
|
||||||
|
bar.Collapse();
|
||||||
|
Text.FadeColour(AccentColour, 120, Easing.InQuad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
osu.Game/Overlays/Settings/SettingsNumberBox.cs
Normal file
17
osu.Game/Overlays/Settings/SettingsNumberBox.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays.Settings
|
||||||
|
{
|
||||||
|
public class SettingsNumberBox : SettingsItem<string>
|
||||||
|
{
|
||||||
|
protected override Drawable CreateControl() => new OsuNumberBox
|
||||||
|
{
|
||||||
|
Margin = new MarginPadding { Top = 5 },
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -9,7 +9,6 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.UserInterface;
|
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Overlays.Profile;
|
using osu.Game.Overlays.Profile;
|
||||||
using osu.Game.Overlays.Profile.Sections;
|
using osu.Game.Overlays.Profile.Sections;
|
||||||
@ -141,31 +140,28 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ProfileTabControl : PageTabControl<ProfileSection>
|
private class ProfileTabControl : OverlayTabControl<ProfileSection>
|
||||||
{
|
{
|
||||||
private readonly Box bottom;
|
|
||||||
|
|
||||||
public ProfileTabControl()
|
public ProfileTabControl()
|
||||||
{
|
{
|
||||||
TabContainer.RelativeSizeAxes &= ~Axes.X;
|
TabContainer.RelativeSizeAxes &= ~Axes.X;
|
||||||
TabContainer.AutoSizeAxes |= Axes.X;
|
TabContainer.AutoSizeAxes |= Axes.X;
|
||||||
TabContainer.Anchor |= Anchor.x1;
|
TabContainer.Anchor |= Anchor.x1;
|
||||||
TabContainer.Origin |= Anchor.x1;
|
TabContainer.Origin |= Anchor.x1;
|
||||||
AddInternal(bottom = new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 1,
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
EdgeSmoothness = new Vector2(1)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override TabItem<ProfileSection> CreateTabItem(ProfileSection value) => new ProfileTabItem(value);
|
protected override TabItem<ProfileSection> CreateTabItem(ProfileSection value) => new ProfileTabItem(value)
|
||||||
|
{
|
||||||
|
AccentColour = AccentColour
|
||||||
|
};
|
||||||
|
|
||||||
protected override Dropdown<ProfileSection> CreateDropdown() => null;
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colours)
|
||||||
|
{
|
||||||
|
AccentColour = colours.Seafoam;
|
||||||
|
}
|
||||||
|
|
||||||
private class ProfileTabItem : PageTabItem
|
private class ProfileTabItem : OverlayTabItem<ProfileSection>
|
||||||
{
|
{
|
||||||
public ProfileTabItem(ProfileSection value)
|
public ProfileTabItem(ProfileSection value)
|
||||||
: base(value)
|
: base(value)
|
||||||
@ -173,12 +169,6 @@ namespace osu.Game.Overlays
|
|||||||
Text.Text = value.Title;
|
Text.Text = value.Title;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colours)
|
|
||||||
{
|
|
||||||
bottom.Colour = colours.Yellow;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ProfileSectionsContainer : SectionsContainer<ProfileSection>
|
private class ProfileSectionsContainer : SectionsContainer<ProfileSection>
|
||||||
|
28
osu.Game/Screens/Play/HotkeyExitOverlay.cs
Normal file
28
osu.Game/Screens/Play/HotkeyExitOverlay.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
|
namespace osu.Game.Screens.Play
|
||||||
|
{
|
||||||
|
public class HotkeyExitOverlay : HoldToConfirmOverlay, IKeyBindingHandler<GlobalAction>
|
||||||
|
{
|
||||||
|
public bool OnPressed(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (action != GlobalAction.QuickExit) return false;
|
||||||
|
|
||||||
|
BeginConfirm();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnReleased(GlobalAction action)
|
||||||
|
{
|
||||||
|
if (action != GlobalAction.QuickExit) return false;
|
||||||
|
|
||||||
|
AbortConfirm();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -177,6 +177,16 @@ namespace osu.Game.Screens.Play
|
|||||||
Restart();
|
Restart();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
new HotkeyExitOverlay
|
||||||
|
{
|
||||||
|
Action = () =>
|
||||||
|
{
|
||||||
|
if (!this.IsCurrentScreen()) return;
|
||||||
|
|
||||||
|
fadeOut(true);
|
||||||
|
performUserRequestedExit();
|
||||||
|
},
|
||||||
|
},
|
||||||
failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, }
|
failAnimation = new FailAnimation(DrawableRuleset) { OnComplete = onFailComplete, }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -245,6 +255,11 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
if (!this.IsCurrentScreen()) return;
|
if (!this.IsCurrentScreen()) return;
|
||||||
|
|
||||||
|
// if a restart has been requested, cancel any pending completion (user has shown intent to restart).
|
||||||
|
onCompletionEvent = null;
|
||||||
|
|
||||||
|
ValidForResume = false;
|
||||||
|
|
||||||
this.Exit();
|
this.Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,10 @@ namespace osu.Game.Skinning
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A drawable which can be skinned via an <see cref="ISkinSource"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">The type of drawable.</typeparam>
|
||||||
public class SkinnableDrawable<T> : SkinReloadableDrawable
|
public class SkinnableDrawable<T> : SkinReloadableDrawable
|
||||||
where T : Drawable
|
where T : Drawable
|
||||||
{
|
{
|
||||||
@ -23,48 +27,63 @@ namespace osu.Game.Skinning
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected Drawable Drawable { get; private set; }
|
protected Drawable Drawable { get; private set; }
|
||||||
|
|
||||||
private readonly Func<string, T> createDefault;
|
|
||||||
|
|
||||||
private readonly string componentName;
|
private readonly string componentName;
|
||||||
|
|
||||||
private readonly bool restrictSize;
|
private readonly bool restrictSize;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
/// Create a new skinnable drawable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name">The namespace-complete resource name for this skinnable element.</param>
|
/// <param name="name">The namespace-complete resource name for this skinnable element.</param>
|
||||||
/// <param name="defaultImplementation">A function to create the default skin implementation of this element.</param>
|
/// <param name="defaultImplementation">A function to create the default skin implementation of this element.</param>
|
||||||
/// <param name="allowFallback">A conditional to decide whether to allow fallback to the default implementation if a skinned element is not present.</param>
|
/// <param name="allowFallback">A conditional to decide whether to allow fallback to the default implementation if a skinned element is not present.</param>
|
||||||
/// <param name="restrictSize">Whether a user-skin drawable should be limited to the size of our parent.</param>
|
/// <param name="restrictSize">Whether a user-skin drawable should be limited to the size of our parent.</param>
|
||||||
public SkinnableDrawable(string name, Func<string, T> defaultImplementation, Func<ISkinSource, bool> allowFallback = null, bool restrictSize = true)
|
public SkinnableDrawable(string name, Func<string, T> defaultImplementation, Func<ISkinSource, bool> allowFallback = null, bool restrictSize = true)
|
||||||
|
: this(name, allowFallback, restrictSize)
|
||||||
|
{
|
||||||
|
createDefault = defaultImplementation;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected SkinnableDrawable(string name, Func<ISkinSource, bool> allowFallback = null, bool restrictSize = true)
|
||||||
: base(allowFallback)
|
: base(allowFallback)
|
||||||
{
|
{
|
||||||
componentName = name;
|
componentName = name;
|
||||||
createDefault = defaultImplementation;
|
|
||||||
this.restrictSize = restrictSize;
|
this.restrictSize = restrictSize;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly Func<string, T> createDefault;
|
||||||
|
|
||||||
|
protected virtual T CreateDefault(string name) => createDefault(name);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether to apply size restrictions (specified via <see cref="restrictSize"/>) to the default implementation.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool ApplySizeRestrictionsToDefault => false;
|
||||||
|
|
||||||
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
|
||||||
{
|
{
|
||||||
Drawable = skin.GetDrawableComponent(componentName);
|
Drawable = skin.GetDrawableComponent(componentName);
|
||||||
|
|
||||||
|
bool isDefault = false;
|
||||||
|
|
||||||
|
if (Drawable == null && allowFallback)
|
||||||
|
{
|
||||||
|
Drawable = CreateDefault(componentName);
|
||||||
|
isDefault = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (Drawable != null)
|
if (Drawable != null)
|
||||||
{
|
{
|
||||||
if (restrictSize)
|
if (restrictSize && (!isDefault || ApplySizeRestrictionsToDefault))
|
||||||
{
|
{
|
||||||
Drawable.RelativeSizeAxes = Axes.Both;
|
Drawable.RelativeSizeAxes = Axes.Both;
|
||||||
Drawable.Size = Vector2.One;
|
Drawable.Size = Vector2.One;
|
||||||
Drawable.Scale = Vector2.One;
|
Drawable.Scale = Vector2.One;
|
||||||
Drawable.FillMode = FillMode.Fit;
|
Drawable.FillMode = FillMode.Fit;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else if (allowFallback)
|
|
||||||
Drawable = createDefault(componentName);
|
|
||||||
|
|
||||||
if (Drawable != null)
|
|
||||||
{
|
|
||||||
Drawable.Origin = Anchor.Centre;
|
Drawable.Origin = Anchor.Centre;
|
||||||
Drawable.Anchor = Anchor.Centre;
|
Drawable.Anchor = Anchor.Centre;
|
||||||
|
|
||||||
|
28
osu.Game/Skinning/SkinnableSprite.cs
Normal file
28
osu.Game/Skinning/SkinnableSprite.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
|
|
||||||
|
namespace osu.Game.Skinning
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A skinnable element which uses a stable sprite and can therefore share implementation logic.
|
||||||
|
/// </summary>
|
||||||
|
public class SkinnableSprite : SkinnableDrawable<Sprite>
|
||||||
|
{
|
||||||
|
protected override bool ApplySizeRestrictionsToDefault => true;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private TextureStore textures { get; set; }
|
||||||
|
|
||||||
|
public SkinnableSprite(string name, Func<ISkinSource, bool> allowFallback = null, bool restrictSize = true)
|
||||||
|
: base(name, allowFallback, restrictSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Sprite CreateDefault(string name) => new Sprite { Texture = textures.Get(name) };
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user