1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-16 20:42:55 +08:00

Merge branch 'master' into temporary-directory-test-storage

This commit is contained in:
Dan Balasescu 2021-08-20 22:09:42 +09:00 committed by GitHub
commit 0c936aec4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 121 additions and 14 deletions

View File

@ -22,7 +22,8 @@ namespace osu.Game.Graphics.Containers
where T : Drawable where T : Drawable
{ {
public Bindable<T> SelectedSection { get; } = new Bindable<T>(); public Bindable<T> SelectedSection { get; } = new Bindable<T>();
private Drawable lastClickedSection;
private T lastClickedSection;
public Drawable ExpandableHeader public Drawable ExpandableHeader
{ {
@ -144,10 +145,25 @@ namespace osu.Game.Graphics.Containers
footerHeight = null; footerHeight = null;
} }
public void ScrollTo(Drawable section) public void ScrollTo(Drawable target)
{ {
lastKnownScroll = null;
float fixedHeaderSize = FixedHeader?.BoundingBox.Height ?? 0;
// implementation similar to ScrollIntoView but a bit more nuanced.
float top = scrollContainer.GetChildPosInContent(target);
float bottomScrollExtent = scrollContainer.ScrollableExtent - fixedHeaderSize;
float scrollTarget = top - fixedHeaderSize - scrollContainer.DisplayableContent * scroll_y_centre;
if (scrollTarget > bottomScrollExtent)
scrollContainer.ScrollToEnd();
else
scrollContainer.ScrollTo(scrollTarget);
if (target is T section)
lastClickedSection = section; lastClickedSection = section;
scrollContainer.ScrollTo(scrollContainer.GetChildPosInContent(section) - scrollContainer.DisplayableContent * scroll_y_centre - (FixedHeader?.BoundingBox.Height ?? 0));
} }
public void ScrollToTop() => scrollContainer.ScrollTo(0); public void ScrollToTop() => scrollContainer.ScrollTo(0);
@ -170,13 +186,22 @@ namespace osu.Game.Graphics.Containers
if (source == InvalidationSource.Child && (invalidation & Invalidation.DrawSize) != 0) if (source == InvalidationSource.Child && (invalidation & Invalidation.DrawSize) != 0)
{ {
lastKnownScroll = null; InvalidateScrollPosition();
result = true; result = true;
} }
return result; return result;
} }
protected void InvalidateScrollPosition()
{
Schedule(() =>
{
lastKnownScroll = null;
lastClickedSection = null;
});
}
protected override void UpdateAfterChildren() protected override void UpdateAfterChildren()
{ {
base.UpdateAfterChildren(); base.UpdateAfterChildren();
@ -224,15 +249,19 @@ namespace osu.Game.Graphics.Containers
float scrollCentre = fixedHeaderSize + scrollContainer.DisplayableContent * scroll_y_centre + selectionLenienceAboveSection; float scrollCentre = fixedHeaderSize + scrollContainer.DisplayableContent * scroll_y_centre + selectionLenienceAboveSection;
if (Precision.AlmostBigger(0, scrollContainer.Current)) var presentChildren = Children.Where(c => c.IsPresent);
SelectedSection.Value = lastClickedSection as T ?? Children.FirstOrDefault();
if (lastClickedSection != null)
SelectedSection.Value = lastClickedSection;
else if (Precision.AlmostBigger(0, scrollContainer.Current))
SelectedSection.Value = presentChildren.FirstOrDefault();
else if (Precision.AlmostBigger(scrollContainer.Current, scrollContainer.ScrollableExtent)) else if (Precision.AlmostBigger(scrollContainer.Current, scrollContainer.ScrollableExtent))
SelectedSection.Value = lastClickedSection as T ?? Children.LastOrDefault(); SelectedSection.Value = presentChildren.LastOrDefault();
else else
{ {
SelectedSection.Value = Children SelectedSection.Value = presentChildren
.TakeWhile(section => scrollContainer.GetChildPosInContent(section) - currentScroll - scrollCentre <= 0) .TakeWhile(section => scrollContainer.GetChildPosInContent(section) - currentScroll - scrollCentre <= 0)
.LastOrDefault() ?? Children.FirstOrDefault(); .LastOrDefault() ?? presentChildren.FirstOrDefault();
} }
} }
} }

View File

@ -42,6 +42,12 @@ namespace osu.Game.Graphics.Containers
base.OnUserScroll(value, animated, distanceDecay); base.OnUserScroll(value, animated, distanceDecay);
} }
public new void ScrollIntoView(Drawable target, bool animated = true)
{
UserScrolling = false;
base.ScrollIntoView(target, animated);
}
public new void ScrollTo(float value, bool animated = true, double? distanceDecay = null) public new void ScrollTo(float value, bool animated = true, double? distanceDecay = null)
{ {
UserScrolling = false; UserScrolling = false;

View File

@ -4,9 +4,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
@ -19,6 +21,10 @@ namespace osu.Game.Overlays.Settings
protected FillFlowContainer FlowContent; protected FillFlowContainer FlowContent;
protected override Container<Drawable> Content => FlowContent; protected override Container<Drawable> Content => FlowContent;
private IBindable<SettingsSection> selectedSection;
private OsuSpriteText header;
public abstract Drawable CreateIcon(); public abstract Drawable CreateIcon();
public abstract LocalisableString Header { get; } public abstract LocalisableString Header { get; }
@ -36,6 +42,9 @@ namespace osu.Game.Overlays.Settings
public bool FilteringActive { get; set; } public bool FilteringActive { get; set; }
[Resolved]
private SettingsPanel settingsPanel { get; set; }
protected SettingsSection() protected SettingsSection()
{ {
Margin = new MarginPadding { Top = margin }; Margin = new MarginPadding { Top = margin };
@ -61,6 +70,7 @@ namespace osu.Game.Overlays.Settings
{ {
new Box new Box
{ {
Name = "separator",
Colour = new Color4(0, 0, 0, 255), Colour = new Color4(0, 0, 0, 255),
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
Height = border_size, Height = border_size,
@ -76,7 +86,7 @@ namespace osu.Game.Overlays.Settings
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Children = new Drawable[] Children = new Drawable[]
{ {
new OsuSpriteText header = new OsuSpriteText
{ {
Font = OsuFont.GetFont(size: header_size), Font = OsuFont.GetFont(size: header_size),
Text = Header, Text = Header,
@ -91,6 +101,51 @@ namespace osu.Game.Overlays.Settings
} }
}, },
}); });
selectedSection = settingsPanel.CurrentSection.GetBoundCopy();
selectedSection.BindValueChanged(_ => updateContentFade(), true);
}
private bool isCurrentSection => selectedSection.Value == this;
protected override bool OnHover(HoverEvent e)
{
updateContentFade();
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
updateContentFade();
base.OnHoverLost(e);
}
protected override bool OnClick(ClickEvent e)
{
if (!isCurrentSection)
settingsPanel.SectionsContainer.ScrollTo(this);
return base.OnClick(e);
}
protected override bool ShouldBeConsideredForInput(Drawable child) =>
// only the current section should accept input.
// this provides the behaviour of the first click scrolling the target section to the centre of the screen.
isCurrentSection;
private void updateContentFade()
{
float contentFade = 1;
float headerFade = 1;
if (!isCurrentSection)
{
contentFade = 0.25f;
headerFade = IsHovered ? 0.5f : 0.25f;
}
header.FadeTo(headerFade, 500, Easing.OutQuint);
FlowContent.FadeTo(contentFade, 500, Easing.OutQuint);
} }
} }
} }

View File

@ -8,6 +8,7 @@ using System.Threading.Tasks;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -21,6 +22,7 @@ using osu.Game.Overlays.Settings;
namespace osu.Game.Overlays namespace osu.Game.Overlays
{ {
[Cached]
public abstract class SettingsPanel : OsuFocusedOverlayContainer public abstract class SettingsPanel : OsuFocusedOverlayContainer
{ {
public const float CONTENT_MARGINS = 15; public const float CONTENT_MARGINS = 15;
@ -46,7 +48,7 @@ namespace osu.Game.Overlays
protected Sidebar Sidebar; protected Sidebar Sidebar;
private SidebarButton selectedSidebarButton; private SidebarButton selectedSidebarButton;
protected SettingsSectionsContainer SectionsContainer; public SettingsSectionsContainer SectionsContainer { get; private set; }
private SeekLimitedSearchTextBox searchTextBox; private SeekLimitedSearchTextBox searchTextBox;
@ -65,6 +67,8 @@ namespace osu.Game.Overlays
private Task sectionsLoadingTask; private Task sectionsLoadingTask;
public IBindable<SettingsSection> CurrentSection = new Bindable<SettingsSection>();
protected SettingsPanel(bool showSidebar) protected SettingsPanel(bool showSidebar)
{ {
this.showSidebar = showSidebar; this.showSidebar = showSidebar;
@ -105,6 +109,7 @@ namespace osu.Game.Overlays
Masking = true, Masking = true,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
ExpandableHeader = CreateHeader(), ExpandableHeader = CreateHeader(),
SelectedSection = { BindTarget = CurrentSection },
FixedHeader = searchTextBox = new SeekLimitedSearchTextBox FixedHeader = searchTextBox = new SeekLimitedSearchTextBox
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
@ -238,7 +243,9 @@ namespace osu.Game.Overlays
if (selectedSidebarButton != null) if (selectedSidebarButton != null)
selectedSidebarButton.Selected = false; selectedSidebarButton.Selected = false;
selectedSidebarButton = Sidebar.Children.Single(b => b.Section == section.NewValue); selectedSidebarButton = Sidebar.Children.FirstOrDefault(b => b.Section == section.NewValue);
if (selectedSidebarButton != null)
selectedSidebarButton.Selected = true; selectedSidebarButton.Selected = true;
}, true); }, true);
}); });
@ -273,6 +280,16 @@ namespace osu.Game.Overlays
{ {
public SearchContainer<SettingsSection> SearchContainer; public SearchContainer<SettingsSection> SearchContainer;
public string SearchTerm
{
get => SearchContainer.SearchTerm;
set
{
SearchContainer.SearchTerm = value;
InvalidateScrollPosition();
}
}
protected override FlowContainer<SettingsSection> CreateScrollContentContainer() protected override FlowContainer<SettingsSection> CreateScrollContentContainer()
=> SearchContainer = new SearchContainer<SettingsSection> => SearchContainer = new SearchContainer<SettingsSection>
{ {