mirror of
https://github.com/ppy/osu.git
synced 2025-01-26 23:13:20 +08:00
Merge branch 'master' into default-fullscreen
This commit is contained in:
commit
c8542d2434
@ -1,20 +0,0 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="osu! (legacy osuTK)" type="DotNetProject" factoryName=".NET Project" folderName="osu!" activateToolWindowBeforeRun="false">
|
||||
<option name="EXE_PATH" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0/osu!.dll" />
|
||||
<option name="PROGRAM_PARAMETERS" value="--tk" />
|
||||
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/osu.Desktop/bin/Debug/net5.0" />
|
||||
<option name="PASS_PARENT_ENVS" value="1" />
|
||||
<option name="USE_EXTERNAL_CONSOLE" value="0" />
|
||||
<option name="USE_MONO" value="0" />
|
||||
<option name="RUNTIME_ARGUMENTS" value="" />
|
||||
<option name="PROJECT_PATH" value="$PROJECT_DIR$/osu.Desktop/osu.Desktop.csproj" />
|
||||
<option name="PROJECT_EXE_PATH_TRACKING" value="1" />
|
||||
<option name="PROJECT_ARGUMENTS_TRACKING" value="1" />
|
||||
<option name="PROJECT_WORKING_DIRECTORY_TRACKING" value="1" />
|
||||
<option name="PROJECT_KIND" value="DotNetCore" />
|
||||
<option name="PROJECT_TFM" value="net5.0" />
|
||||
<method v="2">
|
||||
<option name="Build" />
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
@ -52,6 +52,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2021.211.1" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.309.0" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2021.323.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -136,24 +136,12 @@ namespace osu.Desktop
|
||||
|
||||
var iconStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(GetType(), "lazer.ico");
|
||||
|
||||
switch (host.Window)
|
||||
{
|
||||
// Legacy osuTK DesktopGameWindow
|
||||
case OsuTKDesktopWindow desktopGameWindow:
|
||||
desktopGameWindow.CursorState |= CursorState.Hidden;
|
||||
desktopGameWindow.SetIconFromStream(iconStream);
|
||||
desktopGameWindow.Title = Name;
|
||||
desktopGameWindow.FileDrop += (_, e) => fileDrop(e.FileNames);
|
||||
break;
|
||||
var desktopWindow = (SDL2DesktopWindow)host.Window;
|
||||
|
||||
// SDL2 DesktopWindow
|
||||
case SDL2DesktopWindow desktopWindow:
|
||||
desktopWindow.CursorState |= CursorState.Hidden;
|
||||
desktopWindow.SetIconFromStream(iconStream);
|
||||
desktopWindow.Title = Name;
|
||||
desktopWindow.DragDrop += f => fileDrop(new[] { f });
|
||||
break;
|
||||
}
|
||||
desktopWindow.CursorState |= CursorState.Hidden;
|
||||
desktopWindow.SetIconFromStream(iconStream);
|
||||
desktopWindow.Title = Name;
|
||||
desktopWindow.DragDrop += f => fileDrop(new[] { f });
|
||||
}
|
||||
|
||||
private void fileDrop(string[] filePaths)
|
||||
|
@ -22,9 +22,8 @@ namespace osu.Desktop
|
||||
{
|
||||
// Back up the cwd before DesktopGameHost changes it
|
||||
var cwd = Environment.CurrentDirectory;
|
||||
bool useOsuTK = args.Contains("--tk");
|
||||
|
||||
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true, useOsuTK: useOsuTK))
|
||||
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
|
||||
{
|
||||
host.ExceptionThrown += handleException;
|
||||
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
LocalConfig.Set(OsuSetting.IncreaseFirstObjectVisibility, false);
|
||||
LocalConfig.SetValue(OsuSetting.IncreaseFirstObjectVisibility, false);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -202,7 +202,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
public void TestHitLightingColour()
|
||||
{
|
||||
var fruitColour = SkinConfiguration.DefaultComboColours[1];
|
||||
AddStep("enable hit lighting", () => config.Set(OsuSetting.HitLighting, true));
|
||||
AddStep("enable hit lighting", () => config.SetValue(OsuSetting.HitLighting, true));
|
||||
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||
AddAssert("correct hit lighting colour", () =>
|
||||
catcher.ChildrenOfType<HitExplosion>().First()?.ObjectColour == fruitColour);
|
||||
@ -211,7 +211,7 @@ namespace osu.Game.Rulesets.Catch.Tests
|
||||
[Test]
|
||||
public void TestHitLightingDisabled()
|
||||
{
|
||||
AddStep("disable hit lighting", () => config.Set(OsuSetting.HitLighting, false));
|
||||
AddStep("disable hit lighting", () => config.SetValue(OsuSetting.HitLighting, false));
|
||||
AddStep("catch fruit", () => attemptCatch(new Fruit()));
|
||||
AddAssert("no hit lighting", () => !catcher.ChildrenOfType<HitExplosion>().Any());
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
|
||||
Assert.IsTrue(generated.Frames.Count == frame_offset + 2, "Replay must have 3 frames");
|
||||
Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time");
|
||||
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time");
|
||||
Assert.AreEqual(3000, generated.Frames[frame_offset + 1].Time, "Incorrect release time");
|
||||
Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Special1), "Special1 has not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Special1), "Special1 has not been released");
|
||||
}
|
||||
@ -99,7 +99,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
Assert.IsTrue(generated.Frames.Count == frame_offset + 2, "Replay must have 3 frames");
|
||||
|
||||
Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect hit time");
|
||||
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 1].Time, "Incorrect release time");
|
||||
Assert.AreEqual(3000, generated.Frames[frame_offset + 1].Time, "Incorrect release time");
|
||||
|
||||
Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been released");
|
||||
@ -148,9 +148,9 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
|
||||
Assert.IsTrue(generated.Frames.Count == frame_offset + 4, "Replay must have 4 generated frames");
|
||||
Assert.AreEqual(1000, generated.Frames[frame_offset].Time, "Incorrect first note hit time");
|
||||
Assert.AreEqual(3000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 2].Time, "Incorrect first note release time");
|
||||
Assert.AreEqual(3000, generated.Frames[frame_offset + 2].Time, "Incorrect first note release time");
|
||||
Assert.AreEqual(2000, generated.Frames[frame_offset + 1].Time, "Incorrect second note hit time");
|
||||
Assert.AreEqual(4000 + ManiaAutoGenerator.RELEASE_DELAY, generated.Frames[frame_offset + 3].Time, "Incorrect second note release time");
|
||||
Assert.AreEqual(4000, generated.Frames[frame_offset + 3].Time, "Incorrect second note release time");
|
||||
Assert.IsTrue(checkContains(generated.Frames[frame_offset], ManiaAction.Key1), "Key1 has not been pressed");
|
||||
Assert.IsTrue(checkContains(generated.Frames[frame_offset + 1], ManiaAction.Key1, ManiaAction.Key2), "Key1 & Key2 have not been pressed");
|
||||
Assert.IsFalse(checkContains(generated.Frames[frame_offset + 2], ManiaAction.Key1), "Key1 has not been released");
|
||||
@ -168,7 +168,7 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
// | | |
|
||||
|
||||
var beatmap = new ManiaBeatmap(new StageDefinition { Columns = 2 });
|
||||
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 - ManiaAutoGenerator.RELEASE_DELAY });
|
||||
beatmap.HitObjects.Add(new HoldNote { StartTime = 1000, Duration = 2000 });
|
||||
beatmap.HitObjects.Add(new Note { StartTime = 3000, Column = 1 });
|
||||
|
||||
var generated = new ManiaAutoGenerator(beatmap).Generate();
|
||||
|
@ -5,11 +5,13 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Mania.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Mania.Replays;
|
||||
using osu.Game.Rulesets.Mania.Scoring;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
@ -345,6 +347,14 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
|
||||
AddUntilStep("Beatmap at 0", () => Beatmap.Value.Track.CurrentTime == 0);
|
||||
AddUntilStep("Wait until player is loaded", () => currentPlayer.IsCurrentScreen());
|
||||
|
||||
AddUntilStep("wait for head", () => currentPlayer.GameplayClockContainer.GameplayClock.CurrentTime >= time_head);
|
||||
AddAssert("head is visible",
|
||||
() => currentPlayer.ChildrenOfType<DrawableHoldNote>()
|
||||
.Single(note => note.HitObject == beatmap.HitObjects[0])
|
||||
.Head
|
||||
.Alpha == 1);
|
||||
|
||||
AddUntilStep("Wait for completion", () => currentPlayer.ScoreProcessor.HasCompleted.Value);
|
||||
}
|
||||
|
||||
@ -352,6 +362,8 @@ namespace osu.Game.Rulesets.Mania.Tests
|
||||
{
|
||||
public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
|
||||
|
||||
public new GameplayClockContainer GameplayClockContainer => base.GameplayClockContainer;
|
||||
|
||||
protected override bool PauseOnFocusLost => false;
|
||||
|
||||
public ScoreAccessibleReplayPlayer(Score score)
|
||||
|
@ -20,8 +20,8 @@ namespace osu.Game.Rulesets.Mania.Configuration
|
||||
{
|
||||
base.InitialiseDefaults();
|
||||
|
||||
Set(ManiaRulesetSetting.ScrollTime, 1500.0, DrawableManiaRuleset.MIN_TIME_RANGE, DrawableManiaRuleset.MAX_TIME_RANGE, 5);
|
||||
Set(ManiaRulesetSetting.ScrollDirection, ManiaScrollingDirection.Down);
|
||||
SetDefault(ManiaRulesetSetting.ScrollTime, 1500.0, DrawableManiaRuleset.MIN_TIME_RANGE, DrawableManiaRuleset.MAX_TIME_RANGE, 5);
|
||||
SetDefault(ManiaRulesetSetting.ScrollDirection, ManiaScrollingDirection.Down);
|
||||
}
|
||||
|
||||
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
|
||||
|
@ -1,6 +1,8 @@
|
||||
// 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.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
{
|
||||
/// <summary>
|
||||
@ -25,6 +27,14 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
|
||||
LifetimeEnd = LifetimeStart + 30000;
|
||||
}
|
||||
|
||||
protected override void UpdateHitStateTransforms(ArmedState state)
|
||||
{
|
||||
// suppress the base call explicitly.
|
||||
// the hold note head should never change its visual state on its own due to the "freezing" mechanic
|
||||
// (when hit, it remains visible in place at the judgement line; when dropped, it will scroll past the line).
|
||||
// it will be hidden along with its parenting hold note when required.
|
||||
}
|
||||
|
||||
public override bool OnPressed(ManiaAction action) => false; // Handled by the hold note
|
||||
|
||||
public override void OnReleased(ManiaAction action)
|
||||
|
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Game.Replays;
|
||||
using osu.Game.Rulesets.Mania.Beatmaps;
|
||||
using osu.Game.Rulesets.Mania.Objects;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
@ -85,20 +86,28 @@ namespace osu.Game.Rulesets.Mania.Replays
|
||||
{
|
||||
var currentObject = Beatmap.HitObjects[i];
|
||||
var nextObjectInColumn = GetNextObject(i); // Get the next object that requires pressing the same button
|
||||
|
||||
double endTime = currentObject.GetEndTime();
|
||||
|
||||
bool canDelayKeyUp = nextObjectInColumn == null ||
|
||||
nextObjectInColumn.StartTime > endTime + RELEASE_DELAY;
|
||||
|
||||
double calculatedDelay = canDelayKeyUp ? RELEASE_DELAY : (nextObjectInColumn.StartTime - endTime) * 0.9;
|
||||
var releaseTime = calculateReleaseTime(currentObject, nextObjectInColumn);
|
||||
|
||||
yield return new HitPoint { Time = currentObject.StartTime, Column = currentObject.Column };
|
||||
|
||||
yield return new ReleasePoint { Time = endTime + calculatedDelay, Column = currentObject.Column };
|
||||
yield return new ReleasePoint { Time = releaseTime, Column = currentObject.Column };
|
||||
}
|
||||
}
|
||||
|
||||
private double calculateReleaseTime(HitObject currentObject, HitObject nextObject)
|
||||
{
|
||||
double endTime = currentObject.GetEndTime();
|
||||
|
||||
if (currentObject is HoldNote)
|
||||
// hold note releases must be timed exactly.
|
||||
return endTime;
|
||||
|
||||
bool canDelayKeyUpFully = nextObject == null ||
|
||||
nextObject.StartTime > endTime + RELEASE_DELAY;
|
||||
|
||||
return endTime + (canDelayKeyUpFully ? RELEASE_DELAY : (nextObject.StartTime - endTime) * 0.9);
|
||||
}
|
||||
|
||||
protected override HitObject GetNextObject(int currentIndex)
|
||||
{
|
||||
int desiredColumn = Beatmap.HitObjects[currentIndex].Column;
|
||||
|
@ -17,6 +17,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
public class LegacyHitExplosion : LegacyManiaColumnElement, IHitExplosion
|
||||
{
|
||||
public const double FADE_IN_DURATION = 80;
|
||||
|
||||
private readonly IBindable<ScrollingDirection> direction = new Bindable<ScrollingDirection>();
|
||||
|
||||
private Drawable explosion;
|
||||
@ -72,7 +74,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
|
||||
(explosion as IFramedAnimation)?.GotoFrame(0);
|
||||
|
||||
explosion?.FadeInFromZero(80)
|
||||
explosion?.FadeInFromZero(FADE_IN_DURATION)
|
||||
.Then().FadeOut(120);
|
||||
}
|
||||
}
|
||||
|
@ -101,8 +101,8 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
{
|
||||
if (action == column.Action.Value)
|
||||
{
|
||||
upSprite.FadeTo(1);
|
||||
downSprite.FadeTo(0);
|
||||
upSprite.Delay(LegacyHitExplosion.FADE_IN_DURATION).FadeTo(1);
|
||||
downSprite.Delay(LegacyHitExplosion.FADE_IN_DURATION).FadeTo(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ namespace osu.Game.Rulesets.Mania.Skinning.Legacy
|
||||
return animation == null ? null : new LegacyManiaJudgementPiece(result, animation);
|
||||
}
|
||||
|
||||
public override Sample GetSample(ISampleInfo sampleInfo)
|
||||
public override ISample GetSample(ISampleInfo sampleInfo)
|
||||
{
|
||||
// layered hit sounds never play in mania
|
||||
if (sampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacySample && legacySample.IsLayered)
|
||||
|
@ -15,13 +15,13 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
protected override string ResourceAssembly => "osu.Game.Rulesets.Osu";
|
||||
|
||||
[TestCase(6.9311451172608853d, "diffcalc-test")]
|
||||
[TestCase(1.0736587013228804d, "zero-length-sliders")]
|
||||
[TestCase(6.9311451172574934d, "diffcalc-test")]
|
||||
[TestCase(1.0736586907780401d, "zero-length-sliders")]
|
||||
public void Test(double expected, string name)
|
||||
=> base.Test(expected, name);
|
||||
|
||||
[TestCase(8.6228371119393064d, "diffcalc-test")]
|
||||
[TestCase(1.2864585434597433d, "zero-length-sliders")]
|
||||
[TestCase(8.6228371119271454d, "diffcalc-test")]
|
||||
[TestCase(1.2864585280364178d, "zero-length-sliders")]
|
||||
public void TestClockRateAdjusted(double expected, string name)
|
||||
=> Test(expected, name, new OsuModDoubleTime());
|
||||
|
||||
|
@ -98,7 +98,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
return null;
|
||||
}
|
||||
|
||||
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
||||
|
||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
[Test]
|
||||
public void TestHitLightingDisabled()
|
||||
{
|
||||
AddStep("hit lighting disabled", () => config.Set(OsuSetting.HitLighting, false));
|
||||
AddStep("hit lighting disabled", () => config.SetValue(OsuSetting.HitLighting, false));
|
||||
|
||||
showResult(HitResult.Great);
|
||||
|
||||
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
[Test]
|
||||
public void TestHitLightingEnabled()
|
||||
{
|
||||
AddStep("hit lighting enabled", () => config.Set(OsuSetting.HitLighting, true));
|
||||
AddStep("hit lighting enabled", () => config.SetValue(OsuSetting.HitLighting, true));
|
||||
|
||||
showResult(HitResult.Great);
|
||||
|
||||
|
@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
|
||||
AddSliderStep("circle size", 0f, 10f, 0f, val =>
|
||||
{
|
||||
config.Set(OsuSetting.AutoCursorSize, true);
|
||||
config.SetValue(OsuSetting.AutoCursorSize, true);
|
||||
gameplayBeatmap.BeatmapInfo.BaseDifficulty.CircleSize = val;
|
||||
Scheduler.AddOnce(recreate);
|
||||
});
|
||||
@ -64,21 +64,21 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
[TestCase(10, 1.5f)]
|
||||
public void TestSizing(int circleSize, float userScale)
|
||||
{
|
||||
AddStep($"set user scale to {userScale}", () => config.Set(OsuSetting.GameplayCursorSize, userScale));
|
||||
AddStep($"set user scale to {userScale}", () => config.SetValue(OsuSetting.GameplayCursorSize, userScale));
|
||||
AddStep($"adjust cs to {circleSize}", () => gameplayBeatmap.BeatmapInfo.BaseDifficulty.CircleSize = circleSize);
|
||||
AddStep("turn on autosizing", () => config.Set(OsuSetting.AutoCursorSize, true));
|
||||
AddStep("turn on autosizing", () => config.SetValue(OsuSetting.AutoCursorSize, true));
|
||||
|
||||
AddStep("load content", loadContent);
|
||||
|
||||
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize) * userScale);
|
||||
|
||||
AddStep("set user scale to 1", () => config.Set(OsuSetting.GameplayCursorSize, 1f));
|
||||
AddStep("set user scale to 1", () => config.SetValue(OsuSetting.GameplayCursorSize, 1f));
|
||||
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize));
|
||||
|
||||
AddStep("turn off autosizing", () => config.Set(OsuSetting.AutoCursorSize, false));
|
||||
AddStep("turn off autosizing", () => config.SetValue(OsuSetting.AutoCursorSize, false));
|
||||
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == 1);
|
||||
|
||||
AddStep($"set user scale to {userScale}", () => config.Set(OsuSetting.GameplayCursorSize, userScale));
|
||||
AddStep($"set user scale to {userScale}", () => config.SetValue(OsuSetting.GameplayCursorSize, userScale));
|
||||
AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == userScale);
|
||||
}
|
||||
|
||||
|
@ -42,10 +42,10 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
AddStep("enable user provider", () => testUserSkin.Enabled = true);
|
||||
|
||||
AddStep("enable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, true));
|
||||
AddStep("enable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, true));
|
||||
checkNextHitObject("beatmap");
|
||||
|
||||
AddStep("disable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, false));
|
||||
AddStep("disable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, false));
|
||||
checkNextHitObject("user");
|
||||
|
||||
AddStep("disable user provider", () => testUserSkin.Enabled = false);
|
||||
@ -57,20 +57,20 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
{
|
||||
AddStep("enable user provider", () => testUserSkin.Enabled = true);
|
||||
|
||||
AddStep("enable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, true));
|
||||
AddStep("enable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, true));
|
||||
AddStep("enable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, true));
|
||||
AddStep("enable beatmap colours", () => LocalConfig.SetValue(OsuSetting.BeatmapColours, true));
|
||||
checkNextHitObject("beatmap");
|
||||
|
||||
AddStep("enable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, true));
|
||||
AddStep("disable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, false));
|
||||
AddStep("enable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, true));
|
||||
AddStep("disable beatmap colours", () => LocalConfig.SetValue(OsuSetting.BeatmapColours, false));
|
||||
checkNextHitObject("beatmap");
|
||||
|
||||
AddStep("disable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, false));
|
||||
AddStep("enable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, true));
|
||||
AddStep("disable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, false));
|
||||
AddStep("enable beatmap colours", () => LocalConfig.SetValue(OsuSetting.BeatmapColours, true));
|
||||
checkNextHitObject("user");
|
||||
|
||||
AddStep("disable beatmap skin", () => LocalConfig.Set<bool>(OsuSetting.BeatmapSkins, false));
|
||||
AddStep("disable beatmap colours", () => LocalConfig.Set<bool>(OsuSetting.BeatmapColours, false));
|
||||
AddStep("disable beatmap skin", () => LocalConfig.SetValue(OsuSetting.BeatmapSkins, false));
|
||||
AddStep("disable beatmap colours", () => LocalConfig.SetValue(OsuSetting.BeatmapColours, false));
|
||||
checkNextHitObject("user");
|
||||
|
||||
AddStep("disable user provider", () => testUserSkin.Enabled = false);
|
||||
@ -162,7 +162,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
||||
|
||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => null;
|
||||
|
||||
public Sample GetSample(ISampleInfo sampleInfo) => null;
|
||||
public ISample GetSample(ISampleInfo sampleInfo) => null;
|
||||
|
||||
public TValue GetValue<TConfiguration, TValue>(Func<TConfiguration, TValue> query) where TConfiguration : SkinConfiguration => default;
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => null;
|
||||
|
@ -17,10 +17,10 @@ namespace osu.Game.Rulesets.Osu.Configuration
|
||||
protected override void InitialiseDefaults()
|
||||
{
|
||||
base.InitialiseDefaults();
|
||||
Set(OsuRulesetSetting.SnakingInSliders, true);
|
||||
Set(OsuRulesetSetting.SnakingOutSliders, true);
|
||||
Set(OsuRulesetSetting.ShowCursorTrail, true);
|
||||
Set(OsuRulesetSetting.PlayfieldBorderStyle, PlayfieldBorderStyle.None);
|
||||
SetDefault(OsuRulesetSetting.SnakingInSliders, true);
|
||||
SetDefault(OsuRulesetSetting.SnakingOutSliders, true);
|
||||
SetDefault(OsuRulesetSetting.ShowCursorTrail, true);
|
||||
SetDefault(OsuRulesetSetting.PlayfieldBorderStyle, PlayfieldBorderStyle.None);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,11 +7,13 @@ using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Edit;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Types;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens.Edit;
|
||||
using osuTK;
|
||||
@ -23,7 +25,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
/// <summary>
|
||||
/// A visualisation of a single <see cref="PathControlPoint"/> in a <see cref="Slider"/>.
|
||||
/// </summary>
|
||||
public class PathControlPointPiece : BlueprintPiece<Slider>
|
||||
public class PathControlPointPiece : BlueprintPiece<Slider>, IHasTooltip
|
||||
{
|
||||
public Action<PathControlPointPiece, MouseButtonEvent> RequestSelection;
|
||||
|
||||
@ -195,7 +197,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
|
||||
markerRing.Alpha = IsSelected.Value ? 1 : 0;
|
||||
|
||||
Color4 colour = ControlPoint.Type.Value != null ? colours.Red : colours.Yellow;
|
||||
Color4 colour = getColourFromNodeType();
|
||||
|
||||
if (IsHovered || IsSelected.Value)
|
||||
colour = colour.Lighten(1);
|
||||
@ -203,5 +205,28 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
marker.Colour = colour;
|
||||
marker.Scale = new Vector2(slider.Scale);
|
||||
}
|
||||
|
||||
private Color4 getColourFromNodeType()
|
||||
{
|
||||
if (!(ControlPoint.Type.Value is PathType pathType))
|
||||
return colours.Yellow;
|
||||
|
||||
switch (pathType)
|
||||
{
|
||||
case PathType.Catmull:
|
||||
return colours.Seafoam;
|
||||
|
||||
case PathType.Bezier:
|
||||
return colours.Pink;
|
||||
|
||||
case PathType.PerfectCurve:
|
||||
return colours.PurpleDark;
|
||||
|
||||
default:
|
||||
return colours.Red;
|
||||
}
|
||||
}
|
||||
|
||||
public string TooltipText => ControlPoint.Type.Value.ToString() ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
@ -28,6 +29,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
protected SliderBodyPiece BodyPiece { get; private set; }
|
||||
protected SliderCircleSelectionBlueprint HeadBlueprint { get; private set; }
|
||||
protected SliderCircleSelectionBlueprint TailBlueprint { get; private set; }
|
||||
|
||||
[CanBeNull]
|
||||
protected PathControlPointVisualiser ControlPointVisualiser { get; private set; }
|
||||
|
||||
private readonly DrawableSlider slider;
|
||||
@ -114,6 +117,8 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
|
||||
// throw away frame buffers on deselection.
|
||||
ControlPointVisualiser?.Expire();
|
||||
ControlPointVisualiser = null;
|
||||
|
||||
BodyPiece.RecyclePath();
|
||||
}
|
||||
|
||||
|
@ -164,28 +164,29 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
ApproachCircle.Expire(true);
|
||||
}
|
||||
|
||||
protected override void UpdateStartTimeStateTransforms()
|
||||
{
|
||||
base.UpdateStartTimeStateTransforms();
|
||||
|
||||
ApproachCircle.FadeOut(50);
|
||||
}
|
||||
|
||||
protected override void UpdateHitStateTransforms(ArmedState state)
|
||||
{
|
||||
Debug.Assert(HitObject.HitWindows != null);
|
||||
|
||||
// todo: temporary / arbitrary, used for lifetime optimisation.
|
||||
this.Delay(800).FadeOut();
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case ArmedState.Idle:
|
||||
this.Delay(HitObject.TimePreempt).FadeOut(500);
|
||||
HitArea.HitAction = null;
|
||||
break;
|
||||
|
||||
case ArmedState.Miss:
|
||||
ApproachCircle.FadeOut(50);
|
||||
this.FadeOut(100);
|
||||
break;
|
||||
|
||||
case ArmedState.Hit:
|
||||
ApproachCircle.FadeOut(50);
|
||||
|
||||
// todo: temporary / arbitrary
|
||||
this.Delay(800).FadeOut();
|
||||
break;
|
||||
}
|
||||
|
||||
Expire();
|
||||
|
@ -39,6 +39,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
private Bindable<bool> isSpinning;
|
||||
private bool spinnerFrequencyModulate;
|
||||
|
||||
private const double fade_out_duration = 160;
|
||||
|
||||
public DrawableSpinner()
|
||||
: this(null)
|
||||
{
|
||||
@ -131,12 +133,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
if (tracking.NewValue)
|
||||
{
|
||||
if (!spinningSample.IsPlaying)
|
||||
spinningSample?.Play();
|
||||
spinningSample?.VolumeTo(1, 300);
|
||||
spinningSample.Play();
|
||||
|
||||
spinningSample.VolumeTo(1, 300);
|
||||
}
|
||||
else
|
||||
{
|
||||
spinningSample?.VolumeTo(0, 300).OnComplete(_ => spinningSample.Stop());
|
||||
spinningSample.VolumeTo(0, fade_out_duration);
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,7 +176,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||
{
|
||||
base.UpdateHitStateTransforms(state);
|
||||
|
||||
this.FadeOut(160).Expire();
|
||||
this.FadeOut(fade_out_duration).OnComplete(_ =>
|
||||
{
|
||||
// looping sample should be stopped here as it is safer than running in the OnComplete
|
||||
// of the volume transition above.
|
||||
spinningSample.Stop();
|
||||
});
|
||||
|
||||
Expire();
|
||||
|
||||
// skin change does a rewind of transforms, which will stop the spinning sound from playing if it's currently in playback.
|
||||
isSpinning?.TriggerChange();
|
||||
|
@ -1,5 +1,18 @@
|
||||
{
|
||||
"Mappings": [{
|
||||
"StartTime": 114993,
|
||||
"Objects": [{
|
||||
"StartTime": 114993,
|
||||
"EndTime": 114993,
|
||||
"X": 493,
|
||||
"Y": 92
|
||||
}, {
|
||||
"StartTime": 115290,
|
||||
"EndTime": 115290,
|
||||
"X": 451.659241,
|
||||
"Y": 267.188
|
||||
}]
|
||||
}, {
|
||||
"StartTime": 118858.0,
|
||||
"Objects": [{
|
||||
"StartTime": 118858.0,
|
||||
|
@ -9,7 +9,9 @@ SliderMultiplier:1.87
|
||||
SliderTickRate:1
|
||||
|
||||
[TimingPoints]
|
||||
49051,230.769230769231,4,2,1,15,1,0
|
||||
114000,346.820809248555,4,2,1,71,1,0
|
||||
118000,230.769230769231,4,2,1,15,1,0
|
||||
|
||||
[HitObjects]
|
||||
493,92,114993,2,0,P|472:181|442:308,1,180,12|0,0:0|0:0,0:0:0:0:
|
||||
219,215,118858,2,0,P|224:170|244:-10,1,187,8|2,0:0|0:0,0:0:0:0:
|
||||
|
@ -74,10 +74,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default
|
||||
|
||||
private void updateState(DrawableHitObject drawableObject, ArmedState state)
|
||||
{
|
||||
using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime, true))
|
||||
{
|
||||
using (BeginAbsoluteSequence(drawableObject.StateUpdateTime))
|
||||
glow.FadeOut(400);
|
||||
|
||||
using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime))
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case ArmedState.Hit:
|
||||
|
@ -2,8 +2,12 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
using osu.Game.Rulesets.Taiko.UI;
|
||||
@ -13,6 +17,8 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
||||
[TestFixture]
|
||||
public class TestSceneHitExplosion : TaikoSkinnableTestScene
|
||||
{
|
||||
protected override double TimePerAction => 100;
|
||||
|
||||
[Test]
|
||||
public void TestNormalHit()
|
||||
{
|
||||
@ -21,11 +27,14 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
||||
AddStep("Miss", () => SetContents(() => getContentFor(createHit(HitResult.Miss))));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStrongHit([Values(false, true)] bool hitBoth)
|
||||
[TestCase(HitResult.Great)]
|
||||
[TestCase(HitResult.Ok)]
|
||||
public void TestStrongHit(HitResult type)
|
||||
{
|
||||
AddStep("Great", () => SetContents(() => getContentFor(createStrongHit(HitResult.Great, hitBoth))));
|
||||
AddStep("Good", () => SetContents(() => getContentFor(createStrongHit(HitResult.Ok, hitBoth))));
|
||||
AddStep("create hit", () => SetContents(() => getContentFor(createStrongHit(type))));
|
||||
AddStep("visualise second hit",
|
||||
() => this.ChildrenOfType<HitExplosion>()
|
||||
.ForEach(e => e.VisualiseSecondHit(new JudgementResult(new HitObject { StartTime = Time.Current }, new Judgement()))));
|
||||
}
|
||||
|
||||
private Drawable getContentFor(DrawableTestHit hit)
|
||||
@ -38,17 +47,17 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
||||
// the hit needs to be added to hierarchy in order for nested objects to be created correctly.
|
||||
// setting zero alpha is supposed to prevent the test from looking broken.
|
||||
hit.With(h => h.Alpha = 0),
|
||||
new HitExplosion(hit, hit.Type)
|
||||
new HitExplosion(hit.Type)
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
}
|
||||
}.With(explosion => explosion.Apply(hit))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private DrawableTestHit createHit(HitResult type) => new DrawableTestHit(new Hit { StartTime = Time.Current }, type);
|
||||
|
||||
private DrawableTestHit createStrongHit(HitResult type, bool hitBoth) => new DrawableTestStrongHit(Time.Current, type, hitBoth);
|
||||
private DrawableTestHit createStrongHit(HitResult type) => new DrawableTestStrongHit(Time.Current, type);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ using osu.Game.Audio;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.ControlPoints;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Judgements;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
@ -108,12 +107,12 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
{
|
||||
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Ok : HitResult.Great;
|
||||
|
||||
Hit hit = new Hit();
|
||||
Hit hit = new Hit { StartTime = DrawableRuleset.Playfield.Time.Current };
|
||||
var h = new DrawableTestHit(hit, kiai: kiai) { X = RNG.NextSingle(hitResult == HitResult.Ok ? -0.1f : -0.05f, hitResult == HitResult.Ok ? 0.1f : 0.05f) };
|
||||
|
||||
DrawableRuleset.Playfield.Add(h);
|
||||
|
||||
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult });
|
||||
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(hit, new TaikoJudgement()) { Type = hitResult });
|
||||
}
|
||||
|
||||
private void addStrongHitJudgement(bool kiai)
|
||||
@ -122,6 +121,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
|
||||
Hit hit = new Hit
|
||||
{
|
||||
StartTime = DrawableRuleset.Playfield.Time.Current,
|
||||
IsStrong = true,
|
||||
Samples = createSamples(strong: true)
|
||||
};
|
||||
@ -129,8 +129,8 @@ namespace osu.Game.Rulesets.Taiko.Tests
|
||||
|
||||
DrawableRuleset.Playfield.Add(h);
|
||||
|
||||
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult });
|
||||
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h.NestedHitObjects.Single(), new JudgementResult(new HitObject(), new TaikoStrongJudgement()) { Type = HitResult.Great });
|
||||
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(hit, new TaikoJudgement()) { Type = hitResult });
|
||||
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h.NestedHitObjects.Single(), new JudgementResult(hit.NestedHitObjects.Single(), new TaikoStrongJudgement()) { Type = HitResult.Great });
|
||||
}
|
||||
|
||||
private void addMissJudgement()
|
||||
|
@ -1,22 +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.Linq;
|
||||
using JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Animations;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Taiko.UI;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
||||
{
|
||||
public class LegacyHitExplosion : CompositeDrawable
|
||||
public class LegacyHitExplosion : CompositeDrawable, IAnimatableHitExplosion
|
||||
{
|
||||
private readonly Drawable sprite;
|
||||
private readonly Drawable strongSprite;
|
||||
|
||||
private DrawableStrongNestedHit nestedStrongHit;
|
||||
private bool switchedToStrongSprite;
|
||||
[CanBeNull]
|
||||
private readonly Drawable strongSprite;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new legacy hit explosion.
|
||||
@ -27,14 +27,14 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
||||
/// </remarks>
|
||||
/// <param name="sprite">The normal legacy explosion sprite.</param>
|
||||
/// <param name="strongSprite">The strong legacy explosion sprite.</param>
|
||||
public LegacyHitExplosion(Drawable sprite, Drawable strongSprite = null)
|
||||
public LegacyHitExplosion(Drawable sprite, [CanBeNull] Drawable strongSprite = null)
|
||||
{
|
||||
this.sprite = sprite;
|
||||
this.strongSprite = strongSprite;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(DrawableHitObject judgedObject)
|
||||
private void load()
|
||||
{
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
@ -56,45 +56,30 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
||||
s.Origin = Anchor.Centre;
|
||||
}));
|
||||
}
|
||||
|
||||
if (judgedObject is DrawableHit hit)
|
||||
nestedStrongHit = hit.NestedHitObjects.SingleOrDefault() as DrawableStrongNestedHit;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
public void Animate(DrawableHitObject drawableHitObject)
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
const double animation_time = 120;
|
||||
|
||||
(sprite as IFramedAnimation)?.GotoFrame(0);
|
||||
(strongSprite as IFramedAnimation)?.GotoFrame(0);
|
||||
|
||||
this.FadeInFromZero(animation_time).Then().FadeOut(animation_time * 1.5);
|
||||
|
||||
this.ScaleTo(0.6f)
|
||||
.Then().ScaleTo(1.1f, animation_time * 0.8)
|
||||
.Then().ScaleTo(0.9f, animation_time * 0.4)
|
||||
.Then().ScaleTo(1f, animation_time * 0.2);
|
||||
|
||||
Expire(true);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
public void AnimateSecondHit()
|
||||
{
|
||||
base.Update();
|
||||
if (strongSprite == null)
|
||||
return;
|
||||
|
||||
if (shouldSwitchToStrongSprite() && !switchedToStrongSprite)
|
||||
{
|
||||
sprite.FadeOut(50, Easing.OutQuint);
|
||||
strongSprite.FadeIn(50, Easing.OutQuint);
|
||||
switchedToStrongSprite = true;
|
||||
}
|
||||
}
|
||||
|
||||
private bool shouldSwitchToStrongSprite()
|
||||
{
|
||||
if (nestedStrongHit == null || strongSprite == null)
|
||||
return false;
|
||||
|
||||
return nestedStrongHit.IsHit;
|
||||
sprite.FadeOut(50, Easing.OutQuint);
|
||||
strongSprite.FadeIn(50, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Legacy
|
||||
throw new ArgumentOutOfRangeException(nameof(component), $"Invalid component type: {component}");
|
||||
}
|
||||
|
||||
public override Sample GetSample(ISampleInfo sampleInfo) => Source.GetSample(new LegacyTaikoSampleInfo(sampleInfo));
|
||||
public override ISample GetSample(ISampleInfo sampleInfo) => Source.GetSample(new LegacyTaikoSampleInfo(sampleInfo));
|
||||
|
||||
public override IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => Source.GetConfig<TLookup, TValue>(lookup);
|
||||
|
||||
|
@ -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 JetBrains.Annotations;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -13,19 +14,23 @@ using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
internal class DefaultHitExplosion : CircularContainer
|
||||
internal class DefaultHitExplosion : CircularContainer, IAnimatableHitExplosion
|
||||
{
|
||||
private readonly DrawableHitObject judgedObject;
|
||||
private readonly HitResult result;
|
||||
|
||||
public DefaultHitExplosion(DrawableHitObject judgedObject, HitResult result)
|
||||
[CanBeNull]
|
||||
private Box body;
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; }
|
||||
|
||||
public DefaultHitExplosion(HitResult result)
|
||||
{
|
||||
this.judgedObject = judgedObject;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
@ -40,26 +45,36 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
if (!result.IsHit())
|
||||
return;
|
||||
|
||||
bool isRim = (judgedObject.HitObject as Hit)?.Type == HitType.Rim;
|
||||
|
||||
InternalChildren = new[]
|
||||
{
|
||||
new Box
|
||||
body = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = isRim ? colours.BlueDarker : colours.PinkDarker,
|
||||
}
|
||||
};
|
||||
|
||||
updateColour();
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
private void updateColour([CanBeNull] DrawableHitObject judgedObject = null)
|
||||
{
|
||||
base.LoadComplete();
|
||||
if (body == null)
|
||||
return;
|
||||
|
||||
bool isRim = (judgedObject?.HitObject as Hit)?.Type == HitType.Rim;
|
||||
body.Colour = isRim ? colours.BlueDarker : colours.PinkDarker;
|
||||
}
|
||||
|
||||
public void Animate(DrawableHitObject drawableHitObject)
|
||||
{
|
||||
updateColour(drawableHitObject);
|
||||
|
||||
this.ScaleTo(3f, 1000, Easing.OutQuint);
|
||||
this.FadeOut(500);
|
||||
}
|
||||
|
||||
Expire(true);
|
||||
public void AnimateSecondHit()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,12 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using osuTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Pooling;
|
||||
using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.Taiko.Objects;
|
||||
@ -16,31 +18,37 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
/// <summary>
|
||||
/// A circle explodes from the hit target to indicate a hitobject has been hit.
|
||||
/// </summary>
|
||||
internal class HitExplosion : CircularContainer
|
||||
internal class HitExplosion : PoolableDrawable
|
||||
{
|
||||
public override bool RemoveWhenNotAlive => true;
|
||||
|
||||
[Cached(typeof(DrawableHitObject))]
|
||||
public readonly DrawableHitObject JudgedObject;
|
||||
public override bool RemoveCompletedTransforms => false;
|
||||
|
||||
private readonly HitResult result;
|
||||
|
||||
private double? secondHitTime;
|
||||
|
||||
[CanBeNull]
|
||||
public DrawableHitObject JudgedObject;
|
||||
|
||||
private SkinnableDrawable skinnable;
|
||||
|
||||
public override double LifetimeStart => skinnable.Drawable.LifetimeStart;
|
||||
|
||||
public override double LifetimeEnd => skinnable.Drawable.LifetimeEnd;
|
||||
|
||||
public HitExplosion(DrawableHitObject judgedObject, HitResult result)
|
||||
/// <summary>
|
||||
/// This constructor only exists to meet the <c>new()</c> type constraint of <see cref="DrawablePool{T}"/>.
|
||||
/// </summary>
|
||||
public HitExplosion()
|
||||
: this(HitResult.Great)
|
||||
{
|
||||
}
|
||||
|
||||
public HitExplosion(HitResult result)
|
||||
{
|
||||
JudgedObject = judgedObject;
|
||||
this.result = result;
|
||||
|
||||
Anchor = Anchor.Centre;
|
||||
Origin = Anchor.Centre;
|
||||
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
Size = new Vector2(TaikoHitObject.DEFAULT_SIZE);
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
RelativePositionAxes = Axes.Both;
|
||||
}
|
||||
@ -48,7 +56,47 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Child = skinnable = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(result)), _ => new DefaultHitExplosion(JudgedObject, result));
|
||||
InternalChild = skinnable = new SkinnableDrawable(new TaikoSkinComponent(getComponentName(result)), _ => new DefaultHitExplosion(result));
|
||||
skinnable.OnSkinChanged += runAnimation;
|
||||
}
|
||||
|
||||
public void Apply([CanBeNull] DrawableHitObject drawableHitObject)
|
||||
{
|
||||
JudgedObject = drawableHitObject;
|
||||
secondHitTime = null;
|
||||
}
|
||||
|
||||
protected override void PrepareForUse()
|
||||
{
|
||||
base.PrepareForUse();
|
||||
runAnimation();
|
||||
}
|
||||
|
||||
private void runAnimation()
|
||||
{
|
||||
if (JudgedObject?.Result == null)
|
||||
return;
|
||||
|
||||
double resultTime = JudgedObject.Result.TimeAbsolute;
|
||||
|
||||
LifetimeStart = resultTime;
|
||||
|
||||
ApplyTransformsAt(double.MinValue, true);
|
||||
ClearTransforms(true);
|
||||
|
||||
using (BeginAbsoluteSequence(resultTime))
|
||||
(skinnable.Drawable as IAnimatableHitExplosion)?.Animate(JudgedObject);
|
||||
|
||||
if (secondHitTime != null)
|
||||
{
|
||||
using (BeginAbsoluteSequence(secondHitTime.Value))
|
||||
{
|
||||
this.ResizeTo(new Vector2(TaikoStrongableHitObject.DEFAULT_STRONG_SIZE), 50);
|
||||
(skinnable.Drawable as IAnimatableHitExplosion)?.AnimateSecondHit();
|
||||
}
|
||||
}
|
||||
|
||||
LifetimeEnd = skinnable.Drawable.LatestTransformEndTime;
|
||||
}
|
||||
|
||||
private static TaikoSkinComponents getComponentName(HitResult result)
|
||||
@ -68,12 +116,10 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
throw new ArgumentOutOfRangeException(nameof(result), $"Invalid result type: {result}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Transforms this hit explosion to visualise a secondary hit.
|
||||
/// </summary>
|
||||
public void VisualiseSecondHit()
|
||||
public void VisualiseSecondHit(JudgementResult judgementResult)
|
||||
{
|
||||
this.ResizeTo(new Vector2(TaikoStrongableHitObject.DEFAULT_STRONG_SIZE), 50);
|
||||
secondHitTime = judgementResult.TimeAbsolute;
|
||||
runAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
24
osu.Game.Rulesets.Taiko/UI/HitExplosionPool.cs
Normal file
24
osu.Game.Rulesets.Taiko/UI/HitExplosionPool.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.Graphics.Pooling;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Pool for hit explosions of a specific type.
|
||||
/// </summary>
|
||||
internal class HitExplosionPool : DrawablePool<HitExplosion>
|
||||
{
|
||||
private readonly HitResult hitResult;
|
||||
|
||||
public HitExplosionPool(HitResult hitResult)
|
||||
: base(15)
|
||||
{
|
||||
this.hitResult = hitResult;
|
||||
}
|
||||
|
||||
protected override HitExplosion CreateNewDrawable() => new HitExplosion(hitResult);
|
||||
}
|
||||
}
|
23
osu.Game.Rulesets.Taiko/UI/IAnimatableHitExplosion.cs
Normal file
23
osu.Game.Rulesets.Taiko/UI/IAnimatableHitExplosion.cs
Normal file
@ -0,0 +1,23 @@
|
||||
// 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.Game.Rulesets.Objects.Drawables;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// A skinnable element of a hit explosion that supports playing an animation from the current point in time.
|
||||
/// </summary>
|
||||
public interface IAnimatableHitExplosion
|
||||
{
|
||||
/// <summary>
|
||||
/// Shows the hit explosion for the supplied <paramref name="drawableHitObject"/>.
|
||||
/// </summary>
|
||||
void Animate(DrawableHitObject drawableHitObject);
|
||||
|
||||
/// <summary>
|
||||
/// Transforms the hit explosion to visualise a secondary hit.
|
||||
/// </summary>
|
||||
void AnimateSecondHit();
|
||||
}
|
||||
}
|
@ -42,6 +42,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
private SkinnableDrawable mascot;
|
||||
|
||||
private readonly IDictionary<HitResult, DrawablePool<DrawableTaikoJudgement>> judgementPools = new Dictionary<HitResult, DrawablePool<DrawableTaikoJudgement>>();
|
||||
private readonly IDictionary<HitResult, HitExplosionPool> explosionPools = new Dictionary<HitResult, HitExplosionPool>();
|
||||
|
||||
private ProxyContainer topLevelHitContainer;
|
||||
private Container rightArea;
|
||||
@ -166,10 +167,15 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
RegisterPool<SwellTick, DrawableSwellTick>(100);
|
||||
|
||||
var hitWindows = new TaikoHitWindows();
|
||||
|
||||
foreach (var result in Enum.GetValues(typeof(HitResult)).OfType<HitResult>().Where(r => hitWindows.IsHitResultAllowed(r)))
|
||||
{
|
||||
judgementPools.Add(result, new DrawablePool<DrawableTaikoJudgement>(15));
|
||||
explosionPools.Add(result, new HitExplosionPool(result));
|
||||
}
|
||||
|
||||
AddRangeInternal(judgementPools.Values);
|
||||
AddRangeInternal(explosionPools.Values);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@ -281,7 +287,7 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
{
|
||||
case TaikoStrongJudgement _:
|
||||
if (result.IsHit)
|
||||
hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).ParentHitObject)?.VisualiseSecondHit();
|
||||
hitExplosionContainer.Children.FirstOrDefault(e => e.JudgedObject == ((DrawableStrongNestedHit)judgedObject).ParentHitObject)?.VisualiseSecondHit(result);
|
||||
break;
|
||||
|
||||
case TaikoDrumRollTickJudgement _:
|
||||
@ -315,7 +321,8 @@ namespace osu.Game.Rulesets.Taiko.UI
|
||||
|
||||
private void addExplosion(DrawableHitObject drawableObject, HitResult result, HitType type)
|
||||
{
|
||||
hitExplosionContainer.Add(new HitExplosion(drawableObject, result));
|
||||
hitExplosionContainer.Add(explosionPools[result]
|
||||
.Get(explosion => explosion.Apply(drawableObject)));
|
||||
if (drawableObject.HitObject.Kiai)
|
||||
kiaiExplosionContainer.Add(new KiaiHitExplosion(drawableObject, type));
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
|
||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
|
||||
|
||||
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup)
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
public void TestRetrieveTopLevelSample()
|
||||
{
|
||||
ISkin skin = null;
|
||||
Sample channel = null;
|
||||
ISample channel = null;
|
||||
|
||||
AddStep("create skin", () => skin = new TestSkin("test-sample", this));
|
||||
AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("test-sample")));
|
||||
@ -48,7 +48,7 @@ namespace osu.Game.Tests.Gameplay
|
||||
public void TestRetrieveSampleInSubFolder()
|
||||
{
|
||||
ISkin skin = null;
|
||||
Sample channel = null;
|
||||
ISample channel = null;
|
||||
|
||||
AddStep("create skin", () => skin = new TestSkin("folder/test-sample", this));
|
||||
AddStep("retrieve sample", () => channel = skin.GetSample(new SampleInfo("folder/test-sample")));
|
||||
|
@ -88,7 +88,7 @@ namespace osu.Game.Tests.Input
|
||||
=> AddStep($"make window {mode}", () => frameworkConfigManager.GetBindable<WindowMode>(FrameworkSetting.WindowMode).Value = mode);
|
||||
|
||||
private void setGameSideModeTo(OsuConfineMouseMode mode)
|
||||
=> AddStep($"set {mode} game-side", () => Game.LocalConfig.Set(OsuSetting.ConfineMouseMode, mode));
|
||||
=> AddStep($"set {mode} game-side", () => Game.LocalConfig.SetValue(OsuSetting.ConfineMouseMode, mode));
|
||||
|
||||
private void setLocalUserPlayingTo(bool playing)
|
||||
=> AddStep($"local user {(playing ? "playing" : "not playing")}", () => Game.LocalUserPlaying.Value = playing);
|
||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
using (var host = new CustomTestHeadlessGameHost())
|
||||
{
|
||||
using (var storageConfig = new StorageConfigManager(host.InitialStorage))
|
||||
storageConfig.Set(StorageConfig.FullPath, customPath);
|
||||
storageConfig.SetValue(StorageConfig.FullPath, customPath);
|
||||
|
||||
try
|
||||
{
|
||||
@ -73,7 +73,7 @@ namespace osu.Game.Tests.NonVisual
|
||||
using (var host = new CustomTestHeadlessGameHost())
|
||||
{
|
||||
using (var storageConfig = new StorageConfigManager(host.InitialStorage))
|
||||
storageConfig.Set(StorageConfig.FullPath, customPath);
|
||||
storageConfig.SetValue(StorageConfig.FullPath, customPath);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ namespace osu.Game.Tests.NonVisual.Skinning
|
||||
}
|
||||
|
||||
public Drawable GetDrawableComponent(ISkinComponent component) => throw new NotSupportedException();
|
||||
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException();
|
||||
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotSupportedException();
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotSupportedException();
|
||||
}
|
||||
|
||||
|
@ -23,8 +23,10 @@ namespace osu.Game.Tests.Online
|
||||
{
|
||||
case CommentVoteRequest cRequest:
|
||||
cRequest.TriggerSuccess(new CommentBundle());
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
CommentVoteRequest request = null;
|
||||
@ -108,8 +110,10 @@ namespace osu.Game.Tests.Online
|
||||
{
|
||||
case LeaveChannelRequest cRequest:
|
||||
cRequest.TriggerSuccess();
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
2
osu.Game.Tests/Resources/skin-with-space.ini
Normal file
2
osu.Game.Tests/Resources/skin-with-space.ini
Normal file
@ -0,0 +1,2 @@
|
||||
[General]
|
||||
Version: 2
|
@ -91,6 +91,15 @@ namespace osu.Game.Tests.Skins
|
||||
Assert.AreEqual(2.0m, decoder.Decode(stream).LegacyVersion);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStripWhitespace()
|
||||
{
|
||||
var decoder = new LegacySkinDecoder();
|
||||
using (var resStream = TestResources.OpenResource("skin-with-space.ini"))
|
||||
using (var stream = new LineBufferedReader(resStream))
|
||||
Assert.AreEqual(2.0m, decoder.Decode(stream).LegacyVersion);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDecodeLatestVersion()
|
||||
{
|
||||
|
@ -219,7 +219,7 @@ namespace osu.Game.Tests.Skins
|
||||
|
||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => skin.GetTexture(componentName, wrapModeS, wrapModeT);
|
||||
|
||||
public Sample GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo);
|
||||
public ISample GetSample(ISampleInfo sampleInfo) => skin.GetSample(sampleInfo);
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => skin.GetConfig<TLookup, TValue>(lookup);
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ namespace osu.Game.Tests.Visual.Background
|
||||
public void SetUp() => Schedule(() =>
|
||||
{
|
||||
// reset API response in statics to avoid test crosstalk.
|
||||
statics.Set<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
|
||||
statics.SetValue<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
|
||||
textureStore.PerformedLookups.Clear();
|
||||
dummyAPI.SetState(APIState.Online);
|
||||
|
||||
@ -135,18 +135,20 @@ namespace osu.Game.Tests.Visual.Background
|
||||
dummyAPI.HandleRequest = request =>
|
||||
{
|
||||
if (dummyAPI.State.Value != APIState.Online || !(request is GetSeasonalBackgroundsRequest backgroundsRequest))
|
||||
return;
|
||||
return false;
|
||||
|
||||
backgroundsRequest.TriggerSuccess(new APISeasonalBackgrounds
|
||||
{
|
||||
Backgrounds = seasonal_background_urls.Select(url => new APISeasonalBackground { Url = url }).ToList(),
|
||||
EndDate = endDate
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
});
|
||||
|
||||
private void setSeasonalBackgroundMode(SeasonalBackgroundMode mode)
|
||||
=> AddStep($"set seasonal mode to {mode}", () => config.Set(OsuSetting.SeasonalBackgroundMode, mode));
|
||||
=> AddStep($"set seasonal mode to {mode}", () => config.SetValue(OsuSetting.SeasonalBackgroundMode, mode));
|
||||
|
||||
private void createLoader()
|
||||
=> AddStep("create loader", () =>
|
||||
|
70
osu.Game.Tests/Visual/Editing/TestSceneBlueprintSelection.cs
Normal file
70
osu.Game.Tests/Visual/Editing/TestSceneBlueprintSelection.cs
Normal file
@ -0,0 +1,70 @@
|
||||
// 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.Beatmaps;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Screens.Edit.Compose.Components;
|
||||
using osu.Game.Tests.Beatmaps;
|
||||
using osuTK;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editing
|
||||
{
|
||||
public class TestSceneBlueprintSelection : EditorTestScene
|
||||
{
|
||||
protected override Ruleset CreateEditorRuleset() => new OsuRuleset();
|
||||
|
||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
|
||||
|
||||
private BlueprintContainer blueprintContainer
|
||||
=> Editor.ChildrenOfType<BlueprintContainer>().First();
|
||||
|
||||
[Test]
|
||||
public void TestSelectedObjectHasPriorityWhenOverlapping()
|
||||
{
|
||||
var firstSlider = new Slider
|
||||
{
|
||||
Path = new SliderPath(new[]
|
||||
{
|
||||
new PathControlPoint(new Vector2()),
|
||||
new PathControlPoint(new Vector2(150, -50)),
|
||||
new PathControlPoint(new Vector2(300, 0))
|
||||
}),
|
||||
Position = new Vector2(0, 100)
|
||||
};
|
||||
var secondSlider = new Slider
|
||||
{
|
||||
Path = new SliderPath(new[]
|
||||
{
|
||||
new PathControlPoint(new Vector2()),
|
||||
new PathControlPoint(new Vector2(-50, 50)),
|
||||
new PathControlPoint(new Vector2(-100, 100))
|
||||
}),
|
||||
Position = new Vector2(200, 0)
|
||||
};
|
||||
|
||||
AddStep("add overlapping sliders", () =>
|
||||
{
|
||||
EditorBeatmap.Add(firstSlider);
|
||||
EditorBeatmap.Add(secondSlider);
|
||||
});
|
||||
AddStep("select first slider", () => EditorBeatmap.SelectedHitObjects.Add(firstSlider));
|
||||
|
||||
AddStep("move mouse to common point", () =>
|
||||
{
|
||||
var pos = blueprintContainer.ChildrenOfType<PathControlPointPiece>().ElementAt(1).ScreenSpaceDrawQuad.Centre;
|
||||
InputManager.MoveMouseTo(pos);
|
||||
});
|
||||
AddStep("right click", () => InputManager.Click(MouseButton.Right));
|
||||
|
||||
AddAssert("selection is unchanged", () => EditorBeatmap.SelectedHitObjects.Single() == firstSlider);
|
||||
}
|
||||
}
|
||||
}
|
81
osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs
Normal file
81
osu.Game.Tests/Visual/Editing/TestSceneEditorClock.cs
Normal file
@ -0,0 +1,81 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osu.Game.Screens.Edit.Components;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Editing
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneEditorClock : EditorClockTestScene
|
||||
{
|
||||
public TestSceneEditorClock()
|
||||
{
|
||||
Add(new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new TimeInfoContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(200, 100)
|
||||
},
|
||||
new PlaybackControl
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(200, 100)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||
// ensure that music controller does not change this beatmap due to it
|
||||
// completing naturally as part of the test.
|
||||
Beatmap.Disabled = true;
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestStopAtTrackEnd()
|
||||
{
|
||||
AddStep("reset clock", () => Clock.Seek(0));
|
||||
|
||||
AddStep("start clock", Clock.Start);
|
||||
AddAssert("clock running", () => Clock.IsRunning);
|
||||
|
||||
AddStep("seek near end", () => Clock.Seek(Clock.TrackLength - 250));
|
||||
AddUntilStep("clock stops", () => !Clock.IsRunning);
|
||||
|
||||
AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength);
|
||||
|
||||
AddStep("start clock again", Clock.Start);
|
||||
AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWrapWhenStoppedAtTrackEnd()
|
||||
{
|
||||
AddStep("reset clock", () => Clock.Seek(0));
|
||||
|
||||
AddStep("stop clock", Clock.Stop);
|
||||
AddAssert("clock stopped", () => !Clock.IsRunning);
|
||||
|
||||
AddStep("seek exactly to end", () => Clock.Seek(Clock.TrackLength));
|
||||
AddAssert("clock stopped at end", () => Clock.CurrentTime == Clock.TrackLength);
|
||||
|
||||
AddStep("start clock again", Clock.Start);
|
||||
AddAssert("clock looped to start", () => Clock.IsRunning && Clock.CurrentTime < 500);
|
||||
}
|
||||
}
|
||||
}
|
@ -110,8 +110,6 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
[Resolved]
|
||||
private EditorClock editorClock { get; set; }
|
||||
|
||||
private bool started;
|
||||
|
||||
public StartStopButton()
|
||||
{
|
||||
BackgroundColour = Color4.SlateGray;
|
||||
@ -123,18 +121,17 @@ namespace osu.Game.Tests.Visual.Editing
|
||||
|
||||
private void onClick()
|
||||
{
|
||||
if (started)
|
||||
{
|
||||
if (editorClock.IsRunning)
|
||||
editorClock.Stop();
|
||||
Text = "Start";
|
||||
}
|
||||
else
|
||||
{
|
||||
editorClock.Start();
|
||||
Text = "Stop";
|
||||
}
|
||||
}
|
||||
|
||||
started = !started;
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Text = editorClock.IsRunning ? "Stop" : "Start";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
});
|
||||
|
||||
AddStep("show health", () => showHealth.Value = true);
|
||||
AddStep("enable layer", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, true));
|
||||
AddStep("enable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
|
||||
AddUntilStep("layer is visible", () => layer.IsPresent);
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[Test]
|
||||
public void TestLayerDisabledViaConfig()
|
||||
{
|
||||
AddStep("disable layer", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, false));
|
||||
AddStep("disable layer", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, false));
|
||||
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
||||
AddUntilStep("layer is not visible", () => !layer.IsPresent);
|
||||
}
|
||||
@ -81,19 +81,19 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("set health to 0.10", () => layer.Current.Value = 0.1);
|
||||
|
||||
AddStep("don't show health", () => showHealth.Value = false);
|
||||
AddStep("disable FadePlayfieldWhenHealthLow", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, false));
|
||||
AddStep("disable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, false));
|
||||
AddUntilStep("layer fade is invisible", () => !layer.IsPresent);
|
||||
|
||||
AddStep("don't show health", () => showHealth.Value = false);
|
||||
AddStep("enable FadePlayfieldWhenHealthLow", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, true));
|
||||
AddStep("enable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
|
||||
AddUntilStep("layer fade is invisible", () => !layer.IsPresent);
|
||||
|
||||
AddStep("show health", () => showHealth.Value = true);
|
||||
AddStep("disable FadePlayfieldWhenHealthLow", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, false));
|
||||
AddStep("disable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, false));
|
||||
AddUntilStep("layer fade is invisible", () => !layer.IsPresent);
|
||||
|
||||
AddStep("show health", () => showHealth.Value = true);
|
||||
AddStep("enable FadePlayfieldWhenHealthLow", () => config.Set(OsuSetting.FadePlayfieldWhenHealthLow, true));
|
||||
AddStep("enable FadePlayfieldWhenHealthLow", () => config.SetValue(OsuSetting.FadePlayfieldWhenHealthLow, true));
|
||||
AddUntilStep("layer fade is visible", () => layer.IsPresent);
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
AddStep("get original config value", () => originalConfigValue = config.Get<HUDVisibilityMode>(OsuSetting.HUDVisibilityMode));
|
||||
|
||||
AddStep("set hud to never show", () => config.Set(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
|
||||
AddStep("set hud to never show", () => config.SetValue(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Never));
|
||||
|
||||
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
|
||||
|
||||
@ -91,7 +91,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("stop trigering", () => InputManager.ReleaseKey(Key.ControlLeft));
|
||||
AddUntilStep("wait for fade", () => !hideTarget.IsPresent);
|
||||
|
||||
AddStep("set original config value", () => config.Set(OsuSetting.HUDVisibilityMode, originalConfigValue));
|
||||
AddStep("set original config value", () => config.SetValue(OsuSetting.HUDVisibilityMode, originalConfigValue));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -120,7 +120,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
AddStep("set keycounter visible false", () =>
|
||||
{
|
||||
config.Set<bool>(OsuSetting.KeyOverlay, false);
|
||||
config.SetValue(OsuSetting.KeyOverlay, false);
|
||||
hudOverlay.KeyCounter.AlwaysVisible.Value = false;
|
||||
});
|
||||
|
||||
@ -132,7 +132,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddUntilStep("hidetarget is visible", () => hideTarget.IsPresent);
|
||||
AddAssert("key counters still hidden", () => !keyCounterFlow.IsPresent);
|
||||
|
||||
AddStep("return value", () => config.Set<bool>(OsuSetting.KeyOverlay, keyCounterVisibleValue));
|
||||
AddStep("return value", () => config.SetValue(OsuSetting.KeyOverlay, keyCounterVisibleValue));
|
||||
}
|
||||
|
||||
private void createNew(Action<HUDOverlay> action = null)
|
||||
|
@ -298,7 +298,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
|
||||
|
||||
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
||||
}
|
||||
@ -309,7 +309,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
|
||||
|
||||
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
||||
}
|
||||
@ -321,7 +321,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => throw new NotImplementedException();
|
||||
|
||||
public Sample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
public ISample GetSample(ISampleInfo sampleInfo) => throw new NotImplementedException();
|
||||
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => throw new NotImplementedException();
|
||||
|
||||
|
@ -145,7 +145,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
public Drawable GetDrawableComponent(ISkinComponent component) => source?.GetDrawableComponent(component);
|
||||
public Texture GetTexture(string componentName, WrapMode wrapModeS, WrapMode wrapModeT) => source?.GetTexture(componentName, wrapModeS, wrapModeT);
|
||||
public Sample GetSample(ISampleInfo sampleInfo) => source?.GetSample(sampleInfo);
|
||||
public ISample GetSample(ISampleInfo sampleInfo) => source?.GetSample(sampleInfo);
|
||||
public IBindable<TValue> GetConfig<TLookup, TValue>(TLookup lookup) => source?.GetConfig<TLookup, TValue>(lookup);
|
||||
|
||||
public void TriggerSourceChanged()
|
||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
config.Set(OsuSetting.ShowStoryboard, true);
|
||||
config.SetValue(OsuSetting.ShowStoryboard, true);
|
||||
|
||||
storyboard = new Storyboard();
|
||||
var backgroundLayer = storyboard.GetLayer("Background");
|
||||
|
@ -5,7 +5,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Platform;
|
||||
@ -62,10 +61,6 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
|
||||
RecycleLocalStorage();
|
||||
|
||||
// see MouseSettings
|
||||
var frameworkConfig = host.Dependencies.Get<FrameworkConfigManager>();
|
||||
frameworkConfig.GetBindable<double>(FrameworkSetting.CursorSensitivity).Disabled = false;
|
||||
|
||||
CreateGame();
|
||||
});
|
||||
|
||||
@ -82,7 +77,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
|
||||
// todo: this can be removed once we can run audio tracks without a device present
|
||||
// see https://github.com/ppy/osu/issues/1302
|
||||
Game.LocalConfig.Set(OsuSetting.IntroSequence, IntroSequence.Circles);
|
||||
Game.LocalConfig.SetValue(OsuSetting.IntroSequence, IntroSequence.Circles);
|
||||
|
||||
Add(Game);
|
||||
}
|
||||
@ -136,7 +131,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
base.LoadComplete();
|
||||
API.Login("Rhythm Champion", "osu!");
|
||||
|
||||
Dependencies.Get<SessionStatics>().Set(Static.MutedAudioNotificationShownOnce, true);
|
||||
Dependencies.Get<SessionStatics>().SetValue(Static.MutedAudioNotificationShownOnce, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
|
||||
using (var config = new OsuConfigManager(LocalStorage))
|
||||
{
|
||||
config.Set(OsuSetting.Version, "2020.101.0");
|
||||
config.Set(OsuSetting.DisplayStarsMaximum, 10.0);
|
||||
config.SetValue(OsuSetting.Version, "2020.101.0");
|
||||
config.SetValue(OsuSetting.DisplayStarsMaximum, 10.0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
AddAssert("config has migrated value", () => Precision.AlmostEquals(Game.LocalConfig.Get<double>(OsuSetting.DisplayStarsMaximum), 10.1));
|
||||
|
||||
AddStep("set value again", () => Game.LocalConfig.Set<double>(OsuSetting.DisplayStarsMaximum, 10));
|
||||
AddStep("set value again", () => Game.LocalConfig.SetValue(OsuSetting.DisplayStarsMaximum, 10.0));
|
||||
|
||||
AddStep("force save config", () => Game.LocalConfig.Save());
|
||||
|
||||
|
@ -30,13 +30,14 @@ namespace osu.Game.Tests.Visual.Online
|
||||
|
||||
((DummyAPIAccess)API).HandleRequest = req =>
|
||||
{
|
||||
if (req is SearchBeatmapSetsRequest searchBeatmapSetsRequest)
|
||||
if (!(req is SearchBeatmapSetsRequest searchBeatmapSetsRequest)) return false;
|
||||
|
||||
searchBeatmapSetsRequest.TriggerSuccess(new SearchBeatmapSetsResponse
|
||||
{
|
||||
searchBeatmapSetsRequest.TriggerSuccess(new SearchBeatmapSetsResponse
|
||||
{
|
||||
BeatmapSets = setsForResponse,
|
||||
});
|
||||
}
|
||||
BeatmapSets = setsForResponse,
|
||||
});
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -63,13 +63,15 @@ namespace osu.Game.Tests.Visual.Online
|
||||
Builds = builds.Values.ToList()
|
||||
};
|
||||
changelogRequest.TriggerSuccess(changelogResponse);
|
||||
break;
|
||||
return true;
|
||||
|
||||
case GetChangelogBuildRequest buildRequest:
|
||||
if (requestedBuild != null)
|
||||
buildRequest.TriggerSuccess(requestedBuild);
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
Child = changelog = new TestChangelogOverlay();
|
||||
|
@ -11,6 +11,8 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Online.Chat;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Chat.Selection;
|
||||
@ -64,6 +66,24 @@ namespace osu.Game.Tests.Visual.Online
|
||||
});
|
||||
}
|
||||
|
||||
[SetUpSteps]
|
||||
public void SetUpSteps()
|
||||
{
|
||||
AddStep("register request handling", () =>
|
||||
{
|
||||
((DummyAPIAccess)API).HandleRequest = req =>
|
||||
{
|
||||
switch (req)
|
||||
{
|
||||
case JoinChannelRequest _:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestHideOverlay()
|
||||
{
|
||||
|
@ -85,9 +85,10 @@ namespace osu.Game.Tests.Visual.Online
|
||||
dummyAPI.HandleRequest = request =>
|
||||
{
|
||||
if (!(request is GetCommentsRequest getCommentsRequest))
|
||||
return;
|
||||
return false;
|
||||
|
||||
getCommentsRequest.TriggerSuccess(commentBundle);
|
||||
return true;
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -33,9 +33,10 @@ namespace osu.Game.Tests.Visual.Online
|
||||
dummyAPI.HandleRequest = request =>
|
||||
{
|
||||
if (!(request is GetNewsRequest getNewsRequest))
|
||||
return;
|
||||
return false;
|
||||
|
||||
getNewsRequest.TriggerSuccess(r);
|
||||
return true;
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -170,6 +170,17 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
|
||||
private void bindHandler(bool delayed = false, ScoreInfo userScore = null, bool failRequests = false) => ((DummyAPIAccess)API).HandleRequest = request =>
|
||||
{
|
||||
// pre-check for requests we should be handling (as they are scheduled below).
|
||||
switch (request)
|
||||
{
|
||||
case ShowPlaylistUserScoreRequest _:
|
||||
case IndexPlaylistScoresRequest _:
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
requestComplete = false;
|
||||
|
||||
double delay = delayed ? 3000 : 0;
|
||||
@ -196,6 +207,8 @@ namespace osu.Game.Tests.Visual.Playlists
|
||||
break;
|
||||
}
|
||||
}, delay);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
private void triggerSuccess<T>(APIRequest<T> req, T result)
|
||||
|
@ -49,7 +49,7 @@ namespace osu.Game.Tests.Visual.Ranking
|
||||
}));
|
||||
|
||||
AddAssert("mapped by text not present", () =>
|
||||
this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Current.Value, "mapped", "by")));
|
||||
this.ChildrenOfType<OsuSpriteText>().All(spriteText => !containsAny(spriteText.Text.ToString(), "mapped", "by")));
|
||||
}
|
||||
|
||||
private void showPanel(ScoreInfo score) => Child = new ExpandedPanelMiddleContentContainer(score);
|
||||
|
73
osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs
Normal file
73
osu.Game.Tests/Visual/Settings/TestSceneTabletSettings.cs
Normal file
@ -0,0 +1,73 @@
|
||||
// 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 NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Handlers.Tablet;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Settings.Sections.Input;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Settings
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestSceneTabletSettings : OsuTestScene
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host)
|
||||
{
|
||||
var tabletHandler = new TestTabletHandler();
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
new TabletSettings(tabletHandler)
|
||||
{
|
||||
RelativeSizeAxes = Axes.None,
|
||||
Width = SettingsPanel.WIDTH,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
}
|
||||
});
|
||||
|
||||
AddStep("Test with wide tablet", () => tabletHandler.SetTabletSize(new Vector2(160, 100)));
|
||||
AddStep("Test with square tablet", () => tabletHandler.SetTabletSize(new Vector2(300, 300)));
|
||||
AddStep("Test with tall tablet", () => tabletHandler.SetTabletSize(new Vector2(100, 300)));
|
||||
AddStep("Test with very tall tablet", () => tabletHandler.SetTabletSize(new Vector2(100, 700)));
|
||||
AddStep("Test no tablet present", () => tabletHandler.SetTabletSize(Vector2.Zero));
|
||||
}
|
||||
|
||||
public class TestTabletHandler : ITabletHandler
|
||||
{
|
||||
public Bindable<Vector2> AreaOffset { get; } = new Bindable<Vector2>();
|
||||
public Bindable<Vector2> AreaSize { get; } = new Bindable<Vector2>();
|
||||
|
||||
public IBindable<TabletInfo> Tablet => tablet;
|
||||
|
||||
private readonly Bindable<TabletInfo> tablet = new Bindable<TabletInfo>();
|
||||
|
||||
public BindableBool Enabled { get; } = new BindableBool(true);
|
||||
|
||||
public void SetTabletSize(Vector2 size)
|
||||
{
|
||||
tablet.Value = size != Vector2.Zero ? new TabletInfo($"test tablet T-{RNG.Next(999):000}", size) : null;
|
||||
|
||||
AreaSize.Default = new Vector2(size.X, size.Y);
|
||||
|
||||
// if it's clear the user has not configured the area, take the full area from the tablet that was just found.
|
||||
if (AreaSize.Value == Vector2.Zero)
|
||||
AreaSize.SetDefault();
|
||||
|
||||
AreaOffset.Default = new Vector2(size.X / 2, size.Y / 2);
|
||||
|
||||
// likewise with the position, use the centre point if it has not been configured.
|
||||
// it's safe to assume no user would set their centre point to 0,0 for now.
|
||||
if (AreaOffset.Value == Vector2.Zero)
|
||||
AreaOffset.SetDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -32,8 +32,10 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
{
|
||||
case GetUserRequest userRequest:
|
||||
userRequest.TriggerSuccess(getUser(userRequest.Ruleset.ID));
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -207,14 +207,14 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
addRulesetImportStep(0);
|
||||
addRulesetImportStep(0);
|
||||
|
||||
AddStep("change convert setting", () => config.Set(OsuSetting.ShowConvertedBeatmaps, false));
|
||||
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
|
||||
|
||||
createSongSelect();
|
||||
|
||||
AddStep("push child screen", () => Stack.Push(new TestSceneOsuScreenStack.TestScreen("test child")));
|
||||
AddUntilStep("wait for not current", () => !songSelect.IsCurrentScreen());
|
||||
|
||||
AddStep("change convert setting", () => config.Set(OsuSetting.ShowConvertedBeatmaps, true));
|
||||
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true));
|
||||
|
||||
AddStep("return", () => songSelect.MakeCurrent());
|
||||
AddUntilStep("wait for current", () => songSelect.IsCurrentScreen());
|
||||
@ -297,13 +297,13 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddAssert("random map selected", () => songSelect.CurrentBeatmap != defaultBeatmap);
|
||||
|
||||
AddStep(@"Sort by Artist", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.Artist));
|
||||
AddStep(@"Sort by Title", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.Title));
|
||||
AddStep(@"Sort by Author", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.Author));
|
||||
AddStep(@"Sort by DateAdded", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.DateAdded));
|
||||
AddStep(@"Sort by BPM", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.BPM));
|
||||
AddStep(@"Sort by Length", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.Length));
|
||||
AddStep(@"Sort by Difficulty", () => config.Set(OsuSetting.SongSelectSortingMode, SortMode.Difficulty));
|
||||
AddStep(@"Sort by Artist", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Artist));
|
||||
AddStep(@"Sort by Title", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Title));
|
||||
AddStep(@"Sort by Author", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Author));
|
||||
AddStep(@"Sort by DateAdded", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.DateAdded));
|
||||
AddStep(@"Sort by BPM", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.BPM));
|
||||
AddStep(@"Sort by Length", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Length));
|
||||
AddStep(@"Sort by Difficulty", () => config.SetValue(OsuSetting.SongSelectSortingMode, SortMode.Difficulty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -470,7 +470,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
changeRuleset(0);
|
||||
|
||||
// used for filter check below
|
||||
AddStep("allow convert display", () => config.Set(OsuSetting.ShowConvertedBeatmaps, true));
|
||||
AddStep("allow convert display", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true));
|
||||
|
||||
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
|
||||
|
||||
@ -648,7 +648,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
{
|
||||
int changeCount = 0;
|
||||
|
||||
AddStep("change convert setting", () => config.Set(OsuSetting.ShowConvertedBeatmaps, false));
|
||||
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
|
||||
AddStep("bind beatmap changed", () =>
|
||||
{
|
||||
Beatmap.ValueChanged += onChange;
|
||||
@ -686,7 +686,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddAssert("selection changed only fired twice", () => changeCount == 2);
|
||||
|
||||
AddStep("unbind beatmap changed", () => Beatmap.ValueChanged -= onChange);
|
||||
AddStep("change convert setting", () => config.Set(OsuSetting.ShowConvertedBeatmaps, true));
|
||||
AddStep("change convert setting", () => config.SetValue(OsuSetting.ShowConvertedBeatmaps, true));
|
||||
|
||||
// ReSharper disable once AccessToModifiedClosure
|
||||
void onChange(ValueChangedEvent<WorkingBeatmap> valueChangedEvent) => changeCount++;
|
||||
|
@ -92,10 +92,10 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
[Test]
|
||||
public void TestExplicitConfig()
|
||||
{
|
||||
AddStep("configure explicit content to allowed", () => localConfig.Set(OsuSetting.ShowOnlineExplicitContent, true));
|
||||
AddStep("configure explicit content to allowed", () => localConfig.SetValue(OsuSetting.ShowOnlineExplicitContent, true));
|
||||
AddAssert("explicit control set to show", () => control.ExplicitContent.Value == SearchExplicit.Show);
|
||||
|
||||
AddStep("configure explicit content to disallowed", () => localConfig.Set(OsuSetting.ShowOnlineExplicitContent, false));
|
||||
AddStep("configure explicit content to disallowed", () => localConfig.SetValue(OsuSetting.ShowOnlineExplicitContent, false));
|
||||
AddAssert("explicit control set to hide", () => control.ExplicitContent.Value == SearchExplicit.Hide);
|
||||
}
|
||||
|
||||
|
@ -44,22 +44,22 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
|
||||
protected override void InitialiseDefaults()
|
||||
{
|
||||
Set(TestConfigSetting.ToggleSettingNoKeybind, false);
|
||||
Set(TestConfigSetting.EnumSettingNoKeybind, EnumSetting.Setting1);
|
||||
Set(TestConfigSetting.ToggleSettingWithKeybind, false);
|
||||
Set(TestConfigSetting.EnumSettingWithKeybind, EnumSetting.Setting1);
|
||||
SetDefault(TestConfigSetting.ToggleSettingNoKeybind, false);
|
||||
SetDefault(TestConfigSetting.EnumSettingNoKeybind, EnumSetting.Setting1);
|
||||
SetDefault(TestConfigSetting.ToggleSettingWithKeybind, false);
|
||||
SetDefault(TestConfigSetting.EnumSettingWithKeybind, EnumSetting.Setting1);
|
||||
|
||||
base.InitialiseDefaults();
|
||||
}
|
||||
|
||||
public void ToggleSetting(TestConfigSetting setting) => Set(setting, !Get<bool>(setting));
|
||||
public void ToggleSetting(TestConfigSetting setting) => SetValue(setting, !Get<bool>(setting));
|
||||
|
||||
public void IncrementEnumSetting(TestConfigSetting setting)
|
||||
{
|
||||
var nextValue = Get<EnumSetting>(setting) + 1;
|
||||
if (nextValue > EnumSetting.Setting4)
|
||||
nextValue = EnumSetting.Setting1;
|
||||
Set(setting, nextValue);
|
||||
SetValue(setting, nextValue);
|
||||
}
|
||||
|
||||
public override TrackedSettings CreateTrackedSettings() => new TrackedSettings
|
||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
|
||||
storage.DeleteDirectory(string.Empty);
|
||||
|
||||
using (var storageConfig = new TournamentStorageManager(storage))
|
||||
storageConfig.Set(StorageConfig.CurrentTournament, custom_tournament);
|
||||
storageConfig.SetValue(StorageConfig.CurrentTournament, custom_tournament);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -70,7 +70,7 @@ namespace osu.Game.Tournament.IO
|
||||
moveFileIfExists("drawings.ini", destination);
|
||||
|
||||
ChangeTargetStorage(newStorage);
|
||||
storageConfig.Set(StorageConfig.CurrentTournament, default_tournament);
|
||||
storageConfig.SetValue(StorageConfig.CurrentTournament, default_tournament);
|
||||
storageConfig.Save();
|
||||
}
|
||||
|
||||
|
@ -12,8 +12,8 @@ namespace osu.Game.Tournament.Screens.Drawings.Components
|
||||
|
||||
protected override void InitialiseDefaults()
|
||||
{
|
||||
Set(DrawingsConfig.Groups, 8, 1, 8);
|
||||
Set(DrawingsConfig.TeamsPerGroup, 8, 1, 8);
|
||||
SetDefault(DrawingsConfig.Groups, 8, 1, 8);
|
||||
SetDefault(DrawingsConfig.TeamsPerGroup, 8, 1, 8);
|
||||
}
|
||||
|
||||
public DrawingsConfigManager(Storage storage)
|
||||
|
@ -17,12 +17,12 @@ namespace osu.Game.Beatmaps
|
||||
public abstract class BeatmapConverter<T> : IBeatmapConverter
|
||||
where T : HitObject
|
||||
{
|
||||
private event Action<HitObject, IEnumerable<HitObject>> ObjectConverted;
|
||||
private event Action<HitObject, IEnumerable<HitObject>> objectConverted;
|
||||
|
||||
event Action<HitObject, IEnumerable<HitObject>> IBeatmapConverter.ObjectConverted
|
||||
{
|
||||
add => ObjectConverted += value;
|
||||
remove => ObjectConverted -= value;
|
||||
add => objectConverted += value;
|
||||
remove => objectConverted -= value;
|
||||
}
|
||||
|
||||
public IBeatmap Beatmap { get; }
|
||||
@ -92,10 +92,10 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
var converted = ConvertHitObject(obj, beatmap, cancellationToken);
|
||||
|
||||
if (ObjectConverted != null)
|
||||
if (objectConverted != null)
|
||||
{
|
||||
converted = converted.ToList();
|
||||
ObjectConverted.Invoke(obj, converted);
|
||||
objectConverted.Invoke(obj, converted);
|
||||
}
|
||||
|
||||
foreach (var c in converted)
|
||||
|
@ -113,8 +113,6 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
var metadata = new BeatmapMetadata
|
||||
{
|
||||
Artist = "artist",
|
||||
Title = "title",
|
||||
Author = user,
|
||||
};
|
||||
|
||||
@ -128,7 +126,6 @@ namespace osu.Game.Beatmaps
|
||||
BaseDifficulty = new BeatmapDifficulty(),
|
||||
Ruleset = ruleset,
|
||||
Metadata = metadata,
|
||||
Version = "difficulty"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Beatmaps.ControlPoints
|
||||
/// </summary>
|
||||
public readonly BindableDouble SpeedMultiplierBindable = new BindableDouble(1)
|
||||
{
|
||||
Precision = 0.1,
|
||||
Precision = 0.01,
|
||||
Default = 1,
|
||||
MinValue = 0.1,
|
||||
MaxValue = 10
|
||||
|
@ -67,16 +67,14 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
protected override void ParseLine(Beatmap beatmap, Section section, string line)
|
||||
{
|
||||
var strippedLine = StripComments(line);
|
||||
|
||||
switch (section)
|
||||
{
|
||||
case Section.General:
|
||||
handleGeneral(strippedLine);
|
||||
handleGeneral(line);
|
||||
return;
|
||||
|
||||
case Section.Editor:
|
||||
handleEditor(strippedLine);
|
||||
handleEditor(line);
|
||||
return;
|
||||
|
||||
case Section.Metadata:
|
||||
@ -84,19 +82,19 @@ namespace osu.Game.Beatmaps.Formats
|
||||
return;
|
||||
|
||||
case Section.Difficulty:
|
||||
handleDifficulty(strippedLine);
|
||||
handleDifficulty(line);
|
||||
return;
|
||||
|
||||
case Section.Events:
|
||||
handleEvent(strippedLine);
|
||||
handleEvent(line);
|
||||
return;
|
||||
|
||||
case Section.TimingPoints:
|
||||
handleTimingPoint(strippedLine);
|
||||
handleTimingPoint(line);
|
||||
return;
|
||||
|
||||
case Section.HitObjects:
|
||||
handleHitObject(strippedLine);
|
||||
handleHitObject(line);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -471,9 +471,6 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
private string toLegacyCustomSampleBank(HitSampleInfo hitSampleInfo)
|
||||
{
|
||||
if (hitSampleInfo == null)
|
||||
return "0";
|
||||
|
||||
if (hitSampleInfo is ConvertHitObjectParser.LegacyHitSampleInfo legacy)
|
||||
return legacy.CustomSampleBank.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
|
@ -36,6 +36,8 @@ namespace osu.Game.Beatmaps.Formats
|
||||
if (ShouldSkipLine(line))
|
||||
continue;
|
||||
|
||||
line = StripComments(line).TrimEnd();
|
||||
|
||||
if (line.StartsWith('[') && line.EndsWith(']'))
|
||||
{
|
||||
if (!Enum.TryParse(line[1..^1], out section))
|
||||
@ -71,8 +73,6 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
protected virtual void ParseLine(T output, Section section, string line)
|
||||
{
|
||||
line = StripComments(line);
|
||||
|
||||
switch (section)
|
||||
{
|
||||
case Section.Colours:
|
||||
|
@ -45,8 +45,6 @@ namespace osu.Game.Beatmaps.Formats
|
||||
|
||||
protected override void ParseLine(Storyboard storyboard, Section section, string line)
|
||||
{
|
||||
line = StripComments(line);
|
||||
|
||||
switch (section)
|
||||
{
|
||||
case Section.General:
|
||||
|
@ -24,126 +24,126 @@ namespace osu.Game.Configuration
|
||||
protected override void InitialiseDefaults()
|
||||
{
|
||||
// UI/selection defaults
|
||||
Set(OsuSetting.Ruleset, 0, 0, int.MaxValue);
|
||||
Set(OsuSetting.Skin, 0, -1, int.MaxValue);
|
||||
SetDefault(OsuSetting.Ruleset, 0, 0, int.MaxValue);
|
||||
SetDefault(OsuSetting.Skin, 0, -1, int.MaxValue);
|
||||
|
||||
Set(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details);
|
||||
Set(OsuSetting.BeatmapDetailModsFilter, false);
|
||||
SetDefault(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details);
|
||||
SetDefault(OsuSetting.BeatmapDetailModsFilter, false);
|
||||
|
||||
Set(OsuSetting.ShowConvertedBeatmaps, true);
|
||||
Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
|
||||
Set(OsuSetting.DisplayStarsMaximum, 10.1, 0, 10.1, 0.1);
|
||||
SetDefault(OsuSetting.ShowConvertedBeatmaps, true);
|
||||
SetDefault(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1);
|
||||
SetDefault(OsuSetting.DisplayStarsMaximum, 10.1, 0, 10.1, 0.1);
|
||||
|
||||
Set(OsuSetting.SongSelectGroupingMode, GroupMode.All);
|
||||
Set(OsuSetting.SongSelectSortingMode, SortMode.Title);
|
||||
SetDefault(OsuSetting.SongSelectGroupingMode, GroupMode.All);
|
||||
SetDefault(OsuSetting.SongSelectSortingMode, SortMode.Title);
|
||||
|
||||
Set(OsuSetting.RandomSelectAlgorithm, RandomSelectAlgorithm.RandomPermutation);
|
||||
SetDefault(OsuSetting.RandomSelectAlgorithm, RandomSelectAlgorithm.RandomPermutation);
|
||||
|
||||
Set(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2f, 1f);
|
||||
SetDefault(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2f, 1f);
|
||||
|
||||
// Online settings
|
||||
Set(OsuSetting.Username, string.Empty);
|
||||
Set(OsuSetting.Token, string.Empty);
|
||||
SetDefault(OsuSetting.Username, string.Empty);
|
||||
SetDefault(OsuSetting.Token, string.Empty);
|
||||
|
||||
Set(OsuSetting.AutomaticallyDownloadWhenSpectating, false);
|
||||
SetDefault(OsuSetting.AutomaticallyDownloadWhenSpectating, false);
|
||||
|
||||
Set(OsuSetting.SavePassword, false).ValueChanged += enabled =>
|
||||
SetDefault(OsuSetting.SavePassword, false).ValueChanged += enabled =>
|
||||
{
|
||||
if (enabled.NewValue) Set(OsuSetting.SaveUsername, true);
|
||||
if (enabled.NewValue) SetValue(OsuSetting.SaveUsername, true);
|
||||
};
|
||||
|
||||
Set(OsuSetting.SaveUsername, true).ValueChanged += enabled =>
|
||||
SetDefault(OsuSetting.SaveUsername, true).ValueChanged += enabled =>
|
||||
{
|
||||
if (!enabled.NewValue) Set(OsuSetting.SavePassword, false);
|
||||
if (!enabled.NewValue) SetValue(OsuSetting.SavePassword, false);
|
||||
};
|
||||
|
||||
Set(OsuSetting.ExternalLinkWarning, true);
|
||||
Set(OsuSetting.PreferNoVideo, false);
|
||||
SetDefault(OsuSetting.ExternalLinkWarning, true);
|
||||
SetDefault(OsuSetting.PreferNoVideo, false);
|
||||
|
||||
Set(OsuSetting.ShowOnlineExplicitContent, false);
|
||||
SetDefault(OsuSetting.ShowOnlineExplicitContent, false);
|
||||
|
||||
// Audio
|
||||
Set(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01);
|
||||
SetDefault(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01);
|
||||
|
||||
Set(OsuSetting.MenuVoice, true);
|
||||
Set(OsuSetting.MenuMusic, true);
|
||||
SetDefault(OsuSetting.MenuVoice, true);
|
||||
SetDefault(OsuSetting.MenuMusic, true);
|
||||
|
||||
Set(OsuSetting.AudioOffset, 0, -500.0, 500.0, 1);
|
||||
SetDefault(OsuSetting.AudioOffset, 0, -500.0, 500.0, 1);
|
||||
|
||||
// Input
|
||||
Set(OsuSetting.MenuCursorSize, 1.0f, 0.5f, 2f, 0.01f);
|
||||
Set(OsuSetting.GameplayCursorSize, 1.0f, 0.1f, 2f, 0.01f);
|
||||
Set(OsuSetting.AutoCursorSize, false);
|
||||
SetDefault(OsuSetting.MenuCursorSize, 1.0f, 0.5f, 2f, 0.01f);
|
||||
SetDefault(OsuSetting.GameplayCursorSize, 1.0f, 0.1f, 2f, 0.01f);
|
||||
SetDefault(OsuSetting.AutoCursorSize, false);
|
||||
|
||||
Set(OsuSetting.MouseDisableButtons, false);
|
||||
Set(OsuSetting.MouseDisableWheel, false);
|
||||
Set(OsuSetting.ConfineMouseMode, OsuConfineMouseMode.DuringGameplay);
|
||||
SetDefault(OsuSetting.MouseDisableButtons, false);
|
||||
SetDefault(OsuSetting.MouseDisableWheel, false);
|
||||
SetDefault(OsuSetting.ConfineMouseMode, OsuConfineMouseMode.DuringGameplay);
|
||||
|
||||
// Graphics
|
||||
Set(OsuSetting.ShowFpsDisplay, false);
|
||||
SetDefault(OsuSetting.ShowFpsDisplay, false);
|
||||
|
||||
Set(OsuSetting.ShowStoryboard, true);
|
||||
Set(OsuSetting.BeatmapSkins, true);
|
||||
Set(OsuSetting.BeatmapColours, true);
|
||||
Set(OsuSetting.BeatmapHitsounds, true);
|
||||
SetDefault(OsuSetting.ShowStoryboard, true);
|
||||
SetDefault(OsuSetting.BeatmapSkins, true);
|
||||
SetDefault(OsuSetting.BeatmapColours, true);
|
||||
SetDefault(OsuSetting.BeatmapHitsounds, true);
|
||||
|
||||
Set(OsuSetting.CursorRotation, true);
|
||||
SetDefault(OsuSetting.CursorRotation, true);
|
||||
|
||||
Set(OsuSetting.MenuParallax, true);
|
||||
SetDefault(OsuSetting.MenuParallax, true);
|
||||
|
||||
// Gameplay
|
||||
Set(OsuSetting.DimLevel, 0.8, 0, 1, 0.01);
|
||||
Set(OsuSetting.BlurLevel, 0, 0, 1, 0.01);
|
||||
Set(OsuSetting.LightenDuringBreaks, true);
|
||||
SetDefault(OsuSetting.DimLevel, 0.8, 0, 1, 0.01);
|
||||
SetDefault(OsuSetting.BlurLevel, 0, 0, 1, 0.01);
|
||||
SetDefault(OsuSetting.LightenDuringBreaks, true);
|
||||
|
||||
Set(OsuSetting.HitLighting, true);
|
||||
SetDefault(OsuSetting.HitLighting, true);
|
||||
|
||||
Set(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always);
|
||||
Set(OsuSetting.ShowProgressGraph, true);
|
||||
Set(OsuSetting.ShowHealthDisplayWhenCantFail, true);
|
||||
Set(OsuSetting.FadePlayfieldWhenHealthLow, true);
|
||||
Set(OsuSetting.KeyOverlay, false);
|
||||
Set(OsuSetting.PositionalHitSounds, true);
|
||||
Set(OsuSetting.AlwaysPlayFirstComboBreak, true);
|
||||
Set(OsuSetting.ScoreMeter, ScoreMeterType.HitErrorBoth);
|
||||
SetDefault(OsuSetting.HUDVisibilityMode, HUDVisibilityMode.Always);
|
||||
SetDefault(OsuSetting.ShowProgressGraph, true);
|
||||
SetDefault(OsuSetting.ShowHealthDisplayWhenCantFail, true);
|
||||
SetDefault(OsuSetting.FadePlayfieldWhenHealthLow, true);
|
||||
SetDefault(OsuSetting.KeyOverlay, false);
|
||||
SetDefault(OsuSetting.PositionalHitSounds, true);
|
||||
SetDefault(OsuSetting.AlwaysPlayFirstComboBreak, true);
|
||||
SetDefault(OsuSetting.ScoreMeter, ScoreMeterType.HitErrorBoth);
|
||||
|
||||
Set(OsuSetting.FloatingComments, false);
|
||||
SetDefault(OsuSetting.FloatingComments, false);
|
||||
|
||||
Set(OsuSetting.ScoreDisplayMode, ScoringMode.Standardised);
|
||||
SetDefault(OsuSetting.ScoreDisplayMode, ScoringMode.Standardised);
|
||||
|
||||
Set(OsuSetting.IncreaseFirstObjectVisibility, true);
|
||||
Set(OsuSetting.GameplayDisableWinKey, true);
|
||||
SetDefault(OsuSetting.IncreaseFirstObjectVisibility, true);
|
||||
SetDefault(OsuSetting.GameplayDisableWinKey, true);
|
||||
|
||||
// Update
|
||||
Set(OsuSetting.ReleaseStream, ReleaseStream.Lazer);
|
||||
SetDefault(OsuSetting.ReleaseStream, ReleaseStream.Lazer);
|
||||
|
||||
Set(OsuSetting.Version, string.Empty);
|
||||
SetDefault(OsuSetting.Version, string.Empty);
|
||||
|
||||
Set(OsuSetting.ScreenshotFormat, ScreenshotFormat.Jpg);
|
||||
Set(OsuSetting.ScreenshotCaptureMenuCursor, false);
|
||||
SetDefault(OsuSetting.ScreenshotFormat, ScreenshotFormat.Jpg);
|
||||
SetDefault(OsuSetting.ScreenshotCaptureMenuCursor, false);
|
||||
|
||||
Set(OsuSetting.SongSelectRightMouseScroll, false);
|
||||
SetDefault(OsuSetting.SongSelectRightMouseScroll, false);
|
||||
|
||||
Set(OsuSetting.Scaling, ScalingMode.Off);
|
||||
SetDefault(OsuSetting.Scaling, ScalingMode.Off);
|
||||
|
||||
Set(OsuSetting.ScalingSizeX, 0.8f, 0.2f, 1f);
|
||||
Set(OsuSetting.ScalingSizeY, 0.8f, 0.2f, 1f);
|
||||
SetDefault(OsuSetting.ScalingSizeX, 0.8f, 0.2f, 1f);
|
||||
SetDefault(OsuSetting.ScalingSizeY, 0.8f, 0.2f, 1f);
|
||||
|
||||
Set(OsuSetting.ScalingPositionX, 0.5f, 0f, 1f);
|
||||
Set(OsuSetting.ScalingPositionY, 0.5f, 0f, 1f);
|
||||
SetDefault(OsuSetting.ScalingPositionX, 0.5f, 0f, 1f);
|
||||
SetDefault(OsuSetting.ScalingPositionY, 0.5f, 0f, 1f);
|
||||
|
||||
Set(OsuSetting.UIScale, 1f, 0.8f, 1.6f, 0.01f);
|
||||
SetDefault(OsuSetting.UIScale, 1f, 0.8f, 1.6f, 0.01f);
|
||||
|
||||
Set(OsuSetting.UIHoldActivationDelay, 200f, 0f, 500f, 50f);
|
||||
SetDefault(OsuSetting.UIHoldActivationDelay, 200f, 0f, 500f, 50f);
|
||||
|
||||
Set(OsuSetting.IntroSequence, IntroSequence.Triangles);
|
||||
SetDefault(OsuSetting.IntroSequence, IntroSequence.Triangles);
|
||||
|
||||
Set(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin);
|
||||
Set(OsuSetting.SeasonalBackgroundMode, SeasonalBackgroundMode.Sometimes);
|
||||
SetDefault(OsuSetting.MenuBackgroundSource, BackgroundSource.Skin);
|
||||
SetDefault(OsuSetting.SeasonalBackgroundMode, SeasonalBackgroundMode.Sometimes);
|
||||
|
||||
Set(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full);
|
||||
SetDefault(OsuSetting.DiscordRichPresence, DiscordRichPresenceMode.Full);
|
||||
|
||||
Set(OsuSetting.EditorWaveformOpacity, 1f);
|
||||
SetDefault(OsuSetting.EditorWaveformOpacity, 1f);
|
||||
}
|
||||
|
||||
public OsuConfigManager(Storage storage)
|
||||
|
@ -14,10 +14,10 @@ namespace osu.Game.Configuration
|
||||
{
|
||||
protected override void InitialiseDefaults()
|
||||
{
|
||||
Set(Static.LoginOverlayDisplayed, false);
|
||||
Set(Static.MutedAudioNotificationShownOnce, false);
|
||||
Set(Static.LastHoverSoundPlaybackTime, (double?)null);
|
||||
Set<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
|
||||
SetDefault(Static.LoginOverlayDisplayed, false);
|
||||
SetDefault(Static.MutedAudioNotificationShownOnce, false);
|
||||
SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null);
|
||||
SetDefault<APISeasonalBackgrounds>(Static.SeasonalBackgrounds, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace osu.Game.Configuration
|
||||
{
|
||||
base.InitialiseDefaults();
|
||||
|
||||
Set(StorageConfig.FullPath, string.Empty);
|
||||
SetDefault(StorageConfig.FullPath, string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterfaceV2
|
||||
@ -53,6 +54,14 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
CornerRadius = CORNER_RADIUS,
|
||||
};
|
||||
|
||||
public override bool AcceptsFocus => true;
|
||||
|
||||
protected override void OnFocus(FocusEvent e)
|
||||
{
|
||||
base.OnFocus(e);
|
||||
GetContainingInputManager().ChangeFocus(Component);
|
||||
}
|
||||
|
||||
protected override OsuTextBox CreateComponent() => CreateTextBox().With(t =>
|
||||
{
|
||||
t.OnCommit += (sender, newText) => OnCommit?.Invoke(sender, newText);
|
||||
|
@ -58,7 +58,7 @@ namespace osu.Game.IO
|
||||
/// </summary>
|
||||
public void ResetCustomStoragePath()
|
||||
{
|
||||
storageConfig.Set(StorageConfig.FullPath, string.Empty);
|
||||
storageConfig.SetValue(StorageConfig.FullPath, string.Empty);
|
||||
storageConfig.Save();
|
||||
|
||||
ChangeTargetStorage(defaultStorage);
|
||||
@ -103,7 +103,7 @@ namespace osu.Game.IO
|
||||
public override void Migrate(Storage newStorage)
|
||||
{
|
||||
base.Migrate(newStorage);
|
||||
storageConfig.Set(StorageConfig.FullPath, newStorage.GetFullPath("."));
|
||||
storageConfig.SetValue(StorageConfig.FullPath, newStorage.GetFullPath("."));
|
||||
storageConfig.Save();
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +0,0 @@
|
||||
// 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 Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.IO.Serialization.Converters
|
||||
{
|
||||
/// <summary>
|
||||
/// A type of <see cref="JsonConverter"/> that serializes only the X and Y coordinates of a <see cref="Vector2"/>.
|
||||
/// </summary>
|
||||
public class Vector2Converter : JsonConverter<Vector2>
|
||||
{
|
||||
public override Vector2 ReadJson(JsonReader reader, Type objectType, Vector2 existingValue, bool hasExistingValue, JsonSerializer serializer)
|
||||
{
|
||||
var obj = JObject.Load(reader);
|
||||
return new Vector2((float)obj["x"], (float)obj["y"]);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, Vector2 value, JsonSerializer serializer)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
|
||||
writer.WritePropertyName("x");
|
||||
writer.WriteValue(value.X);
|
||||
writer.WritePropertyName("y");
|
||||
writer.WriteValue(value.Y);
|
||||
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
// 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 Newtonsoft.Json;
|
||||
using osu.Game.IO.Serialization.Converters;
|
||||
using osu.Framework.IO.Serialization;
|
||||
|
||||
namespace osu.Game.IO.Serialization
|
||||
{
|
||||
@ -28,7 +29,7 @@ namespace osu.Game.IO.Serialization
|
||||
Formatting = Formatting.Indented,
|
||||
ObjectCreationHandling = ObjectCreationHandling.Replace,
|
||||
DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate,
|
||||
Converters = new JsonConverter[] { new Vector2Converter() },
|
||||
Converters = new List<JsonConverter> { new Vector2Converter() },
|
||||
ContractResolver = new KeyContractResolver()
|
||||
};
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ namespace osu.Game.Online.API
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
private void onTokenChanged(ValueChangedEvent<OAuthToken> e) => config.Set(OsuSetting.Token, config.Get<bool>(OsuSetting.SavePassword) ? authentication.TokenString : string.Empty);
|
||||
private void onTokenChanged(ValueChangedEvent<OAuthToken> e) => config.SetValue(OsuSetting.Token, config.Get<bool>(OsuSetting.SavePassword) ? authentication.TokenString : string.Empty);
|
||||
|
||||
internal new void Schedule(Action action) => base.Schedule(action);
|
||||
|
||||
@ -134,7 +134,7 @@ namespace osu.Game.Online.API
|
||||
state.Value = APIState.Connecting;
|
||||
|
||||
// save the username at this point, if the user requested for it to be.
|
||||
config.Set(OsuSetting.Username, config.Get<bool>(OsuSetting.SaveUsername) ? ProvidedUsername : string.Empty);
|
||||
config.SetValue(OsuSetting.Username, config.Get<bool>(OsuSetting.SaveUsername) ? ProvidedUsername : string.Empty);
|
||||
|
||||
if (!authentication.HasValidAccessToken && !authentication.AuthenticateWithLogin(ProvidedUsername, password))
|
||||
{
|
||||
|
@ -131,8 +131,11 @@ namespace osu.Game.Online.API
|
||||
{
|
||||
}
|
||||
|
||||
private bool succeeded;
|
||||
|
||||
internal virtual void TriggerSuccess()
|
||||
{
|
||||
succeeded = true;
|
||||
Success?.Invoke();
|
||||
}
|
||||
|
||||
@ -145,10 +148,7 @@ namespace osu.Game.Online.API
|
||||
|
||||
public void Fail(Exception e)
|
||||
{
|
||||
if (WebRequest?.Completed == true)
|
||||
return;
|
||||
|
||||
if (cancelled)
|
||||
if (succeeded || cancelled)
|
||||
return;
|
||||
|
||||
cancelled = true;
|
||||
@ -181,9 +181,13 @@ namespace osu.Game.Online.API
|
||||
/// <returns>Whether we are in a failed or cancelled state.</returns>
|
||||
private bool checkAndScheduleFailure()
|
||||
{
|
||||
if (API == null || pendingFailure == null) return cancelled;
|
||||
if (pendingFailure == null) return cancelled;
|
||||
|
||||
if (API == null)
|
||||
pendingFailure();
|
||||
else
|
||||
API.Schedule(pendingFailure);
|
||||
|
||||
API.Schedule(pendingFailure);
|
||||
pendingFailure = null;
|
||||
return true;
|
||||
}
|
||||
|
@ -34,8 +34,9 @@ namespace osu.Game.Online.API
|
||||
|
||||
/// <summary>
|
||||
/// Provide handling logic for an arbitrary API request.
|
||||
/// Should return true is a request was handled. If null or false return, the request will be failed with a <see cref="NotSupportedException"/>.
|
||||
/// </summary>
|
||||
public Action<APIRequest> HandleRequest;
|
||||
public Func<APIRequest, bool> HandleRequest;
|
||||
|
||||
private readonly Bindable<APIState> state = new Bindable<APIState>(APIState.Online);
|
||||
|
||||
@ -55,7 +56,12 @@ namespace osu.Game.Online.API
|
||||
|
||||
public virtual void Queue(APIRequest request)
|
||||
{
|
||||
HandleRequest?.Invoke(request);
|
||||
if (HandleRequest?.Invoke(request) != true)
|
||||
{
|
||||
// this will fail due to not receiving an APIAccess, and trigger a failure on the request.
|
||||
// this is intended - any request in testing that needs non-failures should use HandleRequest.
|
||||
request.Perform(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void Perform(APIRequest request) => HandleRequest?.Invoke(request);
|
||||
|
@ -8,6 +8,6 @@ namespace osu.Game.Online.Rooms
|
||||
public class APIScoreToken
|
||||
{
|
||||
[JsonProperty("id")]
|
||||
public int ID { get; set; }
|
||||
public long ID { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -758,9 +758,15 @@ namespace osu.Game
|
||||
{
|
||||
otherOverlays.Where(o => o != overlay).ForEach(o => o.Hide());
|
||||
|
||||
// show above others if not visible at all, else leave at current depth.
|
||||
if (!overlay.IsPresent)
|
||||
// Partially visible so leave it at the current depth.
|
||||
if (overlay.IsPresent)
|
||||
return;
|
||||
|
||||
// Show above all other overlays.
|
||||
if (overlay.IsLoaded)
|
||||
overlayContent.ChangeChildDepth(overlay, (float)-Clock.CurrentTime);
|
||||
else
|
||||
overlay.Depth = (float)-Clock.CurrentTime;
|
||||
}
|
||||
|
||||
private void forwardLoggedErrorsToNotifications()
|
||||
@ -880,13 +886,13 @@ namespace osu.Game
|
||||
switch (action)
|
||||
{
|
||||
case GlobalAction.ResetInputSettings:
|
||||
frameworkConfig.GetBindable<string>(FrameworkSetting.IgnoredInputHandlers).SetDefault();
|
||||
frameworkConfig.GetBindable<double>(FrameworkSetting.CursorSensitivity).SetDefault();
|
||||
Host.ResetInputHandlers();
|
||||
frameworkConfig.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode).SetDefault();
|
||||
return true;
|
||||
|
||||
case GlobalAction.ToggleGameplayMouseButtons:
|
||||
LocalConfig.Set(OsuSetting.MouseDisableButtons, !LocalConfig.Get<bool>(OsuSetting.MouseDisableButtons));
|
||||
var mouseDisableButtons = LocalConfig.GetBindable<bool>(OsuSetting.MouseDisableButtons);
|
||||
mouseDisableButtons.Value = !mouseDisableButtons.Value;
|
||||
return true;
|
||||
|
||||
case GlobalAction.RandomSkin:
|
||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Comments
|
||||
{
|
||||
new SpriteIcon
|
||||
{
|
||||
Icon = FontAwesome.Solid.Trash,
|
||||
Icon = FontAwesome.Regular.TrashAlt,
|
||||
Size = new Vector2(14),
|
||||
},
|
||||
countText = new OsuSpriteText
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Humanizer;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
@ -113,7 +114,12 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
}
|
||||
|
||||
topLinkContainer.AddText("Contributed ");
|
||||
topLinkContainer.AddLink($@"{user.PostCount:#,##0} forum posts", $"{api.WebsiteRootUrl}/users/{user.Id}/posts", creationParameters: embolden);
|
||||
topLinkContainer.AddLink("forum post".ToQuantity(user.PostCount, "#,##0"), $"{api.WebsiteRootUrl}/users/{user.Id}/posts", creationParameters: embolden);
|
||||
|
||||
addSpacer(topLinkContainer);
|
||||
|
||||
topLinkContainer.AddText("Posted ");
|
||||
topLinkContainer.AddLink("comment".ToQuantity(user.CommentsCount, "#,##0"), $"{api.WebsiteRootUrl}/comments?user_id={user.Id}", creationParameters: embolden);
|
||||
|
||||
string websiteWithoutProtocol = user.Website;
|
||||
|
||||
@ -138,7 +144,6 @@ namespace osu.Game.Overlays.Profile.Header
|
||||
if (!string.IsNullOrEmpty(user.Twitter))
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Twitter, "@" + user.Twitter, $@"https://twitter.com/{user.Twitter}");
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Discord, user.Discord);
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Brands.Skype, user.Skype, @"skype:" + user.Skype + @"?chat");
|
||||
anyInfoAdded |= tryAddInfo(FontAwesome.Solid.Link, websiteWithoutProtocol, user.Website);
|
||||
|
||||
// If no information was added to the bottomLinkContainer, hide it to avoid unwanted padding
|
||||
|
@ -23,51 +23,24 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu
|
||||
{
|
||||
this.user.BindTo(user);
|
||||
CountSection total;
|
||||
CountSection avaliable;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Masking = true;
|
||||
CornerRadius = 3;
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(5, 0),
|
||||
Children = new[]
|
||||
{
|
||||
total = new CountTotal(),
|
||||
avaliable = new CountAvailable()
|
||||
}
|
||||
}
|
||||
};
|
||||
this.user.ValueChanged += u =>
|
||||
{
|
||||
total.Count = u.NewValue?.Kudosu.Total ?? 0;
|
||||
avaliable.Count = u.NewValue?.Kudosu.Available ?? 0;
|
||||
};
|
||||
Child = total = new CountTotal();
|
||||
|
||||
this.user.ValueChanged += u => total.Count = u.NewValue?.Kudosu.Total ?? 0;
|
||||
}
|
||||
|
||||
protected override bool OnClick(ClickEvent e) => true;
|
||||
|
||||
private class CountAvailable : CountSection
|
||||
{
|
||||
public CountAvailable()
|
||||
: base("Kudosu Avaliable")
|
||||
{
|
||||
DescriptionText.Text = "Kudosu can be traded for kudosu stars, which will help your beatmap get more attention. This is the number of kudosu you haven't traded in yet.";
|
||||
}
|
||||
}
|
||||
|
||||
private class CountTotal : CountSection
|
||||
{
|
||||
public CountTotal()
|
||||
: base("Total Kudosu Earned")
|
||||
{
|
||||
DescriptionText.AddText("Based on how much of a contribution the user has made to beatmap moderation. See ");
|
||||
DescriptionText.AddLink("this link", "https://osu.ppy.sh/wiki/Kudosu");
|
||||
DescriptionText.AddLink("this page", "https://osu.ppy.sh/wiki/Kudosu");
|
||||
DescriptionText.AddText(" for more information.");
|
||||
}
|
||||
}
|
||||
@ -80,13 +53,12 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu
|
||||
|
||||
public new int Count
|
||||
{
|
||||
set => valueText.Text = value.ToString();
|
||||
set => valueText.Text = value.ToString("N0");
|
||||
}
|
||||
|
||||
public CountSection(string header)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Width = 0.5f;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Padding = new MarginPadding { Top = 10, Bottom = 20 };
|
||||
Child = new FillFlowContainer
|
||||
@ -131,7 +103,6 @@ namespace osu.Game.Overlays.Profile.Sections.Kudosu
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
lineBackground.Colour = colourProvider.Highlight1;
|
||||
DescriptionText.Colour = colourProvider.Foreground1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,17 +5,17 @@ using osu.Framework.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
public class KeyboardSettings : SettingsSubsection
|
||||
public class BindingSettings : SettingsSubsection
|
||||
{
|
||||
protected override string Header => "Keyboard";
|
||||
protected override string Header => "Shortcut and gameplay bindings";
|
||||
|
||||
public KeyboardSettings(KeyBindingPanel keyConfig)
|
||||
public BindingSettings(KeyBindingPanel keyConfig)
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsButton
|
||||
{
|
||||
Text = "Key configuration",
|
||||
Text = "Configure",
|
||||
TooltipText = "change global shortcut keys and gameplay bindings",
|
||||
Action = keyConfig.ToggleVisibility
|
||||
},
|
@ -1,11 +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 osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Handlers.Mouse;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Input;
|
||||
@ -14,46 +14,45 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
public class MouseSettings : SettingsSubsection
|
||||
{
|
||||
private readonly MouseHandler mouseHandler;
|
||||
|
||||
protected override string Header => "Mouse";
|
||||
|
||||
private readonly BindableBool rawInputToggle = new BindableBool();
|
||||
|
||||
private Bindable<double> configSensitivity;
|
||||
private Bindable<double> handlerSensitivity;
|
||||
|
||||
private Bindable<double> localSensitivity;
|
||||
|
||||
private Bindable<string> ignoredInputHandlers;
|
||||
|
||||
private Bindable<WindowMode> windowMode;
|
||||
private SettingsEnumDropdown<OsuConfineMouseMode> confineMouseModeSetting;
|
||||
private Bindable<bool> relativeMode;
|
||||
|
||||
public MouseSettings(MouseHandler mouseHandler)
|
||||
{
|
||||
this.mouseHandler = mouseHandler;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager osuConfig, FrameworkConfigManager config)
|
||||
{
|
||||
// use local bindable to avoid changing enabled state of game host's bindable.
|
||||
configSensitivity = config.GetBindable<double>(FrameworkSetting.CursorSensitivity);
|
||||
localSensitivity = configSensitivity.GetUnboundCopy();
|
||||
handlerSensitivity = mouseHandler.Sensitivity.GetBoundCopy();
|
||||
localSensitivity = handlerSensitivity.GetUnboundCopy();
|
||||
|
||||
relativeMode = mouseHandler.UseRelativeMode.GetBoundCopy();
|
||||
windowMode = config.GetBindable<WindowMode>(FrameworkSetting.WindowMode);
|
||||
ignoredInputHandlers = config.GetBindable<string>(FrameworkSetting.IgnoredInputHandlers);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Raw input",
|
||||
Current = rawInputToggle
|
||||
LabelText = "High precision mouse",
|
||||
Current = relativeMode
|
||||
},
|
||||
new SensitivitySetting
|
||||
{
|
||||
LabelText = "Cursor sensitivity",
|
||||
Current = localSensitivity
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Map absolute input to window",
|
||||
Current = config.GetBindable<bool>(FrameworkSetting.MapAbsoluteInputToWindow)
|
||||
},
|
||||
confineMouseModeSetting = new SettingsEnumDropdown<OsuConfineMouseMode>
|
||||
{
|
||||
LabelText = "Confine mouse cursor to window",
|
||||
@ -76,7 +75,9 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
configSensitivity.BindValueChanged(val =>
|
||||
relativeMode.BindValueChanged(relative => localSensitivity.Disabled = !relative.NewValue, true);
|
||||
|
||||
handlerSensitivity.BindValueChanged(val =>
|
||||
{
|
||||
var disabled = localSensitivity.Disabled;
|
||||
|
||||
@ -85,7 +86,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
localSensitivity.Disabled = disabled;
|
||||
}, true);
|
||||
|
||||
localSensitivity.BindValueChanged(val => configSensitivity.Value = val.NewValue);
|
||||
localSensitivity.BindValueChanged(val => handlerSensitivity.Value = val.NewValue);
|
||||
|
||||
windowMode.BindValueChanged(mode =>
|
||||
{
|
||||
@ -102,32 +103,6 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
confineMouseModeSetting.TooltipText = string.Empty;
|
||||
}
|
||||
}, true);
|
||||
|
||||
if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows)
|
||||
{
|
||||
rawInputToggle.Disabled = true;
|
||||
localSensitivity.Disabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
rawInputToggle.ValueChanged += enabled =>
|
||||
{
|
||||
// this is temporary until we support per-handler settings.
|
||||
const string raw_mouse_handler = @"OsuTKRawMouseHandler";
|
||||
const string standard_mouse_handlers = @"OsuTKMouseHandler MouseHandler";
|
||||
|
||||
ignoredInputHandlers.Value = enabled.NewValue ? standard_mouse_handlers : raw_mouse_handler;
|
||||
};
|
||||
|
||||
ignoredInputHandlers.ValueChanged += handler =>
|
||||
{
|
||||
bool raw = !handler.NewValue.Contains("Raw");
|
||||
rawInputToggle.Value = raw;
|
||||
localSensitivity.Disabled = !raw;
|
||||
};
|
||||
|
||||
ignoredInputHandlers.TriggerChange();
|
||||
}
|
||||
}
|
||||
|
||||
private class SensitivitySetting : SettingsSlider<double, SensitivitySlider>
|
||||
@ -141,7 +116,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
|
||||
private class SensitivitySlider : OsuSliderBar<double>
|
||||
{
|
||||
public override string TooltipText => Current.Disabled ? "enable raw input to adjust sensitivity" : $"{base.TooltipText}x";
|
||||
public override string TooltipText => Current.Disabled ? "enable high precision mouse to adjust sensitivity" : $"{base.TooltipText}x";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
185
osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs
Normal file
185
osu.Game/Overlays/Settings/Sections/Input/TabletAreaSelection.cs
Normal file
@ -0,0 +1,185 @@
|
||||
// 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 osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Handlers.Tablet;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
public class TabletAreaSelection : CompositeDrawable
|
||||
{
|
||||
private readonly ITabletHandler handler;
|
||||
|
||||
private Container tabletContainer;
|
||||
private Container usableAreaContainer;
|
||||
|
||||
private readonly Bindable<Vector2> areaOffset = new Bindable<Vector2>();
|
||||
private readonly Bindable<Vector2> areaSize = new Bindable<Vector2>();
|
||||
|
||||
private readonly IBindable<TabletInfo> tablet = new Bindable<TabletInfo>();
|
||||
|
||||
private OsuSpriteText tabletName;
|
||||
|
||||
private Box usableFill;
|
||||
private OsuSpriteText usableAreaText;
|
||||
|
||||
public TabletAreaSelection(ITabletHandler handler)
|
||||
{
|
||||
this.handler = handler;
|
||||
|
||||
Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS };
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChild = tabletContainer = new Container
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Masking = true,
|
||||
CornerRadius = 5,
|
||||
BorderThickness = 2,
|
||||
BorderColour = colour.Gray3,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = colour.Gray1,
|
||||
},
|
||||
usableAreaContainer = new Container
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
usableFill = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0.6f,
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.White,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Height = 5,
|
||||
},
|
||||
new Box
|
||||
{
|
||||
Colour = Color4.White,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Width = 5,
|
||||
},
|
||||
usableAreaText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Colour = Color4.White,
|
||||
Font = OsuFont.Default.With(size: 12),
|
||||
Y = 10
|
||||
}
|
||||
}
|
||||
},
|
||||
tabletName = new OsuSpriteText
|
||||
{
|
||||
Padding = new MarginPadding(3),
|
||||
Font = OsuFont.Default.With(size: 8)
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
areaOffset.BindTo(handler.AreaOffset);
|
||||
areaOffset.BindValueChanged(val =>
|
||||
{
|
||||
usableAreaContainer.MoveTo(val.NewValue, 100, Easing.OutQuint)
|
||||
.OnComplete(_ => checkBounds()); // required as we are using SSDQ.
|
||||
}, true);
|
||||
|
||||
areaSize.BindTo(handler.AreaSize);
|
||||
areaSize.BindValueChanged(val =>
|
||||
{
|
||||
usableAreaContainer.ResizeTo(val.NewValue, 100, Easing.OutQuint)
|
||||
.OnComplete(_ => checkBounds()); // required as we are using SSDQ.
|
||||
|
||||
int x = (int)val.NewValue.X;
|
||||
int y = (int)val.NewValue.Y;
|
||||
int commonDivider = greatestCommonDivider(x, y);
|
||||
|
||||
usableAreaText.Text = $"{(float)x / commonDivider}:{(float)y / commonDivider}";
|
||||
}, true);
|
||||
|
||||
tablet.BindTo(handler.Tablet);
|
||||
tablet.BindValueChanged(_ => Scheduler.AddOnce(updateTabletDetails));
|
||||
|
||||
updateTabletDetails();
|
||||
// initial animation should be instant.
|
||||
FinishTransforms(true);
|
||||
}
|
||||
|
||||
private void updateTabletDetails()
|
||||
{
|
||||
tabletContainer.Size = tablet.Value?.Size ?? Vector2.Zero;
|
||||
tabletName.Text = tablet.Value?.Name ?? string.Empty;
|
||||
checkBounds();
|
||||
}
|
||||
|
||||
private static int greatestCommonDivider(int a, int b)
|
||||
{
|
||||
while (b != 0)
|
||||
{
|
||||
int remainder = a % b;
|
||||
a = b;
|
||||
b = remainder;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colour { get; set; }
|
||||
|
||||
private void checkBounds()
|
||||
{
|
||||
if (tablet.Value == null)
|
||||
return;
|
||||
|
||||
var usableSsdq = usableAreaContainer.ScreenSpaceDrawQuad;
|
||||
|
||||
bool isWithinBounds = tabletContainer.ScreenSpaceDrawQuad.Contains(usableSsdq.TopLeft + new Vector2(1)) &&
|
||||
tabletContainer.ScreenSpaceDrawQuad.Contains(usableSsdq.BottomRight - new Vector2(1));
|
||||
|
||||
usableFill.FadeColour(isWithinBounds ? colour.Blue : colour.RedLight, 100);
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (!(tablet.Value?.Size is Vector2 size))
|
||||
return;
|
||||
|
||||
float fitX = size.X / (DrawWidth - Padding.Left - Padding.Right);
|
||||
float fitY = size.Y / DrawHeight;
|
||||
|
||||
float adjust = MathF.Max(fitX, fitY);
|
||||
|
||||
tabletContainer.Scale = new Vector2(1 / adjust);
|
||||
}
|
||||
}
|
||||
}
|
285
osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs
Normal file
285
osu.Game/Overlays/Settings/Sections/Input/TabletSettings.cs
Normal file
@ -0,0 +1,285 @@
|
||||
// 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.Graphics.Containers;
|
||||
using osu.Framework.Input.Handlers.Tablet;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
public class TabletSettings : SettingsSubsection
|
||||
{
|
||||
private readonly ITabletHandler tabletHandler;
|
||||
|
||||
private readonly Bindable<Vector2> areaOffset = new Bindable<Vector2>();
|
||||
private readonly Bindable<Vector2> areaSize = new Bindable<Vector2>();
|
||||
private readonly IBindable<TabletInfo> tablet = new Bindable<TabletInfo>();
|
||||
|
||||
private readonly BindableNumber<float> offsetX = new BindableNumber<float> { MinValue = 0 };
|
||||
private readonly BindableNumber<float> offsetY = new BindableNumber<float> { MinValue = 0 };
|
||||
|
||||
private readonly BindableNumber<float> sizeX = new BindableNumber<float> { MinValue = 10 };
|
||||
private readonly BindableNumber<float> sizeY = new BindableNumber<float> { MinValue = 10 };
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Based on ultrawide monitor configurations.
|
||||
/// </summary>
|
||||
private const float largest_feasible_aspect_ratio = 21f / 9;
|
||||
|
||||
private readonly BindableNumber<float> aspectRatio = new BindableFloat(1)
|
||||
{
|
||||
MinValue = 1 / largest_feasible_aspect_ratio,
|
||||
MaxValue = largest_feasible_aspect_ratio,
|
||||
Precision = 0.01f,
|
||||
};
|
||||
|
||||
private readonly BindableBool aspectLock = new BindableBool();
|
||||
|
||||
private ScheduledDelegate aspectRatioApplication;
|
||||
|
||||
private FillFlowContainer mainSettings;
|
||||
|
||||
private OsuSpriteText noTabletMessage;
|
||||
|
||||
protected override string Header => "Tablet";
|
||||
|
||||
public TabletSettings(ITabletHandler tabletHandler)
|
||||
{
|
||||
this.tabletHandler = tabletHandler;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Enabled",
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Current = tabletHandler.Enabled
|
||||
},
|
||||
noTabletMessage = new OsuSpriteText
|
||||
{
|
||||
Text = "No tablet detected!",
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS }
|
||||
},
|
||||
mainSettings = new FillFlowContainer
|
||||
{
|
||||
Alpha = 0,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(0, 8),
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new TabletAreaSelection(tabletHandler)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 300,
|
||||
},
|
||||
new DangerousSettingsButton
|
||||
{
|
||||
Text = "Reset to full area",
|
||||
Action = () =>
|
||||
{
|
||||
aspectLock.Value = false;
|
||||
|
||||
areaOffset.SetDefault();
|
||||
areaSize.SetDefault();
|
||||
},
|
||||
},
|
||||
new SettingsButton
|
||||
{
|
||||
Text = "Conform to current game aspect ratio",
|
||||
Action = () =>
|
||||
{
|
||||
forceAspectRatio((float)host.Window.ClientSize.Width / host.Window.ClientSize.Height);
|
||||
}
|
||||
},
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
TransferValueOnCommit = true,
|
||||
LabelText = "Aspect Ratio",
|
||||
Current = aspectRatio
|
||||
},
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
TransferValueOnCommit = true,
|
||||
LabelText = "X Offset",
|
||||
Current = offsetX
|
||||
},
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
TransferValueOnCommit = true,
|
||||
LabelText = "Y Offset",
|
||||
Current = offsetY
|
||||
},
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Lock aspect ratio",
|
||||
Current = aspectLock
|
||||
},
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
TransferValueOnCommit = true,
|
||||
LabelText = "Width",
|
||||
Current = sizeX
|
||||
},
|
||||
new SettingsSlider<float>
|
||||
{
|
||||
TransferValueOnCommit = true,
|
||||
LabelText = "Height",
|
||||
Current = sizeY
|
||||
},
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
areaOffset.BindTo(tabletHandler.AreaOffset);
|
||||
areaOffset.BindValueChanged(val =>
|
||||
{
|
||||
offsetX.Value = val.NewValue.X;
|
||||
offsetY.Value = val.NewValue.Y;
|
||||
}, true);
|
||||
|
||||
offsetX.BindValueChanged(val => areaOffset.Value = new Vector2(val.NewValue, areaOffset.Value.Y));
|
||||
offsetY.BindValueChanged(val => areaOffset.Value = new Vector2(areaOffset.Value.X, val.NewValue));
|
||||
|
||||
areaSize.BindTo(tabletHandler.AreaSize);
|
||||
areaSize.BindValueChanged(val =>
|
||||
{
|
||||
sizeX.Value = val.NewValue.X;
|
||||
sizeY.Value = val.NewValue.Y;
|
||||
}, true);
|
||||
|
||||
sizeX.BindValueChanged(val =>
|
||||
{
|
||||
areaSize.Value = new Vector2(val.NewValue, areaSize.Value.Y);
|
||||
|
||||
aspectRatioApplication?.Cancel();
|
||||
aspectRatioApplication = Schedule(() => applyAspectRatio(sizeX));
|
||||
});
|
||||
|
||||
sizeY.BindValueChanged(val =>
|
||||
{
|
||||
areaSize.Value = new Vector2(areaSize.Value.X, val.NewValue);
|
||||
|
||||
aspectRatioApplication?.Cancel();
|
||||
aspectRatioApplication = Schedule(() => applyAspectRatio(sizeY));
|
||||
});
|
||||
|
||||
updateAspectRatio();
|
||||
aspectRatio.BindValueChanged(aspect =>
|
||||
{
|
||||
aspectRatioApplication?.Cancel();
|
||||
aspectRatioApplication = Schedule(() => forceAspectRatio(aspect.NewValue));
|
||||
});
|
||||
|
||||
tablet.BindTo(tabletHandler.Tablet);
|
||||
tablet.BindValueChanged(val =>
|
||||
{
|
||||
Scheduler.AddOnce(toggleVisibility);
|
||||
|
||||
var tab = val.NewValue;
|
||||
|
||||
bool tabletFound = tab != null;
|
||||
if (!tabletFound)
|
||||
return;
|
||||
|
||||
offsetX.MaxValue = tab.Size.X;
|
||||
offsetX.Default = tab.Size.X / 2;
|
||||
sizeX.Default = sizeX.MaxValue = tab.Size.X;
|
||||
|
||||
offsetY.MaxValue = tab.Size.Y;
|
||||
offsetY.Default = tab.Size.Y / 2;
|
||||
sizeY.Default = sizeY.MaxValue = tab.Size.Y;
|
||||
|
||||
areaSize.Default = new Vector2(sizeX.Default, sizeY.Default);
|
||||
}, true);
|
||||
}
|
||||
|
||||
private void toggleVisibility()
|
||||
{
|
||||
bool tabletFound = tablet.Value != null;
|
||||
|
||||
if (!tabletFound)
|
||||
{
|
||||
mainSettings.Hide();
|
||||
noTabletMessage.Show();
|
||||
return;
|
||||
}
|
||||
|
||||
mainSettings.Show();
|
||||
noTabletMessage.Hide();
|
||||
}
|
||||
|
||||
private void applyAspectRatio(BindableNumber<float> sizeChanged)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!aspectLock.Value)
|
||||
{
|
||||
float proposedAspectRatio = currentAspectRatio;
|
||||
|
||||
if (proposedAspectRatio >= aspectRatio.MinValue && proposedAspectRatio <= aspectRatio.MaxValue)
|
||||
{
|
||||
// aspect ratio was in a valid range.
|
||||
updateAspectRatio();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if lock is applied (or the specified values were out of range) aim to adjust the axis the user was not adjusting to conform.
|
||||
if (sizeChanged == sizeX)
|
||||
sizeY.Value = (int)(areaSize.Value.X / aspectRatio.Value);
|
||||
else
|
||||
sizeX.Value = (int)(areaSize.Value.Y * aspectRatio.Value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// cancel any event which may have fired while updating variables as a result of aspect ratio limitations.
|
||||
// this avoids a potential feedback loop.
|
||||
aspectRatioApplication?.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private void forceAspectRatio(float aspectRatio)
|
||||
{
|
||||
aspectLock.Value = false;
|
||||
|
||||
int proposedHeight = (int)(sizeX.Value / aspectRatio);
|
||||
|
||||
if (proposedHeight < sizeY.MaxValue)
|
||||
sizeY.Value = proposedHeight;
|
||||
else
|
||||
sizeX.Value = (int)(sizeY.Value * aspectRatio);
|
||||
|
||||
updateAspectRatio();
|
||||
|
||||
aspectRatioApplication?.Cancel();
|
||||
aspectLock.Value = true;
|
||||
}
|
||||
|
||||
private void updateAspectRatio() => aspectRatio.Value = currentAspectRatio;
|
||||
|
||||
private float currentAspectRatio => sizeX.Value / sizeY.Value;
|
||||
}
|
||||
}
|
@ -1,28 +1,106 @@
|
||||
// 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.Sprites;
|
||||
using osu.Framework.Input.Handlers;
|
||||
using osu.Framework.Input.Handlers.Joystick;
|
||||
using osu.Framework.Input.Handlers.Midi;
|
||||
using osu.Framework.Input.Handlers.Mouse;
|
||||
using osu.Framework.Input.Handlers.Tablet;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Overlays.Settings.Sections.Input;
|
||||
|
||||
namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
public class InputSection : SettingsSection
|
||||
{
|
||||
private readonly KeyBindingPanel keyConfig;
|
||||
|
||||
public override string Header => "Input";
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon
|
||||
{
|
||||
Icon = FontAwesome.Solid.Keyboard
|
||||
};
|
||||
|
||||
public InputSection(KeyBindingPanel keyConfig)
|
||||
{
|
||||
this.keyConfig = keyConfig;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new MouseSettings(),
|
||||
new KeyboardSettings(keyConfig),
|
||||
new BindingSettings(keyConfig),
|
||||
};
|
||||
|
||||
foreach (var handler in host.AvailableInputHandlers)
|
||||
{
|
||||
var handlerSection = createSectionFor(handler);
|
||||
|
||||
if (handlerSection != null)
|
||||
Add(handlerSection);
|
||||
}
|
||||
}
|
||||
|
||||
private SettingsSubsection createSectionFor(InputHandler handler)
|
||||
{
|
||||
SettingsSubsection section;
|
||||
|
||||
switch (handler)
|
||||
{
|
||||
// ReSharper disable once SuspiciousTypeConversion.Global (net standard fuckery)
|
||||
case ITabletHandler th:
|
||||
section = new TabletSettings(th);
|
||||
break;
|
||||
|
||||
case MouseHandler mh:
|
||||
section = new MouseSettings(mh);
|
||||
break;
|
||||
|
||||
// whitelist the handlers which should be displayed to avoid any weird cases of users touching settings they shouldn't.
|
||||
case JoystickHandler _:
|
||||
case MidiHandler _:
|
||||
section = new HandlerSection(handler);
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
return section;
|
||||
}
|
||||
|
||||
private class HandlerSection : SettingsSubsection
|
||||
{
|
||||
private readonly InputHandler handler;
|
||||
|
||||
public HandlerSection(InputHandler handler)
|
||||
{
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Enabled",
|
||||
Current = handler.Enabled
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
protected override string Header => handler.Description;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,10 +8,12 @@ using osu.Game.Graphics.Sprites;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Settings
|
||||
{
|
||||
[ExcludeFromDynamicCompile]
|
||||
public abstract class SettingsSubsection : FillFlowContainer, IHasFilterableChildren
|
||||
{
|
||||
protected override Container<Drawable> Content => FlowContent;
|
||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
private const float sidebar_width = Sidebar.DEFAULT_WIDTH;
|
||||
|
||||
protected const float WIDTH = 400;
|
||||
public const float WIDTH = 400;
|
||||
|
||||
protected Container<Drawable> ContentContainer;
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user