1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-15 09:07:25 +08:00
osu-lazer/osu.Game/Graphics/Containers/SectionsContainer.cs

195 lines
6.4 KiB
C#
Raw Normal View History

2018-01-05 19:21:19 +08:00
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Linq;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Graphics.Containers
{
/// <summary>
/// A container that can scroll to each section inside it.
/// </summary>
2017-06-09 16:24:19 +08:00
public class SectionsContainer<T> : Container<T>
where T : Drawable
{
private Drawable expandableHeader, fixedHeader, footer, headerBackground;
2017-06-25 10:06:54 +08:00
private readonly ScrollContainer scrollContainer;
2017-06-09 16:24:19 +08:00
private readonly Container headerBackgroundContainer;
2017-06-12 14:39:49 +08:00
private readonly FlowContainer<T> scrollContentContainer;
2017-06-09 16:24:19 +08:00
2017-06-12 14:39:49 +08:00
protected override Container<T> Content => scrollContentContainer;
public Drawable ExpandableHeader
{
get { return expandableHeader; }
set
{
if (value == expandableHeader) return;
2017-06-09 16:24:19 +08:00
expandableHeader?.Expire();
expandableHeader = value;
2017-05-21 02:11:55 +08:00
if (value == null) return;
2017-06-09 16:24:19 +08:00
AddInternal(expandableHeader);
lastKnownScroll = float.NaN;
}
}
public Drawable FixedHeader
{
get { return fixedHeader; }
set
{
if (value == fixedHeader) return;
2017-06-09 16:24:19 +08:00
fixedHeader?.Expire();
fixedHeader = value;
2017-05-21 02:11:55 +08:00
if (value == null) return;
2017-06-09 16:24:19 +08:00
AddInternal(fixedHeader);
lastKnownScroll = float.NaN;
}
}
2017-05-21 03:44:03 +08:00
public Drawable Footer
{
get { return footer; }
set
{
if (value == footer) return;
if (footer != null)
2017-06-25 10:06:54 +08:00
scrollContainer.Remove(footer);
2017-05-21 03:44:03 +08:00
footer = value;
if (value == null) return;
footer.Anchor |= Anchor.y2;
footer.Origin |= Anchor.y2;
2017-06-25 10:06:54 +08:00
scrollContainer.Add(footer);
2017-05-21 03:44:03 +08:00
lastKnownScroll = float.NaN;
}
}
public Drawable HeaderBackground
{
get { return headerBackground; }
set
{
if (value == headerBackground) return;
headerBackgroundContainer.Clear();
headerBackground = value;
if (value == null) return;
headerBackgroundContainer.Add(headerBackground);
lastKnownScroll = float.NaN;
}
}
2017-06-09 16:24:19 +08:00
public Bindable<T> SelectedSection { get; } = new Bindable<T>();
2017-06-09 16:24:19 +08:00
protected virtual FlowContainer<T> CreateScrollContentContainer()
=> new FillFlowContainer<T>
2017-05-20 07:20:46 +08:00
{
Direction = FillDirection.Vertical,
2017-06-09 14:53:00 +08:00
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
2017-05-20 07:20:46 +08:00
};
2017-06-09 16:24:19 +08:00
public override void Add(T drawable)
{
2017-06-09 16:24:19 +08:00
base.Add(drawable);
lastKnownScroll = float.NaN;
2017-06-15 22:42:15 +08:00
headerHeight = float.NaN;
footerHeight = float.NaN;
}
2017-05-21 03:44:03 +08:00
private float headerHeight, footerHeight;
2017-05-21 04:48:43 +08:00
private readonly MarginPadding originalSectionsMargin;
2017-05-21 03:44:03 +08:00
private void updateSectionsMargin()
{
2017-06-09 16:24:19 +08:00
if (!Children.Any()) return;
2017-05-21 03:44:03 +08:00
var newMargin = originalSectionsMargin;
2017-05-21 02:11:55 +08:00
newMargin.Top += headerHeight;
2017-05-21 03:44:03 +08:00
newMargin.Bottom += footerHeight;
2017-06-12 14:39:49 +08:00
scrollContentContainer.Margin = newMargin;
}
public SectionsContainer()
{
2017-07-14 22:52:19 +08:00
AddInternal(scrollContainer = new ScrollContainer
{
2017-05-20 07:20:46 +08:00
RelativeSizeAxes = Axes.Both,
2017-06-09 14:53:00 +08:00
Masking = true,
2017-06-25 10:06:54 +08:00
ScrollbarVisible = false,
Children = new Drawable[] { scrollContentContainer = CreateScrollContentContainer() }
2017-06-09 13:37:55 +08:00
});
2017-06-09 16:24:19 +08:00
AddInternal(headerBackgroundContainer = new Container
2017-06-09 13:37:55 +08:00
{
RelativeSizeAxes = Axes.X
});
2017-06-12 14:39:49 +08:00
originalSectionsMargin = scrollContentContainer.Margin;
}
2017-07-14 22:56:27 +08:00
public void ScrollTo(Drawable section) => scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(section) - (FixedHeader?.BoundingBox.Height ?? 0));
public void ScrollToTop() => scrollContainer.ScrollTo(0);
2017-05-21 04:48:43 +08:00
private float lastKnownScroll;
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
2017-05-21 04:48:43 +08:00
float headerH = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0);
float footerH = Footer?.LayoutSize.Y ?? 0;
if (headerH != headerHeight || footerH != footerHeight)
2017-05-21 02:11:55 +08:00
{
2017-05-21 04:48:43 +08:00
headerHeight = headerH;
footerHeight = footerH;
2017-05-21 03:44:03 +08:00
updateSectionsMargin();
2017-05-21 02:11:55 +08:00
}
float currentScroll = scrollContainer.Current;
if (currentScroll != lastKnownScroll)
{
lastKnownScroll = currentScroll;
2017-06-25 10:07:54 +08:00
if (ExpandableHeader != null && FixedHeader != null)
2017-05-21 02:11:55 +08:00
{
2017-06-25 10:07:54 +08:00
float offset = Math.Min(ExpandableHeader.LayoutSize.Y, currentScroll);
2017-05-21 02:11:55 +08:00
2017-06-25 10:07:54 +08:00
ExpandableHeader.Y = -offset;
FixedHeader.Y = -offset + ExpandableHeader.LayoutSize.Y;
2017-05-21 02:11:55 +08:00
}
headerBackgroundContainer.Height = (ExpandableHeader?.LayoutSize.Y ?? 0) + (FixedHeader?.LayoutSize.Y ?? 0);
headerBackgroundContainer.Y = ExpandableHeader?.Y ?? 0;
2017-06-09 16:24:19 +08:00
T bestMatch = null;
float minDiff = float.MaxValue;
2017-06-25 10:06:54 +08:00
float scrollOffset = FixedHeader?.LayoutSize.Y ?? 0;
2017-06-09 16:24:19 +08:00
foreach (var section in Children)
{
2017-06-25 10:06:54 +08:00
float diff = Math.Abs(scrollContainer.GetChildPosInContent(section) - currentScroll - scrollOffset);
if (diff < minDiff)
{
minDiff = diff;
bestMatch = section;
}
}
if (bestMatch != null)
SelectedSection.Value = bestMatch;
}
}
}
}