mirror of
https://github.com/ppy/osu.git
synced 2024-12-15 00:33:21 +08:00
Merge branch 'master' into fix-taiko-hd-hit-overlap
This commit is contained in:
commit
0b7b70fd9c
1
.gitignore
vendored
1
.gitignore
vendored
@ -339,6 +339,5 @@ inspectcode
|
|||||||
|
|
||||||
# Fody (pulled in by Realm) - schema file
|
# Fody (pulled in by Realm) - schema file
|
||||||
FodyWeavers.xsd
|
FodyWeavers.xsd
|
||||||
**/FodyWeavers.xml
|
|
||||||
|
|
||||||
.idea/.idea.osu.Desktop/.idea/misc.xml
|
.idea/.idea.osu.Desktop/.idea/misc.xml
|
@ -10,7 +10,7 @@
|
|||||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.716.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.724.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<!-- Fody does not handle Android build well, and warns when unchanged.
|
<!-- Fody does not handle Android build well, and warns when unchanged.
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>osu.Game.Rulesets.Catch.Tests.iOS</string>
|
<string>osu.Game.Rulesets.Catch.Tests.iOS</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>ppy.osu-Game-Rulesets-Catch-Tests-iOS</string>
|
<string>sh.ppy.catch-ruleset-tests</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
@ -42,4 +42,4 @@
|
|||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
@ -5,7 +5,7 @@
|
|||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>osu.Game.Rulesets.Mania.Tests.iOS</string>
|
<string>osu.Game.Rulesets.Mania.Tests.iOS</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>ppy.osu-Game-Rulesets-Mania-Tests-iOS</string>
|
<string>sh.ppy.mania-ruleset-tests</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
@ -42,4 +42,4 @@
|
|||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
22
osu.Game.Rulesets.Mania/Edit/Setup/ManiaDifficultySection.cs
Normal file
22
osu.Game.Rulesets.Mania/Edit/Setup/ManiaDifficultySection.cs
Normal file
@ -0,0 +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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Screens.Edit.Setup;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Mania.Edit.Setup
|
||||||
|
{
|
||||||
|
public partial class ManiaDifficultySection : DifficultySection
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
CircleSizeSlider.Label = BeatmapsetsStrings.ShowStatsCsMania;
|
||||||
|
CircleSizeSlider.Description = "The number of columns in the beatmap";
|
||||||
|
if (CircleSizeSlider.Current is BindableNumber<float> circleSizeFloat)
|
||||||
|
circleSizeFloat.Precision = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -425,6 +425,8 @@ namespace osu.Game.Rulesets.Mania
|
|||||||
}
|
}
|
||||||
|
|
||||||
public override RulesetSetupSection CreateEditorSetupSection() => new ManiaSetupSection();
|
public override RulesetSetupSection CreateEditorSetupSection() => new ManiaSetupSection();
|
||||||
|
|
||||||
|
public override DifficultySection CreateEditorDifficultySection() => new ManiaDifficultySection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PlayfieldType
|
public enum PlayfieldType
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>osu.Game.Rulesets.Osu.Tests.iOS</string>
|
<string>osu.Game.Rulesets.Osu.Tests.iOS</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>ppy.osu-Game-Rulesets-Osu-Tests-iOS</string>
|
<string>sh.ppy.osu-ruleset-tests</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
@ -42,4 +42,4 @@
|
|||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
@ -25,6 +25,35 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
|||||||
{
|
{
|
||||||
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
|
protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new TestBeatmap(ruleset, false);
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSelectAfterFadedOut()
|
||||||
|
{
|
||||||
|
var slider = new Slider
|
||||||
|
{
|
||||||
|
StartTime = 0,
|
||||||
|
Position = new Vector2(100, 100),
|
||||||
|
Path = new SliderPath
|
||||||
|
{
|
||||||
|
ControlPoints =
|
||||||
|
{
|
||||||
|
new PathControlPoint(),
|
||||||
|
new PathControlPoint(new Vector2(100))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
AddStep("add slider", () => EditorBeatmap.Add(slider));
|
||||||
|
|
||||||
|
moveMouseToObject(() => slider);
|
||||||
|
|
||||||
|
AddStep("seek after end", () => EditorClock.Seek(750));
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("slider not selected", () => EditorBeatmap.SelectedHitObjects.Count == 0);
|
||||||
|
|
||||||
|
AddStep("seek to visible", () => EditorClock.Seek(650));
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddUntilStep("slider selected", () => EditorBeatmap.SelectedHitObjects.Single() == slider);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestContextMenuShownCorrectlyForSelectedSlider()
|
public void TestContextMenuShownCorrectlyForSelectedSlider()
|
||||||
{
|
{
|
||||||
|
@ -22,7 +22,13 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints
|
|||||||
protected override bool AlwaysShowWhenSelected => true;
|
protected override bool AlwaysShowWhenSelected => true;
|
||||||
|
|
||||||
protected override bool ShouldBeAlive => base.ShouldBeAlive
|
protected override bool ShouldBeAlive => base.ShouldBeAlive
|
||||||
|| (DrawableObject is not DrawableSpinner && ShowHitMarkers.Value && editorClock.CurrentTime >= Item.StartTime && editorClock.CurrentTime - Item.GetEndTime() < HitCircleOverlapMarker.FADE_OUT_EXTENSION);
|
|| (DrawableObject is not DrawableSpinner && ShowHitMarkers.Value && editorClock.CurrentTime >= Item.StartTime
|
||||||
|
&& editorClock.CurrentTime - Item.GetEndTime() < HitCircleOverlapMarker.FADE_OUT_EXTENSION);
|
||||||
|
|
||||||
|
public override bool IsSelectable =>
|
||||||
|
// Bypass fade out extension from hit markers for selection purposes.
|
||||||
|
// This is to match stable, where even when the afterimage hit markers are still visible, objects are not selectable.
|
||||||
|
base.ShouldBeAlive;
|
||||||
|
|
||||||
protected OsuSelectionBlueprint(T hitObject)
|
protected OsuSelectionBlueprint(T hitObject)
|
||||||
: base(hitObject)
|
: base(hitObject)
|
||||||
|
@ -62,12 +62,7 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
// Give a bit of breathing room around the playfield content.
|
// Give a bit of breathing room around the playfield content.
|
||||||
PlayfieldContentContainer.Padding = new MarginPadding
|
PlayfieldContentContainer.Padding = new MarginPadding(10);
|
||||||
{
|
|
||||||
Vertical = 10,
|
|
||||||
Left = TOOLBOX_CONTRACTED_SIZE_LEFT + 10,
|
|
||||||
Right = TOOLBOX_CONTRACTED_SIZE_RIGHT + 10,
|
|
||||||
};
|
|
||||||
|
|
||||||
LayerBelowRuleset.AddRange(new Drawable[]
|
LayerBelowRuleset.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>osu.Game.Rulesets.Taiko.Tests.iOS</string>
|
<string>osu.Game.Rulesets.Taiko.Tests.iOS</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>ppy.osu-Game-Rulesets-Taiko-Tests-iOS</string>
|
<string>sh.ppy.taiko-ruleset-tests</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
@ -42,4 +42,4 @@
|
|||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
@ -5,7 +5,7 @@
|
|||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
<string>osu.Game.Tests.iOS</string>
|
<string>osu.Game.Tests.iOS</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>ppy.osu-Game-Tests-iOS</string>
|
<string>sh.ppy.osu-tests</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>1.0</string>
|
<string>1.0</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
@ -42,4 +42,4 @@
|
|||||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
183
osu.Game.Tests/Editing/Checks/CheckBreaksTest.cs
Normal file
183
osu.Game.Tests/Editing/Checks/CheckBreaksTest.cs
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Timing;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
|
using osu.Game.Rulesets.Edit.Checks;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Editing.Checks
|
||||||
|
{
|
||||||
|
public class CheckBreaksTest
|
||||||
|
{
|
||||||
|
private CheckBreaks check = null!;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
check = new CheckBreaks();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBreakTooShort()
|
||||||
|
{
|
||||||
|
var beatmap = new Beatmap<HitObject>
|
||||||
|
{
|
||||||
|
Breaks = new List<BreakPeriod>
|
||||||
|
{
|
||||||
|
new BreakPeriod(0, 649)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckBreaks.IssueTemplateTooShort);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBreakStartsEarly()
|
||||||
|
{
|
||||||
|
var beatmap = new Beatmap<HitObject>
|
||||||
|
{
|
||||||
|
HitObjects =
|
||||||
|
{
|
||||||
|
new HitCircle { StartTime = 0 },
|
||||||
|
new HitCircle { StartTime = 1_200 }
|
||||||
|
},
|
||||||
|
Breaks = new List<BreakPeriod>
|
||||||
|
{
|
||||||
|
new BreakPeriod(100, 751)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckBreaks.IssueTemplateEarlyStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBreakEndsLate()
|
||||||
|
{
|
||||||
|
var beatmap = new Beatmap<HitObject>
|
||||||
|
{
|
||||||
|
HitObjects =
|
||||||
|
{
|
||||||
|
new HitCircle { StartTime = 0 },
|
||||||
|
new HitCircle { StartTime = 1_298 }
|
||||||
|
},
|
||||||
|
Breaks = new List<BreakPeriod>
|
||||||
|
{
|
||||||
|
new BreakPeriod(200, 850)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckBreaks.IssueTemplateLateEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBreakAfterLastObjectStartsEarly()
|
||||||
|
{
|
||||||
|
var beatmap = new Beatmap<HitObject>
|
||||||
|
{
|
||||||
|
HitObjects =
|
||||||
|
{
|
||||||
|
new HitCircle { StartTime = 0 },
|
||||||
|
new HitCircle { StartTime = 1200 }
|
||||||
|
},
|
||||||
|
Breaks = new List<BreakPeriod>
|
||||||
|
{
|
||||||
|
new BreakPeriod(1398, 2300)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckBreaks.IssueTemplateEarlyStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBreakBeforeFirstObjectEndsLate()
|
||||||
|
{
|
||||||
|
var beatmap = new Beatmap<HitObject>
|
||||||
|
{
|
||||||
|
HitObjects =
|
||||||
|
{
|
||||||
|
new HitCircle { StartTime = 1100 },
|
||||||
|
new HitCircle { StartTime = 1500 }
|
||||||
|
},
|
||||||
|
Breaks = new List<BreakPeriod>
|
||||||
|
{
|
||||||
|
new BreakPeriod(0, 652)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckBreaks.IssueTemplateLateEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBreakMultipleObjectsEarly()
|
||||||
|
{
|
||||||
|
var beatmap = new Beatmap<HitObject>
|
||||||
|
{
|
||||||
|
HitObjects =
|
||||||
|
{
|
||||||
|
new HitCircle { StartTime = 0 },
|
||||||
|
new HitCircle { StartTime = 1_297 },
|
||||||
|
new HitCircle { StartTime = 1_298 }
|
||||||
|
},
|
||||||
|
Breaks = new List<BreakPeriod>
|
||||||
|
{
|
||||||
|
new BreakPeriod(200, 850)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Has.Count.EqualTo(1));
|
||||||
|
Assert.That(issues.Single().Template is CheckBreaks.IssueTemplateLateEnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBreaksCorrect()
|
||||||
|
{
|
||||||
|
var beatmap = new Beatmap<HitObject>
|
||||||
|
{
|
||||||
|
HitObjects =
|
||||||
|
{
|
||||||
|
new HitCircle { StartTime = 0 },
|
||||||
|
new HitCircle { StartTime = 1_300 }
|
||||||
|
},
|
||||||
|
Breaks = new List<BreakPeriod>
|
||||||
|
{
|
||||||
|
new BreakPeriod(200, 850)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var context = new BeatmapVerifierContext(beatmap, new TestWorkingBeatmap(beatmap));
|
||||||
|
|
||||||
|
var issues = check.Run(context).ToList();
|
||||||
|
|
||||||
|
Assert.That(issues, Is.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -22,7 +22,6 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
public partial class TestSceneBeatDivisorControl : OsuManualInputManagerTestScene
|
public partial class TestSceneBeatDivisorControl : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
private BeatDivisorControl beatDivisorControl = null!;
|
private BeatDivisorControl beatDivisorControl = null!;
|
||||||
private BindableBeatDivisor bindableBeatDivisor = null!;
|
|
||||||
|
|
||||||
private SliderBar<int> tickSliderBar => beatDivisorControl.ChildrenOfType<SliderBar<int>>().Single();
|
private SliderBar<int> tickSliderBar => beatDivisorControl.ChildrenOfType<SliderBar<int>>().Single();
|
||||||
private Triangle tickMarkerHead => tickSliderBar.ChildrenOfType<Triangle>().Single();
|
private Triangle tickMarkerHead => tickSliderBar.ChildrenOfType<Triangle>().Single();
|
||||||
@ -30,13 +29,19 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[Cached]
|
[Cached]
|
||||||
private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
|
private readonly OverlayColourProvider overlayColour = new OverlayColourProvider(OverlayColourScheme.Aquamarine);
|
||||||
|
|
||||||
|
[Cached]
|
||||||
|
private readonly BindableBeatDivisor bindableBeatDivisor = new BindableBeatDivisor(16);
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp() => Schedule(() =>
|
public void SetUp() => Schedule(() =>
|
||||||
{
|
{
|
||||||
|
bindableBeatDivisor.ValidDivisors.SetDefault();
|
||||||
|
bindableBeatDivisor.SetDefault();
|
||||||
|
|
||||||
Child = new PopoverContainer
|
Child = new PopoverContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = beatDivisorControl = new BeatDivisorControl(bindableBeatDivisor = new BindableBeatDivisor(16))
|
Child = beatDivisorControl = new BeatDivisorControl
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
|
@ -1,26 +1,24 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Testing;
|
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Rulesets.Osu.Objects;
|
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.HitCircles.Components;
|
||||||
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
||||||
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.UI;
|
using osu.Game.Rulesets.Osu.UI;
|
||||||
using osu.Game.Tests.Beatmaps;
|
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
@ -82,7 +80,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestNudgeSelection()
|
public void TestNudgeSelection()
|
||||||
{
|
{
|
||||||
HitCircle[] addedObjects = null;
|
HitCircle[] addedObjects = null!;
|
||||||
|
|
||||||
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
|
||||||
{
|
{
|
||||||
@ -104,7 +102,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestRotateHotkeys()
|
public void TestRotateHotkeys()
|
||||||
{
|
{
|
||||||
HitCircle[] addedObjects = null;
|
HitCircle[] addedObjects = null!;
|
||||||
|
|
||||||
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
|
||||||
{
|
{
|
||||||
@ -136,7 +134,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestGlobalFlipHotkeys()
|
public void TestGlobalFlipHotkeys()
|
||||||
{
|
{
|
||||||
HitCircle addedObject = null;
|
HitCircle addedObject = null!;
|
||||||
|
|
||||||
AddStep("add hitobjects", () => EditorBeatmap.Add(addedObject = new HitCircle { StartTime = 100 }));
|
AddStep("add hitobjects", () => EditorBeatmap.Add(addedObject = new HitCircle { StartTime = 100 }));
|
||||||
|
|
||||||
@ -217,11 +215,173 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddAssert("2 hitobjects selected", () => EditorBeatmap.SelectedHitObjects.Count == 2 && !EditorBeatmap.SelectedHitObjects.Contains(addedObjects[1]));
|
AddAssert("2 hitobjects selected", () => EditorBeatmap.SelectedHitObjects.Count == 2 && !EditorBeatmap.SelectedHitObjects.Contains(addedObjects[1]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNearestSelection()
|
||||||
|
{
|
||||||
|
var firstObject = new HitCircle { Position = new Vector2(256, 192), StartTime = 0 };
|
||||||
|
var secondObject = new HitCircle { Position = new Vector2(256, 192), StartTime = 600 };
|
||||||
|
|
||||||
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[] { firstObject, secondObject }));
|
||||||
|
|
||||||
|
moveMouseToObject(() => firstObject);
|
||||||
|
|
||||||
|
AddStep("seek near first", () => EditorClock.Seek(100));
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("first selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(firstObject));
|
||||||
|
|
||||||
|
AddStep("deselect", () => EditorBeatmap.SelectedHitObjects.Clear());
|
||||||
|
|
||||||
|
AddStep("seek near second", () => EditorClock.Seek(500));
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("second selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(secondObject));
|
||||||
|
|
||||||
|
AddStep("deselect", () => EditorBeatmap.SelectedHitObjects.Clear());
|
||||||
|
|
||||||
|
AddStep("seek halfway", () => EditorClock.Seek(300));
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("first selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(firstObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestNearestSelectionWithEndTime()
|
||||||
|
{
|
||||||
|
var firstObject = new Slider
|
||||||
|
{
|
||||||
|
Position = new Vector2(256, 192),
|
||||||
|
StartTime = 0,
|
||||||
|
Path = new SliderPath(new[]
|
||||||
|
{
|
||||||
|
new PathControlPoint(),
|
||||||
|
new PathControlPoint(new Vector2(50, 0)),
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
var secondObject = new HitCircle
|
||||||
|
{
|
||||||
|
Position = new Vector2(256, 192),
|
||||||
|
StartTime = 600
|
||||||
|
};
|
||||||
|
|
||||||
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new HitObject[] { firstObject, secondObject }));
|
||||||
|
|
||||||
|
moveMouseToObject(() => firstObject);
|
||||||
|
|
||||||
|
AddStep("seek near first", () => EditorClock.Seek(100));
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("first selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(firstObject));
|
||||||
|
|
||||||
|
AddStep("deselect", () => EditorBeatmap.SelectedHitObjects.Clear());
|
||||||
|
|
||||||
|
AddStep("seek near second", () => EditorClock.Seek(500));
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("second selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(secondObject));
|
||||||
|
|
||||||
|
AddStep("deselect", () => EditorBeatmap.SelectedHitObjects.Clear());
|
||||||
|
|
||||||
|
AddStep("seek roughly halfway", () => EditorClock.Seek(350));
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
// Slider gets priority due to end time.
|
||||||
|
AddAssert("first selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(firstObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCyclicSelection()
|
||||||
|
{
|
||||||
|
var firstObject = new HitCircle { Position = new Vector2(256, 192), StartTime = 0 };
|
||||||
|
var secondObject = new HitCircle { Position = new Vector2(256, 192), StartTime = 300 };
|
||||||
|
var thirdObject = new HitCircle { Position = new Vector2(256, 192), StartTime = 600 };
|
||||||
|
|
||||||
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[] { firstObject, secondObject, thirdObject }));
|
||||||
|
|
||||||
|
moveMouseToObject(() => firstObject);
|
||||||
|
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("first selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(firstObject));
|
||||||
|
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("second selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(secondObject));
|
||||||
|
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("third selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(thirdObject));
|
||||||
|
|
||||||
|
// cycle around
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("first selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(firstObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCyclicSelectionOutwards()
|
||||||
|
{
|
||||||
|
var firstObject = new HitCircle { Position = new Vector2(256, 192), StartTime = 0 };
|
||||||
|
var secondObject = new HitCircle { Position = new Vector2(256, 192), StartTime = 300 };
|
||||||
|
var thirdObject = new HitCircle { Position = new Vector2(256, 192), StartTime = 600 };
|
||||||
|
|
||||||
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[] { firstObject, secondObject, thirdObject }));
|
||||||
|
|
||||||
|
moveMouseToObject(() => firstObject);
|
||||||
|
|
||||||
|
AddStep("seek near second", () => EditorClock.Seek(320));
|
||||||
|
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("second selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(secondObject));
|
||||||
|
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("third selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(thirdObject));
|
||||||
|
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("first selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(firstObject));
|
||||||
|
|
||||||
|
// cycle around
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("second selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(secondObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestCyclicSelectionBackwards()
|
||||||
|
{
|
||||||
|
var firstObject = new HitCircle { Position = new Vector2(256, 192), StartTime = 0 };
|
||||||
|
var secondObject = new HitCircle { Position = new Vector2(256, 192), StartTime = 200 };
|
||||||
|
var thirdObject = new HitCircle { Position = new Vector2(256, 192), StartTime = 400 };
|
||||||
|
|
||||||
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[] { firstObject, secondObject, thirdObject }));
|
||||||
|
|
||||||
|
moveMouseToObject(() => firstObject);
|
||||||
|
|
||||||
|
AddStep("seek to third", () => EditorClock.Seek(350));
|
||||||
|
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("third selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(thirdObject));
|
||||||
|
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("second selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(secondObject));
|
||||||
|
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("first selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(firstObject));
|
||||||
|
|
||||||
|
// cycle around
|
||||||
|
AddStep("left click", () => InputManager.Click(MouseButton.Left));
|
||||||
|
AddAssert("third selected", () => EditorBeatmap.SelectedHitObjects.Single(), () => Is.EqualTo(thirdObject));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestDoubleClickToSeek()
|
||||||
|
{
|
||||||
|
var hitCircle = new HitCircle { Position = new Vector2(256, 192), StartTime = 600 };
|
||||||
|
|
||||||
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[] { hitCircle }));
|
||||||
|
|
||||||
|
moveMouseToObject(() => hitCircle);
|
||||||
|
|
||||||
|
AddRepeatStep("double click", () => InputManager.Click(MouseButton.Left), 2);
|
||||||
|
|
||||||
|
AddUntilStep("seeked to circle", () => EditorClock.CurrentTime, () => Is.EqualTo(600));
|
||||||
|
}
|
||||||
|
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
[TestCase(true)]
|
[TestCase(true)]
|
||||||
public void TestMultiSelectFromDrag(bool alreadySelectedBeforeDrag)
|
public void TestMultiSelectFromDrag(bool alreadySelectedBeforeDrag)
|
||||||
{
|
{
|
||||||
HitCircle[] addedObjects = null;
|
HitCircle[] addedObjects = null!;
|
||||||
|
|
||||||
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(addedObjects = new[]
|
||||||
{
|
{
|
||||||
@ -320,7 +480,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestQuickDeleteRemovesSliderControlPoint()
|
public void TestQuickDeleteRemovesSliderControlPoint()
|
||||||
{
|
{
|
||||||
Slider slider = null;
|
Slider slider = null!;
|
||||||
|
|
||||||
PathControlPoint[] points =
|
PathControlPoint[] points =
|
||||||
{
|
{
|
||||||
|
@ -117,9 +117,9 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddStep("move mouse to overlapping toggle button", () =>
|
AddStep("move mouse to overlapping toggle button", () =>
|
||||||
{
|
{
|
||||||
var playfield = hitObjectComposer.Playfield.ScreenSpaceDrawQuad;
|
var playfield = hitObjectComposer.Playfield.ScreenSpaceDrawQuad;
|
||||||
var button = toolboxContainer.ChildrenOfType<DrawableTernaryButton>().First(b => playfield.Contains(b.ScreenSpaceDrawQuad.Centre));
|
var button = toolboxContainer.ChildrenOfType<DrawableTernaryButton>().First(b => playfield.Contains(getOverlapPoint(b)));
|
||||||
|
|
||||||
InputManager.MoveMouseTo(button);
|
InputManager.MoveMouseTo(getOverlapPoint(button));
|
||||||
});
|
});
|
||||||
|
|
||||||
AddAssert("no circles placed", () => editorBeatmap.HitObjects.Count == 0);
|
AddAssert("no circles placed", () => editorBeatmap.HitObjects.Count == 0);
|
||||||
@ -127,6 +127,12 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddStep("attempt place circle", () => InputManager.Click(MouseButton.Left));
|
AddStep("attempt place circle", () => InputManager.Click(MouseButton.Left));
|
||||||
|
|
||||||
AddAssert("no circles placed", () => editorBeatmap.HitObjects.Count == 0);
|
AddAssert("no circles placed", () => editorBeatmap.HitObjects.Count == 0);
|
||||||
|
|
||||||
|
Vector2 getOverlapPoint(DrawableTernaryButton ternaryButton)
|
||||||
|
{
|
||||||
|
var quad = ternaryButton.ScreenSpaceDrawQuad;
|
||||||
|
return quad.TopLeft + new Vector2(quad.Width * 9 / 10, quad.Height / 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
{
|
{
|
||||||
BeatDivisor.Value = 4;
|
BeatDivisor.Value = 4;
|
||||||
|
|
||||||
Add(new BeatDivisorControl(BeatDivisor)
|
Add(new BeatDivisorControl
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private HUDOverlay hudOverlay = null!;
|
private HUDOverlay hudOverlay = null!;
|
||||||
|
|
||||||
[Cached(typeof(ScoreProcessor))]
|
[Cached(typeof(ScoreProcessor))]
|
||||||
private ScoreProcessor scoreProcessor => gameplayState.ScoreProcessor;
|
private ScoreProcessor scoreProcessor { get; set; }
|
||||||
|
|
||||||
[Cached(typeof(HealthProcessor))]
|
[Cached(typeof(HealthProcessor))]
|
||||||
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
|
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
|
||||||
@ -47,6 +47,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private Drawable hideTarget => hudOverlay.ChildrenOfType<SkinComponentsContainer>().First();
|
private Drawable hideTarget => hudOverlay.ChildrenOfType<SkinComponentsContainer>().First();
|
||||||
private Drawable keyCounterFlow => hudOverlay.ChildrenOfType<KeyCounterDisplay>().First().ChildrenOfType<FillFlowContainer<KeyCounter>>().Single();
|
private Drawable keyCounterFlow => hudOverlay.ChildrenOfType<KeyCounterDisplay>().First().ChildrenOfType<FillFlowContainer<KeyCounter>>().Single();
|
||||||
|
|
||||||
|
public TestSceneHUDOverlay()
|
||||||
|
{
|
||||||
|
scoreProcessor = gameplayState.ScoreProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
|
@ -138,24 +138,28 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestCyclicSelection()
|
public void TestCyclicSelection()
|
||||||
{
|
{
|
||||||
SkinBlueprint[] blueprints = null!;
|
List<SkinBlueprint> blueprints = new List<SkinBlueprint>();
|
||||||
|
|
||||||
AddStep("Add big black boxes", () =>
|
AddStep("clear list", () => blueprints.Clear());
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
InputManager.MoveMouseTo(skinEditor.ChildrenOfType<BigBlackBox>().First());
|
AddStep("Add big black box", () =>
|
||||||
InputManager.Click(MouseButton.Left);
|
{
|
||||||
InputManager.Click(MouseButton.Left);
|
InputManager.MoveMouseTo(skinEditor.ChildrenOfType<BigBlackBox>().First());
|
||||||
InputManager.Click(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddStep("store box", () =>
|
||||||
|
{
|
||||||
|
// Add blueprints one-by-one so we have a stable order for testing reverse cyclic selection against.
|
||||||
|
blueprints.Add(skinEditor.ChildrenOfType<SkinBlueprint>().Single(s => s.IsSelected));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
AddAssert("Three black boxes added", () => targetContainer.Components.OfType<BigBlackBox>().Count(), () => Is.EqualTo(3));
|
AddAssert("Three black boxes added", () => targetContainer.Components.OfType<BigBlackBox>().Count(), () => Is.EqualTo(3));
|
||||||
|
|
||||||
AddStep("Store black box blueprints", () =>
|
AddAssert("Selection is last", () => skinEditor.SelectedComponents.Single(), () => Is.EqualTo(blueprints[2].Item));
|
||||||
{
|
|
||||||
blueprints = skinEditor.ChildrenOfType<SkinBlueprint>().Where(b => b.Item is BigBlackBox).ToArray();
|
|
||||||
});
|
|
||||||
|
|
||||||
AddAssert("Selection is black box 1", () => skinEditor.SelectedComponents.Single(), () => Is.EqualTo(blueprints[0].Item));
|
|
||||||
|
|
||||||
AddStep("move cursor to black box", () =>
|
AddStep("move cursor to black box", () =>
|
||||||
{
|
{
|
||||||
@ -164,13 +168,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
});
|
});
|
||||||
|
|
||||||
AddStep("click on black box stack", () => InputManager.Click(MouseButton.Left));
|
AddStep("click on black box stack", () => InputManager.Click(MouseButton.Left));
|
||||||
AddAssert("Selection is black box 2", () => skinEditor.SelectedComponents.Single(), () => Is.EqualTo(blueprints[1].Item));
|
AddAssert("Selection is second last", () => skinEditor.SelectedComponents.Single(), () => Is.EqualTo(blueprints[1].Item));
|
||||||
|
|
||||||
AddStep("click on black box stack", () => InputManager.Click(MouseButton.Left));
|
AddStep("click on black box stack", () => InputManager.Click(MouseButton.Left));
|
||||||
AddAssert("Selection is black box 3", () => skinEditor.SelectedComponents.Single(), () => Is.EqualTo(blueprints[2].Item));
|
AddAssert("Selection is last", () => skinEditor.SelectedComponents.Single(), () => Is.EqualTo(blueprints[0].Item));
|
||||||
|
|
||||||
AddStep("click on black box stack", () => InputManager.Click(MouseButton.Left));
|
AddStep("click on black box stack", () => InputManager.Click(MouseButton.Left));
|
||||||
AddAssert("Selection is black box 1", () => skinEditor.SelectedComponents.Single(), () => Is.EqualTo(blueprints[0].Item));
|
AddAssert("Selection is first", () => skinEditor.SelectedComponents.Single(), () => Is.EqualTo(blueprints[2].Item));
|
||||||
|
|
||||||
AddStep("select all boxes", () =>
|
AddStep("select all boxes", () =>
|
||||||
{
|
{
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
public partial class TestSceneSkinEditorMultipleSkins : SkinnableTestScene
|
public partial class TestSceneSkinEditorMultipleSkins : SkinnableTestScene
|
||||||
{
|
{
|
||||||
[Cached(typeof(ScoreProcessor))]
|
[Cached(typeof(ScoreProcessor))]
|
||||||
private ScoreProcessor scoreProcessor => gameplayState.ScoreProcessor;
|
private ScoreProcessor scoreProcessor { get; set; }
|
||||||
|
|
||||||
[Cached(typeof(HealthProcessor))]
|
[Cached(typeof(HealthProcessor))]
|
||||||
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
|
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
|
||||||
@ -37,6 +37,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
[Cached]
|
[Cached]
|
||||||
public readonly EditorClipboard Clipboard = new EditorClipboard();
|
public readonly EditorClipboard Clipboard = new EditorClipboard();
|
||||||
|
|
||||||
|
public TestSceneSkinEditorMultipleSkins()
|
||||||
|
{
|
||||||
|
scoreProcessor = gameplayState.ScoreProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
public void SetUpSteps()
|
public void SetUpSteps()
|
||||||
{
|
{
|
||||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private HUDOverlay hudOverlay;
|
private HUDOverlay hudOverlay;
|
||||||
|
|
||||||
[Cached(typeof(ScoreProcessor))]
|
[Cached(typeof(ScoreProcessor))]
|
||||||
private ScoreProcessor scoreProcessor => gameplayState.ScoreProcessor;
|
private ScoreProcessor scoreProcessor { get; set; }
|
||||||
|
|
||||||
[Cached(typeof(HealthProcessor))]
|
[Cached(typeof(HealthProcessor))]
|
||||||
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
|
private HealthProcessor healthProcessor = new DrainingHealthProcessor(0);
|
||||||
@ -47,6 +47,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private Drawable hideTarget => hudOverlay.ChildrenOfType<SkinComponentsContainer>().First();
|
private Drawable hideTarget => hudOverlay.ChildrenOfType<SkinComponentsContainer>().First();
|
||||||
private Drawable keyCounterFlow => hudOverlay.ChildrenOfType<KeyCounterDisplay>().First().ChildrenOfType<FillFlowContainer<KeyCounter>>().Single();
|
private Drawable keyCounterFlow => hudOverlay.ChildrenOfType<KeyCounterDisplay>().First().ChildrenOfType<FillFlowContainer<KeyCounter>>().Single();
|
||||||
|
|
||||||
|
public TestSceneSkinnableHUDOverlay()
|
||||||
|
{
|
||||||
|
scoreProcessor = gameplayState.ScoreProcessor;
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestComboCounterIncrementing()
|
public void TestComboCounterIncrementing()
|
||||||
{
|
{
|
||||||
|
@ -67,6 +67,14 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded);
|
AddUntilStep("wait for present", () => songSelect.IsCurrentScreen() && songSelect.BeatmapSetsLoaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSelectFreeMods()
|
||||||
|
{
|
||||||
|
AddStep("set some freemods", () => songSelect.FreeMods.Value = new OsuRuleset().GetModsFor(ModType.Fun).ToArray());
|
||||||
|
AddStep("set all freemods", () => songSelect.FreeMods.Value = new OsuRuleset().CreateAllMods().ToArray());
|
||||||
|
AddStep("set no freemods", () => songSelect.FreeMods.Value = Array.Empty<Mod>());
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestBeatmapConfirmed()
|
public void TestBeatmapConfirmed()
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Tournament.Models;
|
using osu.Game.Tournament.Models;
|
||||||
using osu.Game.Tournament.Screens.Ladder.Components;
|
using osu.Game.Tournament.Screens.Ladder.Components;
|
||||||
|
|
||||||
@ -10,60 +13,67 @@ namespace osu.Game.Tournament.Tests.Components
|
|||||||
{
|
{
|
||||||
public partial class TestSceneDrawableTournamentMatch : TournamentTestScene
|
public partial class TestSceneDrawableTournamentMatch : TournamentTestScene
|
||||||
{
|
{
|
||||||
public TestSceneDrawableTournamentMatch()
|
[Test]
|
||||||
|
public void TestBasic()
|
||||||
{
|
{
|
||||||
Container<DrawableTournamentMatch> level1;
|
Container<DrawableTournamentMatch> level1 = null!;
|
||||||
Container<DrawableTournamentMatch> level2;
|
Container<DrawableTournamentMatch> level2 = null!;
|
||||||
|
|
||||||
var match1 = new TournamentMatch(
|
TournamentMatch match1 = null!;
|
||||||
new TournamentTeam { FlagName = { Value = "AU" }, FullName = { Value = "Australia" }, },
|
TournamentMatch match2 = null!;
|
||||||
new TournamentTeam { FlagName = { Value = "JP" }, FullName = { Value = "Japan" }, Acronym = { Value = "JPN" } })
|
|
||||||
|
AddStep("setup test", () =>
|
||||||
{
|
{
|
||||||
Team1Score = { Value = 4 },
|
match1 = new TournamentMatch(
|
||||||
Team2Score = { Value = 1 },
|
new TournamentTeam { FlagName = { Value = "AU" }, FullName = { Value = "Australia" }, },
|
||||||
};
|
new TournamentTeam { FlagName = { Value = "JP" }, FullName = { Value = "Japan" }, Acronym = { Value = "JPN" } })
|
||||||
|
|
||||||
var match2 = new TournamentMatch(
|
|
||||||
new TournamentTeam
|
|
||||||
{
|
{
|
||||||
FlagName = { Value = "RO" },
|
Team1Score = { Value = 4 },
|
||||||
FullName = { Value = "Romania" },
|
Team2Score = { Value = 1 },
|
||||||
}
|
};
|
||||||
);
|
|
||||||
|
|
||||||
Child = new FillFlowContainer
|
match2 = new TournamentMatch(
|
||||||
{
|
new TournamentTeam
|
||||||
RelativeSizeAxes = Axes.Both,
|
{
|
||||||
Direction = FillDirection.Horizontal,
|
FlagName = { Value = "RO" },
|
||||||
Children = new Drawable[]
|
FullName = { Value = "Romania" },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
Child = new FillFlowContainer
|
||||||
{
|
{
|
||||||
level1 = new FillFlowContainer<DrawableTournamentMatch>
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Direction = FillDirection.Horizontal,
|
||||||
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.X,
|
level1 = new FillFlowContainer<DrawableTournamentMatch>
|
||||||
Direction = FillDirection.Vertical,
|
|
||||||
Children = new[]
|
|
||||||
{
|
{
|
||||||
new DrawableTournamentMatch(match1),
|
AutoSizeAxes = Axes.X,
|
||||||
new DrawableTournamentMatch(match2),
|
Direction = FillDirection.Vertical,
|
||||||
new DrawableTournamentMatch(new TournamentMatch()),
|
Children = new[]
|
||||||
}
|
{
|
||||||
},
|
new DrawableTournamentMatch(match1),
|
||||||
level2 = new FillFlowContainer<DrawableTournamentMatch>
|
new DrawableTournamentMatch(match2),
|
||||||
{
|
new DrawableTournamentMatch(new TournamentMatch()),
|
||||||
AutoSizeAxes = Axes.X,
|
}
|
||||||
Direction = FillDirection.Vertical,
|
},
|
||||||
Margin = new MarginPadding(20),
|
level2 = new FillFlowContainer<DrawableTournamentMatch>
|
||||||
Children = new[]
|
|
||||||
{
|
{
|
||||||
new DrawableTournamentMatch(new TournamentMatch()),
|
AutoSizeAxes = Axes.X,
|
||||||
new DrawableTournamentMatch(new TournamentMatch())
|
Direction = FillDirection.Vertical,
|
||||||
|
Margin = new MarginPadding(20),
|
||||||
|
Children = new[]
|
||||||
|
{
|
||||||
|
new DrawableTournamentMatch(new TournamentMatch()),
|
||||||
|
new DrawableTournamentMatch(new TournamentMatch())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
level1.Children[0].Match.Progression.Value = level2.Children[0].Match;
|
level1.Children[0].Match.Progression.Value = level2.Children[0].Match;
|
||||||
level1.Children[1].Match.Progression.Value = level2.Children[0].Match;
|
level1.Children[1].Match.Progression.Value = level2.Children[0].Match;
|
||||||
|
});
|
||||||
|
|
||||||
AddRepeatStep("change scores", () => match1.Team2Score.Value++, 4);
|
AddRepeatStep("change scores", () => match1.Team2Score.Value++, 4);
|
||||||
AddStep("add new team", () => match2.Team2.Value = new TournamentTeam { FlagName = { Value = "PT" }, FullName = { Value = "Portugal" } });
|
AddStep("add new team", () => match2.Team2.Value = new TournamentTeam { FlagName = { Value = "PT" }, FullName = { Value = "Portugal" } });
|
||||||
@ -78,6 +88,9 @@ namespace osu.Game.Tournament.Tests.Components
|
|||||||
AddRepeatStep("change scores", () => level2.Children[0].Match.Team1Score.Value++, 5);
|
AddRepeatStep("change scores", () => level2.Children[0].Match.Team1Score.Value++, 5);
|
||||||
|
|
||||||
AddRepeatStep("change scores", () => level2.Children[0].Match.Team2Score.Value++, 4);
|
AddRepeatStep("change scores", () => level2.Children[0].Match.Team2Score.Value++, 4);
|
||||||
|
|
||||||
|
AddStep("select as current", () => match1.Current.Value = true);
|
||||||
|
AddStep("select as editing", () => this.ChildrenOfType<DrawableTournamentMatch>().Last().Selected = true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ using osu.Game.Tournament.Screens.Drawings;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneDrawingsScreen : TournamentTestScene
|
public partial class TestSceneDrawingsScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(Storage storage)
|
private void load(Storage storage)
|
||||||
|
@ -15,11 +15,25 @@ using osu.Game.Tournament.Screens.Gameplay.Components;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneGameplayScreen : TournamentTestScene
|
public partial class TestSceneGameplayScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
[Cached]
|
[Cached]
|
||||||
private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay { Width = 0.5f };
|
private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay { Width = 0.5f };
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestWarmup()
|
||||||
|
{
|
||||||
|
createScreen();
|
||||||
|
|
||||||
|
checkScoreVisibility(false);
|
||||||
|
|
||||||
|
toggleWarmup();
|
||||||
|
checkScoreVisibility(true);
|
||||||
|
|
||||||
|
toggleWarmup();
|
||||||
|
checkScoreVisibility(false);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestStartupState([Values] TourneyState state)
|
public void TestStartupState([Values] TourneyState state)
|
||||||
{
|
{
|
||||||
@ -35,20 +49,6 @@ namespace osu.Game.Tournament.Tests.Screens
|
|||||||
createScreen();
|
createScreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestWarmup()
|
|
||||||
{
|
|
||||||
createScreen();
|
|
||||||
|
|
||||||
checkScoreVisibility(false);
|
|
||||||
|
|
||||||
toggleWarmup();
|
|
||||||
checkScoreVisibility(true);
|
|
||||||
|
|
||||||
toggleWarmup();
|
|
||||||
checkScoreVisibility(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createScreen()
|
private void createScreen()
|
||||||
{
|
{
|
||||||
AddStep("setup screen", () =>
|
AddStep("setup screen", () =>
|
||||||
|
@ -1,23 +1,100 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Tournament.Screens.Editors;
|
using osu.Game.Tournament.Screens.Editors;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Overlays.Dialog;
|
||||||
|
using osu.Game.Tournament.Screens.Editors.Components;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneLadderEditorScreen : TournamentTestScene
|
public partial class TestSceneLadderEditorScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
private LadderEditorScreen ladderEditorScreen = null!;
|
||||||
private void load()
|
private OsuContextMenuContainer? osuContextMenuContainer;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup() => Schedule(() =>
|
||||||
{
|
{
|
||||||
Add(new OsuContextMenuContainer
|
ladderEditorScreen = new LadderEditorScreen();
|
||||||
|
Add(osuContextMenuContainer = new OsuContextMenuContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = new LadderEditorScreen()
|
Child = ladderEditorScreen = new LadderEditorScreen()
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestResetBracketTeamsCancelled()
|
||||||
|
{
|
||||||
|
Bindable<string> matchBeforeReset = new Bindable<string>();
|
||||||
|
AddStep("save current match state", () =>
|
||||||
|
{
|
||||||
|
matchBeforeReset.Value = JsonConvert.SerializeObject(Ladder.CurrentMatch.Value);
|
||||||
|
});
|
||||||
|
AddStep("pull up context menu", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(ladderEditorScreen);
|
||||||
|
InputManager.Click(MouseButton.Right);
|
||||||
|
});
|
||||||
|
AddStep("click Reset teams button", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(osuContextMenuContainer.ChildrenOfType<DrawableOsuMenuItem>().Last(p =>
|
||||||
|
((OsuMenuItem)p.Item).Type == MenuItemType.Destructive), new Vector2(5, 0));
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("dialog displayed", () => DialogOverlay.CurrentDialog is LadderResetTeamsDialog);
|
||||||
|
AddStep("click cancel", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(DialogOverlay.CurrentDialog.ChildrenOfType<PopupDialogButton>().Last());
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("dialog dismissed", () => DialogOverlay.CurrentDialog is not LadderResetTeamsDialog);
|
||||||
|
|
||||||
|
AddAssert("assert ladder teams unchanged", () => string.Equals(matchBeforeReset.Value, JsonConvert.SerializeObject(Ladder.CurrentMatch.Value), StringComparison.Ordinal));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestResetBracketTeams()
|
||||||
|
{
|
||||||
|
AddStep("pull up context menu", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(ladderEditorScreen);
|
||||||
|
InputManager.Click(MouseButton.Right);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("click Reset teams button", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(osuContextMenuContainer.ChildrenOfType<DrawableOsuMenuItem>().Last(p =>
|
||||||
|
((OsuMenuItem)p.Item).Type == MenuItemType.Destructive), new Vector2(5, 0));
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("dialog displayed", () => DialogOverlay.CurrentDialog is LadderResetTeamsDialog);
|
||||||
|
|
||||||
|
AddStep("click confirmation", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(DialogOverlay.CurrentDialog.ChildrenOfType<PopupDialogButton>().First());
|
||||||
|
InputManager.PressButton(MouseButton.Left);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("dialog dismissed", () => DialogOverlay.CurrentDialog is not LadderResetTeamsDialog);
|
||||||
|
|
||||||
|
AddStep("release mouse button", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||||
|
|
||||||
|
AddAssert("assert ladder teams reset", () => Ladder.CurrentMatch.Value.Team1.Value == null && Ladder.CurrentMatch.Value.Team2.Value == null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ using osu.Game.Tournament.Screens.Ladder;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneLadderScreen : TournamentTestScene
|
public partial class TestSceneLadderScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
|
@ -14,7 +14,7 @@ using osu.Game.Tournament.Screens.MapPool;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneMapPoolScreen : TournamentTestScene
|
public partial class TestSceneMapPoolScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
private MapPoolScreen screen;
|
private MapPoolScreen screen;
|
||||||
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Tournament.Screens.Editors;
|
using osu.Game.Tournament.Screens.Editors;
|
||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneRoundEditorScreen : TournamentTestScene
|
public partial class TestSceneRoundEditorScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
public TestSceneRoundEditorScreen()
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
{
|
{
|
||||||
Add(new RoundEditorScreen
|
Add(new RoundEditorScreen
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@ using osu.Game.Tournament.Screens.Schedule;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneScheduleScreen : TournamentTestScene
|
public partial class TestSceneScheduleScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
|
@ -7,12 +7,13 @@ using osu.Game.Tournament.Screens.Editors;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneSeedingEditorScreen : TournamentTestScene
|
public partial class TestSceneSeedingEditorScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
[Cached]
|
[Cached]
|
||||||
private readonly LadderInfo ladder = new LadderInfo();
|
private readonly LadderInfo ladder = new LadderInfo();
|
||||||
|
|
||||||
public TestSceneSeedingEditorScreen()
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
{
|
{
|
||||||
var match = CreateSampleMatch();
|
var match = CreateSampleMatch();
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ using osu.Game.Tournament.Screens.TeamIntro;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneSeedingScreen : TournamentTestScene
|
public partial class TestSceneSeedingScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
[Cached]
|
[Cached]
|
||||||
private readonly LadderInfo ladder = new LadderInfo
|
private readonly LadderInfo ladder = new LadderInfo
|
||||||
|
@ -6,7 +6,7 @@ using osu.Game.Tournament.Screens.Setup;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneSetupScreen : TournamentTestScene
|
public partial class TestSceneSetupScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
|
@ -6,7 +6,7 @@ using osu.Game.Tournament.Screens.Showcase;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneShowcaseScreen : TournamentTestScene
|
public partial class TestSceneShowcaseScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
|
@ -5,7 +5,7 @@ using osu.Game.Tournament.Screens.Setup;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneStablePathSelectScreen : TournamentTestScene
|
public partial class TestSceneStablePathSelectScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
public TestSceneStablePathSelectScreen()
|
public TestSceneStablePathSelectScreen()
|
||||||
{
|
{
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
using osu.Game.Tournament.Screens.Editors;
|
using osu.Game.Tournament.Screens.Editors;
|
||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneTeamEditorScreen : TournamentTestScene
|
public partial class TestSceneTeamEditorScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
public TestSceneTeamEditorScreen()
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
{
|
{
|
||||||
Add(new TeamEditorScreen
|
Add(new TeamEditorScreen
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,7 @@ using osu.Game.Tournament.Screens.TeamIntro;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneTeamIntroScreen : TournamentTestScene
|
public partial class TestSceneTeamIntroScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
[Cached]
|
[Cached]
|
||||||
private readonly LadderInfo ladder = new LadderInfo();
|
private readonly LadderInfo ladder = new LadderInfo();
|
||||||
|
@ -8,7 +8,7 @@ using osu.Game.Tournament.Screens.TeamWin;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests.Screens
|
namespace osu.Game.Tournament.Tests.Screens
|
||||||
{
|
{
|
||||||
public partial class TestSceneTeamWinScreen : TournamentTestScene
|
public partial class TestSceneTeamWinScreen : TournamentScreenTestScene
|
||||||
{
|
{
|
||||||
[Test]
|
[Test]
|
||||||
public void TestBasic()
|
public void TestBasic()
|
||||||
|
38
osu.Game.Tournament.Tests/TournamentScreenTestScene.cs
Normal file
38
osu.Game.Tournament.Tests/TournamentScreenTestScene.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// 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.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Tournament.Tests
|
||||||
|
{
|
||||||
|
public abstract partial class TournamentScreenTestScene : TournamentTestScene
|
||||||
|
{
|
||||||
|
protected override Container<Drawable> Content { get; } = new TournamentScalingContainer();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
base.Content.Add(Content);
|
||||||
|
}
|
||||||
|
|
||||||
|
private partial class TournamentScalingContainer : DrawSizePreservingFillContainer
|
||||||
|
{
|
||||||
|
public TournamentScalingContainer()
|
||||||
|
{
|
||||||
|
TargetDrawSize = new Vector2(1920, 1080);
|
||||||
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
Scale = new Vector2(Math.Min(1, Content.DrawWidth / (1920 + TournamentSceneManager.CONTROL_AREA_WIDTH)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,7 +12,7 @@ namespace osu.Game.Tournament.Tests
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu", new HostOptions { BindIPC = true }))
|
using (DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu-development", new HostOptions { BindIPC = true }))
|
||||||
{
|
{
|
||||||
host.Run(new TournamentTestBrowser());
|
host.Run(new TournamentTestBrowser());
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -10,6 +8,7 @@ using osu.Framework.Platform;
|
|||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Tests.Visual;
|
using osu.Game.Tests.Visual;
|
||||||
using osu.Game.Tournament.IO;
|
using osu.Game.Tournament.IO;
|
||||||
@ -18,19 +17,22 @@ using osu.Game.Tournament.Models;
|
|||||||
|
|
||||||
namespace osu.Game.Tournament.Tests
|
namespace osu.Game.Tournament.Tests
|
||||||
{
|
{
|
||||||
public abstract partial class TournamentTestScene : OsuTestScene
|
public abstract partial class TournamentTestScene : OsuManualInputManagerTestScene
|
||||||
{
|
{
|
||||||
private TournamentMatch match;
|
[Cached(typeof(IDialogOverlay))]
|
||||||
|
protected readonly DialogOverlay DialogOverlay = new DialogOverlay { Depth = float.MinValue };
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
protected LadderInfo Ladder { get; private set; } = new LadderInfo();
|
protected LadderInfo Ladder { get; private set; } = new LadderInfo();
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private RulesetStore rulesetStore { get; set; }
|
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
protected MatchIPCInfo IPCInfo { get; private set; } = new MatchIPCInfo();
|
protected MatchIPCInfo IPCInfo { get; private set; } = new MatchIPCInfo();
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private RulesetStore rulesetStore { get; set; } = null!;
|
||||||
|
|
||||||
|
private TournamentMatch match = null!;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TournamentStorage storage)
|
private void load(TournamentStorage storage)
|
||||||
{
|
{
|
||||||
@ -45,6 +47,8 @@ namespace osu.Game.Tournament.Tests
|
|||||||
|
|
||||||
Ruleset.BindTo(Ladder.Ruleset);
|
Ruleset.BindTo(Ladder.Ruleset);
|
||||||
Dependencies.CacheAs(new StableInfo(storage));
|
Dependencies.CacheAs(new StableInfo(storage));
|
||||||
|
|
||||||
|
Add(DialogOverlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
@ -167,7 +171,7 @@ namespace osu.Game.Tournament.Tests
|
|||||||
|
|
||||||
public partial class TournamentTestSceneTestRunner : TournamentGameBase, ITestSceneTestRunner
|
public partial class TournamentTestSceneTestRunner : TournamentGameBase, ITestSceneTestRunner
|
||||||
{
|
{
|
||||||
private TestSceneTestRunner.TestRunner runner;
|
private TestSceneTestRunner.TestRunner runner = null!;
|
||||||
|
|
||||||
protected override void LoadAsyncComplete()
|
protected override void LoadAsyncComplete()
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -12,24 +10,21 @@ namespace osu.Game.Tournament.Components
|
|||||||
{
|
{
|
||||||
public partial class DateTextBox : SettingsTextBox
|
public partial class DateTextBox : SettingsTextBox
|
||||||
{
|
{
|
||||||
public new Bindable<DateTimeOffset> Current
|
private readonly BindableWithCurrent<DateTimeOffset> current = new BindableWithCurrent<DateTimeOffset>();
|
||||||
|
|
||||||
|
public new Bindable<DateTimeOffset>? Current
|
||||||
{
|
{
|
||||||
get => current;
|
get => current;
|
||||||
set
|
set => current.Current = value;
|
||||||
{
|
|
||||||
current = value.GetBoundCopy();
|
|
||||||
current.BindValueChanged(dto =>
|
|
||||||
base.Current.Value = dto.NewValue.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"), true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// hold a reference to the provided bindable so we don't have to in every settings section.
|
|
||||||
private Bindable<DateTimeOffset> current = new Bindable<DateTimeOffset>();
|
|
||||||
|
|
||||||
public DateTextBox()
|
public DateTextBox()
|
||||||
{
|
{
|
||||||
base.Current = new Bindable<string>(string.Empty);
|
base.Current = new Bindable<string>(string.Empty);
|
||||||
|
|
||||||
|
current.BindValueChanged(dto =>
|
||||||
|
base.Current.Value = dto.NewValue.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"), true);
|
||||||
|
|
||||||
((OsuTextBox)Control).OnCommit += (sender, _) =>
|
((OsuTextBox)Control).OnCommit += (sender, _) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -56,7 +56,7 @@ namespace osu.Game.Tournament.Components
|
|||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = Color4.Black,
|
Colour = Color4.Black,
|
||||||
},
|
},
|
||||||
new UpdateableOnlineBeatmapSetCover
|
new NoUnloadBeatmapSetCover
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = OsuColour.Gray(0.5f),
|
Colour = OsuColour.Gray(0.5f),
|
||||||
@ -180,5 +180,15 @@ namespace osu.Game.Tournament.Components
|
|||||||
Alpha = 1;
|
Alpha = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private partial class NoUnloadBeatmapSetCover : UpdateableOnlineBeatmapSetCover
|
||||||
|
{
|
||||||
|
// As covers are displayed on stream, we want them to load as soon as possible.
|
||||||
|
protected override double LoadDelay => 0;
|
||||||
|
|
||||||
|
// Use DelayedLoadWrapper to avoid content unloading when switching away to another screen.
|
||||||
|
protected override DelayedLoadWrapper CreateDelayedLoadWrapper(Func<Drawable> createContentFunc, double timeBeforeLoad)
|
||||||
|
=> new DelayedLoadWrapper(createContentFunc, timeBeforeLoad);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
@ -43,6 +45,6 @@ namespace osu.Game.Tournament.IO
|
|||||||
Logger.Log("Changing tournament storage: " + GetFullPath(string.Empty));
|
Logger.Log("Changing tournament storage: " + GetFullPath(string.Empty));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<string> ListTournaments() => AllTournaments.GetDirectories(string.Empty);
|
public IEnumerable<string> ListTournaments() => AllTournaments.GetDirectories(string.Empty).OrderBy(directory => directory, StringComparer.CurrentCultureIgnoreCase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,11 @@ namespace osu.Game.Tournament
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
InternalChild = new Container
|
InternalChild = new CircularContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomRight,
|
Anchor = Anchor.BottomRight,
|
||||||
Origin = Anchor.BottomRight,
|
Origin = Anchor.BottomRight,
|
||||||
Position = new Vector2(5),
|
Position = new Vector2(-5),
|
||||||
CornerRadius = 10,
|
|
||||||
Masking = true,
|
Masking = true,
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
@ -43,18 +42,10 @@ namespace osu.Game.Tournament
|
|||||||
saveChangesButton = new TourneyButton
|
saveChangesButton = new TourneyButton
|
||||||
{
|
{
|
||||||
Text = "Save Changes",
|
Text = "Save Changes",
|
||||||
|
RelativeSizeAxes = Axes.None,
|
||||||
Width = 140,
|
Width = 140,
|
||||||
Height = 50,
|
Height = 50,
|
||||||
Padding = new MarginPadding
|
Margin = new MarginPadding(10),
|
||||||
{
|
|
||||||
Top = 10,
|
|
||||||
Left = 10,
|
|
||||||
},
|
|
||||||
Margin = new MarginPadding
|
|
||||||
{
|
|
||||||
Right = 10,
|
|
||||||
Bottom = 10,
|
|
||||||
},
|
|
||||||
Action = saveChanges,
|
Action = saveChanges,
|
||||||
// Enabled = { Value = false },
|
// Enabled = { Value = false },
|
||||||
},
|
},
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
// 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.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays.Dialog;
|
||||||
|
using osu.Game.Tournament.Models;
|
||||||
|
|
||||||
|
namespace osu.Game.Tournament.Screens.Editors.Components
|
||||||
|
{
|
||||||
|
public partial class DeleteRoundDialog : DangerousActionDialog
|
||||||
|
{
|
||||||
|
public DeleteRoundDialog(TournamentRound round, Action action)
|
||||||
|
{
|
||||||
|
HeaderText = round.Name.Value.Length > 0 ? $@"Delete round ""{round.Name.Value}""?" : @"Delete unnamed round?";
|
||||||
|
Icon = FontAwesome.Solid.Trash;
|
||||||
|
DangerousAction = action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +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;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays.Dialog;
|
||||||
|
using osu.Game.Tournament.Models;
|
||||||
|
|
||||||
|
namespace osu.Game.Tournament.Screens.Editors.Components
|
||||||
|
{
|
||||||
|
public partial class DeleteTeamDialog : DangerousActionDialog
|
||||||
|
{
|
||||||
|
public DeleteTeamDialog(TournamentTeam team, Action action)
|
||||||
|
{
|
||||||
|
HeaderText = team.FullName.Value.Length > 0 ? $@"Delete team ""{team.FullName.Value}""?" :
|
||||||
|
team.Acronym.Value.Length > 0 ? $@"Delete team ""{team.Acronym.Value}""?" :
|
||||||
|
@"Delete unnamed team?";
|
||||||
|
Icon = FontAwesome.Solid.Trash;
|
||||||
|
DangerousAction = action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
// 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.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays.Dialog;
|
||||||
|
|
||||||
|
namespace osu.Game.Tournament.Screens.Editors.Components
|
||||||
|
{
|
||||||
|
public partial class LadderResetTeamsDialog : DangerousActionDialog
|
||||||
|
{
|
||||||
|
public LadderResetTeamsDialog(Action action)
|
||||||
|
{
|
||||||
|
HeaderText = @"Reset teams?";
|
||||||
|
Icon = FontAwesome.Solid.Undo;
|
||||||
|
DangerousAction = action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
// 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.Graphics.Sprites;
|
||||||
|
using osu.Game.Overlays.Dialog;
|
||||||
|
|
||||||
|
namespace osu.Game.Tournament.Screens.Editors.Components
|
||||||
|
{
|
||||||
|
public partial class TournamentClearAllDialog : DangerousActionDialog
|
||||||
|
{
|
||||||
|
public TournamentClearAllDialog(Action action)
|
||||||
|
{
|
||||||
|
HeaderText = @"Clear all?";
|
||||||
|
Icon = FontAwesome.Solid.Trash;
|
||||||
|
DangerousAction = action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using JetBrains.Annotations;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -14,7 +15,11 @@ using osu.Framework.Graphics.UserInterface;
|
|||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Input.States;
|
using osu.Framework.Input.States;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
using osu.Game.Tournament.Components;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Tournament.Models;
|
using osu.Game.Tournament.Models;
|
||||||
|
using osu.Game.Tournament.Screens.Editors.Components;
|
||||||
using osu.Game.Tournament.Screens.Ladder;
|
using osu.Game.Tournament.Screens.Ladder;
|
||||||
using osu.Game.Tournament.Screens.Ladder.Components;
|
using osu.Game.Tournament.Screens.Ladder.Components;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -25,25 +30,36 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
[Cached]
|
[Cached]
|
||||||
public partial class LadderEditorScreen : LadderScreen, IHasContextMenu
|
public partial class LadderEditorScreen : LadderScreen, IHasContextMenu
|
||||||
{
|
{
|
||||||
|
public const float GRID_SPACING = 10;
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
private LadderEditorInfo editorInfo = new LadderEditorInfo();
|
private LadderEditorInfo editorInfo = new LadderEditorInfo();
|
||||||
|
|
||||||
private WarningBox rightClickMessage;
|
private WarningBox rightClickMessage;
|
||||||
|
|
||||||
|
[Resolved(canBeNull: true)]
|
||||||
|
[CanBeNull]
|
||||||
|
private IDialogOverlay dialogOverlay { get; set; }
|
||||||
|
|
||||||
protected override bool DrawLoserPaths => true;
|
protected override bool DrawLoserPaths => true;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Content.Add(new LadderEditorSettings
|
AddInternal(new ControlPanel
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Child = new LadderEditorSettings(),
|
||||||
Origin = Anchor.TopRight,
|
|
||||||
Margin = new MarginPadding(5)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
AddInternal(rightClickMessage = new WarningBox("Right click to place and link matches"));
|
AddInternal(rightClickMessage = new WarningBox("Right click to place and link matches"));
|
||||||
|
|
||||||
|
ScrollContent.Add(new RectangularPositionSnapGrid(Vector2.Zero)
|
||||||
|
{
|
||||||
|
Spacing = new Vector2(GRID_SPACING),
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Depth = float.MaxValue
|
||||||
|
});
|
||||||
|
|
||||||
LadderInfo.Matches.CollectionChanged += (_, _) => updateMessage();
|
LadderInfo.Matches.CollectionChanged += (_, _) => updateMessage();
|
||||||
updateMessage();
|
updateMessage();
|
||||||
}
|
}
|
||||||
@ -69,13 +85,20 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
{
|
{
|
||||||
new OsuMenuItem("Create new match", MenuItemType.Highlighted, () =>
|
new OsuMenuItem("Create new match", MenuItemType.Highlighted, () =>
|
||||||
{
|
{
|
||||||
var pos = MatchesContainer.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position);
|
Vector2 pos = MatchesContainer.ToLocalSpace(GetContainingInputManager().CurrentState.Mouse.Position);
|
||||||
LadderInfo.Matches.Add(new TournamentMatch { Position = { Value = new Point((int)pos.X, (int)pos.Y) } });
|
TournamentMatch newMatch = new TournamentMatch { Position = { Value = new Point((int)pos.X, (int)pos.Y) } };
|
||||||
|
|
||||||
|
LadderInfo.Matches.Add(newMatch);
|
||||||
|
|
||||||
|
editorInfo.Selected.Value = newMatch;
|
||||||
}),
|
}),
|
||||||
new OsuMenuItem("Reset teams", MenuItemType.Destructive, () =>
|
new OsuMenuItem("Reset teams", MenuItemType.Destructive, () =>
|
||||||
{
|
{
|
||||||
foreach (var p in MatchesContainer)
|
dialogOverlay?.Push(new LadderResetTeamsDialog(() =>
|
||||||
p.Match.Reset();
|
{
|
||||||
|
foreach (var p in MatchesContainer)
|
||||||
|
p.Match.Reset();
|
||||||
|
}));
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,11 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Tournament.Components;
|
using osu.Game.Tournament.Components;
|
||||||
using osu.Game.Tournament.Models;
|
using osu.Game.Tournament.Models;
|
||||||
|
using osu.Game.Tournament.Screens.Editors.Components;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Tournament.Screens.Editors
|
namespace osu.Game.Tournament.Screens.Editors
|
||||||
@ -29,6 +31,9 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private LadderInfo ladderInfo { get; set; } = null!;
|
private LadderInfo ladderInfo { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IDialogOverlay? dialogOverlay { get; set; }
|
||||||
|
|
||||||
public RoundRow(TournamentRound round)
|
public RoundRow(TournamentRound round)
|
||||||
{
|
{
|
||||||
Model = round;
|
Model = round;
|
||||||
@ -99,11 +104,11 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
RelativeSizeAxes = Axes.None,
|
RelativeSizeAxes = Axes.None,
|
||||||
Width = 150,
|
Width = 150,
|
||||||
Text = "Delete Round",
|
Text = "Delete Round",
|
||||||
Action = () =>
|
Action = () => dialogOverlay?.Push(new DeleteRoundDialog(Model, () =>
|
||||||
{
|
{
|
||||||
Expire();
|
Expire();
|
||||||
ladderInfo.Rounds.Remove(Model);
|
ladderInfo.Rounds.Remove(Model);
|
||||||
},
|
}))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -11,10 +11,11 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Tournament.Components;
|
|
||||||
using osu.Game.Tournament.Models;
|
using osu.Game.Tournament.Models;
|
||||||
|
using osu.Game.Tournament.Screens.Editors.Components;
|
||||||
|
using osu.Game.Tournament.Screens.Drawings.Components;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -59,11 +60,12 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
{
|
{
|
||||||
public TournamentTeam Model { get; }
|
public TournamentTeam Model { get; }
|
||||||
|
|
||||||
private readonly Container drawableContainer;
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private TournamentSceneManager? sceneManager { get; set; }
|
private TournamentSceneManager? sceneManager { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IDialogOverlay? dialogOverlay { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private LadderInfo ladderInfo { get; set; } = null!;
|
private LadderInfo ladderInfo { get; set; } = null!;
|
||||||
|
|
||||||
@ -74,10 +76,10 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
Masking = true;
|
Masking = true;
|
||||||
CornerRadius = 10;
|
CornerRadius = 10;
|
||||||
|
|
||||||
PlayerEditor playerEditor = new PlayerEditor(Model)
|
RelativeSizeAxes = Axes.X;
|
||||||
{
|
AutoSizeAxes = Axes.Y;
|
||||||
Width = 0.95f
|
|
||||||
};
|
PlayerEditor playerEditor = new PlayerEditor(Model);
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -86,17 +88,17 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
Colour = OsuColour.Gray(0.1f),
|
Colour = OsuColour.Gray(0.1f),
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
drawableContainer = new Container
|
new GroupTeam(team)
|
||||||
{
|
{
|
||||||
Size = new Vector2(100, 50),
|
Margin = new MarginPadding(16),
|
||||||
Margin = new MarginPadding(10),
|
Scale = new Vector2(2),
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding(5),
|
|
||||||
Spacing = new Vector2(5),
|
Spacing = new Vector2(5),
|
||||||
|
Padding = new MarginPadding(10),
|
||||||
Direction = FillDirection.Full,
|
Direction = FillDirection.Full,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
@ -133,25 +135,6 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
Current = Model.LastYearPlacing
|
Current = Model.LastYearPlacing
|
||||||
},
|
},
|
||||||
new SettingsButton
|
new SettingsButton
|
||||||
{
|
|
||||||
Width = 0.11f,
|
|
||||||
Margin = new MarginPadding(10),
|
|
||||||
Text = "Add player",
|
|
||||||
Action = () => playerEditor.CreateNew()
|
|
||||||
},
|
|
||||||
new DangerousSettingsButton
|
|
||||||
{
|
|
||||||
Width = 0.11f,
|
|
||||||
Text = "Delete Team",
|
|
||||||
Margin = new MarginPadding(10),
|
|
||||||
Action = () =>
|
|
||||||
{
|
|
||||||
Expire();
|
|
||||||
ladderInfo.Teams.Remove(Model);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
playerEditor,
|
|
||||||
new SettingsButton
|
|
||||||
{
|
{
|
||||||
Width = 0.2f,
|
Width = 0.2f,
|
||||||
Margin = new MarginPadding(10),
|
Margin = new MarginPadding(10),
|
||||||
@ -161,19 +144,35 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
sceneManager?.SetScreen(new SeedingEditorScreen(team, parent));
|
sceneManager?.SetScreen(new SeedingEditorScreen(team, parent));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
playerEditor,
|
||||||
|
new SettingsButton
|
||||||
|
{
|
||||||
|
Text = "Add player",
|
||||||
|
Action = () => playerEditor.CreateNew()
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new DangerousSettingsButton
|
||||||
|
{
|
||||||
|
Width = 0.2f,
|
||||||
|
Text = "Delete Team",
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Action = () => dialogOverlay?.Push(new DeleteTeamDialog(Model, () =>
|
||||||
|
{
|
||||||
|
Expire();
|
||||||
|
ladderInfo.Teams.Remove(Model);
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
|
||||||
AutoSizeAxes = Axes.Y;
|
|
||||||
|
|
||||||
Model.FlagName.BindValueChanged(updateDrawable, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateDrawable(ValueChangedEvent<string> flag)
|
|
||||||
{
|
|
||||||
drawableContainer.Child = new DrawableTeamFlag(Model);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class PlayerEditor : CompositeDrawable
|
public partial class PlayerEditor : CompositeDrawable
|
||||||
@ -193,6 +192,8 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
|
Padding = new MarginPadding(5),
|
||||||
|
Spacing = new Vector2(5),
|
||||||
ChildrenEnumerable = team.Players.Select(p => new PlayerRow(team, p))
|
ChildrenEnumerable = team.Players.Select(p => new PlayerRow(team, p))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -208,27 +209,22 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
{
|
{
|
||||||
private readonly TournamentUser user;
|
private readonly TournamentUser user;
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
protected IAPIProvider API { get; private set; } = null!;
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private TournamentGameBase game { get; set; } = null!;
|
private TournamentGameBase game { get; set; } = null!;
|
||||||
|
|
||||||
private readonly Bindable<int?> playerId = new Bindable<int?>();
|
private readonly Bindable<int?> playerId = new Bindable<int?>();
|
||||||
|
|
||||||
private readonly Container drawableContainer;
|
private readonly Container userPanelContainer;
|
||||||
|
|
||||||
public PlayerRow(TournamentTeam team, TournamentUser user)
|
public PlayerRow(TournamentTeam team, TournamentUser user)
|
||||||
{
|
{
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
|
||||||
Margin = new MarginPadding(10);
|
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
Masking = true;
|
Masking = true;
|
||||||
CornerRadius = 5;
|
CornerRadius = 10;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -240,10 +236,11 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding(5),
|
Margin = new MarginPadding(5),
|
||||||
Padding = new MarginPadding { Right = 160 },
|
Padding = new MarginPadding { Right = 60 },
|
||||||
Spacing = new Vector2(5),
|
Spacing = new Vector2(5),
|
||||||
Direction = FillDirection.Horizontal,
|
Direction = FillDirection.Horizontal,
|
||||||
AutoSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new SettingsNumberBox
|
new SettingsNumberBox
|
||||||
@ -253,9 +250,10 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
Width = 200,
|
Width = 200,
|
||||||
Current = playerId,
|
Current = playerId,
|
||||||
},
|
},
|
||||||
drawableContainer = new Container
|
userPanelContainer = new Container
|
||||||
{
|
{
|
||||||
Size = new Vector2(100, 70),
|
Width = 400,
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -298,7 +296,12 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
|
|
||||||
private void updatePanel() => Scheduler.AddOnce(() =>
|
private void updatePanel() => Scheduler.AddOnce(() =>
|
||||||
{
|
{
|
||||||
drawableContainer.Child = new UserGridPanel(user.ToAPIUser()) { Width = 300 };
|
userPanelContainer.Child = new UserListPanel(user.ToAPIUser())
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
Scale = new Vector2(1f),
|
||||||
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -15,8 +13,9 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Tournament.Components;
|
using osu.Game.Tournament.Components;
|
||||||
|
using osu.Game.Tournament.Screens.Editors.Components;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Tournament.Screens.Editors
|
namespace osu.Game.Tournament.Screens.Editors
|
||||||
@ -27,23 +26,27 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
{
|
{
|
||||||
protected abstract BindableList<TModel> Storage { get; }
|
protected abstract BindableList<TModel> Storage { get; }
|
||||||
|
|
||||||
private FillFlowContainer<TDrawable> flow;
|
[Resolved]
|
||||||
|
private IDialogOverlay? dialogOverlay { get; set; }
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
private FillFlowContainer<TDrawable> flow = null!;
|
||||||
private TournamentSceneManager sceneManager { get; set; }
|
|
||||||
|
|
||||||
protected ControlPanel ControlPanel;
|
[Resolved]
|
||||||
|
private TournamentSceneManager? sceneManager { get; set; }
|
||||||
|
|
||||||
private readonly TournamentScreen parentScreen;
|
protected ControlPanel ControlPanel = null!;
|
||||||
private BackButton backButton;
|
|
||||||
|
|
||||||
protected TournamentEditorScreen(TournamentScreen parentScreen = null)
|
private readonly TournamentScreen? parentScreen;
|
||||||
|
|
||||||
|
private BackButton backButton = null!;
|
||||||
|
|
||||||
|
protected TournamentEditorScreen(TournamentScreen? parentScreen = null)
|
||||||
{
|
{
|
||||||
this.parentScreen = parentScreen;
|
this.parentScreen = parentScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
AddRangeInternal(new Drawable[]
|
AddRangeInternal(new Drawable[]
|
||||||
{
|
{
|
||||||
@ -63,6 +66,7 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Spacing = new Vector2(20),
|
Spacing = new Vector2(20),
|
||||||
|
Padding = new MarginPadding(20),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ControlPanel = new ControlPanel
|
ControlPanel = new ControlPanel
|
||||||
@ -75,11 +79,15 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
Text = "Add new",
|
Text = "Add new",
|
||||||
Action = () => Storage.Add(new TModel())
|
Action = () => Storage.Add(new TModel())
|
||||||
},
|
},
|
||||||
new DangerousSettingsButton
|
new TourneyButton
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
BackgroundColour = colours.Pink3,
|
||||||
Text = "Clear all",
|
Text = "Clear all",
|
||||||
Action = Storage.Clear
|
Action = () =>
|
||||||
|
{
|
||||||
|
dialogOverlay?.Push(new TournamentClearAllDialog(() => Storage.Clear()));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
|
|||||||
private readonly MatchScoreCounter score1Text;
|
private readonly MatchScoreCounter score1Text;
|
||||||
private readonly MatchScoreCounter score2Text;
|
private readonly MatchScoreCounter score2Text;
|
||||||
|
|
||||||
|
private readonly MatchScoreDiffCounter scoreDiffText;
|
||||||
|
|
||||||
private readonly Drawable score1Bar;
|
private readonly Drawable score1Bar;
|
||||||
private readonly Drawable score2Bar;
|
private readonly Drawable score2Bar;
|
||||||
|
|
||||||
@ -88,6 +90,16 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
|
|||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.TopCentre
|
Origin = Anchor.TopCentre
|
||||||
},
|
},
|
||||||
|
scoreDiffText = new MatchScoreDiffCounter
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Margin = new MarginPadding
|
||||||
|
{
|
||||||
|
Top = bar_height / 4,
|
||||||
|
Horizontal = 8
|
||||||
|
},
|
||||||
|
Alpha = 0
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +131,10 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
|
|||||||
|
|
||||||
losingBar.ResizeWidthTo(0, 400, Easing.OutQuint);
|
losingBar.ResizeWidthTo(0, 400, Easing.OutQuint);
|
||||||
winningBar.ResizeWidthTo(Math.Min(0.4f, MathF.Pow(diff / 1500000f, 0.5f) / 2), 400, Easing.OutQuint);
|
winningBar.ResizeWidthTo(Math.Min(0.4f, MathF.Pow(diff / 1500000f, 0.5f) / 2), 400, Easing.OutQuint);
|
||||||
|
|
||||||
|
scoreDiffText.Alpha = diff != 0 ? 1 : 0;
|
||||||
|
scoreDiffText.Current.Value = -diff;
|
||||||
|
scoreDiffText.Origin = score1.Value > score2.Value ? Anchor.TopLeft : Anchor.TopRight;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
protected override void UpdateAfterChildren()
|
||||||
@ -154,5 +170,14 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
|
|||||||
? OsuFont.Torus.With(weight: FontWeight.Bold, size: 50, fixedWidth: true)
|
? OsuFont.Torus.With(weight: FontWeight.Bold, size: 50, fixedWidth: true)
|
||||||
: OsuFont.Torus.With(weight: FontWeight.Regular, size: 40, fixedWidth: true);
|
: OsuFont.Torus.With(weight: FontWeight.Regular, size: 40, fixedWidth: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private partial class MatchScoreDiffCounter : CommaSeparatedScoreCounter
|
||||||
|
{
|
||||||
|
protected override OsuSpriteText CreateSpriteText() => base.CreateSpriteText().With(s =>
|
||||||
|
{
|
||||||
|
s.Spacing = new Vector2(-2);
|
||||||
|
s.Font = OsuFont.Torus.With(weight: FontWeight.Regular, size: bar_height, fixedWidth: true);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -139,7 +139,7 @@ namespace osu.Game.Tournament.Screens.Gameplay
|
|||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
State.BindTo(ipc.State);
|
State.BindTo(ipc.State);
|
||||||
State.BindValueChanged(stateChanged, true);
|
State.BindValueChanged(_ => updateState(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void CurrentMatchChanged(ValueChangedEvent<TournamentMatch> match)
|
protected override void CurrentMatchChanged(ValueChangedEvent<TournamentMatch> match)
|
||||||
@ -150,20 +150,47 @@ namespace osu.Game.Tournament.Screens.Gameplay
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
warmup.Value = match.NewValue.Team1Score.Value + match.NewValue.Team2Score.Value == 0;
|
warmup.Value = match.NewValue.Team1Score.Value + match.NewValue.Team2Score.Value == 0;
|
||||||
scheduledOperation?.Cancel();
|
scheduledScreenChange?.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScheduledDelegate scheduledOperation;
|
private ScheduledDelegate scheduledScreenChange;
|
||||||
|
private ScheduledDelegate scheduledContract;
|
||||||
|
|
||||||
private TournamentMatchScoreDisplay scoreDisplay;
|
private TournamentMatchScoreDisplay scoreDisplay;
|
||||||
|
|
||||||
private TourneyState lastState;
|
private TourneyState lastState;
|
||||||
private MatchHeader header;
|
private MatchHeader header;
|
||||||
|
|
||||||
private void stateChanged(ValueChangedEvent<TourneyState> state)
|
private void contract()
|
||||||
|
{
|
||||||
|
scheduledContract?.Cancel();
|
||||||
|
|
||||||
|
SongBar.Expanded = false;
|
||||||
|
scoreDisplay.FadeOut(100);
|
||||||
|
using (chat?.BeginDelayedSequence(500))
|
||||||
|
chat?.Expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void expand()
|
||||||
|
{
|
||||||
|
scheduledContract?.Cancel();
|
||||||
|
|
||||||
|
chat?.Contract();
|
||||||
|
|
||||||
|
using (BeginDelayedSequence(300))
|
||||||
|
{
|
||||||
|
scoreDisplay.FadeIn(100);
|
||||||
|
SongBar.Expanded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (state.NewValue == TourneyState.Ranking)
|
scheduledScreenChange?.Cancel();
|
||||||
|
|
||||||
|
if (State.Value == TourneyState.Ranking)
|
||||||
{
|
{
|
||||||
if (warmup.Value || CurrentMatch.Value == null) return;
|
if (warmup.Value || CurrentMatch.Value == null) return;
|
||||||
|
|
||||||
@ -173,28 +200,7 @@ namespace osu.Game.Tournament.Screens.Gameplay
|
|||||||
CurrentMatch.Value.Team2Score.Value++;
|
CurrentMatch.Value.Team2Score.Value++;
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduledOperation?.Cancel();
|
switch (State.Value)
|
||||||
|
|
||||||
void expand()
|
|
||||||
{
|
|
||||||
chat?.Contract();
|
|
||||||
|
|
||||||
using (BeginDelayedSequence(300))
|
|
||||||
{
|
|
||||||
scoreDisplay.FadeIn(100);
|
|
||||||
SongBar.Expanded = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void contract()
|
|
||||||
{
|
|
||||||
SongBar.Expanded = false;
|
|
||||||
scoreDisplay.FadeOut(100);
|
|
||||||
using (chat?.BeginDelayedSequence(500))
|
|
||||||
chat?.Expand();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (state.NewValue)
|
|
||||||
{
|
{
|
||||||
case TourneyState.Idle:
|
case TourneyState.Idle:
|
||||||
contract();
|
contract();
|
||||||
@ -208,30 +214,41 @@ namespace osu.Game.Tournament.Screens.Gameplay
|
|||||||
if (lastState == TourneyState.Ranking && !warmup.Value)
|
if (lastState == TourneyState.Ranking && !warmup.Value)
|
||||||
{
|
{
|
||||||
if (CurrentMatch.Value?.Completed.Value == true)
|
if (CurrentMatch.Value?.Completed.Value == true)
|
||||||
scheduledOperation = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(TeamWinScreen)); }, delay_before_progression);
|
scheduledScreenChange = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(TeamWinScreen)); }, delay_before_progression);
|
||||||
else if (CurrentMatch.Value?.Completed.Value == false)
|
else if (CurrentMatch.Value?.Completed.Value == false)
|
||||||
scheduledOperation = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(MapPoolScreen)); }, delay_before_progression);
|
scheduledScreenChange = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(MapPoolScreen)); }, delay_before_progression);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TourneyState.Ranking:
|
case TourneyState.Ranking:
|
||||||
scheduledOperation = Scheduler.AddDelayed(contract, 10000);
|
scheduledContract = Scheduler.AddDelayed(contract, 10000);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
chat.Contract();
|
|
||||||
expand();
|
expand();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
lastState = state.NewValue;
|
lastState = State.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Hide()
|
||||||
|
{
|
||||||
|
scheduledScreenChange?.Cancel();
|
||||||
|
base.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Show()
|
||||||
|
{
|
||||||
|
updateState();
|
||||||
|
base.Show();
|
||||||
|
}
|
||||||
|
|
||||||
private partial class ChromaArea : CompositeDrawable
|
private partial class ChromaArea : CompositeDrawable
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
|
@ -13,6 +13,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Tournament.Models;
|
using osu.Game.Tournament.Models;
|
||||||
|
using osu.Game.Tournament.Screens.Editors;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -25,7 +26,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
private readonly bool editor;
|
private readonly bool editor;
|
||||||
protected readonly FillFlowContainer<DrawableMatchTeam> Flow;
|
protected readonly FillFlowContainer<DrawableMatchTeam> Flow;
|
||||||
private readonly Drawable selectionBox;
|
private readonly Drawable selectionBox;
|
||||||
protected readonly Drawable CurrentMatchSelectionBox;
|
private readonly Drawable currentMatchSelectionBox;
|
||||||
private Bindable<TournamentMatch> globalSelection;
|
private Bindable<TournamentMatch> globalSelection;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
@ -41,35 +42,60 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
|
|
||||||
AutoSizeAxes = Axes.Both;
|
AutoSizeAxes = Axes.Both;
|
||||||
|
|
||||||
Margin = new MarginPadding(5);
|
const float border_thickness = 5;
|
||||||
|
const float spacing = 2;
|
||||||
|
|
||||||
InternalChildren = new[]
|
Margin = new MarginPadding(10);
|
||||||
|
|
||||||
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
selectionBox = new Container
|
|
||||||
{
|
|
||||||
Scale = new Vector2(1.1f),
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Alpha = 0,
|
|
||||||
Colour = Color4.YellowGreen,
|
|
||||||
Child = new Box { RelativeSizeAxes = Axes.Both }
|
|
||||||
},
|
|
||||||
CurrentMatchSelectionBox = new Container
|
|
||||||
{
|
|
||||||
Scale = new Vector2(1.05f, 1.1f),
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
Alpha = 0,
|
|
||||||
Colour = Color4.White,
|
|
||||||
Child = new Box { RelativeSizeAxes = Axes.Both }
|
|
||||||
},
|
|
||||||
Flow = new FillFlowContainer<DrawableMatchTeam>
|
Flow = new FillFlowContainer<DrawableMatchTeam>
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Both,
|
AutoSizeAxes = Axes.Both,
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(2)
|
Spacing = new Vector2(spacing)
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding(-10),
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Child = selectionBox = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
Masking = true,
|
||||||
|
BorderColour = Color4.YellowGreen,
|
||||||
|
BorderThickness = border_thickness,
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
AlwaysPresent = true,
|
||||||
|
Alpha = 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding(-(spacing + border_thickness)),
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Child = currentMatchSelectionBox = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Alpha = 0,
|
||||||
|
BorderColour = Color4.White,
|
||||||
|
BorderThickness = border_thickness,
|
||||||
|
Masking = true,
|
||||||
|
Child = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
AlwaysPresent = true,
|
||||||
|
Alpha = 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -97,12 +123,11 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
Position = new Vector2(pos.NewValue.X, pos.NewValue.Y);
|
Position = new Vector2(pos.NewValue.X, pos.NewValue.Y);
|
||||||
Changed?.Invoke();
|
Changed?.Invoke();
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
updateTeams();
|
updateTeams();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when somethign changed that requires a ladder redraw.
|
/// Fired when something changed that requires a ladder redraw.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Action Changed;
|
public Action Changed;
|
||||||
|
|
||||||
@ -126,9 +151,9 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
private void updateCurrentMatch()
|
private void updateCurrentMatch()
|
||||||
{
|
{
|
||||||
if (Match.Current.Value)
|
if (Match.Current.Value)
|
||||||
CurrentMatchSelectionBox.Show();
|
currentMatchSelectionBox.Show();
|
||||||
else
|
else
|
||||||
CurrentMatchSelectionBox.Hide();
|
currentMatchSelectionBox.Hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool selected;
|
private bool selected;
|
||||||
@ -213,7 +238,8 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
int instantWinAmount = Match.Round.Value.BestOf.Value / 2;
|
int instantWinAmount = Match.Round.Value.BestOf.Value / 2;
|
||||||
|
|
||||||
Match.Completed.Value = Match.Round.Value.BestOf.Value > 0
|
Match.Completed.Value = Match.Round.Value.BestOf.Value > 0
|
||||||
&& (Match.Team1Score.Value + Match.Team2Score.Value >= Match.Round.Value.BestOf.Value || Match.Team1Score.Value > instantWinAmount || Match.Team2Score.Value > instantWinAmount);
|
&& (Match.Team1Score.Value + Match.Team2Score.Value >= Match.Round.Value.BestOf.Value || Match.Team1Score.Value > instantWinAmount
|
||||||
|
|| Match.Team2Score.Value > instantWinAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -224,10 +250,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
if (editorInfo != null)
|
if (editorInfo != null)
|
||||||
{
|
{
|
||||||
globalSelection = editorInfo.Selected.GetBoundCopy();
|
globalSelection = editorInfo.Selected.GetBoundCopy();
|
||||||
globalSelection.BindValueChanged(s =>
|
globalSelection.BindValueChanged(s => Selected = s.NewValue == Match, true);
|
||||||
{
|
|
||||||
if (s.NewValue != Match) Selected = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,8 +288,6 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
|
|
||||||
protected override bool OnMouseDown(MouseDownEvent e) => e.Button == MouseButton.Left && editorInfo != null;
|
protected override bool OnMouseDown(MouseDownEvent e) => e.Button == MouseButton.Left && editorInfo != null;
|
||||||
|
|
||||||
protected override bool OnDragStart(DragStartEvent e) => editorInfo != null;
|
|
||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
{
|
{
|
||||||
if (Selected && editorInfo != null && e.Key == Key.Delete)
|
if (Selected && editorInfo != null && e.Key == Key.Delete)
|
||||||
@ -287,17 +308,36 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Vector2 positionAtStartOfDrag;
|
||||||
|
|
||||||
|
protected override bool OnDragStart(DragStartEvent e)
|
||||||
|
{
|
||||||
|
if (editorInfo != null)
|
||||||
|
{
|
||||||
|
positionAtStartOfDrag = Position;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnDrag(DragEvent e)
|
protected override void OnDrag(DragEvent e)
|
||||||
{
|
{
|
||||||
base.OnDrag(e);
|
base.OnDrag(e);
|
||||||
|
|
||||||
Selected = true;
|
Selected = true;
|
||||||
this.MoveToOffset(e.Delta);
|
|
||||||
|
|
||||||
var pos = Position;
|
this.MoveTo(snapToGrid(positionAtStartOfDrag + (e.MousePosition - e.MouseDownPosition)));
|
||||||
Match.Position.Value = new Point((int)pos.X, (int)pos.Y);
|
|
||||||
|
Match.Position.Value = new Point((int)Position.X, (int)Position.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Vector2 snapToGrid(Vector2 pos) =>
|
||||||
|
new Vector2(
|
||||||
|
(int)(pos.X / LadderEditorScreen.GRID_SPACING) * LadderEditorScreen.GRID_SPACING,
|
||||||
|
(int)(pos.Y / LadderEditorScreen.GRID_SPACING) * LadderEditorScreen.GRID_SPACING
|
||||||
|
);
|
||||||
|
|
||||||
public void Remove()
|
public void Remove()
|
||||||
{
|
{
|
||||||
Selected = false;
|
Selected = false;
|
||||||
|
@ -11,15 +11,17 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Screens.Play.PlayerSettings;
|
using osu.Game.Screens.Play.PlayerSettings;
|
||||||
using osu.Game.Tournament.Components;
|
using osu.Game.Tournament.Components;
|
||||||
using osu.Game.Tournament.Models;
|
using osu.Game.Tournament.Models;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Tournament.Screens.Ladder.Components
|
namespace osu.Game.Tournament.Screens.Ladder.Components
|
||||||
{
|
{
|
||||||
public partial class LadderEditorSettings : PlayerSettingsGroup
|
public partial class LadderEditorSettings : CompositeDrawable
|
||||||
{
|
{
|
||||||
private SettingsDropdown<TournamentRound> roundDropdown;
|
private SettingsDropdown<TournamentRound> roundDropdown;
|
||||||
private PlayerCheckbox losersCheckbox;
|
private PlayerCheckbox losersCheckbox;
|
||||||
@ -33,21 +35,26 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private LadderInfo ladderInfo { get; set; }
|
private LadderInfo ladderInfo { get; set; }
|
||||||
|
|
||||||
public LadderEditorSettings()
|
|
||||||
: base("ladder")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
RelativeSizeAxes = Axes.X;
|
||||||
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
|
InternalChild = new FillFlowContainer
|
||||||
{
|
{
|
||||||
team1Dropdown = new SettingsTeamDropdown(ladderInfo.Teams) { LabelText = "Team 1" },
|
RelativeSizeAxes = Axes.X,
|
||||||
team2Dropdown = new SettingsTeamDropdown(ladderInfo.Teams) { LabelText = "Team 2" },
|
AutoSizeAxes = Axes.Y,
|
||||||
roundDropdown = new SettingsRoundDropdown(ladderInfo.Rounds) { LabelText = "Round" },
|
Direction = FillDirection.Vertical,
|
||||||
losersCheckbox = new PlayerCheckbox { LabelText = "Losers Bracket" },
|
Spacing = new Vector2(5),
|
||||||
dateTimeBox = new DateTextBox { LabelText = "Match Time" },
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
team1Dropdown = new SettingsTeamDropdown(ladderInfo.Teams) { LabelText = "Team 1" },
|
||||||
|
team2Dropdown = new SettingsTeamDropdown(ladderInfo.Teams) { LabelText = "Team 2" },
|
||||||
|
roundDropdown = new SettingsRoundDropdown(ladderInfo.Rounds) { LabelText = "Round" },
|
||||||
|
losersCheckbox = new PlayerCheckbox { LabelText = "Losers Bracket" },
|
||||||
|
dateTimeBox = new DateTextBox { LabelText = "Match Time" },
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
editorInfo.Selected.ValueChanged += selection =>
|
editorInfo.Selected.ValueChanged += selection =>
|
||||||
@ -55,22 +62,28 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
// ensure any ongoing edits are committed out to the *current* selection before changing to a new one.
|
// ensure any ongoing edits are committed out to the *current* selection before changing to a new one.
|
||||||
GetContainingInputManager().TriggerFocusContention(null);
|
GetContainingInputManager().TriggerFocusContention(null);
|
||||||
|
|
||||||
roundDropdown.Current = selection.NewValue?.Round;
|
// Required to avoid cyclic failure in BindableWithCurrent (TriggerChange called during the Current_Set process).
|
||||||
losersCheckbox.Current = selection.NewValue?.Losers;
|
// Arguable a framework issue but since we haven't hit it anywhere else a local workaround seems best.
|
||||||
dateTimeBox.Current = selection.NewValue?.Date;
|
roundDropdown.Current.ValueChanged -= roundDropdownChanged;
|
||||||
|
|
||||||
team1Dropdown.Current = selection.NewValue?.Team1;
|
roundDropdown.Current = selection.NewValue.Round;
|
||||||
team2Dropdown.Current = selection.NewValue?.Team2;
|
losersCheckbox.Current = selection.NewValue.Losers;
|
||||||
|
dateTimeBox.Current = selection.NewValue.Date;
|
||||||
|
|
||||||
|
team1Dropdown.Current = selection.NewValue.Team1;
|
||||||
|
team2Dropdown.Current = selection.NewValue.Team2;
|
||||||
|
|
||||||
|
roundDropdown.Current.ValueChanged += roundDropdownChanged;
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
roundDropdown.Current.ValueChanged += round =>
|
private void roundDropdownChanged(ValueChangedEvent<TournamentRound> round)
|
||||||
|
{
|
||||||
|
if (editorInfo.Selected.Value?.Date.Value < round.NewValue?.StartDate.Value)
|
||||||
{
|
{
|
||||||
if (editorInfo.Selected.Value?.Date.Value < round.NewValue?.StartDate.Value)
|
editorInfo.Selected.Value.Date.Value = round.NewValue.StartDate.Value;
|
||||||
{
|
editorInfo.Selected.TriggerChange();
|
||||||
editorInfo.Selected.Value.Date.Value = round.NewValue.StartDate.Value;
|
}
|
||||||
editorInfo.Selected.TriggerChange();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
|
@ -60,6 +60,7 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
|
|||||||
|
|
||||||
var topLeft = new Vector2(minX, minY);
|
var topLeft = new Vector2(minX, minY);
|
||||||
|
|
||||||
|
OriginPosition = new Vector2(PathRadius);
|
||||||
Position = Parent.ToLocalSpace(topLeft);
|
Position = Parent.ToLocalSpace(topLeft);
|
||||||
Vertices = points.Select(p => Parent.ToLocalSpace(p) - Parent.ToLocalSpace(topLeft)).ToList();
|
Vertices = points.Select(p => Parent.ToLocalSpace(p) - Parent.ToLocalSpace(topLeft)).ToList();
|
||||||
}
|
}
|
||||||
|
@ -36,8 +36,8 @@ namespace osu.Game.Tournament.Screens.Ladder
|
|||||||
{
|
{
|
||||||
float newScale = Math.Clamp(scale + e.ScrollDelta.Y / 15 * scale, min_scale, max_scale);
|
float newScale = Math.Clamp(scale + e.ScrollDelta.Y / 15 * scale, min_scale, max_scale);
|
||||||
|
|
||||||
this.MoveTo(target -= e.MousePosition * (newScale - scale), 2000, Easing.OutQuint);
|
this.MoveTo(target -= e.MousePosition * (newScale - scale), 1000, Easing.OutQuint);
|
||||||
this.ScaleTo(scale = newScale, 2000, Easing.OutQuint);
|
this.ScaleTo(scale = newScale, 1000, Easing.OutQuint);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,7 @@ namespace osu.Game.Tournament.Screens.Ladder
|
|||||||
InternalChild = Content = new Container
|
InternalChild = Content = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new TourneyVideo("ladder")
|
new TourneyVideo("ladder")
|
||||||
|
@ -37,6 +37,8 @@ namespace osu.Game.Tournament.Screens.MapPool
|
|||||||
private OsuButton buttonRedPick;
|
private OsuButton buttonRedPick;
|
||||||
private OsuButton buttonBluePick;
|
private OsuButton buttonBluePick;
|
||||||
|
|
||||||
|
private ScheduledDelegate scheduledScreenChange;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(MatchIPCInfo ipc)
|
private void load(MatchIPCInfo ipc)
|
||||||
{
|
{
|
||||||
@ -188,8 +190,6 @@ namespace osu.Game.Tournament.Screens.MapPool
|
|||||||
setNextMode();
|
setNextMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScheduledDelegate scheduledChange;
|
|
||||||
|
|
||||||
private void addForBeatmap(int beatmapId)
|
private void addForBeatmap(int beatmapId)
|
||||||
{
|
{
|
||||||
if (CurrentMatch.Value == null)
|
if (CurrentMatch.Value == null)
|
||||||
@ -216,12 +216,18 @@ namespace osu.Game.Tournament.Screens.MapPool
|
|||||||
{
|
{
|
||||||
if (pickType == ChoiceType.Pick && CurrentMatch.Value.PicksBans.Any(i => i.Type == ChoiceType.Pick))
|
if (pickType == ChoiceType.Pick && CurrentMatch.Value.PicksBans.Any(i => i.Type == ChoiceType.Pick))
|
||||||
{
|
{
|
||||||
scheduledChange?.Cancel();
|
scheduledScreenChange?.Cancel();
|
||||||
scheduledChange = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(GameplayScreen)); }, 10000);
|
scheduledScreenChange = Scheduler.AddDelayed(() => { sceneManager?.SetScreen(typeof(GameplayScreen)); }, 10000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Hide()
|
||||||
|
{
|
||||||
|
scheduledScreenChange?.Cancel();
|
||||||
|
base.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void CurrentMatchChanged(ValueChangedEvent<TournamentMatch> match)
|
protected override void CurrentMatchChanged(ValueChangedEvent<TournamentMatch> match)
|
||||||
{
|
{
|
||||||
base.CurrentMatchChanged(match);
|
base.CurrentMatchChanged(match);
|
||||||
|
@ -218,8 +218,6 @@ namespace osu.Game.Tournament.Screens.Schedule
|
|||||||
|
|
||||||
Scale = new Vector2(0.8f);
|
Scale = new Vector2(0.8f);
|
||||||
|
|
||||||
CurrentMatchSelectionBox.Scale = new Vector2(1.02f, 1.15f);
|
|
||||||
|
|
||||||
bool conditional = match is ConditionalTournamentMatch;
|
bool conditional = match is ConditionalTournamentMatch;
|
||||||
|
|
||||||
if (conditional)
|
if (conditional)
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -15,7 +13,15 @@ namespace osu.Game.Tournament.Screens.Setup
|
|||||||
{
|
{
|
||||||
internal partial class ActionableInfo : LabelledDrawable<Drawable>
|
internal partial class ActionableInfo : LabelledDrawable<Drawable>
|
||||||
{
|
{
|
||||||
protected OsuButton Button;
|
public const float BUTTON_SIZE = 120;
|
||||||
|
|
||||||
|
public Action? Action;
|
||||||
|
|
||||||
|
protected FillFlowContainer FlowContainer = null!;
|
||||||
|
|
||||||
|
protected OsuButton Button = null!;
|
||||||
|
|
||||||
|
private TournamentSpriteText valueText = null!;
|
||||||
|
|
||||||
public ActionableInfo()
|
public ActionableInfo()
|
||||||
: base(true)
|
: base(true)
|
||||||
@ -37,11 +43,6 @@ namespace osu.Game.Tournament.Screens.Setup
|
|||||||
set => valueText.Colour = value ? Color4.Red : Color4.White;
|
set => valueText.Colour = value ? Color4.Red : Color4.White;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action Action;
|
|
||||||
|
|
||||||
private TournamentSpriteText valueText;
|
|
||||||
protected FillFlowContainer FlowContainer;
|
|
||||||
|
|
||||||
protected override Drawable CreateComponent() => new Container
|
protected override Drawable CreateComponent() => new Container
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
@ -63,7 +64,7 @@ namespace osu.Game.Tournament.Screens.Setup
|
|||||||
{
|
{
|
||||||
Button = new RoundedButton
|
Button = new RoundedButton
|
||||||
{
|
{
|
||||||
Size = new Vector2(100, 40),
|
Size = new Vector2(BUTTON_SIZE, 40),
|
||||||
Action = () => Action?.Invoke()
|
Action = () => Action?.Invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -106,8 +106,8 @@ namespace osu.Game.Tournament.Screens.Setup
|
|||||||
|
|
||||||
loginOverlay.State.Value = Visibility.Visible;
|
loginOverlay.State.Value = Visibility.Visible;
|
||||||
},
|
},
|
||||||
Value = api?.LocalUser.Value.Username,
|
Value = api.LocalUser.Value.Username,
|
||||||
Failing = api?.IsLoggedIn != true,
|
Failing = api.IsLoggedIn != true,
|
||||||
Description = "In order to access the API and display metadata, signing in is required."
|
Description = "In order to access the API and display metadata, signing in is required."
|
||||||
},
|
},
|
||||||
new LabelledDropdown<RulesetInfo>
|
new LabelledDropdown<RulesetInfo>
|
||||||
|
@ -15,6 +15,7 @@ namespace osu.Game.Tournament.Screens.Setup
|
|||||||
{
|
{
|
||||||
private OsuDropdown<string> dropdown;
|
private OsuDropdown<string> dropdown;
|
||||||
private OsuButton folderButton;
|
private OsuButton folderButton;
|
||||||
|
private OsuButton reloadTournamentsButton;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private TournamentGameBase game { get; set; }
|
private TournamentGameBase game { get; set; }
|
||||||
@ -28,6 +29,8 @@ namespace osu.Game.Tournament.Screens.Setup
|
|||||||
dropdown.Items = storage.ListTournaments();
|
dropdown.Items = storage.ListTournaments();
|
||||||
dropdown.Current.BindValueChanged(v => Button.Enabled.Value = v.NewValue != startupTournament, true);
|
dropdown.Current.BindValueChanged(v => Button.Enabled.Value = v.NewValue != startupTournament, true);
|
||||||
|
|
||||||
|
reloadTournamentsButton.Action = () => dropdown.Items = storage.ListTournaments();
|
||||||
|
|
||||||
Action = () =>
|
Action = () =>
|
||||||
{
|
{
|
||||||
game.RestartAppWhenExited();
|
game.RestartAppWhenExited();
|
||||||
@ -45,10 +48,16 @@ namespace osu.Game.Tournament.Screens.Setup
|
|||||||
FlowContainer.Insert(-1, folderButton = new RoundedButton
|
FlowContainer.Insert(-1, folderButton = new RoundedButton
|
||||||
{
|
{
|
||||||
Text = "Open folder",
|
Text = "Open folder",
|
||||||
Width = 100
|
Width = BUTTON_SIZE
|
||||||
});
|
});
|
||||||
|
|
||||||
FlowContainer.Insert(-2, dropdown = new OsuDropdown<string>
|
FlowContainer.Insert(-2, reloadTournamentsButton = new RoundedButton
|
||||||
|
{
|
||||||
|
Text = "Refresh",
|
||||||
|
Width = BUTTON_SIZE
|
||||||
|
});
|
||||||
|
|
||||||
|
FlowContainer.Insert(-3, dropdown = new OsuDropdown<string>
|
||||||
{
|
{
|
||||||
Width = 510
|
Width = 510
|
||||||
});
|
});
|
||||||
|
@ -17,6 +17,7 @@ using osu.Framework.Platform;
|
|||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Tournament.Models;
|
using osu.Game.Tournament.Models;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
|
|
||||||
@ -35,14 +36,22 @@ namespace osu.Game.Tournament
|
|||||||
|
|
||||||
public static readonly Color4 TEXT_COLOUR = Color4Extensions.FromHex("#fff");
|
public static readonly Color4 TEXT_COLOUR = Color4Extensions.FromHex("#fff");
|
||||||
private Drawable heightWarning;
|
private Drawable heightWarning;
|
||||||
private Bindable<Size> windowSize;
|
|
||||||
private Bindable<WindowMode> windowMode;
|
private Bindable<WindowMode> windowMode;
|
||||||
|
private readonly BindableSize windowSize = new BindableSize();
|
||||||
|
|
||||||
private LoadingSpinner loadingSpinner;
|
private LoadingSpinner loadingSpinner;
|
||||||
|
|
||||||
|
[Cached(typeof(IDialogOverlay))]
|
||||||
|
private readonly DialogOverlay dialogOverlay = new DialogOverlay();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(FrameworkConfigManager frameworkConfig, GameHost host)
|
private void load(FrameworkConfigManager frameworkConfig, GameHost host)
|
||||||
{
|
{
|
||||||
windowSize = frameworkConfig.GetBindable<Size>(FrameworkSetting.WindowedSize);
|
frameworkConfig.BindWith(FrameworkSetting.WindowedSize, windowSize);
|
||||||
|
|
||||||
|
windowSize.MinValue = new Size(TournamentSceneManager.REQUIRED_WIDTH, TournamentSceneManager.STREAM_AREA_HEIGHT);
|
||||||
|
|
||||||
windowMode = frameworkConfig.GetBindable<WindowMode>(FrameworkSetting.WindowMode);
|
windowMode = frameworkConfig.GetBindable<WindowMode>(FrameworkSetting.WindowMode);
|
||||||
|
|
||||||
Add(loadingSpinner = new LoadingSpinner(true, true)
|
Add(loadingSpinner = new LoadingSpinner(true, true)
|
||||||
@ -90,12 +99,12 @@ namespace osu.Game.Tournament
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Child = new TournamentSceneManager()
|
Child = new TournamentSceneManager()
|
||||||
}
|
},
|
||||||
|
dialogOverlay
|
||||||
}, drawables =>
|
}, drawables =>
|
||||||
{
|
{
|
||||||
loadingSpinner.Hide();
|
loadingSpinner.Hide();
|
||||||
loadingSpinner.Expire();
|
loadingSpinner.Expire();
|
||||||
|
|
||||||
AddRange(drawables);
|
AddRange(drawables);
|
||||||
|
|
||||||
windowSize.BindValueChanged(size => ScheduleAfterChildren(() =>
|
windowSize.BindValueChanged(size => ScheduleAfterChildren(() =>
|
||||||
|
@ -38,11 +38,14 @@ namespace osu.Game.Tournament
|
|||||||
private Container screens;
|
private Container screens;
|
||||||
private TourneyVideo video;
|
private TourneyVideo video;
|
||||||
|
|
||||||
public const float CONTROL_AREA_WIDTH = 160;
|
public const int CONTROL_AREA_WIDTH = 200;
|
||||||
|
|
||||||
public const float STREAM_AREA_WIDTH = 1366;
|
public const int STREAM_AREA_WIDTH = 1366;
|
||||||
|
public const int STREAM_AREA_HEIGHT = (int)(STREAM_AREA_WIDTH / ASPECT_RATIO);
|
||||||
|
|
||||||
public const double REQUIRED_WIDTH = CONTROL_AREA_WIDTH * 2 + STREAM_AREA_WIDTH;
|
public const float ASPECT_RATIO = 16 / 9f;
|
||||||
|
|
||||||
|
public const int REQUIRED_WIDTH = CONTROL_AREA_WIDTH * 2 + STREAM_AREA_WIDTH;
|
||||||
|
|
||||||
[Cached]
|
[Cached]
|
||||||
private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay();
|
private TournamentMatchChatDisplay chat = new TournamentMatchChatDisplay();
|
||||||
@ -65,13 +68,20 @@ namespace osu.Game.Tournament
|
|||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
X = CONTROL_AREA_WIDTH,
|
X = CONTROL_AREA_WIDTH,
|
||||||
FillMode = FillMode.Fit,
|
FillMode = FillMode.Fit,
|
||||||
FillAspectRatio = 16 / 9f,
|
FillAspectRatio = ASPECT_RATIO,
|
||||||
Anchor = Anchor.TopLeft,
|
Anchor = Anchor.TopLeft,
|
||||||
Origin = Anchor.TopLeft,
|
Origin = Anchor.TopLeft,
|
||||||
Width = STREAM_AREA_WIDTH,
|
Width = STREAM_AREA_WIDTH,
|
||||||
//Masking = true,
|
//Masking = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Colour = new Color4(20, 20, 20, 255),
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Width = 10,
|
||||||
|
},
|
||||||
video = new TourneyVideo("main", true)
|
video = new TourneyVideo("main", true)
|
||||||
{
|
{
|
||||||
Loop = true,
|
Loop = true,
|
||||||
@ -252,14 +262,13 @@ namespace osu.Game.Tournament
|
|||||||
|
|
||||||
if (shortcutKey != null)
|
if (shortcutKey != null)
|
||||||
{
|
{
|
||||||
Add(new Container
|
Add(new CircularContainer
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
Size = new Vector2(24),
|
Size = new Vector2(24),
|
||||||
Margin = new MarginPadding(5),
|
Margin = new MarginPadding(5),
|
||||||
Masking = true,
|
Masking = true,
|
||||||
CornerRadius = 4,
|
|
||||||
Alpha = 0.5f,
|
Alpha = 0.5f,
|
||||||
Blending = BlendingParameters.Additive,
|
Blending = BlendingParameters.Additive,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
|
@ -1,18 +1,21 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Overlays.Settings;
|
||||||
|
|
||||||
namespace osu.Game.Tournament
|
namespace osu.Game.Tournament
|
||||||
{
|
{
|
||||||
public partial class TourneyButton : OsuButton
|
public partial class TourneyButton : SettingsButton
|
||||||
{
|
{
|
||||||
public new Box Background => base.Background;
|
public new Box Background => base.Background;
|
||||||
|
|
||||||
public TourneyButton()
|
[BackgroundDependencyLoader]
|
||||||
: base(null)
|
private void load()
|
||||||
{
|
{
|
||||||
|
Padding = new MarginPadding();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
@ -49,6 +50,9 @@ namespace osu.Game
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private INotificationOverlay? notificationOverlay { get; set; }
|
private INotificationOverlay? notificationOverlay { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private IAPIProvider api { get; set; } = null!;
|
||||||
|
|
||||||
protected virtual int TimeToSleepDuringGameplay => 30000;
|
protected virtual int TimeToSleepDuringGameplay => 30000;
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -118,10 +122,27 @@ namespace osu.Game
|
|||||||
|
|
||||||
realmAccess.Run(r =>
|
realmAccess.Run(r =>
|
||||||
{
|
{
|
||||||
foreach (var b in r.All<BeatmapInfo>().Where(b => b.StarRating < 0 || (b.OnlineID > 0 && b.LastOnlineUpdate == null)))
|
// BeatmapProcessor is responsible for both online and local processing.
|
||||||
|
// In the case a user isn't logged in, it won't update LastOnlineUpdate and therefore re-queue,
|
||||||
|
// causing overhead from the non-online processing to redundantly run every startup.
|
||||||
|
//
|
||||||
|
// We may eventually consider making the Process call more specific (or avoid this in any number
|
||||||
|
// of other possible ways), but for now avoid queueing if the user isn't logged in at startup.
|
||||||
|
if (api.IsLoggedIn)
|
||||||
{
|
{
|
||||||
Debug.Assert(b.BeatmapSet != null);
|
foreach (var b in r.All<BeatmapInfo>().Where(b => b.StarRating < 0 || (b.OnlineID > 0 && b.LastOnlineUpdate == null)))
|
||||||
beatmapSetIds.Add(b.BeatmapSet.ID);
|
{
|
||||||
|
Debug.Assert(b.BeatmapSet != null);
|
||||||
|
beatmapSetIds.Add(b.BeatmapSet.ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var b in r.All<BeatmapInfo>().Where(b => b.StarRating < 0))
|
||||||
|
{
|
||||||
|
Debug.Assert(b.BeatmapSet != null);
|
||||||
|
beatmapSetIds.Add(b.BeatmapSet.ID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ namespace osu.Game.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class BeatmapImporter : RealmArchiveModelImporter<BeatmapSetInfo>
|
public class BeatmapImporter : RealmArchiveModelImporter<BeatmapSetInfo>
|
||||||
{
|
{
|
||||||
public override IEnumerable<string> HandledExtensions => new[] { ".osz" };
|
public override IEnumerable<string> HandledExtensions => new[] { ".osz", ".olz" };
|
||||||
|
|
||||||
protected override string[] HashableFileTypes => new[] { ".osu" };
|
protected override string[] HashableFileTypes => new[] { ".osu" };
|
||||||
|
|
||||||
@ -145,7 +145,7 @@ namespace osu.Game.Beatmaps
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path).ToLowerInvariant() == ".osz";
|
protected override bool ShouldDeleteArchive(string path) => HandledExtensions.Contains(Path.GetExtension(path).ToLowerInvariant());
|
||||||
|
|
||||||
protected override void Populate(BeatmapSetInfo beatmapSet, ArchiveReader? archive, Realm realm, CancellationToken cancellationToken = default)
|
protected override void Populate(BeatmapSetInfo beatmapSet, ArchiveReader? archive, Realm realm, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,9 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
private readonly WorkingBeatmapCache workingBeatmapCache;
|
private readonly WorkingBeatmapCache workingBeatmapCache;
|
||||||
|
|
||||||
private readonly LegacyBeatmapExporter beatmapExporter;
|
private readonly BeatmapExporter beatmapExporter;
|
||||||
|
|
||||||
|
private readonly LegacyBeatmapExporter legacyBeatmapExporter;
|
||||||
|
|
||||||
public ProcessBeatmapDelegate? ProcessBeatmap { private get; set; }
|
public ProcessBeatmapDelegate? ProcessBeatmap { private get; set; }
|
||||||
|
|
||||||
@ -77,7 +79,12 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, gameResources, userResources, defaultBeatmap, host);
|
workingBeatmapCache = CreateWorkingBeatmapCache(audioManager, gameResources, userResources, defaultBeatmap, host);
|
||||||
|
|
||||||
beatmapExporter = new LegacyBeatmapExporter(storage)
|
beatmapExporter = new BeatmapExporter(storage)
|
||||||
|
{
|
||||||
|
PostNotification = obj => PostNotification?.Invoke(obj)
|
||||||
|
};
|
||||||
|
|
||||||
|
legacyBeatmapExporter = new LegacyBeatmapExporter(storage)
|
||||||
{
|
{
|
||||||
PostNotification = obj => PostNotification?.Invoke(obj)
|
PostNotification = obj => PostNotification?.Invoke(obj)
|
||||||
};
|
};
|
||||||
@ -402,6 +409,8 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public Task Export(BeatmapSetInfo beatmap) => beatmapExporter.ExportAsync(beatmap.ToLive(Realm));
|
public Task Export(BeatmapSetInfo beatmap) => beatmapExporter.ExportAsync(beatmap.ToLive(Realm));
|
||||||
|
|
||||||
|
public Task ExportLegacy(BeatmapSetInfo beatmap) => legacyBeatmapExporter.ExportAsync(beatmap.ToLive(Realm));
|
||||||
|
|
||||||
private void updateHashAndMarkDirty(BeatmapSetInfo setInfo)
|
private void updateHashAndMarkDirty(BeatmapSetInfo setInfo)
|
||||||
{
|
{
|
||||||
setInfo.Hash = beatmapImporter.ComputeHash(setInfo);
|
setInfo.Hash = beatmapImporter.ComputeHash(setInfo);
|
||||||
|
22
osu.Game/Database/BeatmapExporter.cs
Normal file
22
osu.Game/Database/BeatmapExporter.cs
Normal file
@ -0,0 +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 osu.Framework.Platform;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
|
||||||
|
namespace osu.Game.Database
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Exporter for beatmap archives.
|
||||||
|
/// This is not for legacy purposes and works for lazer only.
|
||||||
|
/// </summary>
|
||||||
|
public class BeatmapExporter : LegacyArchiveExporter<BeatmapSetInfo>
|
||||||
|
{
|
||||||
|
public BeatmapExporter(Storage storage)
|
||||||
|
: base(storage)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override string FileExtension => @".olz";
|
||||||
|
}
|
||||||
|
}
|
@ -39,7 +39,7 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
using (var stream = UserFileStorage.GetStream(file.File.GetStoragePath()))
|
using (var stream = GetFileContents(model, file))
|
||||||
{
|
{
|
||||||
if (stream == null)
|
if (stream == null)
|
||||||
{
|
{
|
||||||
@ -65,5 +65,7 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual Stream? GetFileContents(TModel model, INamedFileUsage file) => UserFileStorage.GetStream(file.File.GetStoragePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,25 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.Formats;
|
||||||
|
using osu.Game.IO;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
|
using osu.Game.Skinning;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Database
|
namespace osu.Game.Database
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Exporter for osu!stable legacy beatmap archives.
|
||||||
|
/// Converts all beatmaps in the set to legacy format and exports it as a legacy package.
|
||||||
|
/// </summary>
|
||||||
public class LegacyBeatmapExporter : LegacyArchiveExporter<BeatmapSetInfo>
|
public class LegacyBeatmapExporter : LegacyArchiveExporter<BeatmapSetInfo>
|
||||||
{
|
{
|
||||||
public LegacyBeatmapExporter(Storage storage)
|
public LegacyBeatmapExporter(Storage storage)
|
||||||
@ -13,6 +27,72 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override Stream? GetFileContents(BeatmapSetInfo model, INamedFileUsage file)
|
||||||
|
{
|
||||||
|
bool isBeatmap = model.Beatmaps.Any(o => o.Hash == file.File.Hash);
|
||||||
|
|
||||||
|
if (!isBeatmap)
|
||||||
|
return base.GetFileContents(model, file);
|
||||||
|
|
||||||
|
// Read the beatmap contents and skin
|
||||||
|
using var contentStream = base.GetFileContents(model, file);
|
||||||
|
|
||||||
|
if (contentStream == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
using var contentStreamReader = new LineBufferedReader(contentStream);
|
||||||
|
var beatmapContent = new LegacyBeatmapDecoder().Decode(contentStreamReader);
|
||||||
|
|
||||||
|
using var skinStream = base.GetFileContents(model, file);
|
||||||
|
|
||||||
|
if (skinStream == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
using var skinStreamReader = new LineBufferedReader(skinStream);
|
||||||
|
var beatmapSkin = new LegacySkin(new SkinInfo(), null!)
|
||||||
|
{
|
||||||
|
Configuration = new LegacySkinDecoder().Decode(skinStreamReader)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert beatmap elements to be compatible with legacy format
|
||||||
|
// So we truncate time and position values to integers, and convert paths with multiple segments to bezier curves
|
||||||
|
foreach (var controlPoint in beatmapContent.ControlPointInfo.AllControlPoints)
|
||||||
|
controlPoint.Time = Math.Floor(controlPoint.Time);
|
||||||
|
|
||||||
|
foreach (var hitObject in beatmapContent.HitObjects)
|
||||||
|
{
|
||||||
|
// Truncate end time before truncating start time because end time is dependent on start time
|
||||||
|
if (hitObject is IHasDuration hasDuration && hitObject is not IHasPath)
|
||||||
|
hasDuration.Duration = Math.Floor(hasDuration.EndTime) - Math.Floor(hitObject.StartTime);
|
||||||
|
|
||||||
|
hitObject.StartTime = Math.Floor(hitObject.StartTime);
|
||||||
|
|
||||||
|
if (hitObject is not IHasPath hasPath || BezierConverter.CountSegments(hasPath.Path.ControlPoints) <= 1) continue;
|
||||||
|
|
||||||
|
var newControlPoints = BezierConverter.ConvertToModernBezier(hasPath.Path.ControlPoints);
|
||||||
|
|
||||||
|
// Truncate control points to integer positions
|
||||||
|
foreach (var pathControlPoint in newControlPoints)
|
||||||
|
{
|
||||||
|
pathControlPoint.Position = new Vector2(
|
||||||
|
(float)Math.Floor(pathControlPoint.Position.X),
|
||||||
|
(float)Math.Floor(pathControlPoint.Position.Y));
|
||||||
|
}
|
||||||
|
|
||||||
|
hasPath.Path.ControlPoints.Clear();
|
||||||
|
hasPath.Path.ControlPoints.AddRange(newControlPoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode to legacy format
|
||||||
|
var stream = new MemoryStream();
|
||||||
|
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
|
||||||
|
new LegacyBeatmapEncoder(beatmapContent, beatmapSkin).Encode(sw);
|
||||||
|
|
||||||
|
stream.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
protected override string FileExtension => @".osz";
|
protected override string FileExtension => @".osz";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
3
osu.Game/FodyWeavers.xml
Normal file
3
osu.Game/FodyWeavers.xml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||||
|
<Realm DisableAnalytics="true" />
|
||||||
|
</Weavers>
|
@ -20,16 +20,16 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
{
|
{
|
||||||
public const float HEIGHT = 15;
|
public const float HEIGHT = 15;
|
||||||
|
|
||||||
public const float EXPANDED_SIZE = 50;
|
public const float DEFAULT_EXPANDED_SIZE = 50;
|
||||||
|
|
||||||
private const float border_width = 3;
|
private const float border_width = 3;
|
||||||
|
|
||||||
private readonly Box fill;
|
private readonly Box fill;
|
||||||
private readonly Container main;
|
private readonly Container main;
|
||||||
|
|
||||||
public Nub()
|
public Nub(float expandedSize = DEFAULT_EXPANDED_SIZE)
|
||||||
{
|
{
|
||||||
Size = new Vector2(EXPANDED_SIZE, HEIGHT);
|
Size = new Vector2(expandedSize, HEIGHT);
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChildren = new[]
|
||||||
{
|
{
|
||||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
private Sample sampleChecked;
|
private Sample sampleChecked;
|
||||||
private Sample sampleUnchecked;
|
private Sample sampleUnchecked;
|
||||||
|
|
||||||
public OsuCheckbox(bool nubOnRight = true)
|
public OsuCheckbox(bool nubOnRight = true, float nubSize = Nub.DEFAULT_EXPANDED_SIZE)
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
@ -61,7 +61,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
},
|
},
|
||||||
Nub = new Nub(),
|
Nub = new Nub(nubSize),
|
||||||
new HoverSounds()
|
new HoverSounds()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,14 +70,14 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
Nub.Anchor = Anchor.CentreRight;
|
Nub.Anchor = Anchor.CentreRight;
|
||||||
Nub.Origin = Anchor.CentreRight;
|
Nub.Origin = Anchor.CentreRight;
|
||||||
Nub.Margin = new MarginPadding { Right = nub_padding };
|
Nub.Margin = new MarginPadding { Right = nub_padding };
|
||||||
LabelTextFlowContainer.Padding = new MarginPadding { Right = Nub.EXPANDED_SIZE + nub_padding * 2 };
|
LabelTextFlowContainer.Padding = new MarginPadding { Right = Nub.DEFAULT_EXPANDED_SIZE + nub_padding * 2 };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Nub.Anchor = Anchor.CentreLeft;
|
Nub.Anchor = Anchor.CentreLeft;
|
||||||
Nub.Origin = Anchor.CentreLeft;
|
Nub.Origin = Anchor.CentreLeft;
|
||||||
Nub.Margin = new MarginPadding { Left = nub_padding };
|
Nub.Margin = new MarginPadding { Left = nub_padding };
|
||||||
LabelTextFlowContainer.Padding = new MarginPadding { Left = Nub.EXPANDED_SIZE + nub_padding * 2 };
|
LabelTextFlowContainer.Padding = new MarginPadding { Left = Nub.DEFAULT_EXPANDED_SIZE + nub_padding * 2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
Nub.Current.BindTo(Current);
|
Nub.Current.BindTo(Current);
|
||||||
|
@ -51,7 +51,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
public RoundedSliderBar()
|
public RoundedSliderBar()
|
||||||
{
|
{
|
||||||
Height = Nub.HEIGHT;
|
Height = Nub.HEIGHT;
|
||||||
RangePadding = Nub.EXPANDED_SIZE / 2;
|
RangePadding = Nub.DEFAULT_EXPANDED_SIZE / 2;
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
|
@ -39,6 +39,11 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString Default => new TranslatableString(getKey(@"default"), @"Default");
|
public static LocalisableString Default => new TranslatableString(getKey(@"default"), @"Default");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Export"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString Export => new TranslatableString(getKey(@"export"), @"Export");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Width"
|
/// "Width"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -35,9 +35,14 @@ namespace osu.Game.Localisation
|
|||||||
public static LocalisableString SetPreviewPointToCurrent => new TranslatableString(getKey(@"set_preview_point_to_current"), @"Set preview point to current time");
|
public static LocalisableString SetPreviewPointToCurrent => new TranslatableString(getKey(@"set_preview_point_to_current"), @"Set preview point to current time");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Export package"
|
/// "For editing (.olz)"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString ExportPackage => new TranslatableString(getKey(@"export_package"), @"Export package");
|
public static LocalisableString ExportForEditing => new TranslatableString(getKey(@"export_for_editing"), @"For editing (.olz)");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "For compatibility (.osz)"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString ExportForCompatibility => new TranslatableString(getKey(@"export_for_compatibility"), @"For compatibility (.osz)");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Create new difficulty"
|
/// "Create new difficulty"
|
||||||
|
@ -425,7 +425,7 @@ namespace osu.Game.Online.Leaderboards
|
|||||||
|
|
||||||
if (Score.Files.Count > 0)
|
if (Score.Files.Count > 0)
|
||||||
{
|
{
|
||||||
items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => scoreManager.Export(Score)));
|
items.Add(new OsuMenuItem(Localisation.CommonStrings.Export, MenuItemType.Standard, () => scoreManager.Export(Score)));
|
||||||
items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score))));
|
items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> globalAvailableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
|
private readonly Bindable<Dictionary<ModType, IReadOnlyList<Mod>>> globalAvailableMods = new Bindable<Dictionary<ModType, IReadOnlyList<Mod>>>();
|
||||||
|
|
||||||
private IEnumerable<ModState> allAvailableMods => AvailableMods.Value.SelectMany(pair => pair.Value);
|
public IEnumerable<ModState> AllAvailableMods => AvailableMods.Value.SelectMany(pair => pair.Value);
|
||||||
|
|
||||||
private readonly BindableBool customisationVisible = new BindableBool();
|
private readonly BindableBool customisationVisible = new BindableBool();
|
||||||
|
|
||||||
@ -382,7 +382,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
private void filterMods()
|
private void filterMods()
|
||||||
{
|
{
|
||||||
foreach (var modState in allAvailableMods)
|
foreach (var modState in AllAvailableMods)
|
||||||
modState.ValidForSelection.Value = modState.Mod.HasImplementation && IsValidMod.Invoke(modState.Mod);
|
modState.ValidForSelection.Value = modState.Mod.HasImplementation && IsValidMod.Invoke(modState.Mod);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,7 +407,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
bool anyCustomisableModActive = false;
|
bool anyCustomisableModActive = false;
|
||||||
bool anyModPendingConfiguration = false;
|
bool anyModPendingConfiguration = false;
|
||||||
|
|
||||||
foreach (var modState in allAvailableMods)
|
foreach (var modState in AllAvailableMods)
|
||||||
{
|
{
|
||||||
anyCustomisableModActive |= modState.Active.Value && modState.Mod.GetSettingsSourceProperties().Any();
|
anyCustomisableModActive |= modState.Active.Value && modState.Mod.GetSettingsSourceProperties().Any();
|
||||||
anyModPendingConfiguration |= modState.PendingConfiguration;
|
anyModPendingConfiguration |= modState.PendingConfiguration;
|
||||||
@ -464,7 +464,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
|
|
||||||
var newSelection = new List<Mod>();
|
var newSelection = new List<Mod>();
|
||||||
|
|
||||||
foreach (var modState in allAvailableMods)
|
foreach (var modState in AllAvailableMods)
|
||||||
{
|
{
|
||||||
var matchingSelectedMod = SelectedMods.Value.SingleOrDefault(selected => selected.GetType() == modState.Mod.GetType());
|
var matchingSelectedMod = SelectedMods.Value.SingleOrDefault(selected => selected.GetType() == modState.Mod.GetType());
|
||||||
|
|
||||||
@ -491,7 +491,7 @@ namespace osu.Game.Overlays.Mods
|
|||||||
if (externalSelectionUpdateInProgress)
|
if (externalSelectionUpdateInProgress)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var candidateSelection = allAvailableMods.Where(modState => modState.Active.Value)
|
var candidateSelection = AllAvailableMods.Where(modState => modState.Active.Value)
|
||||||
.Select(modState => modState.Mod)
|
.Select(modState => modState.Mod)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
|
@ -196,7 +196,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
Spacing = new Vector2(0, 10),
|
Spacing = new Vector2(0, 5),
|
||||||
Child = Control = CreateControl(),
|
Child = Control = CreateControl(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,6 @@ namespace osu.Game.Overlays.Settings
|
|||||||
{
|
{
|
||||||
numberBox = new OutlinedNumberBox
|
numberBox = new OutlinedNumberBox
|
||||||
{
|
{
|
||||||
Margin = new MarginPadding { Top = 5 },
|
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
CommitOnFocusLost = true
|
CommitOnFocusLost = true
|
||||||
}
|
}
|
||||||
|
@ -25,8 +25,6 @@ namespace osu.Game.Overlays.SkinEditor
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private SkinEditor editor { get; set; } = null!;
|
private SkinEditor editor { get; set; } = null!;
|
||||||
|
|
||||||
protected override bool AllowCyclicSelection => true;
|
|
||||||
|
|
||||||
public SkinBlueprintContainer(ISerialisableDrawableContainer targetContainer)
|
public SkinBlueprintContainer(ISerialisableDrawableContainer targetContainer)
|
||||||
{
|
{
|
||||||
this.targetContainer = targetContainer;
|
this.targetContainer = targetContainer;
|
||||||
|
@ -38,6 +38,9 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
// Timing
|
// Timing
|
||||||
new CheckPreviewTime(),
|
new CheckPreviewTime(),
|
||||||
|
|
||||||
|
// Events
|
||||||
|
new CheckBreaks()
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
|
94
osu.Game/Rulesets/Edit/Checks/CheckBreaks.cs
Normal file
94
osu.Game/Rulesets/Edit/Checks/CheckBreaks.cs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using osu.Game.Beatmaps.Timing;
|
||||||
|
using osu.Game.Rulesets.Edit.Checks.Components;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Edit.Checks
|
||||||
|
{
|
||||||
|
public class CheckBreaks : ICheck
|
||||||
|
{
|
||||||
|
// Breaks may be off by 1 ms.
|
||||||
|
private const int leniency_threshold = 1;
|
||||||
|
private const double minimum_gap_before_break = 200;
|
||||||
|
|
||||||
|
// Break end time depends on the upcoming object's pre-empt time.
|
||||||
|
// As things stand, "pre-empt time" is only defined for osu! standard
|
||||||
|
// This is a generic value representing AR=10
|
||||||
|
// Relevant: https://github.com/ppy/osu/issues/14330#issuecomment-1002158551
|
||||||
|
private const double min_end_threshold = 450;
|
||||||
|
public CheckMetadata Metadata => new CheckMetadata(CheckCategory.Events, "Breaks not achievable using the editor");
|
||||||
|
|
||||||
|
public IEnumerable<IssueTemplate> PossibleTemplates => new IssueTemplate[]
|
||||||
|
{
|
||||||
|
new IssueTemplateEarlyStart(this),
|
||||||
|
new IssueTemplateLateEnd(this),
|
||||||
|
new IssueTemplateTooShort(this)
|
||||||
|
};
|
||||||
|
|
||||||
|
public IEnumerable<Issue> Run(BeatmapVerifierContext context)
|
||||||
|
{
|
||||||
|
var startTimes = context.Beatmap.HitObjects.Select(ho => ho.StartTime).OrderBy(x => x).ToList();
|
||||||
|
var endTimes = context.Beatmap.HitObjects.Select(ho => ho.GetEndTime()).OrderBy(x => x).ToList();
|
||||||
|
|
||||||
|
foreach (var breakPeriod in context.Beatmap.Breaks)
|
||||||
|
{
|
||||||
|
if (breakPeriod.Duration < BreakPeriod.MIN_BREAK_DURATION)
|
||||||
|
yield return new IssueTemplateTooShort(this).Create(breakPeriod.StartTime);
|
||||||
|
|
||||||
|
int previousObjectEndTimeIndex = endTimes.BinarySearch(breakPeriod.StartTime);
|
||||||
|
if (previousObjectEndTimeIndex < 0) previousObjectEndTimeIndex = ~previousObjectEndTimeIndex - 1;
|
||||||
|
|
||||||
|
if (previousObjectEndTimeIndex >= 0)
|
||||||
|
{
|
||||||
|
double gapBeforeBreak = breakPeriod.StartTime - endTimes[previousObjectEndTimeIndex];
|
||||||
|
if (gapBeforeBreak < minimum_gap_before_break - leniency_threshold)
|
||||||
|
yield return new IssueTemplateEarlyStart(this).Create(breakPeriod.StartTime, minimum_gap_before_break - gapBeforeBreak);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nextObjectStartTimeIndex = startTimes.BinarySearch(breakPeriod.EndTime);
|
||||||
|
if (nextObjectStartTimeIndex < 0) nextObjectStartTimeIndex = ~nextObjectStartTimeIndex;
|
||||||
|
|
||||||
|
if (nextObjectStartTimeIndex < startTimes.Count)
|
||||||
|
{
|
||||||
|
double gapAfterBreak = startTimes[nextObjectStartTimeIndex] - breakPeriod.EndTime;
|
||||||
|
if (gapAfterBreak < min_end_threshold - leniency_threshold)
|
||||||
|
yield return new IssueTemplateLateEnd(this).Create(breakPeriod.StartTime, min_end_threshold - gapAfterBreak);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateEarlyStart : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateEarlyStart(ICheck check)
|
||||||
|
: base(check, IssueType.Problem, "Break starts {0} ms early.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create(double startTime, double diff) => new Issue(startTime, this, (int)diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateLateEnd : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateLateEnd(ICheck check)
|
||||||
|
: base(check, IssueType.Problem, "Break ends {0} ms late.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create(double startTime, double diff) => new Issue(startTime, this, (int)diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IssueTemplateTooShort : IssueTemplate
|
||||||
|
{
|
||||||
|
public IssueTemplateTooShort(ICheck check)
|
||||||
|
: base(check, IssueType.Warning, "Break is non-functional due to being less than {0} ms.")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Issue Create(double startTime) => new Issue(startTime, this, BreakPeriod.MIN_BREAK_DURATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -117,13 +117,10 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
{
|
{
|
||||||
PlayfieldContentContainer = new Container
|
PlayfieldContentContainer = new Container
|
||||||
{
|
{
|
||||||
Name = "Content",
|
Name = "Playfield content",
|
||||||
Padding = new MarginPadding
|
RelativeSizeAxes = Axes.Y,
|
||||||
{
|
Anchor = Anchor.Centre,
|
||||||
Left = TOOLBOX_CONTRACTED_SIZE_LEFT,
|
Origin = Anchor.Centre,
|
||||||
Right = TOOLBOX_CONTRACTED_SIZE_RIGHT,
|
|
||||||
},
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
// layers below playfield
|
// layers below playfield
|
||||||
@ -240,6 +237,14 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
// Ensure that the playfield is always centered but also doesn't get cut off by toolboxes.
|
||||||
|
PlayfieldContentContainer.Width = Math.Max(1024, DrawWidth) - TOOLBOX_CONTRACTED_SIZE_RIGHT * 2;
|
||||||
|
}
|
||||||
|
|
||||||
public override Playfield Playfield => drawableRulesetWrapper.Playfield;
|
public override Playfield Playfield => drawableRulesetWrapper.Playfield;
|
||||||
|
|
||||||
public override IEnumerable<DrawableHitObject> HitObjects => drawableRulesetWrapper.Playfield.AllHitObjects;
|
public override IEnumerable<DrawableHitObject> HitObjects => drawableRulesetWrapper.Playfield.AllHitObjects;
|
||||||
@ -472,7 +477,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
public abstract partial class HitObjectComposer : CompositeDrawable, IPositionSnapProvider
|
public abstract partial class HitObjectComposer : CompositeDrawable, IPositionSnapProvider
|
||||||
{
|
{
|
||||||
public const float TOOLBOX_CONTRACTED_SIZE_LEFT = 60;
|
public const float TOOLBOX_CONTRACTED_SIZE_LEFT = 60;
|
||||||
public const float TOOLBOX_CONTRACTED_SIZE_RIGHT = 130;
|
public const float TOOLBOX_CONTRACTED_SIZE_RIGHT = 120;
|
||||||
|
|
||||||
public readonly Ruleset Ruleset;
|
public readonly Ruleset Ruleset;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<SelectionBlueprint<T>> Deselected;
|
public event Action<SelectionBlueprint<T>> Deselected;
|
||||||
|
|
||||||
public override bool HandlePositionalInput => ShouldBeAlive;
|
public override bool HandlePositionalInput => IsSelectable;
|
||||||
public override bool RemoveWhenNotAlive => false;
|
public override bool RemoveWhenNotAlive => false;
|
||||||
|
|
||||||
protected SelectionBlueprint(T item)
|
protected SelectionBlueprint(T item)
|
||||||
@ -125,6 +125,11 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual MenuItem[] ContextMenuItems => Array.Empty<MenuItem>();
|
public virtual MenuItem[] ContextMenuItems => Array.Empty<MenuItem>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether the <see cref="SelectionBlueprint{T}"/> can be currently selected via a click or a drag box.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsSelectable => ShouldBeAlive && IsPresent;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The screen-space main point that causes this <see cref="HitObjectSelectionBlueprint"/> to be selected via a drag.
|
/// The screen-space main point that causes this <see cref="HitObjectSelectionBlueprint"/> to be selected via a drag.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -39,6 +39,13 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
new[] { new Vector2d(1, 0), new Vector2d(1, 1.2447058f), new Vector2d(-0.8526471f, 2.118367f), new Vector2d(-2.6211002f, 7.854936e-06f), new Vector2d(-0.8526448f, -2.118357f), new Vector2d(1, -1.2447058f), new Vector2d(1, 0) })
|
new[] { new Vector2d(1, 0), new Vector2d(1, 1.2447058f), new Vector2d(-0.8526471f, 2.118367f), new Vector2d(-2.6211002f, 7.854936e-06f), new Vector2d(-0.8526448f, -2.118357f), new Vector2d(1, -1.2447058f), new Vector2d(1, 0) })
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Counts the number of segments in a slider path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="controlPoints">The control points of the path.</param>
|
||||||
|
/// <returns>The number of segments in a slider path.</returns>
|
||||||
|
public static int CountSegments(IList<PathControlPoint> controlPoints) => controlPoints.Where((t, i) => t.Type != null && i < controlPoints.Count - 1).Count();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Converts a slider path to bezier control point positions compatible with the legacy osu! client.
|
/// Converts a slider path to bezier control point positions compatible with the legacy osu! client.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -384,5 +384,10 @@ namespace osu.Game.Rulesets
|
|||||||
/// Can be overridden to add a ruleset-specific section to the editor beatmap setup screen.
|
/// Can be overridden to add a ruleset-specific section to the editor beatmap setup screen.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual RulesetSetupSection? CreateEditorSetupSection() => null;
|
public virtual RulesetSetupSection? CreateEditorSetupSection() => null;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Can be overridden to alter the difficulty section to the editor beatmap setup screen.
|
||||||
|
/// </summary>
|
||||||
|
public virtual DifficultySection? CreateEditorDifficultySection() => null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Effects;
|
using osu.Framework.Graphics.Effects;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Screens.Edit.Components;
|
using osu.Game.Screens.Edit.Components;
|
||||||
using osu.Game.Screens.Edit.Components.Timelines.Summary;
|
using osu.Game.Screens.Edit.Components.Timelines.Summary;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@ -57,7 +58,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
new Dimension(GridSizeMode.Absolute, 170),
|
new Dimension(GridSizeMode.Absolute, 170),
|
||||||
new Dimension(),
|
new Dimension(),
|
||||||
new Dimension(GridSizeMode.Absolute, 220),
|
new Dimension(GridSizeMode.Absolute, 220),
|
||||||
new Dimension(GridSizeMode.Absolute, 120),
|
new Dimension(GridSizeMode.Absolute, HitObjectComposer.TOOLBOX_CONTRACTED_SIZE_RIGHT),
|
||||||
},
|
},
|
||||||
Content = new[]
|
Content = new[]
|
||||||
{
|
{
|
||||||
@ -69,7 +70,6 @@ namespace osu.Game.Screens.Edit
|
|||||||
TestGameplayButton = new TestGameplayButton
|
TestGameplayButton = new TestGameplayButton
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding { Left = 10 },
|
|
||||||
Size = new Vector2(1),
|
Size = new Vector2(1),
|
||||||
Action = editor.TestGameplay,
|
Action = editor.TestGameplay,
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -14,19 +18,59 @@ namespace osu.Game.Screens.Edit.Components.Menus
|
|||||||
{
|
{
|
||||||
public partial class EditorMenuBar : OsuMenu
|
public partial class EditorMenuBar : OsuMenu
|
||||||
{
|
{
|
||||||
|
private const float heading_area = 114;
|
||||||
|
|
||||||
public EditorMenuBar()
|
public EditorMenuBar()
|
||||||
: base(Direction.Horizontal, true)
|
: base(Direction.Horizontal, true)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
|
|
||||||
MaskingContainer.CornerRadius = 0;
|
MaskingContainer.CornerRadius = 0;
|
||||||
ItemsContainer.Padding = new MarginPadding { Left = 100 };
|
ItemsContainer.Padding = new MarginPadding();
|
||||||
|
|
||||||
|
ContentContainer.Margin = new MarginPadding { Left = heading_area };
|
||||||
|
ContentContainer.Masking = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load(OverlayColourProvider colourProvider, TextureStore textures)
|
||||||
{
|
{
|
||||||
BackgroundColour = colourProvider.Background3;
|
BackgroundColour = colourProvider.Background3;
|
||||||
|
|
||||||
|
TextFlowContainer text;
|
||||||
|
|
||||||
|
AddRangeInternal(new[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
Width = heading_area,
|
||||||
|
Padding = new MarginPadding(8),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new Sprite
|
||||||
|
{
|
||||||
|
Size = new Vector2(26),
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
Texture = textures.Get("Icons/Hexacons/editor"),
|
||||||
|
},
|
||||||
|
text = new TextFlowContainer
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreRight,
|
||||||
|
Origin = Anchor.CentreRight,
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
text.AddText(@"osu!", t => t.Font = OsuFont.TorusAlternate);
|
||||||
|
text.AddText(@"editor", t =>
|
||||||
|
{
|
||||||
|
t.Font = OsuFont.TorusAlternate;
|
||||||
|
t.Colour = colourProvider.Highlight1;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override Framework.Graphics.UserInterface.Menu CreateSubMenu() => new SubMenu();
|
protected override Framework.Graphics.UserInterface.Menu CreateSubMenu() => new SubMenu();
|
||||||
@ -157,7 +201,17 @@ namespace osu.Game.Screens.Edit.Components.Menus
|
|||||||
public DrawableSpacer(MenuItem item)
|
public DrawableSpacer(MenuItem item)
|
||||||
: base(item)
|
: base(item)
|
||||||
{
|
{
|
||||||
Scale = new Vector2(1, 0.3f);
|
Scale = new Vector2(1, 0.6f);
|
||||||
|
|
||||||
|
AddInternal(new Box
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
Colour = BackgroundColourHover,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 2f,
|
||||||
|
Width = 0.8f,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e) => true;
|
protected override bool OnHover(HoverEvent e) => true;
|
||||||
|
@ -73,6 +73,8 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
|||||||
{
|
{
|
||||||
public MarkerVisualisation()
|
public MarkerVisualisation()
|
||||||
{
|
{
|
||||||
|
const float box_height = 4;
|
||||||
|
|
||||||
Anchor = Anchor.CentreLeft;
|
Anchor = Anchor.CentreLeft;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
RelativePositionAxes = Axes.X;
|
RelativePositionAxes = Axes.X;
|
||||||
@ -80,32 +82,46 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
|||||||
AutoSizeAxes = Axes.X;
|
AutoSizeAxes = Axes.X;
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.TopCentre,
|
||||||
|
Size = new Vector2(14, box_height),
|
||||||
|
},
|
||||||
new Triangle
|
new Triangle
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
Scale = new Vector2(1, -1),
|
Scale = new Vector2(1, -1),
|
||||||
Size = new Vector2(10, 5),
|
Size = new Vector2(10, 5),
|
||||||
|
Y = box_height,
|
||||||
},
|
},
|
||||||
new Triangle
|
new Triangle
|
||||||
{
|
{
|
||||||
Anchor = Anchor.BottomCentre,
|
Anchor = Anchor.BottomCentre,
|
||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
Size = new Vector2(10, 5)
|
Size = new Vector2(10, 5),
|
||||||
|
Y = -box_height,
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Anchor = Anchor.BottomCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
Size = new Vector2(14, box_height),
|
||||||
},
|
},
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Width = 2,
|
Width = 1.4f,
|
||||||
EdgeSmoothness = new Vector2(1, 0)
|
EdgeSmoothness = new Vector2(1, 0)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours) => Colour = colours.Red;
|
private void load(OsuColour colours) => Colour = colours.Red1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,12 +33,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
private int? lastCustomDivisor;
|
private int? lastCustomDivisor;
|
||||||
|
|
||||||
private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor();
|
[Resolved]
|
||||||
|
private BindableBeatDivisor beatDivisor { get; set; } = null!;
|
||||||
public BeatDivisorControl(BindableBeatDivisor beatDivisor)
|
|
||||||
{
|
|
||||||
this.beatDivisor.BindTo(beatDivisor);
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load(OverlayColourProvider colourProvider)
|
||||||
|
@ -46,15 +46,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
protected readonly BindableList<T> SelectedItems = new BindableList<T>();
|
protected readonly BindableList<T> SelectedItems = new BindableList<T>();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether to allow cyclic selection on clicking multiple times.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Disabled by default as it does not work well with editors that support double-clicking or other advanced interactions.
|
|
||||||
/// Can probably be made to work with more thought.
|
|
||||||
/// </remarks>
|
|
||||||
protected virtual bool AllowCyclicSelection => false;
|
|
||||||
|
|
||||||
protected BlueprintContainer()
|
protected BlueprintContainer()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
@ -167,6 +158,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
if (ClickedBlueprint == null || SelectionHandler.SelectedBlueprints.FirstOrDefault(b => b.IsHovered) != ClickedBlueprint)
|
if (ClickedBlueprint == null || SelectionHandler.SelectedBlueprints.FirstOrDefault(b => b.IsHovered) != ClickedBlueprint)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
doubleClickHandled = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,6 +169,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
endClickSelection(e);
|
endClickSelection(e);
|
||||||
clickSelectionHandled = false;
|
clickSelectionHandled = false;
|
||||||
|
doubleClickHandled = false;
|
||||||
isDraggingBlueprint = false;
|
isDraggingBlueprint = false;
|
||||||
wasDragStarted = false;
|
wasDragStarted = false;
|
||||||
});
|
});
|
||||||
@ -376,11 +369,22 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private bool clickSelectionHandled;
|
private bool clickSelectionHandled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether a blueprint was double-clicked since last mouse down.
|
||||||
|
/// </summary>
|
||||||
|
private bool doubleClickHandled;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the selected blueprint(s) were already selected on mouse down. Generally used to perform selection cycling on mouse up in such a case.
|
/// Whether the selected blueprint(s) were already selected on mouse down. Generally used to perform selection cycling on mouse up in such a case.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private bool selectedBlueprintAlreadySelectedOnMouseDown;
|
private bool selectedBlueprintAlreadySelectedOnMouseDown;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sorts the supplied <paramref name="blueprints"/> by the order of preference when making a selection.
|
||||||
|
/// Blueprints at the start of the list will be prioritised over later items if the selection requested is ambiguous due to spatial overlap.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual IEnumerable<SelectionBlueprint<T>> ApplySelectionOrder(IEnumerable<SelectionBlueprint<T>> blueprints) => blueprints.Reverse();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to select any hovered blueprints.
|
/// Attempts to select any hovered blueprints.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -390,15 +394,28 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
// Iterate from the top of the input stack (blueprints closest to the front of the screen first).
|
// Iterate from the top of the input stack (blueprints closest to the front of the screen first).
|
||||||
// Priority is given to already-selected blueprints.
|
// Priority is given to already-selected blueprints.
|
||||||
foreach (SelectionBlueprint<T> blueprint in SelectionBlueprints.AliveChildren.Reverse().OrderByDescending(b => b.IsSelected))
|
foreach (SelectionBlueprint<T> blueprint in SelectionBlueprints.AliveChildren.Where(b => b.IsSelected))
|
||||||
{
|
{
|
||||||
if (!blueprint.IsHovered) continue;
|
if (runForBlueprint(blueprint))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
selectedBlueprintAlreadySelectedOnMouseDown = blueprint.State == SelectionState.Selected;
|
foreach (SelectionBlueprint<T> blueprint in ApplySelectionOrder(SelectionBlueprints.AliveChildren))
|
||||||
return clickSelectionHandled = SelectionHandler.MouseDownSelectionRequested(blueprint, e);
|
{
|
||||||
|
if (runForBlueprint(blueprint))
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
bool runForBlueprint(SelectionBlueprint<T> blueprint)
|
||||||
|
{
|
||||||
|
if (!blueprint.IsHovered) return false;
|
||||||
|
|
||||||
|
selectedBlueprintAlreadySelectedOnMouseDown = blueprint.State == SelectionState.Selected;
|
||||||
|
clickSelectionHandled = SelectionHandler.MouseDownSelectionRequested(blueprint, e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -408,8 +425,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// <returns>Whether a click selection was active.</returns>
|
/// <returns>Whether a click selection was active.</returns>
|
||||||
private bool endClickSelection(MouseButtonEvent e)
|
private bool endClickSelection(MouseButtonEvent e)
|
||||||
{
|
{
|
||||||
// If already handled a selection or drag, we don't want to perform a mouse up / click action.
|
// If already handled a selection, double-click, or drag, we don't want to perform a mouse up / click action.
|
||||||
if (clickSelectionHandled || isDraggingBlueprint) return true;
|
if (clickSelectionHandled || doubleClickHandled || isDraggingBlueprint) return true;
|
||||||
|
|
||||||
if (e.Button != MouseButton.Left) return false;
|
if (e.Button != MouseButton.Left) return false;
|
||||||
|
|
||||||
@ -425,20 +442,20 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wasDragStarted && selectedBlueprintAlreadySelectedOnMouseDown && SelectedItems.Count == 1 && AllowCyclicSelection)
|
if (!wasDragStarted && selectedBlueprintAlreadySelectedOnMouseDown && SelectedItems.Count == 1)
|
||||||
{
|
{
|
||||||
// If a click occurred and was handled by the currently selected blueprint but didn't result in a drag,
|
// If a click occurred and was handled by the currently selected blueprint but didn't result in a drag,
|
||||||
// cycle between other blueprints which are also under the cursor.
|
// cycle between other blueprints which are also under the cursor.
|
||||||
|
|
||||||
// The depth of blueprints is constantly changing (see above where selected blueprints are brought to the front).
|
// The depth of blueprints is constantly changing (see above where selected blueprints are brought to the front).
|
||||||
// For this logic, we want a stable sort order so we can correctly cycle, thus using the blueprintMap instead.
|
// For this logic, we want a stable sort order so we can correctly cycle, thus using the blueprintMap instead.
|
||||||
IEnumerable<SelectionBlueprint<T>> cyclingSelectionBlueprints = blueprintMap.Values;
|
IEnumerable<SelectionBlueprint<T>> cyclingSelectionBlueprints = ApplySelectionOrder(blueprintMap.Values);
|
||||||
|
|
||||||
// If there's already a selection, let's start from the blueprint after the selection.
|
// If there's already a selection, let's start from the blueprint after the selection.
|
||||||
cyclingSelectionBlueprints = cyclingSelectionBlueprints.SkipWhile(b => !b.IsSelected).Skip(1);
|
cyclingSelectionBlueprints = cyclingSelectionBlueprints.SkipWhile(b => !b.IsSelected).Skip(1);
|
||||||
|
|
||||||
// Add the blueprints from before the selection to the end of the enumerable to allow for cyclic selection.
|
// Add the blueprints from before the selection to the end of the enumerable to allow for cyclic selection.
|
||||||
cyclingSelectionBlueprints = cyclingSelectionBlueprints.Concat(blueprintMap.Values.TakeWhile(b => !b.IsSelected));
|
cyclingSelectionBlueprints = cyclingSelectionBlueprints.Concat(ApplySelectionOrder(blueprintMap.Values).TakeWhile(b => !b.IsSelected));
|
||||||
|
|
||||||
foreach (SelectionBlueprint<T> blueprint in cyclingSelectionBlueprints)
|
foreach (SelectionBlueprint<T> blueprint in cyclingSelectionBlueprints)
|
||||||
{
|
{
|
||||||
@ -470,7 +487,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SelectionState.NotSelected:
|
case SelectionState.NotSelected:
|
||||||
if (blueprint.IsAlive && blueprint.IsPresent && quad.Contains(blueprint.ScreenSpaceSelectionPoint))
|
if (blueprint.IsSelectable && quad.Contains(blueprint.ScreenSpaceSelectionPoint))
|
||||||
blueprint.Select();
|
blueprint.Select();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
@ -129,6 +130,10 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<SelectionBlueprint<HitObject>> ApplySelectionOrder(IEnumerable<SelectionBlueprint<HitObject>> blueprints) =>
|
||||||
|
base.ApplySelectionOrder(blueprints)
|
||||||
|
.OrderBy(b => Math.Min(Math.Abs(EditorClock.CurrentTime - b.Item.GetEndTime()), Math.Abs(EditorClock.CurrentTime - b.Item.StartTime)));
|
||||||
|
|
||||||
protected override Container<SelectionBlueprint<HitObject>> CreateSelectionBlueprintContainer() => new HitObjectOrderedSelectionContainer { RelativeSizeAxes = Axes.Both };
|
protected override Container<SelectionBlueprint<HitObject>> CreateSelectionBlueprintContainer() => new HitObjectOrderedSelectionContainer { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
protected override SelectionHandler<HitObject> CreateSelectionHandler() => new EditorSelectionHandler();
|
protected override SelectionHandler<HitObject> CreateSelectionHandler() => new EditorSelectionHandler();
|
||||||
|
@ -12,17 +12,17 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
{
|
{
|
||||||
public partial class CentreMarker : CompositeDrawable
|
public partial class CentreMarker : CompositeDrawable
|
||||||
{
|
{
|
||||||
private const float triangle_width = 15;
|
private const float triangle_width = 8;
|
||||||
private const float triangle_height = 10;
|
|
||||||
private const float bar_width = 2;
|
private const float bar_width = 1.6f;
|
||||||
|
|
||||||
public CentreMarker()
|
public CentreMarker()
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
Size = new Vector2(triangle_width, 1);
|
Size = new Vector2(triangle_width, 1);
|
||||||
|
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.TopCentre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.TopCentre;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -37,22 +37,16 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.TopCentre,
|
Anchor = Anchor.TopCentre,
|
||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
Size = new Vector2(triangle_width, triangle_height),
|
Size = new Vector2(triangle_width, triangle_width * 0.8f),
|
||||||
Scale = new Vector2(1, -1)
|
Scale = new Vector2(1, -1)
|
||||||
},
|
},
|
||||||
new Triangle
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Size = new Vector2(triangle_width, triangle_height),
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
Colour = colours.RedDark;
|
Colour = colours.Red1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,63 +1,68 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osu.Game.Resources.Localisation.Web;
|
using osu.Game.Resources.Localisation.Web;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
||||||
{
|
{
|
||||||
public partial class TimelineArea : CompositeDrawable
|
public partial class TimelineArea : CompositeDrawable
|
||||||
{
|
{
|
||||||
public Timeline Timeline;
|
public Timeline Timeline = null!;
|
||||||
|
|
||||||
private readonly Drawable userContent;
|
private readonly Drawable userContent;
|
||||||
|
|
||||||
public TimelineArea(Drawable content = null)
|
public TimelineArea(Drawable? content = null)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
userContent = content ?? Drawable.Empty();
|
userContent = content ?? Empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load(OverlayColourProvider colourProvider, OsuColour colours)
|
||||||
{
|
{
|
||||||
Masking = true;
|
|
||||||
|
|
||||||
OsuCheckbox waveformCheckbox;
|
OsuCheckbox waveformCheckbox;
|
||||||
OsuCheckbox controlPointsCheckbox;
|
OsuCheckbox controlPointsCheckbox;
|
||||||
OsuCheckbox ticksCheckbox;
|
OsuCheckbox ticksCheckbox;
|
||||||
|
|
||||||
|
const float padding = 10;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Colour = colourProvider.Background5
|
|
||||||
},
|
|
||||||
new GridContainer
|
new GridContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.Y,
|
AutoSizeAxes = Axes.Y,
|
||||||
|
RowDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(GridSizeMode.AutoSize),
|
||||||
|
},
|
||||||
|
ColumnDimensions = new[]
|
||||||
|
{
|
||||||
|
new Dimension(GridSizeMode.Absolute, 135),
|
||||||
|
new Dimension(),
|
||||||
|
new Dimension(GridSizeMode.Absolute, 35),
|
||||||
|
new Dimension(GridSizeMode.Absolute, HitObjectComposer.TOOLBOX_CONTRACTED_SIZE_RIGHT - padding * 2),
|
||||||
|
},
|
||||||
Content = new[]
|
Content = new[]
|
||||||
{
|
{
|
||||||
new Drawable[]
|
new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Both,
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
Name = @"Toggle controls",
|
Name = @"Toggle controls",
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -68,24 +73,23 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
AutoSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Width = 160,
|
Padding = new MarginPadding(padding),
|
||||||
Padding = new MarginPadding(10),
|
|
||||||
Direction = FillDirection.Vertical,
|
Direction = FillDirection.Vertical,
|
||||||
Spacing = new Vector2(0, 4),
|
Spacing = new Vector2(0, 4),
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
waveformCheckbox = new OsuCheckbox
|
waveformCheckbox = new OsuCheckbox(nubSize: 30f)
|
||||||
{
|
{
|
||||||
LabelText = EditorStrings.TimelineWaveform,
|
LabelText = EditorStrings.TimelineWaveform,
|
||||||
Current = { Value = true },
|
Current = { Value = true },
|
||||||
},
|
},
|
||||||
ticksCheckbox = new OsuCheckbox
|
ticksCheckbox = new OsuCheckbox(nubSize: 30f)
|
||||||
{
|
{
|
||||||
LabelText = EditorStrings.TimelineTicks,
|
LabelText = EditorStrings.TimelineTicks,
|
||||||
Current = { Value = true },
|
Current = { Value = true },
|
||||||
},
|
},
|
||||||
controlPointsCheckbox = new OsuCheckbox
|
controlPointsCheckbox = new OsuCheckbox(nubSize: 30f)
|
||||||
{
|
{
|
||||||
LabelText = BeatmapsetsStrings.ShowStatsBpm,
|
LabelText = BeatmapsetsStrings.ShowStatsBpm,
|
||||||
Current = { Value = true },
|
Current = { Value = true },
|
||||||
@ -96,29 +100,52 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.X,
|
||||||
AutoSizeAxes = Axes.X,
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
// the out-of-bounds portion of the centre marker.
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
Width = 24,
|
||||||
|
Height = EditorScreenWithTimeline.PADDING,
|
||||||
|
Depth = float.MaxValue,
|
||||||
|
Colour = colours.Red1,
|
||||||
|
Anchor = Anchor.TopCentre,
|
||||||
|
Origin = Anchor.BottomCentre,
|
||||||
|
},
|
||||||
|
new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Depth = float.MaxValue,
|
||||||
|
Colour = colourProvider.Background5
|
||||||
|
},
|
||||||
|
Timeline = new Timeline(userContent),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
Name = @"Zoom controls",
|
Name = @"Zoom controls",
|
||||||
|
Padding = new MarginPadding { Right = padding },
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new Box
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Colour = colourProvider.Background3,
|
Colour = colourProvider.Background2,
|
||||||
},
|
},
|
||||||
new Container<TimelineButton>
|
new Container<TimelineButton>
|
||||||
{
|
{
|
||||||
Anchor = Anchor.CentreLeft,
|
Anchor = Anchor.CentreLeft,
|
||||||
Origin = Anchor.CentreLeft,
|
Origin = Anchor.CentreLeft,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Both,
|
||||||
AutoSizeAxes = Axes.X,
|
|
||||||
Masking = true,
|
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
new TimelineButton
|
new TimelineButton
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Height = 0.5f,
|
Size = new Vector2(1, 0.5f),
|
||||||
Icon = FontAwesome.Solid.SearchPlus,
|
Icon = FontAwesome.Solid.SearchPlus,
|
||||||
Action = () => Timeline.AdjustZoomRelatively(1)
|
Action = () => Timeline.AdjustZoomRelatively(1)
|
||||||
},
|
},
|
||||||
@ -126,8 +153,8 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.BottomLeft,
|
Anchor = Anchor.BottomLeft,
|
||||||
Origin = Anchor.BottomLeft,
|
Origin = Anchor.BottomLeft,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Height = 0.5f,
|
Size = new Vector2(1, 0.5f),
|
||||||
Icon = FontAwesome.Solid.SearchMinus,
|
Icon = FontAwesome.Solid.SearchMinus,
|
||||||
Action = () => Timeline.AdjustZoomRelatively(-1)
|
Action = () => Timeline.AdjustZoomRelatively(-1)
|
||||||
},
|
},
|
||||||
@ -135,19 +162,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Timeline = new Timeline(userContent),
|
new BeatDivisorControl { RelativeSizeAxes = Axes.Both }
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
RowDimensions = new[]
|
|
||||||
{
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
},
|
|
||||||
ColumnDimensions = new[]
|
|
||||||
{
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
new Dimension(GridSizeMode.AutoSize),
|
|
||||||
new Dimension(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
AutoSizeAxes = Axes.X;
|
AutoSizeAxes = Axes.X;
|
||||||
|
|
||||||
Origin = Anchor.TopCentre;
|
Origin = Anchor.TopLeft;
|
||||||
|
|
||||||
X = (float)group.Time;
|
X = (float)group.Time;
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user