1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 03:22:55 +08:00

Merge branch 'master' into fix-exporting-a-skin-with-too-long-file-name

This commit is contained in:
Cootz 2023-03-07 15:46:52 +03:00 committed by GitHub
commit 5d41d343fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 250 additions and 131 deletions

View File

@ -3,15 +3,53 @@
#
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
$CSPROJ="osu.Game/osu.Game.csproj"
$GAME_CSPROJ="osu.Game/osu.Game.csproj"
$ANDROID_PROPS="osu.Android.props"
$IOS_PROPS="osu.iOS.props"
$SLN="osu.sln"
dotnet remove $CSPROJ package ppy.osu.Framework;
dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj;
dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
dotnet remove $GAME_CSPROJ reference ppy.osu.Framework;
dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android;
dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS;
dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj `
../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj `
../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj `
../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj;
dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj;
dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj;
dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj;
# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files
(Get-Content "osu.Android.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.Android.props"
(Get-Content "osu.iOS.props") -replace "`"..\\osu-framework", "`"`$(MSBuildThisFileDirectory)..\osu-framework" | Set-Content "osu.iOS.props"
# needed because iOS framework nupkg includes a set of properties to work around certain issues during building,
# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference.
(Get-Content "osu.iOS.props") |
Foreach-Object {
if ($_ -match "</Project>")
{
" <Import Project=`"`$(MSBuildThisFileDirectory)../osu-framework/osu.Framework.iOS.props`"/>"
}
$_
} | Set-Content "osu.iOS.props"
$TMP=New-TemporaryFile
$SLNF=Get-Content "osu.Desktop.slnf" | ConvertFrom-Json
$TMP=New-TemporaryFile
$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj")
ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
Move-Item -Path $TMP -Destination "osu.Desktop.slnf" -Force
$SLNF=Get-Content "osu.Android.slnf" | ConvertFrom-Json
$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj")
ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
Move-Item -Path $TMP -Destination "osu.Android.slnf" -Force
$SLNF=Get-Content "osu.iOS.slnf" | ConvertFrom-Json
$SLNF.solution.projects += ("../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj")
ConvertTo-Json $SLNF | Out-File $TMP -Encoding UTF8
Move-Item -Path $TMP -Destination "osu.iOS.slnf" -Force

View File

@ -5,14 +5,41 @@
#
# https://github.com/ppy/osu-framework/wiki/Testing-local-framework-checkout-with-other-projects
CSPROJ="osu.Game/osu.Game.csproj"
GAME_CSPROJ="osu.Game/osu.Game.csproj"
ANDROID_PROPS="osu.Android.props"
IOS_PROPS="osu.iOS.props"
SLN="osu.sln"
dotnet remove $CSPROJ package ppy.osu.Framework
dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj ../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj
dotnet add $CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
dotnet remove $GAME_CSPROJ reference ppy.osu.Framework
dotnet remove $ANDROID_PROPS reference ppy.osu.Framework.Android
dotnet remove $IOS_PROPS reference ppy.osu.Framework.iOS
dotnet sln $SLN add ../osu-framework/osu.Framework/osu.Framework.csproj \
../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj \
../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj \
../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj
dotnet add $GAME_CSPROJ reference ../osu-framework/osu.Framework/osu.Framework.csproj
dotnet add $ANDROID_PROPS reference ../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj
dotnet add $IOS_PROPS reference ../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj
# workaround for dotnet add not inserting $(MSBuildThisFileDirectory) on props files
sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.Android.props && rm osu.Android.props.bak
sed -i.bak 's:"..\\osu-framework:"$(MSBuildThisFileDirectory)..\\osu-framework:g' ./osu.iOS.props && rm osu.iOS.props.bak
# needed because iOS framework nupkg includes a set of properties to work around certain issues during building,
# and those get ignored when referencing framework via project, threfore we have to manually include it via props reference.
sed -i.bak '/<\/Project>/i\
<Import Project=\"$(MSBuildThisFileDirectory)../osu-framework/osu.Framework.iOS.props\"/>\
' ./osu.iOS.props && rm osu.iOS.props.bak
SLNF="osu.Desktop.slnf"
tmp=$(mktemp)
jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj"]' osu.Desktop.slnf > $tmp
mv -f $tmp $SLNF
mv -f $tmp osu.Desktop.slnf
jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.Android/osu.Framework.Android.csproj"]' osu.Android.slnf > $tmp
mv -f $tmp osu.Android.slnf
jq '.solution.projects += ["../osu-framework/osu.Framework/osu.Framework.csproj", "../osu-framework/osu.Framework.NativeLibs/osu.Framework.NativeLibs.csproj", "../osu-framework/osu.Framework.iOS/osu.Framework.iOS.csproj"]' osu.iOS.slnf > $tmp
mv -f $tmp osu.iOS.slnf

View File

@ -8,10 +8,14 @@
<!-- NullabilityInfoContextSupport is disabled by default for Android -->
<NullabilityInfoContextSupport>true</NullabilityInfoContextSupport>
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
<AndroidManifestMerger>manifestmerger.jar</AndroidManifestMerger>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.228.0" />
</ItemGroup>
<ItemGroup>
<AndroidManifestOverlay Include="$(MSBuildThisFileDirectory)osu.Android\Properties\AndroidManifestOverlay.xml" />
</ItemGroup>
<PropertyGroup>
<!-- Fody does not handle Android build well, and warns when unchanged.
Since Realm objects are not declared directly in Android projects, simply disable Fody. -->

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="mailto" />
</intent>
</queries>
</manifest>

View File

@ -167,8 +167,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
{
if (bodySprite != null)
{
bodySprite.Origin = Anchor.BottomCentre;
bodySprite.Scale = new Vector2(bodySprite.Scale.X, Math.Abs(bodySprite.Scale.Y) * -1);
bodySprite.Origin = Anchor.TopCentre;
bodySprite.Anchor = Anchor.BottomCentre; // needs to be flipped due to scale flip in Update.
}
if (light != null)
@ -179,7 +179,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
if (bodySprite != null)
{
bodySprite.Origin = Anchor.TopCentre;
bodySprite.Scale = new Vector2(bodySprite.Scale.X, Math.Abs(bodySprite.Scale.Y));
bodySprite.Anchor = Anchor.TopCentre;
}
if (light != null)
@ -211,11 +211,15 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
base.Update();
missFadeTime.Value ??= holdNote.HoldBrokenTime;
int scaleDirection = (direction.Value == ScrollingDirection.Down ? 1 : -1);
// here we go...
switch (bodyStyle)
{
case LegacyNoteBodyStyle.Stretch:
// this is how lazer works by default. nothing required.
if (bodySprite != null)
bodySprite.Scale = new Vector2(1, scaleDirection);
break;
default:
@ -228,7 +232,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
bodySprite.FillMode = FillMode.Stretch;
// i dunno this looks about right??
bodySprite.Scale = new Vector2(1, 32800 / sprite.DrawHeight);
bodySprite.Scale = new Vector2(1, scaleDirection * 32800 / sprite.DrawHeight);
}
break;

View File

@ -15,6 +15,7 @@ using osu.Game.Overlays.Settings;
using osu.Game.Overlays.SkinEditor;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Edit.Components;
using osu.Game.Screens.Play;
using osu.Game.Screens.Play.HUD.HitErrorMeters;
using osu.Game.Tests.Beatmaps.IO;
@ -188,6 +189,33 @@ namespace osu.Game.Tests.Visual.Navigation
AddUntilStep("mod overlay closed", () => songSelect.ModSelectOverlay.State.Value == Visibility.Hidden);
}
[Test]
public void TestChangeToNonSkinnableScreen()
{
advanceToSongSelect();
openSkinEditor();
AddAssert("blueprint container present", () => skinEditor.ChildrenOfType<SkinBlueprintContainer>().Count(), () => Is.EqualTo(1));
AddAssert("placeholder not present", () => skinEditor.ChildrenOfType<NonSkinnableScreenPlaceholder>().Count(), () => Is.Zero);
AddAssert("editor sidebars not empty", () => skinEditor.ChildrenOfType<EditorSidebar>().SelectMany(sidebar => sidebar.Children).Count(), () => Is.GreaterThan(0));
AddStep("add skinnable component", () =>
{
skinEditor.ChildrenOfType<SkinComponentToolbox.ToolboxComponentButton>().First().TriggerClick();
});
AddUntilStep("newly added component selected", () => skinEditor.SelectedComponents, () => Has.Count.EqualTo(1));
AddStep("exit to main menu", () => Game.ScreenStack.CurrentScreen.Exit());
AddAssert("selection cleared", () => skinEditor.SelectedComponents, () => Has.Count.Zero);
AddAssert("blueprint container not present", () => skinEditor.ChildrenOfType<SkinBlueprintContainer>().Count(), () => Is.Zero);
AddAssert("placeholder present", () => skinEditor.ChildrenOfType<NonSkinnableScreenPlaceholder>().Count(), () => Is.EqualTo(1));
AddAssert("editor sidebars empty", () => skinEditor.ChildrenOfType<EditorSidebar>().SelectMany(sidebar => sidebar.Children).Count(), () => Is.Zero);
advanceToSongSelect();
AddAssert("blueprint container present", () => skinEditor.ChildrenOfType<SkinBlueprintContainer>().Count(), () => Is.EqualTo(1));
AddAssert("placeholder not present", () => skinEditor.ChildrenOfType<NonSkinnableScreenPlaceholder>().Count(), () => Is.Zero);
AddAssert("editor sidebars not empty", () => skinEditor.ChildrenOfType<EditorSidebar>().SelectMany(sidebar => sidebar.Children).Count(), () => Is.GreaterThan(0));
}
private void advanceToSongSelect()
{
PushAndConfirm(() => songSelect = new TestPlaySongSelect());

View File

@ -516,15 +516,20 @@ namespace osu.Game.Tests.Visual.SongSelect
{
sets.Clear();
for (int i = 0; i < 20; i++)
for (int i = 0; i < 10; i++)
{
var set = TestResources.CreateTestBeatmapSetInfo(5);
if (i >= 2 && i < 10)
// A total of 6 sets have date submitted (4 don't)
// A total of 5 sets have artist string (3 of which also have date submitted)
if (i >= 2 && i < 8) // i = 2, 3, 4, 5, 6, 7 have submitted date
set.DateSubmitted = DateTimeOffset.Now.AddMinutes(i);
if (i < 5)
if (i < 5) // i = 0, 1, 2, 3, 4 have matching string
set.Beatmaps.ForEach(b => b.Metadata.Artist = zzz_string);
set.Beatmaps.ForEach(b => b.Metadata.Title = $"submitted: {set.DateSubmitted}");
sets.Add(set);
}
});
@ -532,15 +537,26 @@ namespace osu.Game.Tests.Visual.SongSelect
loadBeatmaps(sets);
AddStep("Sort by date submitted", () => carousel.Filter(new FilterCriteria { Sort = SortMode.DateSubmitted }, false));
checkVisibleItemCount(diff: false, count: 8);
checkVisibleItemCount(diff: false, count: 10);
checkVisibleItemCount(diff: true, count: 5);
AddAssert("missing date are at end",
() => carousel.Items.OfType<DrawableCarouselBeatmapSet>().Reverse().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted == null).Count(), () => Is.EqualTo(4));
AddAssert("rest are at start", () => carousel.Items.OfType<DrawableCarouselBeatmapSet>().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted != null).Count(),
() => Is.EqualTo(6));
AddStep("Sort by date submitted and string", () => carousel.Filter(new FilterCriteria
{
Sort = SortMode.DateSubmitted,
SearchText = zzz_string
}, false));
checkVisibleItemCount(diff: false, count: 3);
checkVisibleItemCount(diff: false, count: 5);
checkVisibleItemCount(diff: true, count: 5);
AddAssert("missing date are at end",
() => carousel.Items.OfType<DrawableCarouselBeatmapSet>().Reverse().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted == null).Count(), () => Is.EqualTo(2));
AddAssert("rest are at start", () => carousel.Items.OfType<DrawableCarouselBeatmapSet>().TakeWhile(i => i.Item is CarouselBeatmapSet s && s.BeatmapSet.DateSubmitted != null).Count(),
() => Is.EqualTo(3));
}
[Test]
@ -1129,7 +1145,7 @@ namespace osu.Game.Tests.Visual.SongSelect
{
// until step required as we are querying against alive items, which are loaded asynchronously inside DrawableCarouselBeatmapSet.
AddUntilStep($"{count} {(diff ? "diffs" : "sets")} visible", () =>
carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count);
carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible), () => Is.EqualTo(count));
}
private void checkSelectionIsCentered()
@ -1190,8 +1206,11 @@ namespace osu.Game.Tests.Visual.SongSelect
{
get
{
foreach (var item in Scroll.Children)
foreach (var item in Scroll.Children.OrderBy(c => c.Y))
{
if (item.Item?.Visible != true)
continue;
yield return item;
if (item is DrawableCarouselBeatmapSet set)

View File

@ -0,0 +1,75 @@
// 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.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterfaceV2;
using osuTK;
namespace osu.Game.Overlays.SkinEditor
{
public partial class NonSkinnableScreenPlaceholder : CompositeDrawable
{
[Resolved]
private SkinEditorOverlay? skinEditorOverlay { get; set; }
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
RelativeSizeAxes = Axes.Both;
InternalChildren = new Drawable[]
{
new Box
{
Colour = colourProvider.Dark6,
RelativeSizeAxes = Axes.Both,
Alpha = 0.95f,
},
new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(0, 5),
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
new SpriteIcon
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Icon = FontAwesome.Solid.ExclamationCircle,
Size = new Vector2(24),
Y = -5,
},
new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(weight: FontWeight.SemiBold, size: 18))
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
TextAnchor = Anchor.Centre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Text = "Please navigate to a skinnable screen using the scene library",
},
new RoundedButton
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 200,
Margin = new MarginPadding { Top = 20 },
Action = () => skinEditorOverlay?.Hide(),
Text = "Return to game"
}
}
},
};
}
}
}

View File

@ -7,15 +7,7 @@ using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Testing;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Rulesets.Edit;
using osu.Game.Screens.Edit.Compose.Components;
using osu.Game.Skinning;
@ -26,16 +18,16 @@ namespace osu.Game.Overlays.SkinEditor
{
public partial class SkinBlueprintContainer : BlueprintContainer<ISerialisableDrawable>
{
private readonly Drawable target;
private readonly ISerialisableDrawableContainer targetContainer;
private readonly List<BindableList<ISerialisableDrawable>> targetComponents = new List<BindableList<ISerialisableDrawable>>();
[Resolved]
private SkinEditor editor { get; set; } = null!;
public SkinBlueprintContainer(Drawable target)
public SkinBlueprintContainer(ISerialisableDrawableContainer targetContainer)
{
this.target = target;
this.targetContainer = targetContainer;
}
protected override void LoadComplete()
@ -44,22 +36,10 @@ namespace osu.Game.Overlays.SkinEditor
SelectedItems.BindTo(editor.SelectedComponents);
// track each target container on the current screen.
var targetContainers = target.ChildrenOfType<ISerialisableDrawableContainer>().ToArray();
var bindableList = new BindableList<ISerialisableDrawable> { BindTarget = targetContainer.Components };
bindableList.BindCollectionChanged(componentsChanged, true);
if (targetContainers.Length == 0)
{
AddInternal(new NonSkinnableScreenPlaceholder());
return;
}
foreach (var targetContainer in targetContainers)
{
var bindableList = new BindableList<ISerialisableDrawable> { BindTarget = targetContainer.Components };
bindableList.BindCollectionChanged(componentsChanged, true);
targetComponents.Add(bindableList);
}
targetComponents.Add(bindableList);
}
private void componentsChanged(object? sender, NotifyCollectionChangedEventArgs e) => Schedule(() =>
@ -160,65 +140,5 @@ namespace osu.Game.Overlays.SkinEditor
foreach (var list in targetComponents)
list.UnbindAll();
}
public partial class NonSkinnableScreenPlaceholder : CompositeDrawable
{
[Resolved]
private SkinEditorOverlay? skinEditorOverlay { get; set; }
[BackgroundDependencyLoader]
private void load(OverlayColourProvider colourProvider)
{
RelativeSizeAxes = Axes.Both;
InternalChildren = new Drawable[]
{
new Box
{
Colour = colourProvider.Dark6,
RelativeSizeAxes = Axes.Both,
Alpha = 0.95f,
},
new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(0, 5),
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
new SpriteIcon
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Icon = FontAwesome.Solid.ExclamationCircle,
Size = new Vector2(24),
Y = -5,
},
new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(weight: FontWeight.SemiBold, size: 18))
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
TextAnchor = Anchor.Centre,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Text = "Please navigate to a skinnable screen using the scene library",
},
new RoundedButton
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Width = 200,
Margin = new MarginPadding { Top = 20 },
Action = () => skinEditorOverlay?.Hide(),
Text = "Return to game"
}
}
},
};
}
}
}
}

View File

@ -304,7 +304,8 @@ namespace osu.Game.Overlays.SkinEditor
changeHandler?.Dispose();
// Immediately clear the previous blueprint container to ensure it doesn't try to interact with the old target.
content?.Clear();
if (content?.Child is SkinBlueprintContainer)
content.Clear();
Scheduler.AddOnce(loadBlueprintContainer);
Scheduler.AddOnce(populateSettings);
@ -323,17 +324,18 @@ namespace osu.Game.Overlays.SkinEditor
foreach (var toolbox in componentsSidebar.OfType<SkinComponentToolbox>())
toolbox.Expire();
if (target.NewValue == null)
return;
componentsSidebar.Clear();
SelectedComponents.Clear();
Debug.Assert(content != null);
SelectedComponents.Clear();
var skinComponentsContainer = getTarget(target.NewValue);
if (skinComponentsContainer == null)
if (target.NewValue == null || skinComponentsContainer == null)
{
content.Child = new NonSkinnableScreenPlaceholder();
return;
}
changeHandler = new SkinEditorChangeHandler(skinComponentsContainer);
changeHandler.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true);

View File

@ -61,7 +61,7 @@ namespace osu.Game.Screens.Select.Carousel
if (!(other is CarouselBeatmapSet otherSet))
return base.CompareTo(criteria, other);
int comparison = 0;
int comparison;
switch (criteria.Sort)
{
@ -87,11 +87,7 @@ namespace osu.Game.Screens.Select.Carousel
break;
case SortMode.DateRanked:
// Beatmaps which have no ranked date should already be filtered away in this mode.
if (BeatmapSet.DateRanked == null || otherSet.BeatmapSet.DateRanked == null)
break;
comparison = otherSet.BeatmapSet.DateRanked.Value.CompareTo(BeatmapSet.DateRanked.Value);
comparison = Nullable.Compare(otherSet.BeatmapSet.DateRanked, BeatmapSet.DateRanked);
break;
case SortMode.LastPlayed:
@ -111,11 +107,7 @@ namespace osu.Game.Screens.Select.Carousel
break;
case SortMode.DateSubmitted:
// Beatmaps which have no submitted date should already be filtered away in this mode.
if (BeatmapSet.DateSubmitted == null || otherSet.BeatmapSet.DateSubmitted == null)
break;
comparison = otherSet.BeatmapSet.DateSubmitted.Value.CompareTo(BeatmapSet.DateSubmitted.Value);
comparison = Nullable.Compare(otherSet.BeatmapSet.DateSubmitted, BeatmapSet.DateSubmitted);
break;
}
@ -153,12 +145,7 @@ namespace osu.Game.Screens.Select.Carousel
{
base.Filter(criteria);
bool filtered = Items.All(i => i.Filtered.Value);
filtered |= criteria.Sort == SortMode.DateRanked && BeatmapSet.DateRanked == null;
filtered |= criteria.Sort == SortMode.DateSubmitted && BeatmapSet.DateSubmitted == null;
Filtered.Value = filtered;
Filtered.Value = Items.All(i => i.Filtered.Value);
}
public override string ToString() => BeatmapSet.ToString();