1
0
mirror of https://github.com/ppy/osu.git synced 2026-05-24 02:09:54 +08:00
Files
osu-lazer/osu.Game/Screens/OnlinePlay/Matchmaking/Queue/PoolSelector.cs
T
2025-11-27 18:25:32 +09:00

278 lines
10 KiB
C#

// 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.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.Matchmaking;
using osu.Game.Overlays;
using osu.Game.Rulesets;
using osuTK;
using osuTK.Graphics;
using osuTK.Input;
namespace osu.Game.Screens.OnlinePlay.Matchmaking.Queue
{
public partial class PoolSelector : CompositeDrawable
{
private const float icon_size = 34;
public readonly Bindable<MatchmakingPool[]> AvailablePools = new Bindable<MatchmakingPool[]>();
public readonly Bindable<MatchmakingPool?> SelectedPool = new Bindable<MatchmakingPool?>();
private FillFlowContainer<SelectorButton> poolFlow = null!;
public PoolSelector()
{
AutoSizeAxes = Axes.Both;
}
[BackgroundDependencyLoader]
private void load()
{
InternalChild = poolFlow = new FillFlowContainer<SelectorButton>
{
AutoSizeAxes = Axes.X,
Height = SelectorButton.SIZE.Y + 10,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(5),
};
}
protected override void LoadComplete()
{
base.LoadComplete();
AvailablePools.BindValueChanged(pools =>
{
poolFlow.Clear();
foreach (var p in pools.NewValue)
{
poolFlow.Add(new SelectorButton(p)
{
SelectedPool = { BindTarget = SelectedPool },
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
});
}
}, true);
}
protected override bool OnKeyDown(KeyDownEvent e)
{
var currentSelection = poolFlow.SingleOrDefault(b => b.IsSelected);
switch (e.Key)
{
case Key.Left:
{
var next = poolFlow.Reverse().SkipWhile(b => b != currentSelection).Skip(1).FirstOrDefault();
(next ?? poolFlow.Last()).TriggerClickWithSound();
return true;
}
case Key.Right:
{
var next = poolFlow.SkipWhile(b => b != currentSelection).Skip(1).FirstOrDefault();
(next ?? poolFlow.First()).TriggerClickWithSound();
return true;
}
}
return false;
}
private partial class SelectorButton : OsuAnimatedButton
{
public static readonly Vector2 SIZE = new Vector2(84, 78);
public bool IsSelected => SelectedPool.Value?.Equals(pool) == true;
public readonly Bindable<MatchmakingPool?> SelectedPool = new Bindable<MatchmakingPool?>();
[Resolved]
private RulesetStore rulesetStore { get; set; } = null!;
private readonly MatchmakingPool pool;
private Drawable iconSprite = null!;
private Box flashLayer = null!;
public SelectorButton(MatchmakingPool pool)
: base(HoverSampleSet.ButtonSidebar)
{
this.pool = pool;
Size = SIZE;
}
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
Content.Masking = true;
Content.CornerRadius = 16;
Content.CornerExponent = 10;
Ruleset? rulesetInstance = rulesetStore.GetRuleset(pool.RulesetId)?.CreateInstance();
string rulesetName = rulesetInstance?.Description ?? string.Empty;
if (pool.Variant != 0)
rulesetName += $" {pool.Variant}K";
Children = new Drawable[]
{
new Box
{
Colour = colourProvider.Background2,
Alpha = 0.4f,
RelativeSizeAxes = Axes.Both,
},
flashLayer = new Box
{
Colour = Color4.White,
Blending = BlendingParameters.Additive,
Alpha = 0,
RelativeSizeAxes = Axes.Both,
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Padding = new MarginPadding(5) { Top = 8 },
Children = new Drawable[]
{
new Container
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Size = new Vector2(icon_size),
Padding = new MarginPadding(2),
Children = new[]
{
iconSprite = createIcon(),
}
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Font = OsuFont.Style.Caption1.With(weight: FontWeight.Bold),
Text = rulesetName,
},
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Font = OsuFont.Style.Caption2,
Text = pool.Name
}
}
}
}
},
};
Action = () => SelectedPool.Value = pool;
}
protected override void LoadComplete()
{
base.LoadComplete();
SelectedPool.BindValueChanged(onSelectionChanged, true);
FinishTransforms(true);
}
protected override bool OnHover(HoverEvent e)
{
if (!IsSelected)
flashLayer.FadeTo(0.05f, 200, Easing.OutQuint);
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
if (!IsSelected)
flashLayer.FadeTo(0f, 200, Easing.OutQuint);
base.OnHoverLost(e);
}
private void onSelectionChanged(ValueChangedEvent<MatchmakingPool?> selection)
{
if (IsSelected)
{
this.ScaleTo(1.2f, 200, Easing.OutQuint);
iconSprite.FadeColour(Color4.Gold, 100, Easing.OutQuint);
flashLayer.FadeTo(0.1f, 200, Easing.OutQuint);
}
else
{
this.ScaleTo(1f, 200, Easing.OutQuint);
iconSprite.FadeColour(OsuColour.Gray(0.5f), 100);
flashLayer.FadeOut(200, Easing.OutQuint);
}
}
private Drawable createIcon()
{
Ruleset? rulesetInstance = rulesetStore.GetRuleset(pool.RulesetId)?.CreateInstance();
if (rulesetInstance == null)
return Empty();
Drawable icon = rulesetInstance.CreateIcon().With(d => d.RelativeSizeAxes = Axes.Both);
if (pool.Variant == 0)
return icon;
return new BufferedContainer(pixelSnapping: true)
{
RelativeSizeAxes = Axes.Both,
Children = new[]
{
icon,
new Container
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Size = icon_size * new Vector2(0.4f, 0.28f),
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
},
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Text = $"{pool.Variant}K",
Font = OsuFont.Default.With(size: icon_size * 0.3f, weight: FontWeight.Bold),
UseFullGlyphHeight = false,
Blending = new BlendingParameters
{
AlphaEquation = BlendingEquation.ReverseSubtract
}
}
}
}
}
};
}
}
}
}