Skip to content

Commit

Permalink
Implement group panel design
Browse files Browse the repository at this point in the history
  • Loading branch information
frenzibyte committed Feb 5, 2025
1 parent e102981 commit cb89684
Show file tree
Hide file tree
Showing 4 changed files with 541 additions and 48 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright (c) ppy Pty Ltd <[email protected]>. 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.Containers;
using osu.Game.Screens.SelectV2;
using osu.Game.Tests.Visual.UserInterface;
using osuTK;

namespace osu.Game.Tests.Visual.SongSelectV2
{
public partial class TestSceneBeatmapCarouselGroupPanel : ThemeComparisonTestScene
{
public TestSceneBeatmapCarouselGroupPanel()
: base(false)
{
}

protected override Drawable CreateContent()
{
return new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 0.5f,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0f, 5f),
Children = new Drawable[]
{
new GroupPanel
{
Item = new CarouselItem(new GroupDefinition("Group A"))
},
new GroupPanel
{
Item = new CarouselItem(new GroupDefinition("Group A")),
KeyboardSelected = { Value = true }
},
new GroupPanel
{
Item = new CarouselItem(new GroupDefinition("Group A")),
Selected = { Value = true }
},
new GroupPanel
{
Item = new CarouselItem(new GroupDefinition("Group A")),
KeyboardSelected = { Value = true },
Selected = { Value = true }
},
new StarsGroupPanel
{
Item = new CarouselItem(new StarsGroupDefinition(1))
},
new StarsGroupPanel
{
Item = new CarouselItem(new StarsGroupDefinition(3)),
},
new StarsGroupPanel
{
Item = new CarouselItem(new StarsGroupDefinition(5)),
},
new StarsGroupPanel
{
Item = new CarouselItem(new StarsGroupDefinition(7)),
},
new StarsGroupPanel
{
Item = new CarouselItem(new StarsGroupDefinition(8)),
},
new StarsGroupPanel
{
Item = new CarouselItem(new StarsGroupDefinition(9)),
},
}
};
}
}
}
1 change: 1 addition & 0 deletions osu.Game/Screens/SelectV2/BeatmapCarousel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -264,4 +264,5 @@ protected override Drawable GetDrawableForDisplay(CarouselItem item)
}

public record GroupDefinition(string Title);
public record StarsGroupDefinition(int StarNumber);

Check failure on line 267 in osu.Game/Screens/SelectV2/BeatmapCarousel.cs

View workflow job for this annotation

GitHub Actions / Code Quality

Blank lines are missing, expected minimum 1 instead of 0 in osu.Game\Screens\SelectV2\BeatmapCarousel.cs on line 267
}
220 changes: 172 additions & 48 deletions osu.Game/Screens/SelectV2/GroupPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,35 @@
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
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.Overlays;
using osuTK;
using osuTK.Graphics;

namespace osu.Game.Screens.SelectV2
{
public partial class GroupPanel : PoolableDrawable, ICarouselPanel
{
public const float HEIGHT = CarouselItem.DEFAULT_HEIGHT * 2;
public const float HEIGHT = CarouselItem.DEFAULT_HEIGHT;

private const float glow_offset = 10f; // extra space for the edge effect to not be cutoff by the right edge of the carousel.
private const float preselected_x_offset = 25f;
private const float selected_x_offset = 50f;

private const float duration = 500;

[Resolved]
private BeatmapCarousel carousel { get; set; } = null!;
private BeatmapCarousel? carousel { get; set; }

private Box activationFlash = null!;
private OsuSpriteText text = null!;

private Box box = null!;
private OsuSpriteText titleText = null!;
private Box hoverLayer = null!;

public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
{
Expand All @@ -39,56 +48,128 @@ public override bool ReceivePositionalInputAt(Vector2 screenSpacePos)
}

[BackgroundDependencyLoader]
private void load()
private void load(OverlayColourProvider colourProvider, OsuColour colours)
{
Size = new Vector2(500, HEIGHT);
Masking = true;
Anchor = Anchor.TopRight;
Origin = Anchor.TopRight;
RelativeSizeAxes = Axes.X;
Height = HEIGHT;

InternalChildren = new Drawable[]
InternalChild = new Container
{
box = new Box
{
Colour = Color4.DarkBlue.Darken(5),
Alpha = 0.8f,
RelativeSizeAxes = Axes.Both,
},
activationFlash = new Box
{
Colour = Color4.White,
Blending = BlendingParameters.Additive,
Alpha = 0,
RelativeSizeAxes = Axes.Both,
},
text = new OsuSpriteText
RelativeSizeAxes = Axes.Both,
CornerRadius = 10f,
Masking = true,
Children = new Drawable[]
{
Padding = new MarginPadding(5),
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = 10f },
Child = new Container
{
RelativeSizeAxes = Axes.Both,
CornerRadius = 10f,
Masking = true,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colourProvider.Background6,
},
}
}
},
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colourProvider.Background3,
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = 10f },
Child = new Container
{
RelativeSizeAxes = Axes.Both,
CornerRadius = 10f,
Masking = true,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colourProvider.Background5,
},
titleText = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
X = 10f,
},
new CircularContainer
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Size = new Vector2(50f, 14f),
Margin = new MarginPadding { Right = 30f },
Masking = true,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black.Opacity(0.7f),
},
new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.Torus.With(size: 14.4f, weight: FontWeight.Bold),
// TODO: requires Carousel/CarouselItem-side implementation
Text = "43",
UseFullGlyphHeight = false,
}
},
},
}
}
},
activationFlash = new Box
{
Colour = Color4.White,
Blending = BlendingParameters.Additive,
Alpha = 0,
RelativeSizeAxes = Axes.Both,
},
hoverLayer = new Box
{
Colour = colours.Blue.Opacity(0.1f),
Alpha = 0,
Blending = BlendingParameters.Additive,
RelativeSizeAxes = Axes.Both,
},
new HoverSounds(),
}
};
}

Selected.BindValueChanged(value =>
{
activationFlash.FadeTo(value.NewValue ? 0.2f : 0, 500, Easing.OutQuint);
});
protected override void LoadComplete()
{
base.LoadComplete();

Expanded.BindValueChanged(value =>
{
box.FadeColour(value.NewValue ? Color4.SkyBlue : Color4.DarkBlue.Darken(5), 500, Easing.OutQuint);
});
Expanded.BindValueChanged(_ => updateExpandedDisplay(), true);
KeyboardSelected.BindValueChanged(_ => updateKeyboardSelectedDisplay(), true);
}

KeyboardSelected.BindValueChanged(value =>
{
if (value.NewValue)
{
BorderThickness = 5;
BorderColour = Color4.Pink;
}
else
{
BorderThickness = 0;
}
});
private void updateExpandedDisplay()
{
updatePanelPosition();

// todo: figma shares no extra visual feedback on this.

activationFlash.FadeTo(0.2f).FadeTo(0f, 500, Easing.OutQuint);
}

protected override void PrepareForUse()
Expand All @@ -99,17 +180,60 @@ protected override void PrepareForUse()

GroupDefinition group = (GroupDefinition)Item.Model;

text.Text = group.Title;
titleText.Text = group.Title;

this.FadeInFromZero(500, Easing.OutQuint);
}

protected override bool OnClick(ClickEvent e)
{
carousel.CurrentSelection = Item!.Model;
if (carousel != null)
carousel.CurrentSelection = Item!.Model;

return true;
}

private void updateKeyboardSelectedDisplay()
{
updatePanelPosition();
updateHover();
}

private void updatePanelPosition()
{
float x = glow_offset + selected_x_offset + preselected_x_offset;

if (Expanded.Value)
x -= selected_x_offset;

if (KeyboardSelected.Value)
x -= preselected_x_offset;

this.TransformTo(nameof(Padding), new MarginPadding { Left = x }, duration, Easing.OutQuint);
}

private void updateHover()
{
bool hovered = IsHovered || KeyboardSelected.Value;

if (hovered)
hoverLayer.FadeIn(100, Easing.OutQuint);
else
hoverLayer.FadeOut(1000, Easing.OutQuint);
}

protected override bool OnHover(HoverEvent e)
{
updateHover();
return true;
}

protected override void OnHoverLost(HoverLostEvent e)
{
updateHover();
base.OnHoverLost(e);
}

#region ICarouselPanel

public CarouselItem? Item { get; set; }
Expand Down
Loading

0 comments on commit cb89684

Please sign in to comment.