mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 12:17:26 +08:00
Merge branch 'master' into settings-filter-regression-fix-2
This commit is contained in:
commit
83970f009c
@ -52,7 +52,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.422.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.421.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2022.423.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Transitive Dependencies">
|
||||
<!-- Realm needs to be directly referenced in all Xamarin projects, as it will not pull in its transitive dependencies otherwise. -->
|
||||
|
@ -0,0 +1,46 @@
|
||||
// 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.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osu.Game.Screens.Select;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
public class TestSceneButtonSystemNavigation : OsuGameTestScene
|
||||
{
|
||||
private ButtonSystem buttons => ((MainMenu)Game.ScreenStack.CurrentScreen).ChildrenOfType<ButtonSystem>().Single();
|
||||
|
||||
[Test]
|
||||
public void TestGlobalActionHasPriority()
|
||||
{
|
||||
AddAssert("state is initial", () => buttons.State == ButtonSystemState.Initial);
|
||||
|
||||
// triggering the cookie in the initial state with any key should only happen if no other action is bound to that key.
|
||||
// here, F10 is bound to GlobalAction.ToggleGameplayMouseButtons.
|
||||
AddStep("press F10", () => InputManager.Key(Key.F10));
|
||||
AddAssert("state is initial", () => buttons.State == ButtonSystemState.Initial);
|
||||
|
||||
AddStep("press P", () => InputManager.Key(Key.P));
|
||||
AddAssert("state is top level", () => buttons.State == ButtonSystemState.TopLevel);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestShortcutKeys()
|
||||
{
|
||||
AddAssert("state is initial", () => buttons.State == ButtonSystemState.Initial);
|
||||
|
||||
AddStep("press P", () => InputManager.Key(Key.P));
|
||||
AddAssert("state is top level", () => buttons.State == ButtonSystemState.TopLevel);
|
||||
|
||||
AddStep("press P", () => InputManager.Key(Key.P));
|
||||
AddAssert("state is play", () => buttons.State == ButtonSystemState.Play);
|
||||
|
||||
AddStep("press P", () => InputManager.Key(Key.P));
|
||||
AddAssert("entered song select", () => Game.ScreenStack.CurrentScreen is PlaySongSelect);
|
||||
}
|
||||
}
|
||||
}
|
@ -10,11 +10,12 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneButtonSystem : OsuTestScene
|
||||
public class TestSceneButtonSystem : OsuManualInputManagerTestScene
|
||||
{
|
||||
private OsuLogo logo;
|
||||
private ButtonSystem buttons;
|
||||
@ -64,6 +65,66 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddStep("Enter mode", performEnterMode);
|
||||
}
|
||||
|
||||
[TestCase(Key.P, true)]
|
||||
[TestCase(Key.M, true)]
|
||||
[TestCase(Key.L, true)]
|
||||
[TestCase(Key.E, false)]
|
||||
[TestCase(Key.D, false)]
|
||||
[TestCase(Key.Q, false)]
|
||||
[TestCase(Key.O, false)]
|
||||
public void TestShortcutKeys(Key key, bool entersPlay)
|
||||
{
|
||||
int activationCount = -1;
|
||||
AddStep("set up action", () =>
|
||||
{
|
||||
activationCount = 0;
|
||||
void action() => activationCount++;
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Key.P:
|
||||
buttons.OnSolo = action;
|
||||
break;
|
||||
|
||||
case Key.M:
|
||||
buttons.OnMultiplayer = action;
|
||||
break;
|
||||
|
||||
case Key.L:
|
||||
buttons.OnPlaylists = action;
|
||||
break;
|
||||
|
||||
case Key.E:
|
||||
buttons.OnEdit = action;
|
||||
break;
|
||||
|
||||
case Key.D:
|
||||
buttons.OnBeatmapListing = action;
|
||||
break;
|
||||
|
||||
case Key.Q:
|
||||
buttons.OnExit = action;
|
||||
break;
|
||||
|
||||
case Key.O:
|
||||
buttons.OnSettings = action;
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
AddStep($"press {key}", () => InputManager.Key(key));
|
||||
AddAssert("state is top level", () => buttons.State == ButtonSystemState.TopLevel);
|
||||
|
||||
if (entersPlay)
|
||||
{
|
||||
AddStep("press P", () => InputManager.Key(Key.P));
|
||||
AddAssert("state is play", () => buttons.State == ButtonSystemState.Play);
|
||||
}
|
||||
|
||||
AddStep($"press {key}", () => InputManager.Key(key));
|
||||
AddAssert("action triggered", () => activationCount == 1);
|
||||
}
|
||||
|
||||
private void performEnterMode()
|
||||
{
|
||||
buttons.State = ButtonSystemState.EnteringMode;
|
||||
|
@ -66,6 +66,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("Enable when first run setup is being displayed on first run.")]
|
||||
public void TestDoesntOpenOnSecondRun()
|
||||
{
|
||||
AddStep("set first run", () => LocalConfig.SetValue(OsuSetting.ShowFirstRunSetup, true));
|
||||
@ -165,7 +166,7 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddStep("click outside content", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(overlay.ScreenSpaceDrawQuad.TopLeft - new Vector2(1));
|
||||
InputManager.MoveMouseTo(new Vector2(overlay.ScreenSpaceDrawQuad.TopLeft.X, overlay.ScreenSpaceDrawQuad.Centre.Y));
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
|
@ -47,12 +47,22 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
IncompatibilityDisplayingModPanel panel = null;
|
||||
|
||||
AddStep("create panel with DT", () => Child = panel = new IncompatibilityDisplayingModPanel(new OsuModDoubleTime())
|
||||
AddStep("create panel with DT", () =>
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.None,
|
||||
Width = 300
|
||||
Child = panel = new IncompatibilityDisplayingModPanel(new OsuModDoubleTime())
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.None,
|
||||
Width = 300,
|
||||
};
|
||||
|
||||
panel.Active.BindValueChanged(active =>
|
||||
{
|
||||
SelectedMods.Value = active.NewValue
|
||||
? Array.Empty<Mod>()
|
||||
: new[] { panel.Mod };
|
||||
});
|
||||
});
|
||||
|
||||
clickPanel();
|
||||
@ -63,11 +73,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
AddStep("set incompatible mod", () => SelectedMods.Value = new[] { new OsuModHalfTime() });
|
||||
|
||||
clickPanel();
|
||||
AddAssert("panel not active", () => !panel.Active.Value);
|
||||
|
||||
AddStep("reset mods", () => SelectedMods.Value = Array.Empty<Mod>());
|
||||
|
||||
clickPanel();
|
||||
AddAssert("panel active", () => panel.Active.Value);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
// 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;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
@ -89,6 +90,27 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
changeRuleset(3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestIncompatibilityToggling()
|
||||
{
|
||||
createScreen();
|
||||
changeRuleset(0);
|
||||
|
||||
AddStep("activate DT", () => getPanelForMod(typeof(OsuModDoubleTime)).TriggerClick());
|
||||
AddAssert("DT active", () => SelectedMods.Value.Single().GetType() == typeof(OsuModDoubleTime));
|
||||
|
||||
AddStep("activate NC", () => getPanelForMod(typeof(OsuModNightcore)).TriggerClick());
|
||||
AddAssert("only NC active", () => SelectedMods.Value.Single().GetType() == typeof(OsuModNightcore));
|
||||
|
||||
AddStep("activate HR", () => getPanelForMod(typeof(OsuModHardRock)).TriggerClick());
|
||||
AddAssert("NC+HR active", () => SelectedMods.Value.Any(mod => mod.GetType() == typeof(OsuModNightcore))
|
||||
&& SelectedMods.Value.Any(mod => mod.GetType() == typeof(OsuModHardRock)));
|
||||
|
||||
AddStep("activate MR", () => getPanelForMod(typeof(OsuModMirror)).TriggerClick());
|
||||
AddAssert("NC+MR active", () => SelectedMods.Value.Any(mod => mod.GetType() == typeof(OsuModNightcore))
|
||||
&& SelectedMods.Value.Any(mod => mod.GetType() == typeof(OsuModMirror)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCustomisationToggleState()
|
||||
{
|
||||
@ -136,5 +158,8 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddAssert($"customisation toggle is {(disabled ? "" : "not ")}disabled", () => getToggle().Active.Disabled == disabled);
|
||||
AddAssert($"customisation toggle is {(active ? "" : "not ")}active", () => getToggle().Active.Value == active);
|
||||
}
|
||||
|
||||
private ModPanel getPanelForMod(Type modType)
|
||||
=> modSelectScreen.ChildrenOfType<ModPanel>().Single(panel => panel.Mod.GetType() == modType);
|
||||
}
|
||||
}
|
||||
|
@ -3,45 +3,79 @@
|
||||
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneSectionsContainer : OsuManualInputManagerTestScene
|
||||
{
|
||||
private readonly SectionsContainer<TestSection> container;
|
||||
private SectionsContainer<TestSection> container;
|
||||
private float custom;
|
||||
private const float header_height = 100;
|
||||
|
||||
public TestSceneSectionsContainer()
|
||||
private const float header_expandable_height = 300;
|
||||
private const float header_fixed_height = 100;
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
container = new SectionsContainer<TestSection>
|
||||
AddStep("setup container", () =>
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 300,
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
FixedHeader = new Box
|
||||
container = new SectionsContainer<TestSection>
|
||||
{
|
||||
Alpha = 0.5f,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
Width = 300,
|
||||
Height = header_height,
|
||||
Colour = Color4.Red
|
||||
}
|
||||
};
|
||||
container.SelectedSection.ValueChanged += section =>
|
||||
{
|
||||
if (section.OldValue != null)
|
||||
section.OldValue.Selected = false;
|
||||
if (section.NewValue != null)
|
||||
section.NewValue.Selected = true;
|
||||
};
|
||||
Add(container);
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
};
|
||||
|
||||
container.SelectedSection.ValueChanged += section =>
|
||||
{
|
||||
if (section.OldValue != null)
|
||||
section.OldValue.Selected = false;
|
||||
if (section.NewValue != null)
|
||||
section.NewValue.Selected = true;
|
||||
};
|
||||
|
||||
Child = container;
|
||||
});
|
||||
|
||||
AddToggleStep("disable expandable header", v => container.ExpandableHeader = v
|
||||
? null
|
||||
: new TestBox(@"Expandable Header")
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = header_expandable_height,
|
||||
BackgroundColour = new OsuColour().GreySky,
|
||||
});
|
||||
|
||||
AddToggleStep("disable fixed header", v => container.FixedHeader = v
|
||||
? null
|
||||
: new TestBox(@"Fixed Header")
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = header_fixed_height,
|
||||
BackgroundColour = new OsuColour().Red.Opacity(0.5f),
|
||||
});
|
||||
|
||||
AddToggleStep("disable footer", v => container.Footer = v
|
||||
? null
|
||||
: new TestBox("Footer")
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 200,
|
||||
BackgroundColour = new OsuColour().Green4,
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -71,7 +105,6 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
const int sections_count = 11;
|
||||
float[] alternating = { 0.07f, 0.33f, 0.16f, 0.33f };
|
||||
AddStep("clear", () => container.Clear());
|
||||
AddStep("fill with sections", () =>
|
||||
{
|
||||
for (int i = 0; i < sections_count; i++)
|
||||
@ -84,9 +117,9 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddUntilStep("correct section selected", () => container.SelectedSection.Value == container.Children[scrollIndex]);
|
||||
AddUntilStep("section top is visible", () =>
|
||||
{
|
||||
float scrollPosition = container.ChildrenOfType<UserTrackingScrollContainer>().First().Current;
|
||||
float sectionTop = container.Children[scrollIndex].BoundingBox.Top;
|
||||
return scrollPosition < sectionTop;
|
||||
var scrollContainer = container.ChildrenOfType<UserTrackingScrollContainer>().Single();
|
||||
float sectionPosition = scrollContainer.GetChildPosInContent(container.Children[scrollIndex]);
|
||||
return scrollContainer.Current < sectionPosition;
|
||||
});
|
||||
}
|
||||
|
||||
@ -101,15 +134,56 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddUntilStep("correct section selected", () => container.SelectedSection.Value == container.Children[sections_count - 1]);
|
||||
}
|
||||
|
||||
private static readonly ColourInfo selected_colour = ColourInfo.GradientVertical(Color4.Yellow, Color4.Gold);
|
||||
[Test]
|
||||
public void TestNavigation()
|
||||
{
|
||||
AddRepeatStep("add sections", () => append(1f), 3);
|
||||
AddUntilStep("wait for load", () => container.Children.Any());
|
||||
|
||||
AddStep("hover sections container", () => InputManager.MoveMouseTo(container));
|
||||
AddStep("press page down", () => InputManager.Key(Key.PageDown));
|
||||
AddUntilStep("scrolled one page down", () =>
|
||||
{
|
||||
var scroll = container.ChildrenOfType<UserTrackingScrollContainer>().First();
|
||||
return Precision.AlmostEquals(scroll.Current, Content.DrawHeight - header_fixed_height, 1f);
|
||||
});
|
||||
|
||||
AddStep("press page down", () => InputManager.Key(Key.PageDown));
|
||||
AddUntilStep("scrolled two pages down", () =>
|
||||
{
|
||||
var scroll = container.ChildrenOfType<UserTrackingScrollContainer>().First();
|
||||
return Precision.AlmostEquals(scroll.Current, (Content.DrawHeight - header_fixed_height) * 2, 1f);
|
||||
});
|
||||
|
||||
AddStep("press page up", () => InputManager.Key(Key.PageUp));
|
||||
AddUntilStep("scrolled one page up", () =>
|
||||
{
|
||||
var scroll = container.ChildrenOfType<UserTrackingScrollContainer>().First();
|
||||
return Precision.AlmostEquals(scroll.Current, Content.DrawHeight - header_fixed_height, 1f);
|
||||
});
|
||||
}
|
||||
|
||||
private static readonly ColourInfo selected_colour = ColourInfo.GradientVertical(new OsuColour().Orange2, new OsuColour().Orange3);
|
||||
private static readonly ColourInfo default_colour = ColourInfo.GradientVertical(Color4.White, Color4.DarkGray);
|
||||
|
||||
private void append(float multiplier)
|
||||
{
|
||||
container.Add(new TestSection
|
||||
float fixedHeaderHeight = container.FixedHeader?.Height ?? 0;
|
||||
float expandableHeaderHeight = container.ExpandableHeader?.Height ?? 0;
|
||||
|
||||
float totalHeaderHeight = expandableHeaderHeight + fixedHeaderHeight;
|
||||
float effectiveHeaderHeight = totalHeaderHeight;
|
||||
|
||||
// if we're in the "next page" of the sections container,
|
||||
// height of the expandable header should not be accounted.
|
||||
var scrollContent = container.ChildrenOfType<UserTrackingScrollContainer>().Single().ScrollContent;
|
||||
if (totalHeaderHeight + scrollContent.Height >= Content.DrawHeight)
|
||||
effectiveHeaderHeight -= expandableHeaderHeight;
|
||||
|
||||
container.Add(new TestSection($"Section #{container.Children.Count + 1}")
|
||||
{
|
||||
Width = 300,
|
||||
Height = (container.ChildSize.Y - header_height) * multiplier,
|
||||
Height = (Content.DrawHeight - effectiveHeaderHeight) * multiplier,
|
||||
Colour = default_colour
|
||||
});
|
||||
}
|
||||
@ -120,11 +194,50 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
InputManager.ScrollVerticalBy(direction);
|
||||
}
|
||||
|
||||
private class TestSection : Box
|
||||
private class TestSection : TestBox
|
||||
{
|
||||
public bool Selected
|
||||
{
|
||||
set => Colour = value ? selected_colour : default_colour;
|
||||
set => BackgroundColour = value ? selected_colour : default_colour;
|
||||
}
|
||||
|
||||
public TestSection(string label)
|
||||
: base(label)
|
||||
{
|
||||
BackgroundColour = default_colour;
|
||||
}
|
||||
}
|
||||
|
||||
private class TestBox : Container
|
||||
{
|
||||
private readonly Box background;
|
||||
private readonly OsuSpriteText text;
|
||||
|
||||
public ColourInfo BackgroundColour
|
||||
{
|
||||
set
|
||||
{
|
||||
background.Colour = value;
|
||||
text.Colour = OsuColour.ForegroundTextColourFor(value.AverageColour);
|
||||
}
|
||||
}
|
||||
|
||||
public TestBox(string label)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
text = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Text = label,
|
||||
Font = OsuFont.Default.With(size: 36),
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,102 @@
|
||||
// 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.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneShearedOverlayContainer : OsuManualInputManagerTestScene
|
||||
{
|
||||
private TestShearedOverlayContainer overlay;
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("create overlay", () =>
|
||||
{
|
||||
Child = overlay = new TestShearedOverlayContainer
|
||||
{
|
||||
State = { Value = Visibility.Visible }
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestClickAwayToExit()
|
||||
{
|
||||
AddStep("click inside header", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(overlay.ChildrenOfType<ShearedOverlayHeader>().First().ScreenSpaceDrawQuad.Centre);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddAssert("overlay not dismissed", () => overlay.State.Value == Visibility.Visible);
|
||||
|
||||
AddStep("click inside content", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(overlay.ScreenSpaceDrawQuad.Centre);
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddAssert("overlay not dismissed", () => overlay.State.Value == Visibility.Visible);
|
||||
|
||||
AddStep("click outside header", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(new Vector2(overlay.ScreenSpaceDrawQuad.TopLeft.X, overlay.ScreenSpaceDrawQuad.Centre.Y));
|
||||
InputManager.Click(MouseButton.Left);
|
||||
});
|
||||
|
||||
AddAssert("overlay dismissed", () => overlay.State.Value == Visibility.Hidden);
|
||||
}
|
||||
|
||||
public class TestShearedOverlayContainer : ShearedOverlayContainer
|
||||
{
|
||||
protected override OverlayColourScheme ColourScheme => OverlayColourScheme.Green;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Header.Title = "Sheared overlay header";
|
||||
Header.Description = string.Join(" ", Enumerable.Repeat("This is a description.", 20));
|
||||
|
||||
MainAreaContent.Child = new InputBlockingContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(0.9f),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.Blue,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.Default.With(size: 24),
|
||||
Text = "Content",
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -149,13 +149,11 @@ namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
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;
|
||||
float bottomScrollExtent = scrollContainer.ScrollableExtent;
|
||||
float scrollTarget = top - scrollContainer.DisplayableContent * scroll_y_centre;
|
||||
|
||||
if (scrollTarget > bottomScrollExtent)
|
||||
scrollContainer.ScrollToEnd();
|
||||
@ -267,9 +265,13 @@ namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
if (!Children.Any()) return;
|
||||
|
||||
var newMargin = originalSectionsMargin;
|
||||
// if a fixed header is present, apply top padding for it
|
||||
// to make the scroll container aware of its displayable area.
|
||||
// (i.e. for page up/down to work properly)
|
||||
scrollContainer.Padding = new MarginPadding { Top = FixedHeader?.LayoutSize.Y ?? 0 };
|
||||
|
||||
newMargin.Top += (headerHeight ?? 0);
|
||||
var newMargin = originalSectionsMargin;
|
||||
newMargin.Top += (ExpandableHeader?.LayoutSize.Y ?? 0);
|
||||
newMargin.Bottom += (footerHeight ?? 0);
|
||||
|
||||
scrollContentContainer.Margin = newMargin;
|
||||
|
21
osu.Game/Graphics/InputBlockingContainer.cs
Normal file
21
osu.Game/Graphics/InputBlockingContainer.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// 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.
|
||||
|
||||
#nullable enable
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
|
||||
namespace osu.Game.Graphics
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple container which blocks input events from travelling through it.
|
||||
/// </summary>
|
||||
public class InputBlockingContainer : Container
|
||||
{
|
||||
protected override bool OnHover(HoverEvent e) => true;
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e) => true;
|
||||
|
||||
protected override bool OnClick(ClickEvent e) => true;
|
||||
}
|
||||
}
|
@ -66,7 +66,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
underlayContainer = new Container
|
||||
underlayContainer = new InputBlockingContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = HEIGHT,
|
||||
|
24
osu.Game/Localisation/JoystickSettingsStrings.cs
Normal file
24
osu.Game/Localisation/JoystickSettingsStrings.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// 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.Localisation;
|
||||
|
||||
namespace osu.Game.Localisation
|
||||
{
|
||||
public static class JoystickSettingsStrings
|
||||
{
|
||||
private const string prefix = @"osu.Game.Resources.Localisation.JoystickSettings";
|
||||
|
||||
/// <summary>
|
||||
/// "Joystick / Gamepad"
|
||||
/// </summary>
|
||||
public static LocalisableString JoystickGamepad => new TranslatableString(getKey(@"joystick_gamepad"), @"Joystick / Gamepad");
|
||||
|
||||
/// <summary>
|
||||
/// "Deadzone Threshold"
|
||||
/// </summary>
|
||||
public static LocalisableString DeadzoneThreshold => new TranslatableString(getKey(@"deadzone_threshold"), @"Deadzone");
|
||||
|
||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||
}
|
||||
}
|
@ -7,10 +7,8 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
@ -18,25 +16,22 @@ using osu.Framework.Localisation;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Localisation;
|
||||
using osu.Game.Overlays.FirstRunSetup;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Screens;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osu.Game.Screens.OnlinePlay.Match.Components;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
[Cached]
|
||||
public class FirstRunSetupOverlay : OsuFocusedOverlayContainer
|
||||
public class FirstRunSetupOverlay : ShearedOverlayContainer
|
||||
{
|
||||
protected override bool StartHidden => true;
|
||||
protected override OverlayColourScheme ColourScheme => OverlayColourScheme.Purple;
|
||||
|
||||
[Resolved]
|
||||
private IPerformFromScreenRunner performer { get; set; } = null!;
|
||||
@ -52,15 +47,10 @@ namespace osu.Game.Overlays
|
||||
public PurpleTriangleButton NextButton = null!;
|
||||
public DangerousTriangleButton BackButton = null!;
|
||||
|
||||
[Cached]
|
||||
private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple);
|
||||
|
||||
private readonly Bindable<bool> showFirstRunSetup = new Bindable<bool>();
|
||||
|
||||
private int? currentStepIndex;
|
||||
|
||||
private const float scale_when_hidden = 0.9f;
|
||||
|
||||
/// <summary>
|
||||
/// The currently displayed screen, if any.
|
||||
/// </summary>
|
||||
@ -76,149 +66,89 @@ namespace osu.Game.Overlays
|
||||
|
||||
private Bindable<OverlayActivation>? overlayActivationMode;
|
||||
|
||||
public FirstRunSetupOverlay()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
private Container content = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
Header.Title = FirstRunSetupOverlayStrings.FirstRunSetupTitle;
|
||||
Header.Description = FirstRunSetupOverlayStrings.FirstRunSetupDescription;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Size = new Vector2(0.95f);
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
MainAreaContent.AddRange(new Drawable[]
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 5,
|
||||
Colour = Color4.Black.Opacity(0.2f),
|
||||
};
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 10;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
content = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colourProvider.Background6,
|
||||
},
|
||||
new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RowDimensions = new[]
|
||||
Padding = new MarginPadding { Horizontal = 50 },
|
||||
Child = new InputBlockingContainer
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(),
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
Masking = true,
|
||||
CornerRadius = 14,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = colourProvider.Background5,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Margin = new MarginPadding(10),
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = FirstRunSetupOverlayStrings.FirstRunSetupTitle,
|
||||
Font = OsuFont.Default.With(size: 32),
|
||||
Colour = colourProvider.Content1,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
},
|
||||
new OsuTextFlowContainer
|
||||
{
|
||||
Text = FirstRunSetupOverlayStrings.FirstRunSetupDescription,
|
||||
Colour = colourProvider.Content2,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
stackContainer = new Container
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding(20),
|
||||
Colour = ColourProvider.Background6,
|
||||
},
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
new Container
|
||||
stackContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding(20)
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Top = 0 // provided by the stack container above.
|
||||
},
|
||||
Child = new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
ColumnDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.Absolute, 10),
|
||||
new Dimension(),
|
||||
},
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
BackButton = new DangerousTriangleButton
|
||||
{
|
||||
Width = 200,
|
||||
Text = CommonStrings.Back,
|
||||
Action = showPreviousStep,
|
||||
Enabled = { Value = false },
|
||||
},
|
||||
Empty(),
|
||||
NextButton = new PurpleTriangleButton
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 1,
|
||||
Text = FirstRunSetupOverlayStrings.GetStarted,
|
||||
Action = showNextStep
|
||||
}
|
||||
},
|
||||
}
|
||||
Vertical = 20,
|
||||
Horizontal = 20,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
FooterContent.Add(new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Width = 0.98f,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
ColumnDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
new Dimension(GridSizeMode.Absolute, 10),
|
||||
new Dimension(),
|
||||
},
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.AutoSize),
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
BackButton = new DangerousTriangleButton
|
||||
{
|
||||
Width = 200,
|
||||
Text = CommonStrings.Back,
|
||||
Action = showPreviousStep,
|
||||
Enabled = { Value = false },
|
||||
},
|
||||
Empty(),
|
||||
NextButton = new PurpleTriangleButton
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 1,
|
||||
Text = FirstRunSetupOverlayStrings.GetStarted,
|
||||
Action = showNextStep
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@ -227,7 +157,8 @@ namespace osu.Game.Overlays
|
||||
|
||||
config.BindWith(OsuSetting.ShowFirstRunSetup, showFirstRunSetup);
|
||||
|
||||
if (showFirstRunSetup.Value) Show();
|
||||
// TODO: uncomment when happy with the whole flow.
|
||||
// if (showFirstRunSetup.Value) Show();
|
||||
}
|
||||
|
||||
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||
@ -280,10 +211,8 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
base.PopIn();
|
||||
|
||||
this.ScaleTo(scale_when_hidden)
|
||||
.ScaleTo(1, 400, Easing.OutElasticHalf);
|
||||
|
||||
this.FadeIn(400, Easing.OutQuint);
|
||||
content.ScaleTo(0.99f)
|
||||
.ScaleTo(1, 400, Easing.OutQuint);
|
||||
|
||||
if (currentStepIndex == null)
|
||||
showFirstStep();
|
||||
@ -291,6 +220,10 @@ namespace osu.Game.Overlays
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
base.PopOut();
|
||||
|
||||
content.ScaleTo(0.99f, 400, Easing.OutQuint);
|
||||
|
||||
if (overlayActivationMode != null)
|
||||
{
|
||||
// If this is non-null we are guaranteed to have come from the main menu.
|
||||
@ -316,11 +249,6 @@ namespace osu.Game.Overlays
|
||||
stack?.FadeOut(100)
|
||||
.Expire();
|
||||
}
|
||||
|
||||
base.PopOut();
|
||||
|
||||
this.ScaleTo(0.96f, 400, Easing.OutQuint);
|
||||
this.FadeOut(200, Easing.OutQuint);
|
||||
}
|
||||
|
||||
private void showFirstStep()
|
||||
@ -362,7 +290,8 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
else
|
||||
{
|
||||
showFirstRunSetup.Value = false;
|
||||
// TODO: uncomment when happy with the whole flow.
|
||||
// showFirstRunSetup.Value = false;
|
||||
currentStepIndex = null;
|
||||
Hide();
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.LocalisationExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
@ -51,14 +52,14 @@ namespace osu.Game.Overlays.Login
|
||||
{
|
||||
username = new OsuTextBox
|
||||
{
|
||||
PlaceholderText = UsersStrings.LoginUsername,
|
||||
PlaceholderText = UsersStrings.LoginUsername.ToLower(),
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Text = api?.ProvidedUsername ?? string.Empty,
|
||||
TabbableContentContainer = this
|
||||
},
|
||||
password = new OsuPasswordTextBox
|
||||
{
|
||||
PlaceholderText = UsersStrings.LoginPassword,
|
||||
PlaceholderText = UsersStrings.LoginPassword.ToLower(),
|
||||
RelativeSizeAxes = Axes.X,
|
||||
TabbableContentContainer = this,
|
||||
},
|
||||
|
@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Mods
|
||||
Height = HEIGHT;
|
||||
AutoSizeAxes = Axes.X;
|
||||
|
||||
InternalChild = new Container
|
||||
InternalChild = new InputBlockingContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
|
@ -1,15 +1,12 @@
|
||||
// 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;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Utils;
|
||||
|
||||
@ -42,41 +39,13 @@ namespace osu.Game.Overlays.Mods
|
||||
&& !ModUtils.CheckCompatibleSet(selectedMods.Value.Append(Mod));
|
||||
}
|
||||
|
||||
protected override Colour4 BackgroundColour => incompatible.Value ? (Colour4)ColourProvider.Background6 : base.BackgroundColour;
|
||||
protected override Colour4 ForegroundColour => incompatible.Value ? (Colour4)ColourProvider.Background5 : base.ForegroundColour;
|
||||
|
||||
protected override void UpdateState()
|
||||
{
|
||||
Action = incompatible.Value ? () => { } : (Action)Active.Toggle;
|
||||
|
||||
if (incompatible.Value)
|
||||
{
|
||||
Colour4 backgroundColour = ColourProvider.Background6;
|
||||
Colour4 textBackgroundColour = ColourProvider.Background5;
|
||||
|
||||
Content.TransformTo(nameof(BorderColour), ColourInfo.GradientVertical(backgroundColour, textBackgroundColour), TRANSITION_DURATION, Easing.OutQuint);
|
||||
Background.FadeColour(backgroundColour, TRANSITION_DURATION, Easing.OutQuint);
|
||||
|
||||
SwitchContainer.ResizeWidthTo(IDLE_SWITCH_WIDTH, TRANSITION_DURATION, Easing.OutQuint);
|
||||
SwitchContainer.FadeColour(Colour4.Gray, TRANSITION_DURATION, Easing.OutQuint);
|
||||
MainContentContainer.TransformTo(nameof(Padding), new MarginPadding
|
||||
{
|
||||
Left = IDLE_SWITCH_WIDTH,
|
||||
Right = CORNER_RADIUS
|
||||
}, TRANSITION_DURATION, Easing.OutQuint);
|
||||
|
||||
TextBackground.FadeColour(textBackgroundColour, TRANSITION_DURATION, Easing.OutQuint);
|
||||
TextFlow.FadeColour(Colour4.White.Opacity(0.5f), TRANSITION_DURATION, Easing.OutQuint);
|
||||
return;
|
||||
}
|
||||
|
||||
SwitchContainer.FadeColour(Colour4.White, TRANSITION_DURATION, Easing.OutQuint);
|
||||
base.UpdateState();
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(MouseDownEvent e)
|
||||
{
|
||||
if (incompatible.Value)
|
||||
return true; // bypasses base call purposely in order to not play out the intermediate state animation.
|
||||
|
||||
return base.OnMouseDown(e);
|
||||
SwitchContainer.FadeColour(incompatible.Value ? Colour4.Gray : Colour4.White, TRANSITION_DURATION, Easing.OutQuint);
|
||||
}
|
||||
|
||||
#region IHasCustomTooltip
|
||||
|
@ -203,20 +203,24 @@ namespace osu.Game.Overlays.Mods
|
||||
base.OnMouseUp(e);
|
||||
}
|
||||
|
||||
protected virtual Colour4 BackgroundColour => Active.Value ? activeColour.Darken(0.3f) : (Colour4)ColourProvider.Background3;
|
||||
protected virtual Colour4 ForegroundColour => Active.Value ? activeColour : (Colour4)ColourProvider.Background2;
|
||||
protected virtual Colour4 TextColour => Active.Value ? (Colour4)ColourProvider.Background6 : Colour4.White;
|
||||
|
||||
protected virtual void UpdateState()
|
||||
{
|
||||
float targetWidth = Active.Value ? EXPANDED_SWITCH_WIDTH : IDLE_SWITCH_WIDTH;
|
||||
double transitionDuration = TRANSITION_DURATION;
|
||||
|
||||
Colour4 textBackgroundColour = Active.Value ? activeColour : (Colour4)ColourProvider.Background2;
|
||||
Colour4 mainBackgroundColour = Active.Value ? activeColour.Darken(0.3f) : (Colour4)ColourProvider.Background3;
|
||||
Colour4 textColour = Active.Value ? (Colour4)ColourProvider.Background6 : Colour4.White;
|
||||
Colour4 backgroundColour = BackgroundColour;
|
||||
Colour4 foregroundColour = ForegroundColour;
|
||||
Colour4 textColour = TextColour;
|
||||
|
||||
// Hover affects colour of button background
|
||||
if (IsHovered)
|
||||
{
|
||||
textBackgroundColour = textBackgroundColour.Lighten(0.1f);
|
||||
mainBackgroundColour = mainBackgroundColour.Lighten(0.1f);
|
||||
backgroundColour = backgroundColour.Lighten(0.1f);
|
||||
foregroundColour = foregroundColour.Lighten(0.1f);
|
||||
}
|
||||
|
||||
// Mouse down adds a halfway tween of the movement
|
||||
@ -226,15 +230,15 @@ namespace osu.Game.Overlays.Mods
|
||||
transitionDuration *= 4;
|
||||
}
|
||||
|
||||
Content.TransformTo(nameof(BorderColour), ColourInfo.GradientVertical(mainBackgroundColour, textBackgroundColour), transitionDuration, Easing.OutQuint);
|
||||
Background.FadeColour(mainBackgroundColour, transitionDuration, Easing.OutQuint);
|
||||
Content.TransformTo(nameof(BorderColour), ColourInfo.GradientVertical(backgroundColour, foregroundColour), transitionDuration, Easing.OutQuint);
|
||||
Background.FadeColour(backgroundColour, transitionDuration, Easing.OutQuint);
|
||||
SwitchContainer.ResizeWidthTo(targetWidth, transitionDuration, Easing.OutQuint);
|
||||
MainContentContainer.TransformTo(nameof(Padding), new MarginPadding
|
||||
{
|
||||
Left = targetWidth,
|
||||
Right = CORNER_RADIUS
|
||||
}, transitionDuration, Easing.OutQuint);
|
||||
TextBackground.FadeColour(textBackgroundColour, transitionDuration, Easing.OutQuint);
|
||||
TextBackground.FadeColour(foregroundColour, transitionDuration, Easing.OutQuint);
|
||||
TextFlow.FadeColour(textColour, transitionDuration, Easing.OutQuint);
|
||||
}
|
||||
|
||||
|
@ -168,7 +168,7 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
foreach (var column in columnFlow)
|
||||
{
|
||||
column.SelectedMods.BindValueChanged(_ => updateBindableFromSelection());
|
||||
column.SelectedMods.BindValueChanged(updateBindableFromSelection);
|
||||
}
|
||||
|
||||
customisationVisible.BindValueChanged(_ => updateCustomisationVisualState(), true);
|
||||
@ -237,33 +237,36 @@ namespace osu.Game.Overlays.Mods
|
||||
TopLevelContent.MoveToY(-modAreaHeight, transition_duration, Easing.InOutCubic);
|
||||
}
|
||||
|
||||
private bool selectionBindableSyncInProgress;
|
||||
|
||||
private void updateSelectionFromBindable()
|
||||
{
|
||||
if (selectionBindableSyncInProgress)
|
||||
return;
|
||||
|
||||
selectionBindableSyncInProgress = true;
|
||||
|
||||
// note that selectionBindableSyncInProgress is purposefully not checked here.
|
||||
// this is because in the case of mod selection in solo gameplay, a user selection of a mod can actually lead to deselection of other incompatible mods.
|
||||
// to synchronise state correctly, updateBindableFromSelection() computes the final mods (including incompatibility rules) and updates SelectedMods,
|
||||
// and this method then runs unconditionally again to make sure the new visual selection accurately reflects the final set of selected mods.
|
||||
// selectionBindableSyncInProgress ensures that mutual infinite recursion does not happen after that unconditional call.
|
||||
foreach (var column in columnFlow)
|
||||
column.SelectedMods.Value = SelectedMods.Value.Where(mod => mod.Type == column.ModType).ToArray();
|
||||
|
||||
selectionBindableSyncInProgress = false;
|
||||
}
|
||||
|
||||
private void updateBindableFromSelection()
|
||||
private bool selectionBindableSyncInProgress;
|
||||
|
||||
private void updateBindableFromSelection(ValueChangedEvent<IReadOnlyList<Mod>> modSelectionChange)
|
||||
{
|
||||
if (selectionBindableSyncInProgress)
|
||||
return;
|
||||
|
||||
selectionBindableSyncInProgress = true;
|
||||
|
||||
SelectedMods.Value = columnFlow.SelectMany(column => column.SelectedMods.Value).ToArray();
|
||||
SelectedMods.Value = ComputeNewModsFromSelection(
|
||||
modSelectionChange.NewValue.Except(modSelectionChange.OldValue),
|
||||
modSelectionChange.OldValue.Except(modSelectionChange.NewValue));
|
||||
|
||||
selectionBindableSyncInProgress = false;
|
||||
}
|
||||
|
||||
protected virtual IReadOnlyList<Mod> ComputeNewModsFromSelection(IEnumerable<Mod> addedMods, IEnumerable<Mod> removedMods)
|
||||
=> columnFlow.SelectMany(column => column.SelectedMods.Value).ToArray();
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
const double fade_in_duration = 400;
|
||||
|
@ -5,6 +5,8 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
@ -88,7 +90,7 @@ namespace osu.Game.Overlays.Mods
|
||||
Bottom = footer_height + PADDING,
|
||||
}
|
||||
},
|
||||
Footer = new Container
|
||||
Footer = new InputBlockingContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Depth = float.MinValue,
|
||||
@ -113,6 +115,17 @@ namespace osu.Game.Overlays.Mods
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
if (State.Value == Visibility.Visible)
|
||||
{
|
||||
Hide();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnClick(e);
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
const double fade_in_duration = 400;
|
||||
|
@ -1,8 +1,11 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Utils;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Overlays.Mods
|
||||
@ -11,6 +14,24 @@ namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
protected override ModColumn CreateModColumn(ModType modType, Key[] toggleKeys = null) => new UserModColumn(modType, false, toggleKeys);
|
||||
|
||||
protected override IReadOnlyList<Mod> ComputeNewModsFromSelection(IEnumerable<Mod> addedMods, IEnumerable<Mod> removedMods)
|
||||
{
|
||||
IEnumerable<Mod> modsAfterRemoval = SelectedMods.Value.Except(removedMods).ToList();
|
||||
|
||||
// the preference is that all new mods should override potential incompatible old mods.
|
||||
// in general that's a bit difficult to compute if more than one mod is added at a time,
|
||||
// so be conservative and just remove all mods that aren't compatible with any one added mod.
|
||||
foreach (var addedMod in addedMods)
|
||||
{
|
||||
if (!ModUtils.CheckCompatibleSet(modsAfterRemoval.Append(addedMod), out var invalidMods))
|
||||
modsAfterRemoval = modsAfterRemoval.Except(invalidMods);
|
||||
|
||||
modsAfterRemoval = modsAfterRemoval.Append(addedMod).ToList();
|
||||
}
|
||||
|
||||
return modsAfterRemoval.ToList();
|
||||
}
|
||||
|
||||
private class UserModColumn : ModColumn
|
||||
{
|
||||
public UserModColumn(ModType modType, bool allowBulkSelection, [CanBeNull] Key[] toggleKeys = null)
|
||||
|
@ -0,0 +1,56 @@
|
||||
// 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.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Handlers.Joystick;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Localisation;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
public class JoystickSettings : SettingsSubsection
|
||||
{
|
||||
protected override LocalisableString Header => JoystickSettingsStrings.JoystickGamepad;
|
||||
|
||||
private readonly JoystickHandler joystickHandler;
|
||||
|
||||
private readonly Bindable<bool> enabled = new BindableBool(true);
|
||||
|
||||
private SettingsSlider<float> deadzoneSlider;
|
||||
|
||||
public JoystickSettings(JoystickHandler joystickHandler)
|
||||
{
|
||||
this.joystickHandler = joystickHandler;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = CommonStrings.Enabled,
|
||||
Current = enabled
|
||||
},
|
||||
deadzoneSlider = new SettingsSlider<float>
|
||||
{
|
||||
LabelText = JoystickSettingsStrings.DeadzoneThreshold,
|
||||
KeyboardStep = 0.01f,
|
||||
DisplayAsPercentage = true,
|
||||
Current = joystickHandler.DeadzoneThreshold,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
enabled.BindTo(joystickHandler.Enabled);
|
||||
enabled.BindValueChanged(e => deadzoneSlider.Current.Disabled = !e.NewValue, true);
|
||||
}
|
||||
}
|
||||
}
|
@ -68,7 +68,10 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
break;
|
||||
|
||||
// whitelist the handlers which should be displayed to avoid any weird cases of users touching settings they shouldn't.
|
||||
case JoystickHandler _:
|
||||
case JoystickHandler jh:
|
||||
section = new JoystickSettings(jh);
|
||||
break;
|
||||
|
||||
case MidiHandler _:
|
||||
section = new HandlerSection(handler);
|
||||
break;
|
||||
|
@ -196,11 +196,8 @@ namespace osu.Game.Screens.Menu
|
||||
|
||||
if (State == ButtonSystemState.Initial)
|
||||
{
|
||||
if (buttonsTopLevel.Any(b => e.Key == b.TriggerKey))
|
||||
{
|
||||
logo?.TriggerClick();
|
||||
return true;
|
||||
}
|
||||
logo?.TriggerClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnKeyDown(e);
|
||||
|
@ -244,7 +244,7 @@ namespace osu.Game.Screens.Select.Carousel
|
||||
}
|
||||
|
||||
if (hideRequested != null)
|
||||
items.Add(new OsuMenuItem(CommonStrings.ButtonsHide, MenuItemType.Destructive, () => hideRequested(beatmapInfo)));
|
||||
items.Add(new OsuMenuItem("Hide", MenuItemType.Destructive, () => hideRequested(beatmapInfo)));
|
||||
|
||||
return items.ToArray();
|
||||
}
|
||||
|
@ -390,7 +390,7 @@ namespace osu.Game.Skinning
|
||||
return new LegacyJudgementPieceOld(resultComponent.Component, createDrawable);
|
||||
}
|
||||
|
||||
break;
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.GetAnimation(component.LookupName, false, false);
|
||||
|
@ -35,7 +35,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="10.10.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2022.421.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2022.423.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.422.0" />
|
||||
<PackageReference Include="Sentry" Version="3.14.1" />
|
||||
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
||||
|
@ -61,7 +61,7 @@
|
||||
<Reference Include="System.Net.Http" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Package References">
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.421.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2022.423.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2022.422.0" />
|
||||
</ItemGroup>
|
||||
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net6.0) -->
|
||||
@ -84,7 +84,7 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="5.0.14" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="5.0.14" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2022.421.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2022.423.0" />
|
||||
<PackageReference Include="SharpCompress" Version="0.30.1" />
|
||||
<PackageReference Include="NUnit" Version="3.13.2" />
|
||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
||||
|
Loading…
Reference in New Issue
Block a user