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:
commit
0c936aec4b
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user