mirror of
https://github.com/osukey/osukey.git
synced 2025-08-04 07:06:35 +09:00
Merge remote-tracking branch 'upstream/master' into songselect-best-user-score
This commit is contained in:
@ -24,8 +24,11 @@ using osu.Game.Screens.Select.Carousel;
|
||||
|
||||
namespace osu.Game.Screens.Select
|
||||
{
|
||||
public class BeatmapCarousel : OsuScrollContainer
|
||||
public class BeatmapCarousel : CompositeDrawable
|
||||
{
|
||||
private const float bleed_top = FilterControl.HEIGHT;
|
||||
private const float bleed_bottom = Footer.HEIGHT;
|
||||
|
||||
/// <summary>
|
||||
/// Triggered when the <see cref="BeatmapSets"/> loaded change and are completely loaded.
|
||||
/// </summary>
|
||||
@ -58,6 +61,8 @@ namespace osu.Game.Screens.Select
|
||||
/// </summary>
|
||||
public bool BeatmapSetsLoaded { get; private set; }
|
||||
|
||||
private readonly OsuScrollContainer scroll;
|
||||
|
||||
private IEnumerable<CarouselBeatmapSet> beatmapSets => root.Children.OfType<CarouselBeatmapSet>();
|
||||
|
||||
public IEnumerable<BeatmapSetInfo> BeatmapSets
|
||||
@ -81,7 +86,8 @@ namespace osu.Game.Screens.Select
|
||||
itemsCache.Invalidate();
|
||||
scrollPositionCache.Invalidate();
|
||||
|
||||
Schedule(() =>
|
||||
// Run on late scheduler want to ensure this runs after all pending UpdateBeatmapSet / RemoveBeatmapSet operations are run.
|
||||
SchedulerAfterChildren.Add(() =>
|
||||
{
|
||||
BeatmapSetsChanged?.Invoke();
|
||||
BeatmapSetsLoaded = true;
|
||||
@ -89,8 +95,8 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
|
||||
private readonly List<float> yPositions = new List<float>();
|
||||
private Cached itemsCache = new Cached();
|
||||
private Cached scrollPositionCache = new Cached();
|
||||
private readonly Cached itemsCache = new Cached();
|
||||
private readonly Cached scrollPositionCache = new Cached();
|
||||
|
||||
private readonly Container<DrawableCarouselItem> scrollableContent;
|
||||
|
||||
@ -106,13 +112,17 @@ namespace osu.Game.Screens.Select
|
||||
public BeatmapCarousel()
|
||||
{
|
||||
root = new CarouselRoot(this);
|
||||
Child = new OsuContextMenuContainer
|
||||
InternalChild = new OsuContextMenuContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Child = scrollableContent = new Container<DrawableCarouselItem>
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = scroll = new CarouselScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Masking = false,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = scrollableContent = new Container<DrawableCarouselItem>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -123,25 +133,22 @@ namespace osu.Game.Screens.Select
|
||||
config.BindWith(OsuSetting.RandomSelectAlgorithm, RandomAlgorithm);
|
||||
config.BindWith(OsuSetting.SongSelectRightMouseScroll, RightClickScrollingEnabled);
|
||||
|
||||
RightClickScrollingEnabled.ValueChanged += enabled => RightMouseScrollbar = enabled.NewValue;
|
||||
RightClickScrollingEnabled.ValueChanged += enabled => scroll.RightMouseScrollbar = enabled.NewValue;
|
||||
RightClickScrollingEnabled.TriggerChange();
|
||||
|
||||
loadBeatmapSets(beatmaps.GetAllUsableBeatmapSetsEnumerable());
|
||||
}
|
||||
|
||||
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet)
|
||||
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() =>
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
var existingSet = beatmapSets.FirstOrDefault(b => b.BeatmapSet.ID == beatmapSet.ID);
|
||||
var existingSet = beatmapSets.FirstOrDefault(b => b.BeatmapSet.ID == beatmapSet.ID);
|
||||
|
||||
if (existingSet == null)
|
||||
return;
|
||||
if (existingSet == null)
|
||||
return;
|
||||
|
||||
root.RemoveChild(existingSet);
|
||||
itemsCache.Invalidate();
|
||||
});
|
||||
}
|
||||
root.RemoveChild(existingSet);
|
||||
itemsCache.Invalidate();
|
||||
});
|
||||
|
||||
public void UpdateBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() =>
|
||||
{
|
||||
@ -338,6 +345,25 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
public bool AllowSelection = true;
|
||||
|
||||
/// <summary>
|
||||
/// Half the height of the visible content.
|
||||
/// <remarks>
|
||||
/// This is different from the height of <see cref="ScrollContainer{T}.displayableContent"/>, since
|
||||
/// the beatmap carousel bleeds into the <see cref="FilterControl"/> and the <see cref="Footer"/>
|
||||
/// </remarks>
|
||||
/// </summary>
|
||||
private float visibleHalfHeight => (DrawHeight + bleed_bottom + bleed_top) / 2;
|
||||
|
||||
/// <summary>
|
||||
/// The position of the lower visible bound with respect to the current scroll position.
|
||||
/// </summary>
|
||||
private float visibleBottomBound => scroll.Current + DrawHeight + bleed_bottom;
|
||||
|
||||
/// <summary>
|
||||
/// The position of the upper visible bound with respect to the current scroll position.
|
||||
/// </summary>
|
||||
private float visibleUpperBound => scroll.Current - bleed_top;
|
||||
|
||||
public void FlushPendingFilterOperations()
|
||||
{
|
||||
if (PendingFilter?.Completed == false)
|
||||
@ -414,6 +440,8 @@ namespace osu.Game.Screens.Select
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool ReceivePositionalInputAtSubTree(Vector2 screenSpacePos) => ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
@ -424,17 +452,15 @@ namespace osu.Game.Screens.Select
|
||||
if (!scrollPositionCache.IsValid)
|
||||
updateScrollPosition();
|
||||
|
||||
float drawHeight = DrawHeight;
|
||||
|
||||
// Remove all items that should no longer be on-screen
|
||||
scrollableContent.RemoveAll(p => p.Y < Current - p.DrawHeight || p.Y > Current + drawHeight || !p.IsPresent);
|
||||
scrollableContent.RemoveAll(p => p.Y < visibleUpperBound - p.DrawHeight || p.Y > visibleBottomBound || !p.IsPresent);
|
||||
|
||||
// Find index range of all items that should be on-screen
|
||||
Trace.Assert(Items.Count == yPositions.Count);
|
||||
|
||||
int firstIndex = yPositions.BinarySearch(Current - DrawableCarouselItem.MAX_HEIGHT);
|
||||
int firstIndex = yPositions.BinarySearch(visibleUpperBound - DrawableCarouselItem.MAX_HEIGHT);
|
||||
if (firstIndex < 0) firstIndex = ~firstIndex;
|
||||
int lastIndex = yPositions.BinarySearch(Current + drawHeight);
|
||||
int lastIndex = yPositions.BinarySearch(visibleBottomBound);
|
||||
if (lastIndex < 0) lastIndex = ~lastIndex;
|
||||
|
||||
int notVisibleCount = 0;
|
||||
@ -486,9 +512,8 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
// Update externally controlled state of currently visible items
|
||||
// (e.g. x-offset and opacity).
|
||||
float halfHeight = drawHeight / 2;
|
||||
foreach (DrawableCarouselItem p in scrollableContent.Children)
|
||||
updateItem(p, halfHeight);
|
||||
updateItem(p);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
@ -542,7 +567,7 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
yPositions.Clear();
|
||||
|
||||
float currentY = DrawHeight / 2;
|
||||
float currentY = visibleHalfHeight;
|
||||
DrawableCarouselBeatmapSet lastSet = null;
|
||||
|
||||
scrollTarget = null;
|
||||
@ -575,7 +600,6 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
float? setY = null;
|
||||
if (!d.IsLoaded || beatmap.Alpha == 0) // can't use IsPresent due to DrawableCarouselItem override.
|
||||
// ReSharper disable once PossibleNullReferenceException (resharper broken?)
|
||||
setY = lastSet.Y + lastSet.DrawHeight + 5;
|
||||
|
||||
if (d.IsLoaded)
|
||||
@ -596,7 +620,7 @@ namespace osu.Game.Screens.Select
|
||||
currentY += d.DrawHeight + 5;
|
||||
}
|
||||
|
||||
currentY += DrawHeight / 2;
|
||||
currentY += visibleHalfHeight;
|
||||
scrollableContent.Height = currentY;
|
||||
|
||||
if (BeatmapSetsLoaded && (selectedBeatmapSet == null || selectedBeatmap == null || selectedBeatmapSet.State.Value != CarouselItemState.Selected))
|
||||
@ -610,7 +634,7 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
private void updateScrollPosition()
|
||||
{
|
||||
if (scrollTarget != null) ScrollTo(scrollTarget.Value);
|
||||
if (scrollTarget != null) scroll.ScrollTo(scrollTarget.Value);
|
||||
scrollPositionCache.Validate();
|
||||
}
|
||||
|
||||
@ -637,18 +661,15 @@ namespace osu.Game.Screens.Select
|
||||
/// the current scroll position.
|
||||
/// </summary>
|
||||
/// <param name="p">The item to be updated.</param>
|
||||
/// <param name="halfHeight">Half the draw height of the carousel container.</param>
|
||||
private void updateItem(DrawableCarouselItem p, float halfHeight)
|
||||
private void updateItem(DrawableCarouselItem p)
|
||||
{
|
||||
var height = p.IsPresent ? p.DrawHeight : 0;
|
||||
|
||||
float itemDrawY = p.Position.Y - Current + height / 2;
|
||||
float dist = Math.Abs(1f - itemDrawY / halfHeight);
|
||||
float itemDrawY = p.Position.Y - visibleUpperBound + p.DrawHeight / 2;
|
||||
float dist = Math.Abs(1f - itemDrawY / visibleHalfHeight);
|
||||
|
||||
// Setting the origin position serves as an additive position on top of potential
|
||||
// local transformation we may want to apply (e.g. when a item gets selected, we
|
||||
// may want to smoothly transform it leftwards.)
|
||||
p.OriginPosition = new Vector2(-offsetX(dist, halfHeight), 0);
|
||||
p.OriginPosition = new Vector2(-offsetX(dist, visibleHalfHeight), 0);
|
||||
|
||||
// We are applying a multiplicative alpha (which is internally done by nesting an
|
||||
// additional container and setting that container's alpha) such that we can
|
||||
@ -673,5 +694,35 @@ namespace osu.Game.Screens.Select
|
||||
base.PerformSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private class CarouselScrollContainer : OsuScrollContainer
|
||||
{
|
||||
private bool rightMouseScrollBlocked;
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
if (e.Button == MouseButton.Right)
|
||||
{
|
||||
// we need to block right click absolute scrolling when hovering a carousel item so context menus can display.
|
||||
// this can be reconsidered when we have an alternative to right click scrolling.
|
||||
if (GetContainingInputManager().HoveredDrawables.OfType<DrawableCarouselItem>().Any())
|
||||
{
|
||||
rightMouseScrollBlocked = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
rightMouseScrollBlocked = false;
|
||||
return base.OnMouseDown(e);
|
||||
}
|
||||
|
||||
protected override bool OnDragStart(DragStartEvent e)
|
||||
{
|
||||
if (rightMouseScrollBlocked)
|
||||
return false;
|
||||
|
||||
return base.OnDragStart(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,8 +25,8 @@ namespace osu.Game.Screens.Select
|
||||
set
|
||||
{
|
||||
beatmap = value;
|
||||
Leaderboard.Beatmap = beatmap?.BeatmapInfo;
|
||||
Details.Beatmap = beatmap?.BeatmapInfo;
|
||||
Leaderboard.Beatmap = beatmap is DummyWorkingBeatmap ? null : beatmap?.BeatmapInfo;
|
||||
TopScore.Hide();
|
||||
}
|
||||
}
|
||||
|
@ -25,22 +25,6 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
private Bindable<BeatmapDetailTab> selectedTab;
|
||||
|
||||
private void invokeOnFilter()
|
||||
{
|
||||
OnFilter?.Invoke(tabs.Current.Value, modsCheckbox.Current.Value);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colour, OsuConfigManager config)
|
||||
{
|
||||
modsCheckbox.AccentColour = tabs.AccentColour = colour.YellowLight;
|
||||
|
||||
selectedTab = config.GetBindable<BeatmapDetailTab>(OsuSetting.BeatmapDetailTab);
|
||||
|
||||
tabs.Current.BindTo(selectedTab);
|
||||
tabs.Current.TriggerChange();
|
||||
}
|
||||
|
||||
public BeatmapDetailAreaTabControl()
|
||||
{
|
||||
Height = HEIGHT;
|
||||
@ -66,12 +50,31 @@ namespace osu.Game.Screens.Select
|
||||
Anchor = Anchor.BottomRight,
|
||||
Origin = Anchor.BottomRight,
|
||||
Text = @"Mods",
|
||||
Alpha = 0,
|
||||
},
|
||||
};
|
||||
|
||||
tabs.Current.ValueChanged += _ => invokeOnFilter();
|
||||
modsCheckbox.Current.ValueChanged += _ => invokeOnFilter();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colour, OsuConfigManager config)
|
||||
{
|
||||
modsCheckbox.AccentColour = tabs.AccentColour = colour.YellowLight;
|
||||
|
||||
selectedTab = config.GetBindable<BeatmapDetailTab>(OsuSetting.BeatmapDetailTab);
|
||||
|
||||
tabs.Current.BindTo(selectedTab);
|
||||
tabs.Current.TriggerChange();
|
||||
}
|
||||
|
||||
private void invokeOnFilter()
|
||||
{
|
||||
OnFilter?.Invoke(tabs.Current.Value, modsCheckbox.Current.Value);
|
||||
|
||||
modsCheckbox.FadeTo(tabs.Current.Value == BeatmapDetailTab.Details ? 0 : 1, 200, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
public enum BeatmapDetailTab
|
||||
|
@ -35,7 +35,7 @@ namespace osu.Game.Screens.Select
|
||||
private readonly MetadataSection description, source, tags;
|
||||
private readonly Container failRetryContainer;
|
||||
private readonly FailRetryGraph failRetryGraph;
|
||||
private readonly DimmedLoadingAnimation loading;
|
||||
private readonly DimmedLoadingLayer loading;
|
||||
|
||||
private IAPIProvider api;
|
||||
|
||||
@ -156,10 +156,7 @@ namespace osu.Game.Screens.Select
|
||||
},
|
||||
},
|
||||
},
|
||||
loading = new DimmedLoadingAnimation
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
loading = new DimmedLoadingLayer(),
|
||||
};
|
||||
}
|
||||
|
||||
@ -365,35 +362,5 @@ namespace osu.Game.Screens.Select
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class DimmedLoadingAnimation : VisibilityContainer
|
||||
{
|
||||
private readonly LoadingAnimation loading;
|
||||
|
||||
public DimmedLoadingAnimation()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black.Opacity(0.5f),
|
||||
},
|
||||
loading = new LoadingAnimation(),
|
||||
};
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
this.FadeIn(transition_duration, Easing.OutQuint);
|
||||
loading.Show();
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
this.FadeOut(transition_duration, Easing.OutQuint);
|
||||
loading.Hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -141,6 +141,7 @@ namespace osu.Game.Screens.Select
|
||||
private readonly RulesetInfo ruleset;
|
||||
|
||||
public BufferedWedgeInfo(WorkingBeatmap beatmap, RulesetInfo userRuleset)
|
||||
: base(pixelSnapping: true)
|
||||
{
|
||||
this.beatmap = beatmap;
|
||||
ruleset = userRuleset ?? beatmap.BeatmapInfo.Ruleset;
|
||||
@ -152,8 +153,9 @@ namespace osu.Game.Screens.Select
|
||||
var beatmapInfo = beatmap.BeatmapInfo;
|
||||
var metadata = beatmapInfo.Metadata ?? beatmap.BeatmapSetInfo?.Metadata ?? new BeatmapMetadata();
|
||||
|
||||
PixelSnapping = true;
|
||||
CacheDrawnFrameBuffer = true;
|
||||
RedrawOnScale = false;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
titleBinding = localisation.GetLocalisedString(new LocalisedString((metadata.TitleUnicode, metadata.Title)));
|
||||
@ -402,31 +404,35 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
}
|
||||
|
||||
private class DifficultyColourBar : DifficultyColouredContainer
|
||||
private class DifficultyColourBar : Container
|
||||
{
|
||||
private readonly BeatmapInfo beatmap;
|
||||
|
||||
public DifficultyColourBar(BeatmapInfo beatmap)
|
||||
: base(beatmap)
|
||||
{
|
||||
this.beatmap = beatmap;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
const float full_opacity_ratio = 0.7f;
|
||||
|
||||
var difficultyColour = colours.ForDifficultyRating(beatmap.DifficultyRating);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = AccentColour,
|
||||
Colour = difficultyColour,
|
||||
Width = full_opacity_ratio,
|
||||
},
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RelativePositionAxes = Axes.Both,
|
||||
Colour = AccentColour,
|
||||
Colour = difficultyColour,
|
||||
Alpha = 0.5f,
|
||||
X = full_opacity_ratio,
|
||||
Width = 1 - full_opacity_ratio,
|
||||
|
@ -82,7 +82,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
Origin = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new DifficultyIcon(beatmap)
|
||||
new DifficultyIcon(beatmap, shouldShowTooltip: false)
|
||||
{
|
||||
Scale = new Vector2(1.8f),
|
||||
},
|
||||
|
@ -19,6 +19,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Rulesets;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
@ -95,10 +96,11 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
TextPadding = new MarginPadding { Horizontal = 8, Vertical = 2 },
|
||||
Status = beatmapSet.Status
|
||||
},
|
||||
new FillFlowContainer<FilterableDifficultyIcon>
|
||||
new FillFlowContainer<DifficultyIcon>
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Children = ((CarouselBeatmapSet)Item).Beatmaps.Select(b => new FilterableDifficultyIcon(b)).ToList()
|
||||
Spacing = new Vector2(3),
|
||||
ChildrenEnumerable = getDifficultyIcons(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@ -107,6 +109,17 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
};
|
||||
}
|
||||
|
||||
private const int maximum_difficulty_icons = 18;
|
||||
|
||||
private IEnumerable<DifficultyIcon> getDifficultyIcons()
|
||||
{
|
||||
var beatmaps = ((CarouselBeatmapSet)Item).Beatmaps.ToList();
|
||||
|
||||
return beatmaps.Count > maximum_difficulty_icons
|
||||
? (IEnumerable<DifficultyIcon>)beatmaps.GroupBy(b => b.Beatmap.Ruleset).Select(group => new FilterableGroupedDifficultyIcon(group.ToList(), group.Key))
|
||||
: beatmaps.Select(b => new FilterableDifficultyIcon(b));
|
||||
}
|
||||
|
||||
public MenuItem[] ContextMenuItems
|
||||
{
|
||||
get
|
||||
@ -133,6 +146,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
public PanelBackground(WorkingBeatmap working)
|
||||
{
|
||||
CacheDrawnFrameBuffer = true;
|
||||
RedrawOnScale = false;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -204,5 +218,27 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
filtered.TriggerChange();
|
||||
}
|
||||
}
|
||||
|
||||
public class FilterableGroupedDifficultyIcon : GroupedDifficultyIcon
|
||||
{
|
||||
private readonly List<CarouselBeatmap> items;
|
||||
|
||||
public FilterableGroupedDifficultyIcon(List<CarouselBeatmap> items, RulesetInfo ruleset)
|
||||
: base(items.Select(i => i.Beatmap).ToList(), ruleset, Color4.White)
|
||||
{
|
||||
this.items = items;
|
||||
|
||||
foreach (var item in items)
|
||||
item.Filtered.BindValueChanged(_ => Scheduler.AddOnce(updateFilteredDisplay));
|
||||
|
||||
updateFilteredDisplay();
|
||||
}
|
||||
|
||||
private void updateFilteredDisplay()
|
||||
{
|
||||
// for now, fade the whole group based on the ratio of hidden items.
|
||||
this.FadeTo(1 - 0.9f * ((float)items.Count(i => i.Filtered.Value) / items.Count), 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
Blending = BlendingMode.Additive,
|
||||
Blending = BlendingParameters.Additive,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -14,7 +14,6 @@ using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Screens.Select.Filter;
|
||||
using Container = osu.Framework.Graphics.Containers.Container;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Rulesets;
|
||||
|
||||
@ -22,46 +21,22 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
public class FilterControl : Container
|
||||
{
|
||||
public const float HEIGHT = 100;
|
||||
|
||||
public Action<FilterCriteria> FilterChanged;
|
||||
|
||||
private readonly OsuTabControl<SortMode> sortTabs;
|
||||
|
||||
private readonly TabControl<GroupMode> groupTabs;
|
||||
|
||||
private SortMode sort = SortMode.Title;
|
||||
private Bindable<SortMode> sortMode;
|
||||
|
||||
public SortMode Sort
|
||||
{
|
||||
get => sort;
|
||||
set
|
||||
{
|
||||
if (sort != value)
|
||||
{
|
||||
sort = value;
|
||||
FilterChanged?.Invoke(CreateCriteria());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private GroupMode group = GroupMode.All;
|
||||
|
||||
public GroupMode Group
|
||||
{
|
||||
get => group;
|
||||
set
|
||||
{
|
||||
if (group != value)
|
||||
{
|
||||
group = value;
|
||||
FilterChanged?.Invoke(CreateCriteria());
|
||||
}
|
||||
}
|
||||
}
|
||||
private Bindable<GroupMode> groupMode;
|
||||
|
||||
public FilterCriteria CreateCriteria() => new FilterCriteria
|
||||
{
|
||||
Group = group,
|
||||
Sort = sort,
|
||||
Group = groupMode.Value,
|
||||
Sort = sortMode.Value,
|
||||
SearchText = searchTextBox.Text,
|
||||
AllowConvertedBeatmaps = showConverted.Value,
|
||||
Ruleset = ruleset.Value
|
||||
@ -121,7 +96,6 @@ namespace osu.Game.Screens.Select
|
||||
Height = 24,
|
||||
Width = 0.5f,
|
||||
AutoSort = true,
|
||||
Current = { Value = GroupMode.Title }
|
||||
},
|
||||
//spriteText = new OsuSpriteText
|
||||
//{
|
||||
@ -140,7 +114,6 @@ namespace osu.Game.Screens.Select
|
||||
Width = 0.5f,
|
||||
Height = 24,
|
||||
AutoSort = true,
|
||||
Current = { Value = SortMode.Title }
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -152,8 +125,6 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
groupTabs.PinItem(GroupMode.All);
|
||||
groupTabs.PinItem(GroupMode.RecentlyPlayed);
|
||||
groupTabs.Current.ValueChanged += group => Group = group.NewValue;
|
||||
sortTabs.Current.ValueChanged += sort => Sort = sort.NewValue;
|
||||
}
|
||||
|
||||
public void Deactivate()
|
||||
@ -183,15 +154,20 @@ namespace osu.Game.Screens.Select
|
||||
showConverted.ValueChanged += _ => updateCriteria();
|
||||
|
||||
ruleset.BindTo(parentRuleset);
|
||||
ruleset.BindValueChanged(_ => updateCriteria(), true);
|
||||
ruleset.BindValueChanged(_ => updateCriteria());
|
||||
|
||||
sortMode = config.GetBindable<SortMode>(OsuSetting.SongSelectSortingMode);
|
||||
groupMode = config.GetBindable<GroupMode>(OsuSetting.SongSelectGroupingMode);
|
||||
|
||||
sortTabs.Current.BindTo(sortMode);
|
||||
groupTabs.Current.BindTo(groupMode);
|
||||
|
||||
groupMode.BindValueChanged(_ => updateCriteria());
|
||||
sortMode.BindValueChanged(_ => updateCriteria());
|
||||
|
||||
updateCriteria();
|
||||
}
|
||||
|
||||
private void updateCriteria() => FilterChanged?.Invoke(CreateCriteria());
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e) => true;
|
||||
|
||||
protected override bool OnMouseMove(MouseMoveEvent e) => true;
|
||||
|
||||
protected override bool OnClick(ClickEvent e) => true;
|
||||
}
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ namespace osu.Game.Screens.Select
|
||||
buttons = new FillFlowContainer<FooterButton>
|
||||
{
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(0.2f, 0),
|
||||
Spacing = new Vector2(-FooterButton.SHEAR_WIDTH, 0),
|
||||
AutoSizeAxes = Axes.Both,
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,9 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
public class FooterButton : OsuClickableContainer
|
||||
{
|
||||
private static readonly Vector2 shearing = new Vector2(0.15f, 0);
|
||||
public static readonly float SHEAR_WIDTH = 7.5f;
|
||||
|
||||
protected static readonly Vector2 SHEAR = new Vector2(SHEAR_WIDTH / Footer.HEIGHT, 0);
|
||||
|
||||
public string Text
|
||||
{
|
||||
@ -59,37 +61,35 @@ namespace osu.Game.Screens.Select
|
||||
private readonly Box box;
|
||||
private readonly Box light;
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => box.ReceivePositionalInputAt(screenSpacePos);
|
||||
|
||||
public FooterButton()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Shear = SHEAR;
|
||||
Children = new Drawable[]
|
||||
{
|
||||
TextContainer = new Container
|
||||
{
|
||||
Size = new Vector2(100, 50),
|
||||
Child = SpriteText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
},
|
||||
box = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Shear = shearing,
|
||||
EdgeSmoothness = new Vector2(2, 0),
|
||||
Colour = Color4.White,
|
||||
Alpha = 0,
|
||||
},
|
||||
light = new Box
|
||||
{
|
||||
Shear = shearing,
|
||||
Height = 4,
|
||||
EdgeSmoothness = new Vector2(2, 0),
|
||||
RelativeSizeAxes = Axes.X,
|
||||
},
|
||||
TextContainer = new Container
|
||||
{
|
||||
Size = new Vector2(100 - SHEAR_WIDTH, 50),
|
||||
Shear = -SHEAR,
|
||||
Child = SpriteText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Shear = -SHEAR,
|
||||
Child = modDisplay = new FooterModDisplay
|
||||
{
|
||||
DisplayUnrankedText = false,
|
||||
|
@ -88,6 +88,12 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
{
|
||||
TopScore.Value = null;
|
||||
|
||||
if (Beatmap == null)
|
||||
{
|
||||
PlaceholderState = PlaceholderState.NoneSelected;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Scope == BeatmapLeaderboardScope.Local)
|
||||
{
|
||||
var scores = scoreManager
|
||||
@ -118,7 +124,7 @@ namespace osu.Game.Screens.Select.Leaderboards
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Beatmap?.OnlineBeatmapID == null || Beatmap?.Status <= BeatmapSetOnlineStatus.Pending)
|
||||
if (Beatmap.OnlineBeatmapID == null || Beatmap?.Status <= BeatmapSetOnlineStatus.Pending)
|
||||
{
|
||||
PlaceholderState = PlaceholderState.Unavailable;
|
||||
return null;
|
||||
|
@ -1,13 +1,22 @@
|
||||
// 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.ComponentModel;
|
||||
|
||||
namespace osu.Game.Screens.Select.Leaderboards
|
||||
{
|
||||
public enum BeatmapLeaderboardScope
|
||||
{
|
||||
[Description("Local Ranking")]
|
||||
Local,
|
||||
|
||||
[Description("Country Ranking")]
|
||||
Country,
|
||||
|
||||
[Description("Global Ranking")]
|
||||
Global,
|
||||
|
||||
[Description("Friend Ranking")]
|
||||
Friend,
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ namespace osu.Game.Screens.Select.Options
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
EdgeSmoothness = new Vector2(1.5f, 0),
|
||||
Blending = BlendingMode.Additive,
|
||||
Blending = BlendingParameters.Additive,
|
||||
Colour = Color4.White,
|
||||
Alpha = 0,
|
||||
},
|
||||
|
@ -121,7 +121,7 @@ namespace osu.Game.Screens.Select
|
||||
Size = new Vector2(wedged_container_size.X, 1),
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Bottom = 50,
|
||||
Bottom = Footer.HEIGHT,
|
||||
Top = wedged_container_size.Y + left_area_padding,
|
||||
Left = left_area_padding,
|
||||
Right = left_area_padding * 2,
|
||||
@ -147,20 +147,28 @@ namespace osu.Game.Screens.Select
|
||||
Width = 0.5f,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Carousel = new BeatmapCarousel
|
||||
new Container
|
||||
{
|
||||
Masking = false,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(1 - wedged_container_size.X, 1),
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
SelectionChanged = updateSelectedBeatmap,
|
||||
BeatmapSetsChanged = carouselBeatmapsLoaded,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Top = FilterControl.HEIGHT,
|
||||
Bottom = Footer.HEIGHT
|
||||
},
|
||||
Child = Carousel = new BeatmapCarousel
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Size = new Vector2(1 - wedged_container_size.X, 1),
|
||||
Anchor = Anchor.CentreRight,
|
||||
Origin = Anchor.CentreRight,
|
||||
SelectionChanged = updateSelectedBeatmap,
|
||||
BeatmapSetsChanged = carouselBeatmapsLoaded,
|
||||
},
|
||||
},
|
||||
FilterControl = new FilterControl
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 100,
|
||||
Height = FilterControl.HEIGHT,
|
||||
FilterChanged = c => Carousel.Filter(c),
|
||||
Background = { Width = 2 },
|
||||
Exit = () =>
|
||||
@ -354,6 +362,7 @@ namespace osu.Game.Screens.Select
|
||||
return;
|
||||
|
||||
beatmapNoDebounce = beatmap;
|
||||
|
||||
performUpdateSelected();
|
||||
}
|
||||
|
||||
@ -408,7 +417,11 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
Logger.Log($"beatmap changed from \"{Beatmap.Value.BeatmapInfo}\" to \"{beatmap}\"");
|
||||
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, Beatmap.Value);
|
||||
WorkingBeatmap previous = Beatmap.Value;
|
||||
Beatmap.Value = beatmaps.GetWorkingBeatmap(beatmap, previous);
|
||||
|
||||
if (this.IsCurrentScreen() && Beatmap.Value?.Track != previous?.Track)
|
||||
ensurePlayingSelected();
|
||||
|
||||
if (beatmap != null)
|
||||
{
|
||||
@ -419,8 +432,6 @@ namespace osu.Game.Screens.Select
|
||||
}
|
||||
}
|
||||
|
||||
if (this.IsCurrentScreen())
|
||||
ensurePlayingSelected();
|
||||
UpdateBeatmap(Beatmap.Value);
|
||||
}
|
||||
}
|
||||
@ -581,10 +592,18 @@ namespace osu.Game.Screens.Select
|
||||
{
|
||||
Track track = Beatmap.Value.Track;
|
||||
|
||||
if ((!track.IsRunning || restart) && music?.IsUserPaused != true)
|
||||
if (!track.IsRunning || restart)
|
||||
{
|
||||
track.RestartPoint = Beatmap.Value.Metadata.PreviewTime;
|
||||
track.Restart();
|
||||
|
||||
if (music != null)
|
||||
{
|
||||
// use the global music controller (when available) to cancel a potential local user paused state.
|
||||
music.SeekTo(track.RestartPoint);
|
||||
music.Play();
|
||||
}
|
||||
else
|
||||
track.Restart();
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user