1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-12 07:27:51 +08:00
osu-lazer/osu.Game/Graphics/Containers/SelectionCycleFillFlowContainer.cs
2021-07-06 14:39:53 +02:00

106 lines
3.3 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;
using System.Collections.Generic;
using osu.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Graphics.Containers
{
/// <summary>
/// A FillFlowContainer that provides functionality to cycle selection between children
/// The selection wraps around when overflowing past the first or last child.
/// </summary>
public class SelectionCycleFillFlowContainer<T> : FillFlowContainer<T> where T : Drawable, IStateful<SelectionState>
{
private int? selectedIndex;
public T Selected => (selectedIndex >= 0 && selectedIndex < Count) ? this[selectedIndex.Value] : null;
private void setSelected(int? value)
{
if (selectedIndex == value)
return;
// Deselect the previously-selected button
if (selectedIndex.HasValue)
this[selectedIndex.Value].State = SelectionState.NotSelected;
selectedIndex = value;
// Select the newly-selected button
if (selectedIndex.HasValue)
this[selectedIndex.Value].State = SelectionState.Selected;
}
public void SelectNext()
{
if (!selectedIndex.HasValue || selectedIndex == Count - 1)
setSelected(0);
else
setSelected(selectedIndex.Value + 1);
}
public void SelectPrevious()
{
if (!selectedIndex.HasValue || selectedIndex == 0)
setSelected(Count - 1);
else
setSelected(selectedIndex.Value - 1);
}
public void Deselect() => setSelected(null);
public void Select(T item)
{
var newIndex = IndexOf(item);
if (newIndex < 0)
setSelected(null);
else
setSelected(IndexOf(item));
}
private readonly Dictionary<T, Action<SelectionState>> handlerMap = new Dictionary<T, Action<SelectionState>>();
public override void Add(T drawable)
{
base.Add(drawable);
if (drawable != null)
{
// This event is used to update selection state when modified within the drawable itself.
// It is added to a dictionary so that we can unsubscribe if the drawable is removed from this container
handlerMap[drawable] = state => selectionChanged(drawable, state);
drawable.StateChanged += handlerMap[drawable];
}
}
public override bool Remove(T drawable)
{
if (!base.Remove(drawable))
return false;
if (drawable != null && handlerMap.TryGetValue(drawable, out var action))
{
drawable.StateChanged -= action;
handlerMap.Remove(drawable);
}
return true;
}
private void selectionChanged(T drawable, SelectionState state)
{
if (state == SelectionState.NotSelected)
Deselect();
else
Select(drawable);
}
}
}