mirror of
https://github.com/osukey/osukey.git
synced 2025-05-30 09:57:21 +09:00
Merge branch 'master' into fix-skin-sample-lookup
This commit is contained in:
commit
6268bbea85
@ -1,7 +0,0 @@
|
|||||||
---
|
|
||||||
name: Feature Request
|
|
||||||
about: Propose a feature you would like to see in the game!
|
|
||||||
---
|
|
||||||
**Describe the new feature:**
|
|
||||||
|
|
||||||
**Proposal designs of the feature:**
|
|
9
.github/ISSUE_TEMPLATE/config.yml
vendored
9
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,5 +1,12 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
|
- name: Suggestions or feature request
|
||||||
|
url: https://github.com/ppy/osu/discussions/categories/ideas
|
||||||
|
about: Got something you think should change or be added? Search for or start a new discussion!
|
||||||
|
- name: Help
|
||||||
|
url: https://github.com/ppy/osu/discussions/categories/q-a
|
||||||
|
about: osu! not working as you'd expect? Not sure it's a bug? Check the Q&A section!
|
||||||
- name: osu!stable issues
|
- name: osu!stable issues
|
||||||
url: https://github.com/ppy/osu-stable-issues
|
url: https://github.com/ppy/osu-stable-issues
|
||||||
about: For issues regarding osu!stable (not osu!lazer), open them here.
|
about: For osu!stable bugs (not osu!lazer), check out the dedicated repository. Note that we only accept serious bug reports.
|
||||||
|
|
||||||
|
@ -7,13 +7,14 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Rulesets.Osu.Skinning.Default;
|
using osu.Game.Rulesets.Osu.Skinning.Default;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
||||||
{
|
{
|
||||||
public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking, ITrackSnaking, IHasMainCirclePiece
|
public class DrawableSliderTail : DrawableOsuHitObject, IRequireTracking, IHasMainCirclePiece
|
||||||
{
|
{
|
||||||
public new SliderTailCircle HitObject => (SliderTailCircle)base.HitObject;
|
public new SliderTailCircle HitObject => (SliderTailCircle)base.HitObject;
|
||||||
|
|
||||||
@ -111,7 +112,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
|
|||||||
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : r.Judgement.MinResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateSnakingPosition(Vector2 start, Vector2 end) =>
|
protected override void OnApply()
|
||||||
Position = HitObject.RepeatIndex % 2 == 0 ? end : start;
|
{
|
||||||
|
base.OnApply();
|
||||||
|
|
||||||
|
if (Slider != null)
|
||||||
|
Position = Slider.CurvePositionAt(HitObject.RepeatIndex % 2 == 0 ? 1 : 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
// Old osu! used hit sounding to determine various hit type information
|
// Old osu! used hit sounding to determine various hit type information
|
||||||
IList<HitSampleInfo> samples = obj.Samples;
|
IList<HitSampleInfo> samples = obj.Samples;
|
||||||
|
|
||||||
bool strong = samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
|
|
||||||
|
|
||||||
switch (obj)
|
switch (obj)
|
||||||
{
|
{
|
||||||
case IHasDistance distanceData:
|
case IHasDistance distanceData:
|
||||||
@ -94,15 +92,11 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing)
|
for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing)
|
||||||
{
|
{
|
||||||
IList<HitSampleInfo> currentSamples = allSamples[i];
|
IList<HitSampleInfo> currentSamples = allSamples[i];
|
||||||
bool isRim = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE);
|
|
||||||
strong = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
|
|
||||||
|
|
||||||
yield return new Hit
|
yield return new Hit
|
||||||
{
|
{
|
||||||
StartTime = j,
|
StartTime = j,
|
||||||
Type = isRim ? HitType.Rim : HitType.Centre,
|
|
||||||
Samples = currentSamples,
|
Samples = currentSamples,
|
||||||
IsStrong = strong
|
|
||||||
};
|
};
|
||||||
|
|
||||||
i = (i + 1) % allSamples.Count;
|
i = (i + 1) % allSamples.Count;
|
||||||
@ -117,7 +111,6 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
{
|
{
|
||||||
StartTime = obj.StartTime,
|
StartTime = obj.StartTime,
|
||||||
Samples = obj.Samples,
|
Samples = obj.Samples,
|
||||||
IsStrong = strong,
|
|
||||||
Duration = taikoDuration,
|
Duration = taikoDuration,
|
||||||
TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4
|
TickRate = beatmap.BeatmapInfo.BaseDifficulty.SliderTickRate == 3 ? 3 : 4
|
||||||
};
|
};
|
||||||
@ -143,16 +136,10 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
bool isRimDefinition(HitSampleInfo s) => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE;
|
|
||||||
|
|
||||||
bool isRim = samples.Any(isRimDefinition);
|
|
||||||
|
|
||||||
yield return new Hit
|
yield return new Hit
|
||||||
{
|
{
|
||||||
StartTime = obj.StartTime,
|
StartTime = obj.StartTime,
|
||||||
Type = isRim ? HitType.Rim : HitType.Centre,
|
|
||||||
Samples = samples,
|
Samples = samples,
|
||||||
IsStrong = strong
|
|
||||||
};
|
};
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -69,7 +69,11 @@ namespace osu.Game.Rulesets.Taiko.Edit
|
|||||||
{
|
{
|
||||||
EditorBeatmap.PerformOnSelection(h =>
|
EditorBeatmap.PerformOnSelection(h =>
|
||||||
{
|
{
|
||||||
if (h is Hit taikoHit) taikoHit.Type = state ? HitType.Rim : HitType.Centre;
|
if (h is Hit taikoHit)
|
||||||
|
{
|
||||||
|
taikoHit.Type = state ? HitType.Rim : HitType.Centre;
|
||||||
|
EditorBeatmap.Update(h);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,13 +17,25 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
public HitType Type
|
public HitType Type
|
||||||
{
|
{
|
||||||
get => TypeBindable.Value;
|
get => TypeBindable.Value;
|
||||||
set
|
set => TypeBindable.Value = value;
|
||||||
{
|
|
||||||
TypeBindable.Value = value;
|
|
||||||
updateSamplesFromType();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Hit()
|
||||||
|
{
|
||||||
|
TypeBindable.BindValueChanged(_ => updateSamplesFromType());
|
||||||
|
SamplesBindable.BindCollectionChanged((_, __) => updateTypeFromSamples());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTypeFromSamples()
|
||||||
|
{
|
||||||
|
Type = getRimSamples().Any() ? HitType.Rim : HitType.Centre;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns an array of any samples which would cause this object to be a "rim" type hit.
|
||||||
|
/// </summary>
|
||||||
|
private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray();
|
||||||
|
|
||||||
private void updateSamplesFromType()
|
private void updateSamplesFromType()
|
||||||
{
|
{
|
||||||
var rimSamples = getRimSamples();
|
var rimSamples = getRimSamples();
|
||||||
@ -42,11 +54,6 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns an array of any samples which would cause this object to be a "rim" type hit.
|
|
||||||
/// </summary>
|
|
||||||
private HitSampleInfo[] getRimSamples() => Samples.Where(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE).ToArray();
|
|
||||||
|
|
||||||
protected override StrongNestedHitObject CreateStrongNestedHit(double startTime) => new StrongNestedHit { StartTime = startTime };
|
protected override StrongNestedHitObject CreateStrongNestedHit(double startTime) => new StrongNestedHit { StartTime = startTime };
|
||||||
|
|
||||||
public class StrongNestedHit : StrongNestedHitObject
|
public class StrongNestedHit : StrongNestedHitObject
|
||||||
|
@ -33,14 +33,21 @@ namespace osu.Game.Rulesets.Taiko.Objects
|
|||||||
public bool IsStrong
|
public bool IsStrong
|
||||||
{
|
{
|
||||||
get => IsStrongBindable.Value;
|
get => IsStrongBindable.Value;
|
||||||
set
|
set => IsStrongBindable.Value = value;
|
||||||
{
|
|
||||||
IsStrongBindable.Value = value;
|
|
||||||
updateSamplesFromStrong();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSamplesFromStrong()
|
protected TaikoStrongableHitObject()
|
||||||
|
{
|
||||||
|
IsStrongBindable.BindValueChanged(_ => updateSamplesFromType());
|
||||||
|
SamplesBindable.BindCollectionChanged((_, __) => updateTypeFromSamples());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTypeFromSamples()
|
||||||
|
{
|
||||||
|
IsStrong = getStrongSamples().Any();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSamplesFromType()
|
||||||
{
|
{
|
||||||
var strongSamples = getStrongSamples();
|
var strongSamples = getStrongSamples();
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
{
|
{
|
||||||
var osu = LoadOsuIntoHost(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
await osu.CollectionManager.Import(new MemoryStream());
|
await importCollectionsFromStream(osu, new MemoryStream());
|
||||||
|
|
||||||
Assert.That(osu.CollectionManager.Collections.Count, Is.Zero);
|
Assert.That(osu.CollectionManager.Collections.Count, Is.Zero);
|
||||||
}
|
}
|
||||||
@ -43,7 +43,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
{
|
{
|
||||||
var osu = LoadOsuIntoHost(host);
|
var osu = LoadOsuIntoHost(host);
|
||||||
|
|
||||||
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db"));
|
await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db"));
|
||||||
|
|
||||||
Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2));
|
Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2));
|
||||||
|
|
||||||
@ -69,7 +69,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
{
|
{
|
||||||
var osu = LoadOsuIntoHost(host, true);
|
var osu = LoadOsuIntoHost(host, true);
|
||||||
|
|
||||||
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db"));
|
await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db"));
|
||||||
|
|
||||||
Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2));
|
Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(2));
|
||||||
|
|
||||||
@ -110,7 +110,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
|
|
||||||
ms.Seek(0, SeekOrigin.Begin);
|
ms.Seek(0, SeekOrigin.Begin);
|
||||||
|
|
||||||
await osu.CollectionManager.Import(ms);
|
await importCollectionsFromStream(osu, ms);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert.That(host.UpdateThread.Running, Is.True);
|
Assert.That(host.UpdateThread.Running, Is.True);
|
||||||
@ -134,7 +134,7 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
{
|
{
|
||||||
var osu = LoadOsuIntoHost(host, true);
|
var osu = LoadOsuIntoHost(host, true);
|
||||||
|
|
||||||
await osu.CollectionManager.Import(TestResources.OpenResource("Collections/collections.db"));
|
await importCollectionsFromStream(osu, TestResources.OpenResource("Collections/collections.db"));
|
||||||
|
|
||||||
// Move first beatmap from second collection into the first.
|
// Move first beatmap from second collection into the first.
|
||||||
osu.CollectionManager.Collections[0].Beatmaps.Add(osu.CollectionManager.Collections[1].Beatmaps[0]);
|
osu.CollectionManager.Collections[0].Beatmaps.Add(osu.CollectionManager.Collections[1].Beatmaps[0]);
|
||||||
@ -169,5 +169,12 @@ namespace osu.Game.Tests.Collections.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static async Task importCollectionsFromStream(TestOsuGameBase osu, Stream stream)
|
||||||
|
{
|
||||||
|
// intentionally spin this up on a separate task to avoid disposal deadlocks.
|
||||||
|
// see https://github.com/EventStore/EventStore/issues/1179
|
||||||
|
await Task.Run(() => osu.CollectionManager.Import(stream).Wait());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,13 +88,18 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
beforeLoadAction?.Invoke();
|
beforeLoadAction?.Invoke();
|
||||||
|
|
||||||
|
prepareBeatmap();
|
||||||
|
|
||||||
|
LoadScreen(loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareBeatmap()
|
||||||
|
{
|
||||||
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
|
||||||
Beatmap.Value.BeatmapInfo.EpilepsyWarning = epilepsyWarning;
|
Beatmap.Value.BeatmapInfo.EpilepsyWarning = epilepsyWarning;
|
||||||
|
|
||||||
foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>())
|
foreach (var mod in SelectedMods.Value.OfType<IApplicableToTrack>())
|
||||||
mod.ApplyToTrack(Beatmap.Value.Track);
|
mod.ApplyToTrack(Beatmap.Value.Track);
|
||||||
|
|
||||||
LoadScreen(loader = new TestPlayerLoader(() => player = new TestPlayer(interactive, interactive)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -178,10 +183,13 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
|
|
||||||
AddStep("load slow dummy beatmap", () =>
|
AddStep("load slow dummy beatmap", () =>
|
||||||
{
|
{
|
||||||
LoadScreen(loader = new TestPlayerLoader(() => slowPlayer = new SlowLoadPlayer(false, false)));
|
prepareBeatmap();
|
||||||
Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000);
|
slowPlayer = new SlowLoadPlayer(false, false);
|
||||||
|
LoadScreen(loader = new TestPlayerLoader(() => slowPlayer));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddStep("schedule slow load", () => Scheduler.AddDelayed(() => slowPlayer.AllowLoad.Set(), 5000));
|
||||||
|
|
||||||
AddUntilStep("wait for player to be current", () => slowPlayer.IsCurrentScreen());
|
AddUntilStep("wait for player to be current", () => slowPlayer.IsCurrentScreen());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
CreateTest(null);
|
CreateTest(null);
|
||||||
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
|
AddUntilStep("completion set by processor", () => Player.ScoreProcessor.HasCompleted.Value);
|
||||||
AddStep("skip outro", () => InputManager.Key(osuTK.Input.Key.Space));
|
AddStep("skip outro", () => InputManager.Key(osuTK.Input.Key.Space));
|
||||||
AddAssert("score shown", () => Player.IsScoreShown);
|
AddUntilStep("wait for score shown", () => Player.IsScoreShown);
|
||||||
|
AddUntilStep("time less than storyboard duration", () => Player.GameplayClockContainer.GameplayClock.CurrentTime < currentStoryboardDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -73,8 +73,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
for (int i = 0; i < users; i++)
|
for (int i = 0; i < users; i++)
|
||||||
spectatorClient.StartPlay(i, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
|
spectatorClient.StartPlay(i, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
|
||||||
|
|
||||||
Client.CurrentMatchPlayingUserIds.Clear();
|
spectatorClient.Schedule(() =>
|
||||||
Client.CurrentMatchPlayingUserIds.AddRange(spectatorClient.PlayingUsers);
|
{
|
||||||
|
Client.CurrentMatchPlayingUserIds.Clear();
|
||||||
|
Client.CurrentMatchPlayingUserIds.AddRange(spectatorClient.PlayingUsers);
|
||||||
|
});
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -91,6 +94,7 @@ namespace osu.Game.Tests.Visual.Multiplayer
|
|||||||
});
|
});
|
||||||
|
|
||||||
AddUntilStep("wait for load", () => leaderboard.IsLoaded);
|
AddUntilStep("wait for load", () => leaderboard.IsLoaded);
|
||||||
|
AddUntilStep("wait for user population", () => Client.CurrentMatchPlayingUserIds.Count > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -70,6 +70,7 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
AddStep("click first row", () =>
|
AddStep("click first row", () =>
|
||||||
{
|
{
|
||||||
firstRow = panel.ChildrenOfType<KeyBindingRow>().First();
|
firstRow = panel.ChildrenOfType<KeyBindingRow>().First();
|
||||||
|
|
||||||
InputManager.MoveMouseTo(firstRow);
|
InputManager.MoveMouseTo(firstRow);
|
||||||
InputManager.Click(MouseButton.Left);
|
InputManager.Click(MouseButton.Left);
|
||||||
});
|
});
|
||||||
@ -138,6 +139,64 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestSingleBindingResetButton()
|
||||||
|
{
|
||||||
|
KeyBindingRow settingsKeyBindingRow = null;
|
||||||
|
|
||||||
|
AddStep("click first row", () =>
|
||||||
|
{
|
||||||
|
settingsKeyBindingRow = panel.ChildrenOfType<KeyBindingRow>().First();
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(settingsKeyBindingRow);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
InputManager.PressKey(Key.P);
|
||||||
|
InputManager.ReleaseKey(Key.P);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType<RestoreDefaultValueButton<bool>>().First().Alpha > 0);
|
||||||
|
|
||||||
|
AddStep("click reset button for bindings", () =>
|
||||||
|
{
|
||||||
|
var resetButton = settingsKeyBindingRow.ChildrenOfType<RestoreDefaultValueButton<bool>>().First();
|
||||||
|
|
||||||
|
resetButton.Click();
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType<RestoreDefaultValueButton<bool>>().First().Alpha == 0);
|
||||||
|
|
||||||
|
AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType<KeyBindingRow.KeyButton>().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestResetAllBindingsButton()
|
||||||
|
{
|
||||||
|
KeyBindingRow settingsKeyBindingRow = null;
|
||||||
|
|
||||||
|
AddStep("click first row", () =>
|
||||||
|
{
|
||||||
|
settingsKeyBindingRow = panel.ChildrenOfType<KeyBindingRow>().First();
|
||||||
|
|
||||||
|
InputManager.MoveMouseTo(settingsKeyBindingRow);
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
InputManager.PressKey(Key.P);
|
||||||
|
InputManager.ReleaseKey(Key.P);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("restore button shown", () => settingsKeyBindingRow.ChildrenOfType<RestoreDefaultValueButton<bool>>().First().Alpha > 0);
|
||||||
|
|
||||||
|
AddStep("click reset button for bindings", () =>
|
||||||
|
{
|
||||||
|
var resetButton = panel.ChildrenOfType<ResetButton>().First();
|
||||||
|
|
||||||
|
resetButton.Click();
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType<RestoreDefaultValueButton<bool>>().First().Alpha == 0);
|
||||||
|
|
||||||
|
AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType<KeyBindingRow.KeyButton>().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0)));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestClickRowSelectsFirstBinding()
|
public void TestClickRowSelectsFirstBinding()
|
||||||
{
|
{
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
|
using osu.Game.Overlays;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Settings
|
namespace osu.Game.Tests.Visual.Settings
|
||||||
{
|
{
|
||||||
@ -37,7 +38,7 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
|
|
||||||
private class TestSettingsTextBox : SettingsTextBox
|
private class TestSettingsTextBox : SettingsTextBox
|
||||||
{
|
{
|
||||||
public new Drawable RestoreDefaultValueButton => this.ChildrenOfType<RestoreDefaultValueButton>().Single();
|
public Drawable RestoreDefaultValueButton => this.ChildrenOfType<RestoreDefaultValueButton<string>>().Single();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -786,9 +786,12 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkVisibleItemCount(bool diff, int count) =>
|
private void checkVisibleItemCount(bool diff, int count)
|
||||||
AddAssert($"{count} {(diff ? "diffs" : "sets")} visible", () =>
|
{
|
||||||
|
// until step required as we are querying against alive items, which are loaded asynchronously inside DrawableCarouselBeatmapSet.
|
||||||
|
AddUntilStep($"{count} {(diff ? "diffs" : "sets")} visible", () =>
|
||||||
carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count);
|
carousel.Items.Count(s => (diff ? s.Item is CarouselBeatmap : s.Item is CarouselBeatmapSet) && s.Item.Visible) == count);
|
||||||
|
}
|
||||||
|
|
||||||
private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null);
|
private void checkNoSelection() => AddAssert("Selection is null", () => currentSelection == null);
|
||||||
|
|
||||||
|
@ -58,8 +58,13 @@ namespace osu.Game.Collections
|
|||||||
|
|
||||||
if (storage.Exists(database_name))
|
if (storage.Exists(database_name))
|
||||||
{
|
{
|
||||||
|
List<BeatmapCollection> beatmapCollections;
|
||||||
|
|
||||||
using (var stream = storage.GetStream(database_name))
|
using (var stream = storage.GetStream(database_name))
|
||||||
importCollections(readCollections(stream));
|
beatmapCollections = readCollections(stream);
|
||||||
|
|
||||||
|
// intentionally fire-and-forget async.
|
||||||
|
importCollections(beatmapCollections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -46,12 +47,19 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Container content;
|
||||||
|
|
||||||
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) =>
|
||||||
|
content.ReceivePositionalInputAt(screenSpacePos);
|
||||||
|
|
||||||
public bool FilteringActive { get; set; }
|
public bool FilteringActive { get; set; }
|
||||||
|
|
||||||
private OsuSpriteText text;
|
private OsuSpriteText text;
|
||||||
private FillFlowContainer cancelAndClearButtons;
|
private FillFlowContainer cancelAndClearButtons;
|
||||||
private FillFlowContainer<KeyButton> buttons;
|
private FillFlowContainer<KeyButton> buttons;
|
||||||
|
|
||||||
|
private Bindable<bool> isDefault { get; } = new BindableBool(true);
|
||||||
|
|
||||||
public IEnumerable<string> FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString());
|
public IEnumerable<string> FilterTerms => bindings.Select(b => b.KeyCombination.ReadableString()).Prepend(text.Text.ToString());
|
||||||
|
|
||||||
public KeyBindingRow(object action, IEnumerable<Framework.Input.Bindings.KeyBinding> bindings)
|
public KeyBindingRow(object action, IEnumerable<Framework.Input.Bindings.KeyBinding> bindings)
|
||||||
@ -61,9 +69,6 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
|
||||||
Masking = true;
|
|
||||||
CornerRadius = padding;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
@ -72,51 +77,72 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
EdgeEffect = new EdgeEffectParameters
|
RelativeSizeAxes = Axes.X;
|
||||||
{
|
AutoSizeAxes = Axes.Y;
|
||||||
Radius = 2,
|
Padding = new MarginPadding { Horizontal = SettingsPanel.CONTENT_MARGINS };
|
||||||
Colour = colours.YellowDark.Opacity(0),
|
|
||||||
Type = EdgeEffectType.Shadow,
|
|
||||||
Hollow = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
new Box
|
new RestoreDefaultValueButton<bool>
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
Current = isDefault,
|
||||||
Colour = Color4.Black,
|
Action = RestoreDefaults,
|
||||||
Alpha = 0.6f,
|
|
||||||
},
|
|
||||||
text = new OsuSpriteText
|
|
||||||
{
|
|
||||||
Text = action.GetDescription(),
|
|
||||||
Margin = new MarginPadding(padding),
|
|
||||||
},
|
|
||||||
buttons = new FillFlowContainer<KeyButton>
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight
|
|
||||||
},
|
|
||||||
cancelAndClearButtons = new FillFlowContainer
|
|
||||||
{
|
|
||||||
AutoSizeAxes = Axes.Both,
|
|
||||||
Padding = new MarginPadding(padding) { Top = height + padding * 2 },
|
|
||||||
Anchor = Anchor.TopRight,
|
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
Alpha = 0,
|
},
|
||||||
Spacing = new Vector2(5),
|
content = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
AutoSizeAxes = Axes.Y,
|
||||||
|
Masking = true,
|
||||||
|
CornerRadius = padding,
|
||||||
|
EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Radius = 2,
|
||||||
|
Colour = colours.YellowDark.Opacity(0),
|
||||||
|
Type = EdgeEffectType.Shadow,
|
||||||
|
Hollow = true,
|
||||||
|
},
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new CancelButton { Action = finalise },
|
new Box
|
||||||
new ClearButton { Action = clear },
|
{
|
||||||
},
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Colour = Color4.Black,
|
||||||
|
Alpha = 0.6f,
|
||||||
|
},
|
||||||
|
text = new OsuSpriteText
|
||||||
|
{
|
||||||
|
Text = action.GetDescription(),
|
||||||
|
Margin = new MarginPadding(padding),
|
||||||
|
},
|
||||||
|
buttons = new FillFlowContainer<KeyButton>
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight
|
||||||
|
},
|
||||||
|
cancelAndClearButtons = new FillFlowContainer
|
||||||
|
{
|
||||||
|
AutoSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding(padding) { Top = height + padding * 2 },
|
||||||
|
Anchor = Anchor.TopRight,
|
||||||
|
Origin = Anchor.TopRight,
|
||||||
|
Alpha = 0,
|
||||||
|
Spacing = new Vector2(5),
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
new CancelButton { Action = finalise },
|
||||||
|
new ClearButton { Action = clear },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var b in bindings)
|
foreach (var b in bindings)
|
||||||
buttons.Add(new KeyButton(b));
|
buttons.Add(new KeyButton(b));
|
||||||
|
|
||||||
|
updateIsDefaultValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RestoreDefaults()
|
public void RestoreDefaults()
|
||||||
@ -129,18 +155,20 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
button.UpdateKeyCombination(d);
|
button.UpdateKeyCombination(d);
|
||||||
store.Update(button.KeyBinding);
|
store.Update(button.KeyBinding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isDefault.Value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e)
|
protected override bool OnHover(HoverEvent e)
|
||||||
{
|
{
|
||||||
FadeEdgeEffectTo(1, transition_time, Easing.OutQuint);
|
content.FadeEdgeEffectTo(1, transition_time, Easing.OutQuint);
|
||||||
|
|
||||||
return base.OnHover(e);
|
return base.OnHover(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(HoverLostEvent e)
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
{
|
{
|
||||||
FadeEdgeEffectTo(0, transition_time, Easing.OutQuint);
|
content.FadeEdgeEffectTo(0, transition_time, Easing.OutQuint);
|
||||||
|
|
||||||
base.OnHoverLost(e);
|
base.OnHoverLost(e);
|
||||||
}
|
}
|
||||||
@ -288,6 +316,8 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
{
|
{
|
||||||
store.Update(bindTarget.KeyBinding);
|
store.Update(bindTarget.KeyBinding);
|
||||||
|
|
||||||
|
updateIsDefaultValue();
|
||||||
|
|
||||||
bindTarget.IsBinding = false;
|
bindTarget.IsBinding = false;
|
||||||
Schedule(() =>
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
@ -305,8 +335,8 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
|
|
||||||
protected override void OnFocus(FocusEvent e)
|
protected override void OnFocus(FocusEvent e)
|
||||||
{
|
{
|
||||||
AutoSizeDuration = 500;
|
content.AutoSizeDuration = 500;
|
||||||
AutoSizeEasing = Easing.OutQuint;
|
content.AutoSizeEasing = Easing.OutQuint;
|
||||||
|
|
||||||
cancelAndClearButtons.FadeIn(300, Easing.OutQuint);
|
cancelAndClearButtons.FadeIn(300, Easing.OutQuint);
|
||||||
cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y;
|
cancelAndClearButtons.BypassAutoSizeAxes &= ~Axes.Y;
|
||||||
@ -331,6 +361,11 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
if (bindTarget != null) bindTarget.IsBinding = true;
|
if (bindTarget != null) bindTarget.IsBinding = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateIsDefaultValue()
|
||||||
|
{
|
||||||
|
isDefault.Value = bindings.Select(b => b.KeyCombination).SequenceEqual(Defaults);
|
||||||
|
}
|
||||||
|
|
||||||
private class CancelButton : TriangleButton
|
private class CancelButton : TriangleButton
|
||||||
{
|
{
|
||||||
public CancelButton()
|
public CancelButton()
|
||||||
@ -379,9 +414,6 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
|
|
||||||
Margin = new MarginPadding(padding);
|
Margin = new MarginPadding(padding);
|
||||||
|
|
||||||
// todo: use this in a meaningful way
|
|
||||||
// var isDefault = keyBinding.Action is Enum;
|
|
||||||
|
|
||||||
Masking = true;
|
Masking = true;
|
||||||
CornerRadius = padding;
|
CornerRadius = padding;
|
||||||
|
|
||||||
|
@ -61,8 +61,11 @@ namespace osu.Game.Overlays.KeyBinding
|
|||||||
{
|
{
|
||||||
Text = "Reset all bindings in section";
|
Text = "Reset all bindings in section";
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Margin = new MarginPadding { Top = 5 };
|
Width = 0.5f;
|
||||||
Height = 20;
|
Anchor = Anchor.TopCentre;
|
||||||
|
Origin = Anchor.TopCentre;
|
||||||
|
Margin = new MarginPadding { Top = 15 };
|
||||||
|
Height = 30;
|
||||||
|
|
||||||
Content.CornerRadius = 5;
|
Content.CornerRadius = 5;
|
||||||
}
|
}
|
||||||
|
106
osu.Game/Overlays/RestoreDefaultValueButton.cs
Normal file
106
osu.Game/Overlays/RestoreDefaultValueButton.cs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
|
using osu.Framework.Graphics.Effects;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
|
|
||||||
|
namespace osu.Game.Overlays
|
||||||
|
{
|
||||||
|
public class RestoreDefaultValueButton<T> : OsuButton, IHasTooltip, IHasCurrentValue<T>
|
||||||
|
{
|
||||||
|
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
|
||||||
|
|
||||||
|
private readonly BindableWithCurrent<T> current = new BindableWithCurrent<T>();
|
||||||
|
|
||||||
|
// this is done to ensure a click on this button doesn't trigger focus on a parent element which contains the button.
|
||||||
|
public override bool AcceptsFocus => true;
|
||||||
|
|
||||||
|
public Bindable<T> Current
|
||||||
|
{
|
||||||
|
get => current.Current;
|
||||||
|
set => current.Current = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Color4 buttonColour;
|
||||||
|
|
||||||
|
private bool hovering;
|
||||||
|
|
||||||
|
public RestoreDefaultValueButton()
|
||||||
|
{
|
||||||
|
Height = 1;
|
||||||
|
|
||||||
|
RelativeSizeAxes = Axes.Y;
|
||||||
|
Width = SettingsPanel.CONTENT_MARGINS;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuColour colour)
|
||||||
|
{
|
||||||
|
BackgroundColour = colour.Yellow;
|
||||||
|
buttonColour = colour.Yellow;
|
||||||
|
Content.Width = 0.33f;
|
||||||
|
Content.CornerRadius = 3;
|
||||||
|
Content.EdgeEffect = new EdgeEffectParameters
|
||||||
|
{
|
||||||
|
Colour = buttonColour.Opacity(0.1f),
|
||||||
|
Type = EdgeEffectType.Glow,
|
||||||
|
Radius = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
Padding = new MarginPadding { Vertical = 1.5f };
|
||||||
|
Alpha = 0f;
|
||||||
|
|
||||||
|
Action += () =>
|
||||||
|
{
|
||||||
|
if (!current.Disabled) current.SetDefault();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
|
||||||
|
Current.ValueChanged += _ => UpdateState();
|
||||||
|
Current.DisabledChanged += _ => UpdateState();
|
||||||
|
Current.DefaultChanged += _ => UpdateState();
|
||||||
|
|
||||||
|
UpdateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string TooltipText => "revert to default";
|
||||||
|
|
||||||
|
protected override bool OnHover(HoverEvent e)
|
||||||
|
{
|
||||||
|
hovering = true;
|
||||||
|
UpdateState();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
|
{
|
||||||
|
hovering = false;
|
||||||
|
UpdateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateState() => Scheduler.AddOnce(updateState);
|
||||||
|
|
||||||
|
private void updateState()
|
||||||
|
{
|
||||||
|
if (current == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.FadeTo(current.IsDefault ? 0f :
|
||||||
|
hovering && !current.Disabled ? 1f : 0.65f, 200, Easing.OutQuint);
|
||||||
|
this.FadeColour(current.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,16 +5,11 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osuTK.Graphics;
|
|
||||||
using osu.Framework.Extensions.Color4Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Cursor;
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Effects;
|
|
||||||
using osu.Framework.Graphics.Shapes;
|
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
@ -108,7 +103,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
|
|
||||||
protected SettingsItem()
|
protected SettingsItem()
|
||||||
{
|
{
|
||||||
RestoreDefaultValueButton restoreDefaultButton;
|
RestoreDefaultValueButton<T> restoreDefaultButton;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
@ -116,7 +111,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
restoreDefaultButton = new RestoreDefaultValueButton(),
|
restoreDefaultButton = new RestoreDefaultValueButton<T>(),
|
||||||
FlowContent = new FillFlowContainer
|
FlowContent = new FillFlowContainer
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
@ -137,7 +132,7 @@ namespace osu.Game.Overlays.Settings
|
|||||||
controlWithCurrent.Current.DisabledChanged += _ => updateDisabled();
|
controlWithCurrent.Current.DisabledChanged += _ => updateDisabled();
|
||||||
|
|
||||||
if (ShowsDefaultIndicator)
|
if (ShowsDefaultIndicator)
|
||||||
restoreDefaultButton.Bindable = controlWithCurrent.Current;
|
restoreDefaultButton.Current = controlWithCurrent.Current;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,101 +141,5 @@ namespace osu.Game.Overlays.Settings
|
|||||||
if (labelText != null)
|
if (labelText != null)
|
||||||
labelText.Alpha = controlWithCurrent.Current.Disabled ? 0.3f : 1;
|
labelText.Alpha = controlWithCurrent.Current.Disabled ? 0.3f : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected internal class RestoreDefaultValueButton : Container, IHasTooltip
|
|
||||||
{
|
|
||||||
public override bool IsPresent => base.IsPresent || Scheduler.HasPendingTasks;
|
|
||||||
|
|
||||||
private Bindable<T> bindable;
|
|
||||||
|
|
||||||
public Bindable<T> Bindable
|
|
||||||
{
|
|
||||||
get => bindable;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
bindable = value;
|
|
||||||
bindable.ValueChanged += _ => UpdateState();
|
|
||||||
bindable.DisabledChanged += _ => UpdateState();
|
|
||||||
bindable.DefaultChanged += _ => UpdateState();
|
|
||||||
UpdateState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Color4 buttonColour;
|
|
||||||
|
|
||||||
private bool hovering;
|
|
||||||
|
|
||||||
public RestoreDefaultValueButton()
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Y;
|
|
||||||
Width = SettingsPanel.CONTENT_MARGINS;
|
|
||||||
Padding = new MarginPadding { Vertical = 1.5f };
|
|
||||||
Alpha = 0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuColour colour)
|
|
||||||
{
|
|
||||||
buttonColour = colour.Yellow;
|
|
||||||
|
|
||||||
Child = new Container
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
CornerRadius = 3,
|
|
||||||
Masking = true,
|
|
||||||
Colour = buttonColour,
|
|
||||||
EdgeEffect = new EdgeEffectParameters
|
|
||||||
{
|
|
||||||
Colour = buttonColour.Opacity(0.1f),
|
|
||||||
Type = EdgeEffectType.Glow,
|
|
||||||
Radius = 2,
|
|
||||||
},
|
|
||||||
Width = 0.33f,
|
|
||||||
Child = new Box { RelativeSizeAxes = Axes.Both },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
|
||||||
{
|
|
||||||
base.LoadComplete();
|
|
||||||
UpdateState();
|
|
||||||
}
|
|
||||||
|
|
||||||
public string TooltipText => "revert to default";
|
|
||||||
|
|
||||||
protected override bool OnClick(ClickEvent e)
|
|
||||||
{
|
|
||||||
if (bindable != null && !bindable.Disabled)
|
|
||||||
bindable.SetDefault();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool OnHover(HoverEvent e)
|
|
||||||
{
|
|
||||||
hovering = true;
|
|
||||||
UpdateState();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnHoverLost(HoverLostEvent e)
|
|
||||||
{
|
|
||||||
hovering = false;
|
|
||||||
UpdateState();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateState() => Scheduler.AddOnce(updateState);
|
|
||||||
|
|
||||||
private void updateState()
|
|
||||||
{
|
|
||||||
if (bindable == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this.FadeTo(bindable.IsDefault ? 0f :
|
|
||||||
hovering && !bindable.Disabled ? 1f : 0.65f, 200, Easing.OutQuint);
|
|
||||||
this.FadeColour(bindable.Disabled ? Color4.Gray : buttonColour, 200, Easing.OutQuint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,6 +10,7 @@ using osu.Framework.Allocation;
|
|||||||
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.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -49,8 +50,6 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private readonly bool showSidebar;
|
private readonly bool showSidebar;
|
||||||
|
|
||||||
protected Box Background;
|
|
||||||
|
|
||||||
protected SettingsPanel(bool showSidebar)
|
protected SettingsPanel(bool showSidebar)
|
||||||
{
|
{
|
||||||
this.showSidebar = showSidebar;
|
this.showSidebar = showSidebar;
|
||||||
@ -63,13 +62,13 @@ namespace osu.Game.Overlays
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
InternalChild = ContentContainer = new Container
|
InternalChild = ContentContainer = new NonMaskedContent
|
||||||
{
|
{
|
||||||
Width = WIDTH,
|
Width = WIDTH,
|
||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
Background = new Box
|
new Box
|
||||||
{
|
{
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
@ -165,7 +164,7 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
base.PopOut();
|
base.PopOut();
|
||||||
|
|
||||||
ContentContainer.MoveToX(-WIDTH, TRANSITION_LENGTH, Easing.OutQuint);
|
ContentContainer.MoveToX(-WIDTH + ExpandedPosition, TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
|
|
||||||
Sidebar?.MoveToX(-sidebar_width, TRANSITION_LENGTH, Easing.OutQuint);
|
Sidebar?.MoveToX(-sidebar_width, TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint);
|
this.FadeTo(0, TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
@ -191,6 +190,12 @@ namespace osu.Game.Overlays
|
|||||||
Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
|
Padding = new MarginPadding { Top = GetToolbarHeight?.Invoke() ?? 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class NonMaskedContent : Container<Drawable>
|
||||||
|
{
|
||||||
|
// masking breaks the pan-out transform with nested sub-settings panels.
|
||||||
|
protected override bool ComputeIsMaskedAway(RectangleF maskingBounds) => false;
|
||||||
|
}
|
||||||
|
|
||||||
public class SettingsSectionsContainer : SectionsContainer<SettingsSection>
|
public class SettingsSectionsContainer : SectionsContainer<SettingsSection>
|
||||||
{
|
{
|
||||||
public SearchContainer<SettingsSection> SearchContainer;
|
public SearchContainer<SettingsSection> SearchContainer;
|
||||||
|
@ -311,6 +311,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked for this <see cref="DrawableHitObject"/> to take on any values from a newly-applied <see cref="HitObject"/>.
|
/// Invoked for this <see cref="DrawableHitObject"/> to take on any values from a newly-applied <see cref="HitObject"/>.
|
||||||
|
/// This is also fired after any changes which occurred via an <see cref="osu.Game.Rulesets.Objects.HitObject.ApplyDefaults"/> call.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnApply()
|
protected virtual void OnApply()
|
||||||
{
|
{
|
||||||
@ -318,6 +319,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked for this <see cref="DrawableHitObject"/> to revert any values previously taken on from the currently-applied <see cref="HitObject"/>.
|
/// Invoked for this <see cref="DrawableHitObject"/> to revert any values previously taken on from the currently-applied <see cref="HitObject"/>.
|
||||||
|
/// This is also fired after any changes which occurred via an <see cref="osu.Game.Rulesets.Objects.HitObject.ApplyDefaults"/> call.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual void OnFree()
|
protected virtual void OnFree()
|
||||||
{
|
{
|
||||||
|
@ -77,7 +77,13 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
double offset = result.Time.Value - blueprints.First().Item.StartTime;
|
double offset = result.Time.Value - blueprints.First().Item.StartTime;
|
||||||
|
|
||||||
if (offset != 0)
|
if (offset != 0)
|
||||||
Beatmap.PerformOnSelection(obj => obj.StartTime += offset);
|
{
|
||||||
|
Beatmap.PerformOnSelection(obj =>
|
||||||
|
{
|
||||||
|
obj.StartTime += offset;
|
||||||
|
Beatmap.Update(obj);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -125,6 +125,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
h.Samples.Add(new HitSampleInfo(sampleName));
|
h.Samples.Add(new HitSampleInfo(sampleName));
|
||||||
|
EditorBeatmap.Update(h);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +135,11 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// <param name="sampleName">The name of the hit sample.</param>
|
/// <param name="sampleName">The name of the hit sample.</param>
|
||||||
public void RemoveHitSample(string sampleName)
|
public void RemoveHitSample(string sampleName)
|
||||||
{
|
{
|
||||||
EditorBeatmap.PerformOnSelection(h => h.SamplesBindable.RemoveAll(s => s.Name == sampleName));
|
EditorBeatmap.PerformOnSelection(h =>
|
||||||
|
{
|
||||||
|
h.SamplesBindable.RemoveAll(s => s.Name == sampleName);
|
||||||
|
EditorBeatmap.Update(h);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -276,7 +276,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
var timingPoint = EditorBeatmap.ControlPointInfo.TimingPointAt(selected.First().StartTime);
|
var timingPoint = EditorBeatmap.ControlPointInfo.TimingPointAt(selected.First().StartTime);
|
||||||
double adjustment = timingPoint.BeatLength / EditorBeatmap.BeatDivisor * amount;
|
double adjustment = timingPoint.BeatLength / EditorBeatmap.BeatDivisor * amount;
|
||||||
|
|
||||||
EditorBeatmap.PerformOnSelection(h => h.StartTime += adjustment);
|
EditorBeatmap.PerformOnSelection(h =>
|
||||||
|
{
|
||||||
|
h.StartTime += adjustment;
|
||||||
|
EditorBeatmap.Update(h);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -522,7 +522,10 @@ namespace osu.Game.Screens.Play
|
|||||||
if (!this.IsCurrentScreen())
|
if (!this.IsCurrentScreen())
|
||||||
{
|
{
|
||||||
ValidForResume = false;
|
ValidForResume = false;
|
||||||
this.MakeCurrent();
|
|
||||||
|
// in the potential case that this instance has already been exited, this is required to avoid a crash.
|
||||||
|
if (this.GetChildScreen() != null)
|
||||||
|
this.MakeCurrent();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Screens.Select.Carousel
|
|||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private ManageCollectionsDialog manageCollectionsDialog { get; set; }
|
private ManageCollectionsDialog manageCollectionsDialog { get; set; }
|
||||||
|
|
||||||
public IEnumerable<DrawableCarouselItem> DrawableBeatmaps => beatmapContainer?.Children ?? Enumerable.Empty<DrawableCarouselItem>();
|
public IEnumerable<DrawableCarouselItem> DrawableBeatmaps => beatmapContainer?.IsLoaded != true ? Enumerable.Empty<DrawableCarouselItem>() : beatmapContainer.AliveChildren;
|
||||||
|
|
||||||
[CanBeNull]
|
[CanBeNull]
|
||||||
private Container<DrawableCarouselItem> beatmapContainer;
|
private Container<DrawableCarouselItem> beatmapContainer;
|
||||||
|
@ -57,7 +57,13 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
public DrawableStoryboard(Storyboard storyboard)
|
public DrawableStoryboard(Storyboard storyboard)
|
||||||
{
|
{
|
||||||
Storyboard = storyboard;
|
Storyboard = storyboard;
|
||||||
|
|
||||||
Size = new Vector2(640, 480);
|
Size = new Vector2(640, 480);
|
||||||
|
|
||||||
|
bool onlyHasVideoElements = Storyboard.Layers.SelectMany(l => l.Elements).Any(e => !(e is StoryboardVideo));
|
||||||
|
|
||||||
|
Width = Height * (storyboard.BeatmapInfo.WidescreenStoryboard || onlyHasVideoElements ? 16 / 9f : 4 / 3f);
|
||||||
|
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ using System.Threading;
|
|||||||
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 osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Storyboards.Drawables
|
namespace osu.Game.Storyboards.Drawables
|
||||||
{
|
{
|
||||||
@ -15,6 +16,8 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
|
|
||||||
public override bool IsPresent => Enabled && base.IsPresent;
|
public override bool IsPresent => Enabled && base.IsPresent;
|
||||||
|
|
||||||
|
protected LayerElementContainer ElementContainer { get; }
|
||||||
|
|
||||||
public DrawableStoryboardLayer(StoryboardLayer layer)
|
public DrawableStoryboardLayer(StoryboardLayer layer)
|
||||||
{
|
{
|
||||||
Layer = layer;
|
Layer = layer;
|
||||||
@ -24,10 +27,10 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
Enabled = layer.VisibleWhenPassing;
|
Enabled = layer.VisibleWhenPassing;
|
||||||
Masking = layer.Masking;
|
Masking = layer.Masking;
|
||||||
|
|
||||||
InternalChild = new LayerElementContainer(layer);
|
InternalChild = ElementContainer = new LayerElementContainer(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class LayerElementContainer : LifetimeManagementContainer
|
protected class LayerElementContainer : LifetimeManagementContainer
|
||||||
{
|
{
|
||||||
private readonly StoryboardLayer storyboardLayer;
|
private readonly StoryboardLayer storyboardLayer;
|
||||||
|
|
||||||
@ -35,8 +38,8 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
{
|
{
|
||||||
storyboardLayer = layer;
|
storyboardLayer = layer;
|
||||||
|
|
||||||
Width = 640;
|
Size = new Vector2(640, 480);
|
||||||
Height = 480;
|
|
||||||
Anchor = Anchor.Centre;
|
Anchor = Anchor.Centre;
|
||||||
Origin = Anchor.Centre;
|
Origin = Anchor.Centre;
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ namespace osu.Game.Storyboards
|
|||||||
|
|
||||||
public Storyboard()
|
public Storyboard()
|
||||||
{
|
{
|
||||||
layers.Add("Video", new StoryboardLayer("Video", 4, false));
|
layers.Add("Video", new StoryboardVideoLayer("Video", 4, false));
|
||||||
layers.Add("Background", new StoryboardLayer("Background", 3));
|
layers.Add("Background", new StoryboardLayer("Background", 3));
|
||||||
layers.Add("Fail", new StoryboardLayer("Fail", 2) { VisibleWhenPassing = false, });
|
layers.Add("Fail", new StoryboardLayer("Fail", 2) { VisibleWhenPassing = false, });
|
||||||
layers.Add("Pass", new StoryboardLayer("Pass", 1) { VisibleWhenFailing = false, });
|
layers.Add("Pass", new StoryboardLayer("Pass", 1) { VisibleWhenFailing = false, });
|
||||||
@ -85,12 +85,8 @@ namespace osu.Game.Storyboards
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DrawableStoryboard CreateDrawable(WorkingBeatmap working = null)
|
public DrawableStoryboard CreateDrawable(WorkingBeatmap working = null) =>
|
||||||
{
|
new DrawableStoryboard(this);
|
||||||
var drawable = new DrawableStoryboard(this);
|
|
||||||
drawable.Width = drawable.Height * (BeatmapInfo.WidescreenStoryboard ? 16 / 9f : 4 / 3f);
|
|
||||||
return drawable;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Drawable CreateSpriteFromResourcePath(string path, TextureStore textureStore)
|
public Drawable CreateSpriteFromResourcePath(string path, TextureStore textureStore)
|
||||||
{
|
{
|
||||||
|
@ -32,7 +32,7 @@ namespace osu.Game.Storyboards
|
|||||||
Elements.Add(element);
|
Elements.Add(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DrawableStoryboardLayer CreateDrawable()
|
public virtual DrawableStoryboardLayer CreateDrawable()
|
||||||
=> new DrawableStoryboardLayer(this) { Depth = Depth, Name = Name };
|
=> new DrawableStoryboardLayer(this) { Depth = Depth, Name = Name };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
32
osu.Game/Storyboards/StoryboardVideoLayer.cs
Normal file
32
osu.Game/Storyboards/StoryboardVideoLayer.cs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Storyboards.Drawables;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
|
namespace osu.Game.Storyboards
|
||||||
|
{
|
||||||
|
public class StoryboardVideoLayer : StoryboardLayer
|
||||||
|
{
|
||||||
|
public StoryboardVideoLayer(string name, int depth, bool masking)
|
||||||
|
: base(name, depth, masking)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DrawableStoryboardLayer CreateDrawable()
|
||||||
|
=> new DrawableStoryboardVideoLayer(this) { Depth = Depth, Name = Name };
|
||||||
|
|
||||||
|
public class DrawableStoryboardVideoLayer : DrawableStoryboardLayer
|
||||||
|
{
|
||||||
|
public DrawableStoryboardVideoLayer(StoryboardVideoLayer layer)
|
||||||
|
: base(layer)
|
||||||
|
{
|
||||||
|
// for videos we want to take on the full size of the storyboard container hierarchy
|
||||||
|
// to allow the video to fill the full available region.
|
||||||
|
ElementContainer.RelativeSizeAxes = Axes.Both;
|
||||||
|
ElementContainer.Size = Vector2.One;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#nullable enable
|
#nullable enable
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -53,6 +54,8 @@ namespace osu.Game.Tests.Visual.Spectator
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public new void Schedule(Action action) => base.Schedule(action);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends frames for an arbitrary user.
|
/// Sends frames for an arbitrary user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user