1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-12 17:43:05 +08:00

Extract common rearrangeable list design

This commit is contained in:
smoogipoo 2020-02-14 15:36:16 +09:00
parent eb14dbcd77
commit eb75d26c8f
4 changed files with 190 additions and 118 deletions

View File

@ -0,0 +1,26 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Graphics.Containers
{
public abstract class OsuRearrangeableListContainer<TModel> : RearrangeableListContainer<TModel>
{
/// <summary>
/// Whether any item is currently being dragged. Used to hide other items' drag handles.
/// </summary>
private readonly BindableBool playlistDragActive = new BindableBool();
protected override ScrollContainer<Drawable> CreateScrollContainer() => new OsuScrollContainer();
protected sealed override RearrangeableListItem<TModel> CreateDrawable(TModel item) => CreateOsuDrawable(item).With(d =>
{
d.PlaylistDragActive.BindTo(playlistDragActive);
});
protected abstract OsuRearrangeableListItem<TModel> CreateOsuDrawable(TModel item);
}
}

View File

@ -0,0 +1,149 @@
// 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.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Graphics.Containers
{
public abstract class OsuRearrangeableListItem<TModel> : RearrangeableListItem<TModel>
{
public const float FADE_DURATION = 100;
/// <summary>
/// Whether any item is currently being dragged. Used to hide other items' drag handles.
/// </summary>
public readonly BindableBool PlaylistDragActive = new BindableBool();
private Color4 handleColour = Color4.White;
protected Color4 HandleColour
{
get => handleColour;
set
{
if (handleColour == value)
return;
handleColour = value;
if (handle != null)
handle.Colour = value;
}
}
private PlaylistItemHandle handle;
protected OsuRearrangeableListItem(TModel item)
: base(item)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
}
[BackgroundDependencyLoader]
private void load()
{
InternalChild = new GridContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Content = new[]
{
new[]
{
new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Padding = new MarginPadding { Horizontal = 5 },
Child = handle = new PlaylistItemHandle
{
Size = new Vector2(12),
Colour = HandleColour,
AlwaysPresent = true,
Alpha = 0
}
},
CreateContent()
}
},
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
};
}
protected override bool OnDragStart(DragStartEvent e)
{
if (!base.OnDragStart(e))
return false;
PlaylistDragActive.Value = true;
return true;
}
protected override void OnDragEnd(DragEndEvent e)
{
PlaylistDragActive.Value = false;
base.OnDragEnd(e);
}
protected override bool IsDraggableAt(Vector2 screenSpacePos) => handle.HandlingDrag;
protected override bool OnHover(HoverEvent e)
{
handle.UpdateHoverState(IsDragged || !PlaylistDragActive.Value);
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e) => handle.UpdateHoverState(false);
protected abstract Drawable CreateContent();
private class PlaylistItemHandle : SpriteIcon
{
public bool HandlingDrag { get; private set; }
private bool isHovering;
public PlaylistItemHandle()
{
Icon = FontAwesome.Solid.Bars;
}
protected override bool OnMouseDown(MouseDownEvent e)
{
base.OnMouseDown(e);
HandlingDrag = true;
UpdateHoverState(isHovering);
return false;
}
protected override void OnMouseUp(MouseUpEvent e)
{
base.OnMouseUp(e);
HandlingDrag = false;
UpdateHoverState(isHovering);
}
public void UpdateHoverState(bool hovering)
{
isHovering = hovering;
if (isHovering || HandlingDrag)
this.FadeIn(FADE_DURATION);
else
this.FadeOut(FADE_DURATION);
}
}
}
}

View File

@ -12,17 +12,12 @@ using osuTK;
namespace osu.Game.Overlays.Music
{
public class Playlist : RearrangeableListContainer<BeatmapSetInfo>
public class Playlist : OsuRearrangeableListContainer<BeatmapSetInfo>
{
public Action<BeatmapSetInfo> RequestSelection;
public readonly Bindable<BeatmapSetInfo> SelectedSet = new Bindable<BeatmapSetInfo>();
/// <summary>
/// Whether any item is currently being dragged. Used to hide other items' drag handles.
/// </summary>
private readonly BindableBool playlistDragActive = new BindableBool();
public new MarginPadding Padding
{
get => base.Padding;
@ -33,15 +28,12 @@ namespace osu.Game.Overlays.Music
public BeatmapSetInfo FirstVisibleSet => Items.FirstOrDefault(i => ((PlaylistItem)ItemMap[i]).MatchingFilter);
protected override RearrangeableListItem<BeatmapSetInfo> CreateDrawable(BeatmapSetInfo item) => new PlaylistItem(item)
protected override OsuRearrangeableListItem<BeatmapSetInfo> CreateOsuDrawable(BeatmapSetInfo item) => new PlaylistItem(item)
{
SelectedSet = { BindTarget = SelectedSet },
PlaylistDragActive = { BindTarget = playlistDragActive },
RequestSelection = set => RequestSelection?.Invoke(set)
};
protected override ScrollContainer<Drawable> CreateScrollContainer() => new OsuScrollContainer();
protected override FillFlowContainer<RearrangeableListItem<BeatmapSetInfo>> CreateListFillFlowContainer() => new SearchContainer<RearrangeableListItem<BeatmapSetInfo>>
{
Spacing = new Vector2(0, 3),

View File

@ -14,36 +14,27 @@ using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Music
{
public class PlaylistItem : RearrangeableListItem<BeatmapSetInfo>, IFilterable
public class PlaylistItem : OsuRearrangeableListItem<BeatmapSetInfo>, IFilterable
{
private const float fade_duration = 100;
public BindableBool PlaylistDragActive = new BindableBool();
public readonly Bindable<BeatmapSetInfo> SelectedSet = new Bindable<BeatmapSetInfo>();
public Action<BeatmapSetInfo> RequestSelection;
private PlaylistItemHandle handle;
private TextFlowContainer text;
private IEnumerable<Drawable> titleSprites;
private ILocalisedBindableString titleBind;
private ILocalisedBindableString artistBind;
private Color4 hoverColour;
private Color4 selectedColour;
private Color4 artistColour;
public PlaylistItem(BeatmapSetInfo item)
: base(item)
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Padding = new MarginPadding { Left = 5 };
FilterTerms = item.Metadata.SearchableTerms;
@ -52,42 +43,12 @@ namespace osu.Game.Overlays.Music
[BackgroundDependencyLoader]
private void load(OsuColour colours, LocalisationManager localisation)
{
hoverColour = colours.Yellow;
selectedColour = colours.Yellow;
artistColour = colours.Gray9;
InternalChild = new GridContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Content = new[]
{
new Drawable[]
{
handle = new PlaylistItemHandle
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Size = new Vector2(12),
Colour = colours.Gray5,
AlwaysPresent = true,
Alpha = 0
},
text = new OsuTextFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Left = 5 },
},
}
},
ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize) },
RowDimensions = new[] { new Dimension(GridSizeMode.AutoSize) }
};
HandleColour = colours.Gray5;
titleBind = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.TitleUnicode, Model.Metadata.Title)));
artistBind = localisation.GetLocalisedString(new LocalisedString((Model.Metadata.ArtistUnicode, Model.Metadata.Artist)));
artistBind.BindValueChanged(_ => recreateText(), true);
}
protected override void LoadComplete()
@ -100,10 +61,18 @@ namespace osu.Game.Overlays.Music
return;
foreach (Drawable s in titleSprites)
s.FadeColour(set.NewValue == Model ? hoverColour : Color4.White, fade_duration);
s.FadeColour(set.NewValue == Model ? selectedColour : Color4.White, FADE_DURATION);
}, true);
artistBind.BindValueChanged(_ => recreateText(), true);
}
protected override Drawable CreateContent() => text = new OsuTextFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
};
private void recreateText()
{
text.Clear();
@ -125,31 +94,6 @@ namespace osu.Game.Overlays.Music
return true;
}
protected override bool OnDragStart(DragStartEvent e)
{
if (!base.OnDragStart(e))
return false;
PlaylistDragActive.Value = true;
return true;
}
protected override void OnDragEnd(DragEndEvent e)
{
PlaylistDragActive.Value = false;
base.OnDragEnd(e);
}
protected override bool IsDraggableAt(Vector2 screenSpacePos) => handle.HandlingDrag;
protected override bool OnHover(HoverEvent e)
{
handle.UpdateHoverState(IsDragged || !PlaylistDragActive.Value);
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e) => handle.UpdateHoverState(false);
public IEnumerable<string> FilterTerms { get; }
private bool matching = true;
@ -168,44 +112,5 @@ namespace osu.Game.Overlays.Music
}
public bool FilteringActive { get; set; }
private class PlaylistItemHandle : SpriteIcon
{
public bool HandlingDrag { get; private set; }
private bool isHovering;
public PlaylistItemHandle()
{
Icon = FontAwesome.Solid.Bars;
}
protected override bool OnMouseDown(MouseDownEvent e)
{
base.OnMouseDown(e);
HandlingDrag = true;
UpdateHoverState(isHovering);
return false;
}
protected override void OnMouseUp(MouseUpEvent e)
{
base.OnMouseUp(e);
HandlingDrag = false;
UpdateHoverState(isHovering);
}
public void UpdateHoverState(bool hovering)
{
isHovering = hovering;
if (isHovering || HandlingDrag)
this.FadeIn(fade_duration);
else
this.FadeOut(fade_duration);
}
}
}
}