1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-30 04:23:21 +08:00

Add basic selection support

This commit is contained in:
Dean Herbert 2025-01-10 19:34:56 +09:00
parent 5e9a7532d3
commit 288be46b17
No known key found for this signature in database
5 changed files with 100 additions and 7 deletions

View File

@ -14,6 +14,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Game.Beatmaps;
using osu.Game.Database;
using osu.Game.Graphics.Sprites;
@ -23,6 +24,7 @@ using osuTK.Graphics;
namespace osu.Game.Screens.SelectV2
{
[Cached]
public partial class BeatmapCarouselV2 : Carousel
{
private IBindableList<BeatmapSetInfo> detachedBeatmaps = null!;
@ -102,7 +104,48 @@ namespace osu.Game.Screens.SelectV2
public partial class BeatmapCarouselPanel : PoolableDrawable, ICarouselPanel
{
public CarouselItem? Item { get; set; }
[Resolved]
private BeatmapCarouselV2 carousel { get; set; } = null!;
public CarouselItem? Item
{
get => item;
set
{
item = value;
selected.UnbindBindings();
if (item != null)
selected.BindTo(item.Selected);
}
}
private readonly BindableBool selected = new BindableBool();
private CarouselItem? item;
[BackgroundDependencyLoader]
private void load()
{
selected.BindValueChanged(value =>
{
if (value.NewValue)
{
BorderThickness = 5;
BorderColour = Color4.Pink;
}
else
{
BorderThickness = 0;
}
});
}
protected override void FreeAfterUse()
{
base.FreeAfterUse();
Item = null;
}
protected override void PrepareForUse()
{
@ -111,6 +154,7 @@ namespace osu.Game.Screens.SelectV2
Debug.Assert(Item != null);
Size = new Vector2(500, Item.DrawHeight);
Masking = true;
InternalChildren = new Drawable[]
{
@ -128,6 +172,12 @@ namespace osu.Game.Screens.SelectV2
}
};
}
protected override bool OnClick(ClickEvent e)
{
carousel.CurrentSelection = Item!.Model;
return true;
}
}
public class BeatmapCarouselItem : CarouselItem
@ -165,7 +215,7 @@ namespace osu.Game.Screens.SelectV2
CarouselItem? lastItem = null;
var newItems = new List<CarouselItem>();
var newItems = new List<CarouselItem>(items.Count());
foreach (var item in items)
{

View File

@ -77,8 +77,28 @@ namespace osu.Game.Screens.SelectV2
/// All items which are to be considered for display in this carousel.
/// Mutating this list will automatically queue a <see cref="QueueFilter"/>.
/// </summary>
/// <remarks>
/// Note that an <see cref="ICarouselFilter"/> may add new items which are displayed but not tracked in this list.
/// </remarks>
protected readonly BindableList<CarouselItem> Items = new BindableList<CarouselItem>();
/// <summary>
/// The currently selected model.
/// </summary>
/// <remarks>
/// Setting this will ensure <see cref="CarouselItem.Selected"/> is set to <c>true</c> only on the matching <see cref="CarouselItem"/>.
/// Of note, if no matching item exists all items will be deselected while waiting for potential new item which matches.
/// </remarks>
public virtual object? CurrentSelection
{
get => currentSelection;
set
{
currentSelection = value;
updateSelection();
}
}
private List<CarouselItem>? displayedCarouselItems;
private readonly DoublePrecisionScroll scroll;
@ -169,6 +189,8 @@ namespace osu.Game.Screens.SelectV2
displayedCarouselItems = items.ToList();
displayedRange = null;
updateSelection();
void log(string text) => Logger.Log($"Carousel[op {cts.GetHashCode().ToString().Substring(0, 5)}] {stopwatch.ElapsedMilliseconds} ms: {text}");
}
@ -186,6 +208,24 @@ namespace osu.Game.Screens.SelectV2
#endregion
#region Selection handling
private object? currentSelection;
private void updateSelection()
{
if (displayedCarouselItems == null) return;
// TODO: this is ugly, we probably should stop exposing CarouselItem externally.
foreach (var item in Items)
item.Selected.Value = item.Model == currentSelection;
foreach (var item in displayedCarouselItems)
item.Selected.Value = item.Model == currentSelection;
}
#endregion
#region Display handling
private DisplayRange? displayedRange;

View File

@ -2,22 +2,25 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Bindables;
namespace osu.Game.Screens.SelectV2
{
/// <summary>
/// Represents a single display item for display in a <see cref="Carousel"/>.
/// Represents a single display item for display in a <see cref="Carousel{T}"/>.
/// This is used to house information related to the attached model that helps with display and tracking.
/// </summary>
public abstract class CarouselItem : IComparable<CarouselItem>
{
public readonly BindableBool Selected = new BindableBool();
/// <summary>
/// The model this item is representing.
/// </summary>
public readonly object Model;
/// <summary>
/// The current Y position in the carousel. This is managed by <see cref="Carousel"/> and should not be set manually.
/// The current Y position in the carousel. This is managed by <see cref="Carousel{T}"/> and should not be set manually.
/// </summary>
public double CarouselYPosition { get; set; }

View File

@ -8,7 +8,7 @@ using System.Threading.Tasks;
namespace osu.Game.Screens.SelectV2
{
/// <summary>
/// An interface representing a filter operation which can be run on a <see cref="Carousel"/>.
/// An interface representing a filter operation which can be run on a <see cref="Carousel{T}"/>.
/// </summary>
public interface ICarouselFilter
{

View File

@ -6,7 +6,7 @@ using osu.Framework.Graphics;
namespace osu.Game.Screens.SelectV2
{
/// <summary>
/// An interface to be attached to any <see cref="Drawable"/>s which are used for display inside a <see cref="Carousel"/>.
/// An interface to be attached to any <see cref="Drawable"/>s which are used for display inside a <see cref="Carousel{T}"/>.
/// </summary>
public interface ICarouselPanel
{
@ -16,7 +16,7 @@ namespace osu.Game.Screens.SelectV2
double YPosition => Item!.CarouselYPosition;
/// <summary>
/// The carousel item this drawable is representing. This is managed by <see cref="Carousel"/> and should not be set manually.
/// The carousel item this drawable is representing. This is managed by <see cref="Carousel{T}"/> and should not be set manually.
/// </summary>
CarouselItem? Item { get; set; }
}