mirror of
https://github.com/ppy/osu.git
synced 2025-01-27 10:23:03 +08:00
Merge branch 'master' into master
This commit is contained in:
commit
363fc0d5da
@ -254,5 +254,7 @@ namespace osu.Game.Rulesets.Catch
|
|||||||
|
|
||||||
return adjustedDifficulty;
|
return adjustedDifficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool EditorShowScrollSpeed => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -359,5 +359,7 @@ namespace osu.Game.Rulesets.Osu
|
|||||||
|
|
||||||
return adjustedDifficulty;
|
return adjustedDifficulty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool EditorShowScrollSpeed => false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -537,7 +537,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
|||||||
[TestCaseSource(nameof(correct_date_query_examples))]
|
[TestCaseSource(nameof(correct_date_query_examples))]
|
||||||
public void TestValidDateQueries(string dateQuery)
|
public void TestValidDateQueries(string dateQuery)
|
||||||
{
|
{
|
||||||
string query = $"played<{dateQuery} time";
|
string query = $"lastplayed<{dateQuery} time";
|
||||||
var filterCriteria = new FilterCriteria();
|
var filterCriteria = new FilterCriteria();
|
||||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||||
Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter);
|
Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter);
|
||||||
@ -571,7 +571,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestGreaterDateQuery()
|
public void TestGreaterDateQuery()
|
||||||
{
|
{
|
||||||
const string query = "played>50";
|
const string query = "lastplayed>50";
|
||||||
var filterCriteria = new FilterCriteria();
|
var filterCriteria = new FilterCriteria();
|
||||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||||
Assert.That(filterCriteria.LastPlayed.Max, Is.Not.Null);
|
Assert.That(filterCriteria.LastPlayed.Max, Is.Not.Null);
|
||||||
@ -584,7 +584,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestLowerDateQuery()
|
public void TestLowerDateQuery()
|
||||||
{
|
{
|
||||||
const string query = "played<50";
|
const string query = "lastplayed<50";
|
||||||
var filterCriteria = new FilterCriteria();
|
var filterCriteria = new FilterCriteria();
|
||||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||||
Assert.That(filterCriteria.LastPlayed.Max, Is.Null);
|
Assert.That(filterCriteria.LastPlayed.Max, Is.Null);
|
||||||
@ -597,7 +597,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestBothSidesDateQuery()
|
public void TestBothSidesDateQuery()
|
||||||
{
|
{
|
||||||
const string query = "played>3M played<1y6M";
|
const string query = "lastplayed>3M lastplayed<1y6M";
|
||||||
var filterCriteria = new FilterCriteria();
|
var filterCriteria = new FilterCriteria();
|
||||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||||
Assert.That(filterCriteria.LastPlayed.Min, Is.Not.Null);
|
Assert.That(filterCriteria.LastPlayed.Min, Is.Not.Null);
|
||||||
@ -611,7 +611,7 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestEqualDateQuery()
|
public void TestEqualDateQuery()
|
||||||
{
|
{
|
||||||
const string query = "played=50";
|
const string query = "lastplayed=50";
|
||||||
var filterCriteria = new FilterCriteria();
|
var filterCriteria = new FilterCriteria();
|
||||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||||
Assert.AreEqual(false, filterCriteria.LastPlayed.HasFilter);
|
Assert.AreEqual(false, filterCriteria.LastPlayed.HasFilter);
|
||||||
@ -620,11 +620,34 @@ namespace osu.Game.Tests.NonVisual.Filtering
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestOutOfRangeDateQuery()
|
public void TestOutOfRangeDateQuery()
|
||||||
{
|
{
|
||||||
const string query = "played<10000y";
|
const string query = "lastplayed<10000y";
|
||||||
var filterCriteria = new FilterCriteria();
|
var filterCriteria = new FilterCriteria();
|
||||||
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
FilterQueryParser.ApplyQueries(filterCriteria, query);
|
||||||
Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter);
|
Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter);
|
||||||
Assert.AreEqual(DateTimeOffset.MinValue.AddMilliseconds(1), filterCriteria.LastPlayed.Min);
|
Assert.AreEqual(DateTimeOffset.MinValue.AddMilliseconds(1), filterCriteria.LastPlayed.Min);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly object[] played_query_tests =
|
||||||
|
{
|
||||||
|
new object[] { "0", DateTimeOffset.MinValue, true },
|
||||||
|
new object[] { "0", DateTimeOffset.Now, false },
|
||||||
|
new object[] { "false", DateTimeOffset.MinValue, true },
|
||||||
|
new object[] { "false", DateTimeOffset.Now, false },
|
||||||
|
|
||||||
|
new object[] { "1", DateTimeOffset.MinValue, false },
|
||||||
|
new object[] { "1", DateTimeOffset.Now, true },
|
||||||
|
new object[] { "true", DateTimeOffset.MinValue, false },
|
||||||
|
new object[] { "true", DateTimeOffset.Now, true },
|
||||||
|
};
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCaseSource(nameof(played_query_tests))]
|
||||||
|
public void TestPlayedQuery(string query, DateTimeOffset reference, bool matched)
|
||||||
|
{
|
||||||
|
var filterCriteria = new FilterCriteria();
|
||||||
|
FilterQueryParser.ApplyQueries(filterCriteria, $"played={query}");
|
||||||
|
Assert.AreEqual(true, filterCriteria.LastPlayed.HasFilter);
|
||||||
|
Assert.AreEqual(matched, filterCriteria.LastPlayed.IsInRange(reference));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ using Humanizer;
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -307,6 +308,46 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
hitObjectNodeHasSampleVolume(0, 1, 10);
|
hitObjectNodeHasSampleVolume(0, 1, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSamplePointSeek()
|
||||||
|
{
|
||||||
|
AddStep("add slider", () =>
|
||||||
|
{
|
||||||
|
EditorBeatmap.Clear();
|
||||||
|
EditorBeatmap.Add(new Slider
|
||||||
|
{
|
||||||
|
Position = new Vector2(256, 256),
|
||||||
|
StartTime = 0,
|
||||||
|
Path = new SliderPath(new[] { new PathControlPoint(Vector2.Zero), new PathControlPoint(new Vector2(250, 0)) }),
|
||||||
|
Samples =
|
||||||
|
{
|
||||||
|
new HitSampleInfo(HitSampleInfo.HIT_NORMAL)
|
||||||
|
},
|
||||||
|
NodeSamples =
|
||||||
|
{
|
||||||
|
new List<HitSampleInfo> { new HitSampleInfo(HitSampleInfo.HIT_NORMAL) },
|
||||||
|
new List<HitSampleInfo> { new HitSampleInfo(HitSampleInfo.HIT_NORMAL) },
|
||||||
|
},
|
||||||
|
RepeatCount = 1
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
seekSamplePiece(-1);
|
||||||
|
editorTimeIs(0);
|
||||||
|
samplePopoverIsOpen();
|
||||||
|
seekSamplePiece(-1);
|
||||||
|
editorTimeIs(0);
|
||||||
|
samplePopoverIsOpen();
|
||||||
|
seekSamplePiece(1);
|
||||||
|
editorTimeIs(406);
|
||||||
|
seekSamplePiece(1);
|
||||||
|
editorTimeIs(813);
|
||||||
|
seekSamplePiece(1);
|
||||||
|
editorTimeIs(1627);
|
||||||
|
seekSamplePiece(1);
|
||||||
|
editorTimeIs(1627);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestHotkeysMultipleSelectionWithSameSampleBank()
|
public void TestHotkeysMultipleSelectionWithSameSampleBank()
|
||||||
{
|
{
|
||||||
@ -548,6 +589,63 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
hitObjectNodeHasSamples(2, 1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);
|
hitObjectNodeHasSamples(2, 1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestHotkeysUnifySliderSamplesAndNodeSamples()
|
||||||
|
{
|
||||||
|
AddStep("add slider", () =>
|
||||||
|
{
|
||||||
|
EditorBeatmap.Clear();
|
||||||
|
EditorBeatmap.Add(new Slider
|
||||||
|
{
|
||||||
|
Position = new Vector2(256, 256),
|
||||||
|
StartTime = 1000,
|
||||||
|
Path = new SliderPath(new[] { new PathControlPoint(Vector2.Zero), new PathControlPoint(new Vector2(250, 0)) }),
|
||||||
|
Samples =
|
||||||
|
{
|
||||||
|
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, HitSampleInfo.BANK_SOFT),
|
||||||
|
new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, bank: HitSampleInfo.BANK_DRUM),
|
||||||
|
},
|
||||||
|
NodeSamples = new List<IList<HitSampleInfo>>
|
||||||
|
{
|
||||||
|
new List<HitSampleInfo>
|
||||||
|
{
|
||||||
|
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_DRUM),
|
||||||
|
new HitSampleInfo(HitSampleInfo.HIT_CLAP, bank: HitSampleInfo.BANK_DRUM),
|
||||||
|
},
|
||||||
|
new List<HitSampleInfo>
|
||||||
|
{
|
||||||
|
new HitSampleInfo(HitSampleInfo.HIT_NORMAL, bank: HitSampleInfo.BANK_SOFT),
|
||||||
|
new HitSampleInfo(HitSampleInfo.HIT_WHISTLE, bank: HitSampleInfo.BANK_SOFT),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
AddStep("select everything", () => EditorBeatmap.SelectedHitObjects.AddRange(EditorBeatmap.HitObjects));
|
||||||
|
|
||||||
|
AddStep("set soft bank", () =>
|
||||||
|
{
|
||||||
|
InputManager.PressKey(Key.LShift);
|
||||||
|
InputManager.Key(Key.E);
|
||||||
|
InputManager.ReleaseKey(Key.LShift);
|
||||||
|
});
|
||||||
|
|
||||||
|
hitObjectHasSampleBank(0, HitSampleInfo.BANK_SOFT);
|
||||||
|
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);
|
||||||
|
hitObjectNodeHasSampleBank(0, 0, HitSampleInfo.BANK_SOFT);
|
||||||
|
hitObjectNodeHasSamples(0, 0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_CLAP);
|
||||||
|
hitObjectNodeHasSampleBank(0, 1, HitSampleInfo.BANK_SOFT);
|
||||||
|
hitObjectNodeHasSamples(0, 1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);
|
||||||
|
|
||||||
|
AddStep("unify whistle addition", () => InputManager.Key(Key.W));
|
||||||
|
|
||||||
|
hitObjectHasSampleBank(0, HitSampleInfo.BANK_SOFT);
|
||||||
|
hitObjectHasSamples(0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);
|
||||||
|
hitObjectNodeHasSampleBank(0, 0, HitSampleInfo.BANK_SOFT);
|
||||||
|
hitObjectNodeHasSamples(0, 0, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_CLAP, HitSampleInfo.HIT_WHISTLE);
|
||||||
|
hitObjectNodeHasSampleBank(0, 1, HitSampleInfo.BANK_SOFT);
|
||||||
|
hitObjectNodeHasSamples(0, 1, HitSampleInfo.HIT_NORMAL, HitSampleInfo.HIT_WHISTLE);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestSelectingObjectDoesNotMutateSamples()
|
public void TestSelectingObjectDoesNotMutateSamples()
|
||||||
{
|
{
|
||||||
@ -569,7 +667,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
private void clickSamplePiece(int objectIndex) => AddStep($"click {objectIndex.ToOrdinalWords()} sample piece", () =>
|
private void clickSamplePiece(int objectIndex) => AddStep($"click {objectIndex.ToOrdinalWords()} sample piece", () =>
|
||||||
{
|
{
|
||||||
var samplePiece = this.ChildrenOfType<SamplePointPiece>().Single(piece => piece.HitObject == EditorBeatmap.HitObjects.ElementAt(objectIndex));
|
var samplePiece = this.ChildrenOfType<SamplePointPiece>().Single(piece => piece is not NodeSamplePointPiece && piece.HitObject == EditorBeatmap.HitObjects.ElementAt(objectIndex));
|
||||||
|
|
||||||
InputManager.MoveMouseTo(samplePiece);
|
InputManager.MoveMouseTo(samplePiece);
|
||||||
InputManager.Click(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
@ -583,6 +681,21 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
InputManager.Click(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private void seekSamplePiece(int direction) => AddStep($"seek sample piece {direction}", () =>
|
||||||
|
{
|
||||||
|
InputManager.PressKey(Key.ControlLeft);
|
||||||
|
InputManager.PressKey(Key.ShiftLeft);
|
||||||
|
InputManager.Key(direction < 1 ? Key.Left : Key.Right);
|
||||||
|
InputManager.ReleaseKey(Key.ShiftLeft);
|
||||||
|
InputManager.ReleaseKey(Key.ControlLeft);
|
||||||
|
});
|
||||||
|
|
||||||
|
private void samplePopoverIsOpen() => AddUntilStep("sample popover is open", () =>
|
||||||
|
{
|
||||||
|
var popover = this.ChildrenOfType<SamplePointPiece.SampleEditPopover>().SingleOrDefault(o => o.IsPresent);
|
||||||
|
return popover != null;
|
||||||
|
});
|
||||||
|
|
||||||
private void samplePopoverHasNoFocus() => AddUntilStep("sample popover textbox not focused", () =>
|
private void samplePopoverHasNoFocus() => AddUntilStep("sample popover textbox not focused", () =>
|
||||||
{
|
{
|
||||||
var popover = this.ChildrenOfType<SamplePointPiece.SampleEditPopover>().SingleOrDefault();
|
var popover = this.ChildrenOfType<SamplePointPiece.SampleEditPopover>().SingleOrDefault();
|
||||||
@ -727,5 +840,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
var h = EditorBeatmap.HitObjects.ElementAt(objectIndex) as IHasRepeats;
|
var h = EditorBeatmap.HitObjects.ElementAt(objectIndex) as IHasRepeats;
|
||||||
return h is not null && h.NodeSamples[nodeIndex].Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(o => o.Bank == bank);
|
return h is not null && h.NodeSamples[nodeIndex].Where(o => o.Name != HitSampleInfo.HIT_NORMAL).All(o => o.Bank == bank);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private void editorTimeIs(double time) => AddAssert($"editor time is {time}", () => Precision.AlmostEquals(EditorClock.CurrentTimeAccurate, time, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,32 +96,6 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddAssert("slider placed", () => EditorBeatmap.HitObjects.Count, () => Is.EqualTo(1));
|
AddAssert("slider placed", () => EditorBeatmap.HitObjects.Count, () => Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestCommitPlacementViaGlobalAction()
|
|
||||||
{
|
|
||||||
Playfield playfield = null!;
|
|
||||||
|
|
||||||
AddStep("select slider placement tool", () => InputManager.Key(Key.Number3));
|
|
||||||
AddStep("move mouse to top left of playfield", () =>
|
|
||||||
{
|
|
||||||
playfield = this.ChildrenOfType<Playfield>().Single();
|
|
||||||
var location = (3 * playfield.ScreenSpaceDrawQuad.TopLeft + playfield.ScreenSpaceDrawQuad.BottomRight) / 4;
|
|
||||||
InputManager.MoveMouseTo(location);
|
|
||||||
});
|
|
||||||
AddStep("begin placement", () => InputManager.Click(MouseButton.Left));
|
|
||||||
AddStep("move mouse to bottom right of playfield", () =>
|
|
||||||
{
|
|
||||||
var location = (playfield.ScreenSpaceDrawQuad.TopLeft + 3 * playfield.ScreenSpaceDrawQuad.BottomRight) / 4;
|
|
||||||
InputManager.MoveMouseTo(location);
|
|
||||||
});
|
|
||||||
AddStep("confirm via global action", () =>
|
|
||||||
{
|
|
||||||
globalActionContainer.TriggerPressed(GlobalAction.Select);
|
|
||||||
globalActionContainer.TriggerReleased(GlobalAction.Select);
|
|
||||||
});
|
|
||||||
AddAssert("slider placed", () => EditorBeatmap.HitObjects.Count, () => Is.EqualTo(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestAbortPlacementViaGlobalAction()
|
public void TestAbortPlacementViaGlobalAction()
|
||||||
{
|
{
|
||||||
@ -272,11 +246,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
var location = (playfield.ScreenSpaceDrawQuad.TopLeft + 3 * playfield.ScreenSpaceDrawQuad.BottomRight) / 4;
|
var location = (playfield.ScreenSpaceDrawQuad.TopLeft + 3 * playfield.ScreenSpaceDrawQuad.BottomRight) / 4;
|
||||||
InputManager.MoveMouseTo(location);
|
InputManager.MoveMouseTo(location);
|
||||||
});
|
});
|
||||||
AddStep("confirm via global action", () =>
|
AddStep("confirm via right click", () => InputManager.Click(MouseButton.Right));
|
||||||
{
|
|
||||||
globalActionContainer.TriggerPressed(GlobalAction.Select);
|
|
||||||
globalActionContainer.TriggerReleased(GlobalAction.Select);
|
|
||||||
});
|
|
||||||
AddAssert("slider placed", () => EditorBeatmap.HitObjects.Count, () => Is.EqualTo(1));
|
AddAssert("slider placed", () => EditorBeatmap.HitObjects.Count, () => Is.EqualTo(1));
|
||||||
|
|
||||||
AddAssert("slider samples have drum bank", () => EditorBeatmap.HitObjects[0].Samples.All(s => s.Bank == HitSampleInfo.BANK_DRUM));
|
AddAssert("slider samples have drum bank", () => EditorBeatmap.HitObjects[0].Samples.All(s => s.Bank == HitSampleInfo.BANK_DRUM));
|
||||||
|
@ -17,6 +17,7 @@ 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.Comments;
|
using osu.Game.Overlays.Comments;
|
||||||
|
using osu.Game.Overlays.Comments.Buttons;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Online
|
namespace osu.Game.Tests.Visual.Online
|
||||||
{
|
{
|
||||||
@ -58,6 +59,11 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123));
|
AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123));
|
||||||
AddUntilStep("show more button hidden",
|
AddUntilStep("show more button hidden",
|
||||||
() => commentsContainer.ChildrenOfType<CommentsShowMoreButton>().Single().Alpha == 0);
|
() => commentsContainer.ChildrenOfType<CommentsShowMoreButton>().Single().Alpha == 0);
|
||||||
|
|
||||||
|
if (withPinned)
|
||||||
|
AddAssert("pinned comment replies collapsed", () => commentsContainer.ChildrenOfType<ShowRepliesButton>().First().Expanded.Value, () => Is.False);
|
||||||
|
else
|
||||||
|
AddAssert("first comment replies expanded", () => commentsContainer.ChildrenOfType<ShowRepliesButton>().First().Expanded.Value, () => Is.True);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestCase(false)]
|
[TestCase(false)]
|
||||||
@ -302,7 +308,7 @@ namespace osu.Game.Tests.Visual.Online
|
|||||||
bundle.Comments.Add(new Comment
|
bundle.Comments.Add(new Comment
|
||||||
{
|
{
|
||||||
Id = 20,
|
Id = 20,
|
||||||
Message = "Reply to pinned comment",
|
Message = "Reply to pinned comment initially hidden",
|
||||||
LegacyName = "AbandonedUser",
|
LegacyName = "AbandonedUser",
|
||||||
CreatedAt = DateTimeOffset.Now,
|
CreatedAt = DateTimeOffset.Now,
|
||||||
VotesCount = 0,
|
VotesCount = 0,
|
||||||
|
@ -147,6 +147,10 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.MouseWheelLeft }, GlobalAction.EditorCycleNextBeatSnapDivisor),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.MouseWheelLeft }, GlobalAction.EditorCycleNextBeatSnapDivisor),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.R }, GlobalAction.EditorToggleRotateControl),
|
new KeyBinding(new[] { InputKey.Control, InputKey.R }, GlobalAction.EditorToggleRotateControl),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.E }, GlobalAction.EditorToggleScaleControl),
|
new KeyBinding(new[] { InputKey.Control, InputKey.E }, GlobalAction.EditorToggleScaleControl),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Left }, GlobalAction.EditorSeekToPreviousHitObject),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Right }, GlobalAction.EditorSeekToNextHitObject),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.Left }, GlobalAction.EditorSeekToPreviousSamplePoint),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.Right }, GlobalAction.EditorSeekToNextSamplePoint),
|
||||||
};
|
};
|
||||||
|
|
||||||
private static IEnumerable<KeyBinding> editorTestPlayKeyBindings => new[]
|
private static IEnumerable<KeyBinding> editorTestPlayKeyBindings => new[]
|
||||||
@ -456,6 +460,18 @@ namespace osu.Game.Input.Bindings
|
|||||||
|
|
||||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorTestPlayQuickExitToCurrentTime))]
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorTestPlayQuickExitToCurrentTime))]
|
||||||
EditorTestPlayQuickExitToCurrentTime,
|
EditorTestPlayQuickExitToCurrentTime,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorSeekToPreviousHitObject))]
|
||||||
|
EditorSeekToPreviousHitObject,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorSeekToNextHitObject))]
|
||||||
|
EditorSeekToNextHitObject,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorSeekToPreviousSamplePoint))]
|
||||||
|
EditorSeekToPreviousSamplePoint,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorSeekToNextSamplePoint))]
|
||||||
|
EditorSeekToNextSamplePoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum GlobalActionCategory
|
public enum GlobalActionCategory
|
||||||
|
@ -404,6 +404,26 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString DecreaseModSpeed => new TranslatableString(getKey(@"decrease_mod_speed"), @"Decrease mod speed");
|
public static LocalisableString DecreaseModSpeed => new TranslatableString(getKey(@"decrease_mod_speed"), @"Decrease mod speed");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Seek to previous hit object"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString EditorSeekToPreviousHitObject => new TranslatableString(getKey(@"editor_seek_to_previous_hit_object"), @"Seek to previous hit object");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Seek to next hit object"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString EditorSeekToNextHitObject => new TranslatableString(getKey(@"editor_seek_to_next_hit_object"), @"Seek to next hit object");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Seek to previous sample point"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString EditorSeekToPreviousSamplePoint => new TranslatableString(getKey(@"editor_seek_to_previous_sample_point"), @"Seek to previous sample point");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Seek to next sample point"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString EditorSeekToNextSamplePoint => new TranslatableString(getKey(@"editor_seek_to_next_sample_point"), @"Seek to next sample point");
|
||||||
|
|
||||||
private static string getKey(string key) => $@"{prefix}:{key}";
|
private static string getKey(string key) => $@"{prefix}:{key}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ namespace osu.Game.Overlays.Comments
|
|||||||
|
|
||||||
public readonly BindableList<DrawableComment> Replies = new BindableList<DrawableComment>();
|
public readonly BindableList<DrawableComment> Replies = new BindableList<DrawableComment>();
|
||||||
|
|
||||||
private readonly BindableBool childrenExpanded = new BindableBool(true);
|
private readonly BindableBool childrenExpanded;
|
||||||
|
|
||||||
private int currentPage;
|
private int currentPage;
|
||||||
|
|
||||||
@ -92,6 +92,8 @@ namespace osu.Game.Overlays.Comments
|
|||||||
{
|
{
|
||||||
Comment = comment;
|
Comment = comment;
|
||||||
Meta = meta;
|
Meta = meta;
|
||||||
|
|
||||||
|
childrenExpanded = new BindableBool(!comment.Pinned);
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
|
@ -115,7 +115,7 @@ namespace osu.Game.Overlays
|
|||||||
seekDelegate?.Cancel();
|
seekDelegate?.Cancel();
|
||||||
seekDelegate = Schedule(() =>
|
seekDelegate = Schedule(() =>
|
||||||
{
|
{
|
||||||
if (beatmap.Disabled || !AllowTrackControl.Value)
|
if (!AllowTrackControl.Value)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
CurrentTrack.Seek(position);
|
CurrentTrack.Seek(position);
|
||||||
|
@ -23,15 +23,15 @@ namespace osu.Game.Overlays.Volume
|
|||||||
{
|
{
|
||||||
case GlobalAction.DecreaseVolume:
|
case GlobalAction.DecreaseVolume:
|
||||||
case GlobalAction.IncreaseVolume:
|
case GlobalAction.IncreaseVolume:
|
||||||
ActionRequested?.Invoke(e.Action);
|
return ActionRequested?.Invoke(e.Action) == true;
|
||||||
return true;
|
|
||||||
|
|
||||||
case GlobalAction.ToggleMute:
|
case GlobalAction.ToggleMute:
|
||||||
case GlobalAction.NextVolumeMeter:
|
case GlobalAction.NextVolumeMeter:
|
||||||
case GlobalAction.PreviousVolumeMeter:
|
case GlobalAction.PreviousVolumeMeter:
|
||||||
if (!e.Repeat)
|
if (!e.Repeat)
|
||||||
ActionRequested?.Invoke(e.Action);
|
return ActionRequested?.Invoke(e.Action) == true;
|
||||||
return true;
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -110,14 +110,18 @@ namespace osu.Game.Overlays
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
case GlobalAction.NextVolumeMeter:
|
case GlobalAction.NextVolumeMeter:
|
||||||
if (State.Value == Visibility.Visible)
|
if (State.Value != Visibility.Visible)
|
||||||
volumeMeters.SelectNext();
|
return false;
|
||||||
|
|
||||||
|
volumeMeters.SelectNext();
|
||||||
Show();
|
Show();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case GlobalAction.PreviousVolumeMeter:
|
case GlobalAction.PreviousVolumeMeter:
|
||||||
if (State.Value == Visibility.Visible)
|
if (State.Value != Visibility.Visible)
|
||||||
volumeMeters.SelectPrevious();
|
return false;
|
||||||
|
|
||||||
|
volumeMeters.SelectPrevious();
|
||||||
Show();
|
Show();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -125,10 +125,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
switch (e.Action)
|
switch (e.Action)
|
||||||
{
|
{
|
||||||
case GlobalAction.Select:
|
|
||||||
EndPlacement(true);
|
|
||||||
return true;
|
|
||||||
|
|
||||||
case GlobalAction.Back:
|
case GlobalAction.Back:
|
||||||
EndPlacement(false);
|
EndPlacement(false);
|
||||||
return true;
|
return true;
|
||||||
|
@ -401,5 +401,10 @@ namespace osu.Game.Rulesets
|
|||||||
new DifficultySection(),
|
new DifficultySection(),
|
||||||
new ColoursSection(),
|
new ColoursSection(),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Can be overridden to avoid showing scroll speed changes in the editor.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool EditorShowScrollSpeed => true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
MaxValue = time_span_max
|
MaxValue = time_span_max
|
||||||
};
|
};
|
||||||
|
|
||||||
ScrollVisualisationMethod IDrawableScrollingRuleset.VisualisationMethod => VisualisationMethod;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the player can change <see cref="TimeRange"/>.
|
/// Whether the player can change <see cref="TimeRange"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -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.
|
||||||
|
|
||||||
using osu.Game.Configuration;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.UI.Scrolling
|
namespace osu.Game.Rulesets.UI.Scrolling
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -10,8 +8,6 @@ namespace osu.Game.Rulesets.UI.Scrolling
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IDrawableScrollingRuleset
|
public interface IDrawableScrollingRuleset
|
||||||
{
|
{
|
||||||
ScrollVisualisationMethod VisualisationMethod { get; }
|
|
||||||
|
|
||||||
IScrollingInfo ScrollingInfo { get; }
|
IScrollingInfo ScrollingInfo { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,14 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
|||||||
{
|
{
|
||||||
ClearInternal();
|
ClearInternal();
|
||||||
|
|
||||||
AddInternal(new ControlPointVisualisation(effect));
|
if (beatmap.BeatmapInfo.Ruleset.CreateInstance().EditorShowScrollSpeed)
|
||||||
|
{
|
||||||
|
AddInternal(new ControlPointVisualisation(effect)
|
||||||
|
{
|
||||||
|
// importantly, override the x position being set since we do that in the GroupVisualisation parent drawable.
|
||||||
|
X = 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!kiai.Value)
|
if (!kiai.Value)
|
||||||
return;
|
return;
|
||||||
|
@ -229,7 +229,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
EditorBeatmap.PerformOnSelection(h =>
|
EditorBeatmap.PerformOnSelection(h =>
|
||||||
{
|
{
|
||||||
if (h.Samples.All(s => s.Bank == bankName))
|
if (hasRelevantBank(h))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
h.Samples = h.Samples.Select(s => s.With(newBank: bankName)).ToList();
|
h.Samples = h.Samples.Select(s => s.With(newBank: bankName)).ToList();
|
||||||
@ -269,10 +269,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
EditorBeatmap.PerformOnSelection(h =>
|
EditorBeatmap.PerformOnSelection(h =>
|
||||||
{
|
{
|
||||||
// Make sure there isn't already an existing sample
|
// Make sure there isn't already an existing sample
|
||||||
if (h.Samples.Any(s => s.Name == sampleName))
|
if (h.Samples.All(s => s.Name != sampleName))
|
||||||
return;
|
h.Samples.Add(h.CreateHitSampleInfo(sampleName));
|
||||||
|
|
||||||
h.Samples.Add(h.CreateHitSampleInfo(sampleName));
|
|
||||||
|
|
||||||
if (h is IHasRepeats hasRepeats)
|
if (h is IHasRepeats hasRepeats)
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,12 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
NodeIndex = nodeIndex;
|
NodeIndex = nodeIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override double GetTime()
|
||||||
|
{
|
||||||
|
var hasRepeats = (IHasRepeats)HitObject;
|
||||||
|
return HitObject.StartTime + hasRepeats.Duration * NodeIndex / hasRepeats.SpanCount();
|
||||||
|
}
|
||||||
|
|
||||||
protected override IList<HitSampleInfo> GetSamples()
|
protected override IList<HitSampleInfo> GetSamples()
|
||||||
{
|
{
|
||||||
var hasRepeats = (IHasRepeats)HitObject;
|
var hasRepeats = (IHasRepeats)HitObject;
|
||||||
|
@ -14,6 +14,7 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -33,6 +34,12 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
{
|
{
|
||||||
public readonly HitObject HitObject;
|
public readonly HitObject HitObject;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private EditorClock? editorClock { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private Editor? editor { get; set; }
|
||||||
|
|
||||||
public SamplePointPiece(HitObject hitObject)
|
public SamplePointPiece(HitObject hitObject)
|
||||||
{
|
{
|
||||||
HitObject = hitObject;
|
HitObject = hitObject;
|
||||||
@ -43,11 +50,32 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
|
|
||||||
protected override Color4 GetRepresentingColour(OsuColour colours) => AlternativeColor ? colours.Pink2 : colours.Pink1;
|
protected override Color4 GetRepresentingColour(OsuColour colours) => AlternativeColor ? colours.Pink2 : colours.Pink1;
|
||||||
|
|
||||||
|
protected virtual double GetTime() => HitObject is IHasRepeats r ? HitObject.StartTime + r.Duration / r.SpanCount() / 2 : HitObject.StartTime;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
HitObject.DefaultsApplied += _ => updateText();
|
HitObject.DefaultsApplied += _ => updateText();
|
||||||
updateText();
|
updateText();
|
||||||
|
|
||||||
|
if (editor != null)
|
||||||
|
editor.ShowSampleEditPopoverRequested += onShowSampleEditPopoverRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
if (editor != null)
|
||||||
|
editor.ShowSampleEditPopoverRequested -= onShowSampleEditPopoverRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onShowSampleEditPopoverRequested(double time)
|
||||||
|
{
|
||||||
|
if (!Precision.AlmostEquals(time, GetTime())) return;
|
||||||
|
|
||||||
|
editorClock?.SeekSmoothlyTo(GetTime());
|
||||||
|
this.ShowPopover();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnClick(ClickEvent e)
|
protected override bool OnClick(ClickEvent e)
|
||||||
|
@ -44,6 +44,7 @@ using osu.Game.Overlays.OSD;
|
|||||||
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.Objects.Types;
|
||||||
using osu.Game.Screens.Edit.Components.Menus;
|
using osu.Game.Screens.Edit.Components.Menus;
|
||||||
using osu.Game.Screens.Edit.Compose;
|
using osu.Game.Screens.Edit.Compose;
|
||||||
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
using osu.Game.Screens.Edit.Compose.Components.Timeline;
|
||||||
@ -224,6 +225,9 @@ namespace osu.Game.Screens.Edit
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public Bindable<bool> ComposerFocusMode { get; } = new Bindable<bool>();
|
public Bindable<bool> ComposerFocusMode { get; } = new Bindable<bool>();
|
||||||
|
|
||||||
|
[CanBeNull]
|
||||||
|
public event Action<double> ShowSampleEditPopoverRequested;
|
||||||
|
|
||||||
public Editor(EditorLoader loader = null)
|
public Editor(EditorLoader loader = null)
|
||||||
{
|
{
|
||||||
this.loader = loader;
|
this.loader = loader;
|
||||||
@ -713,6 +717,26 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||||
{
|
{
|
||||||
|
// Repeatable actions
|
||||||
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
case GlobalAction.EditorSeekToPreviousHitObject:
|
||||||
|
seekHitObject(-1);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GlobalAction.EditorSeekToNextHitObject:
|
||||||
|
seekHitObject(1);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GlobalAction.EditorSeekToPreviousSamplePoint:
|
||||||
|
seekSamplePoint(-1);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GlobalAction.EditorSeekToNextSamplePoint:
|
||||||
|
seekSamplePoint(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (e.Repeat)
|
if (e.Repeat)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -750,10 +774,9 @@ namespace osu.Game.Screens.Edit
|
|||||||
case GlobalAction.EditorTestGameplay:
|
case GlobalAction.EditorTestGameplay:
|
||||||
bottomBar.TestGameplayButton.TriggerClick();
|
bottomBar.TestGameplayButton.TriggerClick();
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
|
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
|
||||||
@ -1077,6 +1100,66 @@ namespace osu.Game.Screens.Edit
|
|||||||
clock.Seek(found.Time);
|
clock.Seek(found.Time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void seekHitObject(int direction)
|
||||||
|
{
|
||||||
|
var found = direction < 1
|
||||||
|
? editorBeatmap.HitObjects.LastOrDefault(p => p.StartTime < clock.CurrentTimeAccurate)
|
||||||
|
: editorBeatmap.HitObjects.FirstOrDefault(p => p.StartTime > clock.CurrentTimeAccurate);
|
||||||
|
|
||||||
|
if (found != null)
|
||||||
|
clock.SeekSmoothlyTo(found.StartTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void seekSamplePoint(int direction)
|
||||||
|
{
|
||||||
|
double currentTime = clock.CurrentTimeAccurate;
|
||||||
|
|
||||||
|
// Check if we are currently inside a hit object with node samples, if so seek to the next node sample point
|
||||||
|
var current = direction < 1
|
||||||
|
? editorBeatmap.HitObjects.LastOrDefault(p => p is IHasRepeats r && p.StartTime < currentTime && r.EndTime >= currentTime)
|
||||||
|
: editorBeatmap.HitObjects.LastOrDefault(p => p is IHasRepeats r && p.StartTime <= currentTime && r.EndTime > currentTime);
|
||||||
|
|
||||||
|
if (current != null)
|
||||||
|
{
|
||||||
|
// Find the next node sample point
|
||||||
|
var r = (IHasRepeats)current;
|
||||||
|
double[] nodeSamplePointTimes = new double[r.RepeatCount + 3];
|
||||||
|
|
||||||
|
nodeSamplePointTimes[0] = current.StartTime;
|
||||||
|
// The sample point for the main samples is sandwiched between the head and the first repeat
|
||||||
|
nodeSamplePointTimes[1] = current.StartTime + r.Duration / r.SpanCount() / 2;
|
||||||
|
|
||||||
|
for (int i = 0; i < r.SpanCount(); i++)
|
||||||
|
{
|
||||||
|
nodeSamplePointTimes[i + 2] = current.StartTime + r.Duration * (i + 1) / r.SpanCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
double found = direction < 1
|
||||||
|
? nodeSamplePointTimes.Last(p => p < currentTime)
|
||||||
|
: nodeSamplePointTimes.First(p => p > currentTime);
|
||||||
|
|
||||||
|
clock.SeekSmoothlyTo(found);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (direction < 1)
|
||||||
|
{
|
||||||
|
current = editorBeatmap.HitObjects.LastOrDefault(p => p.StartTime < currentTime);
|
||||||
|
if (current != null)
|
||||||
|
clock.SeekSmoothlyTo(current is IHasRepeats r ? r.EndTime : current.StartTime);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
current = editorBeatmap.HitObjects.FirstOrDefault(p => p.StartTime > currentTime);
|
||||||
|
if (current != null)
|
||||||
|
clock.SeekSmoothlyTo(current.StartTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the sample edit popover at the current time
|
||||||
|
ShowSampleEditPopoverRequested?.Invoke(clock.CurrentTimeAccurate);
|
||||||
|
}
|
||||||
|
|
||||||
private void seek(UIEvent e, int direction)
|
private void seek(UIEvent e, int direction)
|
||||||
{
|
{
|
||||||
double amount = e.ShiftPressed ? 4 : 1;
|
double amount = e.ShiftPressed ? 4 : 1;
|
||||||
|
@ -5,9 +5,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Graphics.UserInterfaceV2;
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
using osu.Game.Rulesets.UI.Scrolling;
|
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Timing
|
namespace osu.Game.Screens.Edit.Timing
|
||||||
{
|
{
|
||||||
@ -38,8 +36,7 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
kiai.Current.BindValueChanged(_ => saveChanges());
|
kiai.Current.BindValueChanged(_ => saveChanges());
|
||||||
scrollSpeedSlider.Current.BindValueChanged(_ => saveChanges());
|
scrollSpeedSlider.Current.BindValueChanged(_ => saveChanges());
|
||||||
|
|
||||||
var drawableRuleset = Beatmap.BeatmapInfo.Ruleset.CreateInstance().CreateDrawableRulesetWith(Beatmap.PlayableBeatmap);
|
if (!Beatmap.BeatmapInfo.Ruleset.CreateInstance().EditorShowScrollSpeed)
|
||||||
if (drawableRuleset is not IDrawableScrollingRuleset scrollingRuleset || scrollingRuleset.VisualisationMethod == ScrollVisualisationMethod.Constant)
|
|
||||||
scrollSpeedSlider.Hide();
|
scrollSpeedSlider.Hide();
|
||||||
|
|
||||||
void saveChanges()
|
void saveChanges()
|
||||||
|
@ -15,6 +15,10 @@ namespace osu.Game.Screens.Edit.Timing.RowAttributes
|
|||||||
|
|
||||||
private AttributeText kiaiModeBubble = null!;
|
private AttributeText kiaiModeBubble = null!;
|
||||||
private AttributeText text = null!;
|
private AttributeText text = null!;
|
||||||
|
private AttributeProgressBar progressBar = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
protected EditorBeatmap Beatmap { get; private set; } = null!;
|
||||||
|
|
||||||
public EffectRowAttribute(EffectControlPoint effect)
|
public EffectRowAttribute(EffectControlPoint effect)
|
||||||
: base(effect, "effect")
|
: base(effect, "effect")
|
||||||
@ -28,7 +32,7 @@ namespace osu.Game.Screens.Edit.Timing.RowAttributes
|
|||||||
{
|
{
|
||||||
Content.AddRange(new Drawable[]
|
Content.AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
new AttributeProgressBar(Point)
|
progressBar = new AttributeProgressBar(Point)
|
||||||
{
|
{
|
||||||
Current = scrollSpeed,
|
Current = scrollSpeed,
|
||||||
},
|
},
|
||||||
@ -36,6 +40,12 @@ namespace osu.Game.Screens.Edit.Timing.RowAttributes
|
|||||||
kiaiModeBubble = new AttributeText(Point) { Text = "kiai" },
|
kiaiModeBubble = new AttributeText(Point) { Text = "kiai" },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!Beatmap.BeatmapInfo.Ruleset.CreateInstance().EditorShowScrollSpeed)
|
||||||
|
{
|
||||||
|
text.Hide();
|
||||||
|
progressBar.Hide();
|
||||||
|
}
|
||||||
|
|
||||||
kiaiMode.BindValueChanged(enabled => kiaiModeBubble.FadeTo(enabled.NewValue ? 1 : 0), true);
|
kiaiMode.BindValueChanged(enabled => kiaiModeBubble.FadeTo(enabled.NewValue ? 1 : 0), true);
|
||||||
scrollSpeed.BindValueChanged(_ => updateText(), true);
|
scrollSpeed.BindValueChanged(_ => updateText(), true);
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,10 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
|
|||||||
base.Dispose(isDisposing);
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
if (client.IsNotNull())
|
if (client.IsNotNull())
|
||||||
|
{
|
||||||
client.RoomUpdated -= onRoomUpdated;
|
client.RoomUpdated -= onRoomUpdated;
|
||||||
|
client.GameplayAborted -= onGameplayAborted;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,10 +62,31 @@ namespace osu.Game.Screens.Select
|
|||||||
case "length":
|
case "length":
|
||||||
return tryUpdateLengthRange(criteria, op, value);
|
return tryUpdateLengthRange(criteria, op, value);
|
||||||
|
|
||||||
case "played":
|
|
||||||
case "lastplayed":
|
case "lastplayed":
|
||||||
return tryUpdateDateAgoRange(ref criteria.LastPlayed, op, value);
|
return tryUpdateDateAgoRange(ref criteria.LastPlayed, op, value);
|
||||||
|
|
||||||
|
case "played":
|
||||||
|
if (!tryParseBool(value, out bool played))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Unplayed beatmaps are filtered on DateTimeOffset.MinValue.
|
||||||
|
|
||||||
|
if (played)
|
||||||
|
{
|
||||||
|
criteria.LastPlayed.Min = DateTimeOffset.MinValue;
|
||||||
|
criteria.LastPlayed.Max = DateTimeOffset.MaxValue;
|
||||||
|
criteria.LastPlayed.IsLowerInclusive = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
criteria.LastPlayed.Min = DateTimeOffset.MinValue;
|
||||||
|
criteria.LastPlayed.Max = DateTimeOffset.MinValue;
|
||||||
|
criteria.LastPlayed.IsLowerInclusive = true;
|
||||||
|
criteria.LastPlayed.IsUpperInclusive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
case "divisor":
|
case "divisor":
|
||||||
return TryUpdateCriteriaRange(ref criteria.BeatDivisor, op, value, tryParseInt);
|
return TryUpdateCriteriaRange(ref criteria.BeatDivisor, op, value, tryParseInt);
|
||||||
|
|
||||||
@ -133,6 +154,23 @@ namespace osu.Game.Screens.Select
|
|||||||
private static bool tryParseInt(string value, out int result) =>
|
private static bool tryParseInt(string value, out int result) =>
|
||||||
int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result);
|
int.TryParse(value, NumberStyles.None, CultureInfo.InvariantCulture, out result);
|
||||||
|
|
||||||
|
private static bool tryParseBool(string value, out bool result)
|
||||||
|
{
|
||||||
|
switch (value)
|
||||||
|
{
|
||||||
|
case "1":
|
||||||
|
result = true;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case "0":
|
||||||
|
result = false;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return bool.TryParse(value, out result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static bool tryParseEnum<TEnum>(string value, out TEnum result) where TEnum : struct
|
private static bool tryParseEnum<TEnum>(string value, out TEnum result) where TEnum : struct
|
||||||
{
|
{
|
||||||
// First try an exact match.
|
// First try an exact match.
|
||||||
|
Loading…
Reference in New Issue
Block a user