mirror of
https://github.com/ppy/osu.git
synced 2025-02-13 10:33:07 +08:00
Merge branch 'master' into da-mod-refactor
This commit is contained in:
commit
6f89f8e572
@ -11,7 +11,7 @@
|
||||
|
||||
A free-to-win rhythm game. Rhythm is just a *click* away!
|
||||
|
||||
The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Commonly known by the codename *osu!lazer*. Pew pew.
|
||||
The future of [osu!](https://osu.ppy.sh) and the beginning of an open era! Currently known by and released under the codename "*lazer*". As in sharper than cutting-edge.
|
||||
|
||||
## Status
|
||||
|
||||
@ -23,7 +23,7 @@ We are accepting bug reports (please report with as much detail as possible and
|
||||
|
||||
- Detailed release changelogs are available on the [official osu! site](https://osu.ppy.sh/home/changelog/lazer).
|
||||
- You can learn more about our approach to [project management](https://github.com/ppy/osu/wiki/Project-management).
|
||||
- Read peppy's [latest blog post](https://blog.ppy.sh/a-definitive-lazer-faq/) exploring where lazer is currently and the roadmap going forward.
|
||||
- Read peppy's [latest blog post](https://blog.ppy.sh/a-definitive-lazer-faq/) exploring where the project is currently and the roadmap going forward.
|
||||
|
||||
## Running osu!
|
||||
|
||||
|
@ -13,6 +13,8 @@ namespace osu.Game.Rulesets.Catch.Edit.Blueprints
|
||||
public abstract class CatchSelectionBlueprint<THitObject> : HitObjectSelectionBlueprint<THitObject>
|
||||
where THitObject : CatchHitObject
|
||||
{
|
||||
protected override bool AlwaysShowWhenSelected => true;
|
||||
|
||||
public override Vector2 ScreenSpaceSelectionPoint
|
||||
{
|
||||
get
|
||||
|
@ -11,7 +11,6 @@ using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Play.Break;
|
||||
using osu.Game.Screens.Ranking;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
@ -36,18 +35,6 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000));
|
||||
AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
|
||||
|
||||
double? time = null;
|
||||
|
||||
AddStep("store time", () => time = Player.GameplayClockContainer.GameplayClock.CurrentTime);
|
||||
|
||||
// test seek via keyboard
|
||||
AddStep("seek with right arrow key", () => InputManager.Key(Key.Right));
|
||||
AddAssert("time seeked forward", () => Player.GameplayClockContainer.GameplayClock.CurrentTime > time + 2000);
|
||||
|
||||
AddStep("store time", () => time = Player.GameplayClockContainer.GameplayClock.CurrentTime);
|
||||
AddStep("seek with left arrow key", () => InputManager.Key(Key.Left));
|
||||
AddAssert("time seeked backward", () => Player.GameplayClockContainer.GameplayClock.CurrentTime < time);
|
||||
|
||||
seekToBreak(0);
|
||||
seekToBreak(1);
|
||||
|
||||
|
@ -87,7 +87,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
showOverlay();
|
||||
|
||||
AddStep("Up arrow", () => InputManager.Key(Key.Up));
|
||||
AddAssert("Last button selected", () => pauseOverlay.Buttons.Last().Selected.Value);
|
||||
AddAssert("Last button selected", () => pauseOverlay.Buttons.Last().State == SelectionState.Selected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -99,7 +99,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
showOverlay();
|
||||
|
||||
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||
AddAssert("First button selected", () => getButton(0).Selected.Value);
|
||||
AddAssert("First button selected", () => getButton(0).State == SelectionState.Selected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -111,11 +111,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("Show overlay", () => failOverlay.Show());
|
||||
|
||||
AddStep("Up arrow", () => InputManager.Key(Key.Up));
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().State == SelectionState.Selected);
|
||||
AddStep("Up arrow", () => InputManager.Key(Key.Up));
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().State == SelectionState.Selected);
|
||||
AddStep("Up arrow", () => InputManager.Key(Key.Up));
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().State == SelectionState.Selected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -127,11 +127,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("Show overlay", () => failOverlay.Show());
|
||||
|
||||
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().State == SelectionState.Selected);
|
||||
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().Selected.Value);
|
||||
AddAssert("Last button selected", () => failOverlay.Buttons.Last().State == SelectionState.Selected);
|
||||
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().Selected.Value);
|
||||
AddAssert("First button selected", () => failOverlay.Buttons.First().State == SelectionState.Selected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -145,7 +145,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("Hover first button", () => InputManager.MoveMouseTo(failOverlay.Buttons.First()));
|
||||
AddStep("Hide overlay", () => failOverlay.Hide());
|
||||
|
||||
AddAssert("Overlay state is reset", () => !failOverlay.Buttons.Any(b => b.Selected.Value));
|
||||
AddAssert("Overlay state is reset", () => failOverlay.Buttons.All(b => b.State == SelectionState.NotSelected));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -162,11 +162,11 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("Hide overlay", () => pauseOverlay.Hide());
|
||||
showOverlay();
|
||||
|
||||
AddAssert("First button not selected", () => !getButton(0).Selected.Value);
|
||||
AddAssert("First button not selected", () => getButton(0).State == SelectionState.NotSelected);
|
||||
|
||||
AddStep("Move slightly", () => InputManager.MoveMouseTo(InputManager.CurrentState.Mouse.Position + new Vector2(1)));
|
||||
|
||||
AddAssert("First button selected", () => getButton(0).Selected.Value);
|
||||
AddAssert("First button selected", () => getButton(0).State == SelectionState.Selected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -179,8 +179,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
||||
AddAssert("First button not selected", () => !getButton(0).Selected.Value);
|
||||
AddAssert("Second button selected", () => getButton(1).Selected.Value);
|
||||
AddAssert("First button not selected", () => getButton(0).State == SelectionState.NotSelected);
|
||||
AddAssert("Second button selected", () => getButton(1).State == SelectionState.Selected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -196,8 +196,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
|
||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
||||
AddStep("Up arrow", () => InputManager.Key(Key.Up));
|
||||
AddAssert("Second button not selected", () => !getButton(1).Selected.Value);
|
||||
AddAssert("First button selected", () => getButton(0).Selected.Value);
|
||||
AddAssert("Second button not selected", () => getButton(1).State == SelectionState.NotSelected);
|
||||
AddAssert("First button selected", () => getButton(0).State == SelectionState.Selected);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -211,7 +211,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
AddStep("Hover second button", () => InputManager.MoveMouseTo(getButton(1)));
|
||||
AddStep("Unhover second button", () => InputManager.MoveMouseTo(Vector2.Zero));
|
||||
AddStep("Down arrow", () => InputManager.Key(Key.Down));
|
||||
AddAssert("First button selected", () => getButton(0).Selected.Value); // Initial state condition
|
||||
AddAssert("First button selected", () => getButton(0).State == SelectionState.Selected); // Initial state condition
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -282,7 +282,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
||||
showOverlay();
|
||||
|
||||
AddAssert("No button selected",
|
||||
() => pauseOverlay.Buttons.All(button => !button.Selected.Value));
|
||||
() => pauseOverlay.Buttons.All(button => button.State == SelectionState.NotSelected));
|
||||
}
|
||||
|
||||
private void showOverlay() => AddStep("Show overlay", () => pauseOverlay.Show());
|
||||
|
87
osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs
Normal file
87
osu.Game.Tests/Visual/Gameplay/TestSceneReplayPlayer.cs
Normal file
@ -0,0 +1,87 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Osu;
|
||||
using osuTK.Input;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Gameplay
|
||||
{
|
||||
public class TestSceneReplayPlayer : RateAdjustedBeatmapTestScene
|
||||
{
|
||||
protected TestReplayPlayer Player;
|
||||
|
||||
public override void SetUpSteps()
|
||||
{
|
||||
base.SetUpSteps();
|
||||
|
||||
AddStep("Initialise player", () => Player = CreatePlayer(new OsuRuleset()));
|
||||
AddStep("Load player", () => LoadScreen(Player));
|
||||
AddUntilStep("player loaded", () => Player.IsLoaded);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPause()
|
||||
{
|
||||
double? lastTime = null;
|
||||
|
||||
AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0);
|
||||
|
||||
AddStep("Pause playback", () => InputManager.Key(Key.Space));
|
||||
|
||||
AddUntilStep("Time stopped progressing", () =>
|
||||
{
|
||||
double current = Player.GameplayClockContainer.CurrentTime;
|
||||
bool changed = lastTime != current;
|
||||
lastTime = current;
|
||||
|
||||
return !changed;
|
||||
});
|
||||
|
||||
AddWaitStep("wait some", 10);
|
||||
|
||||
AddAssert("Time still stopped", () => lastTime == Player.GameplayClockContainer.CurrentTime);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSeekBackwards()
|
||||
{
|
||||
double? lastTime = null;
|
||||
|
||||
AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0);
|
||||
|
||||
AddStep("Seek backwards", () =>
|
||||
{
|
||||
lastTime = Player.GameplayClockContainer.CurrentTime;
|
||||
InputManager.Key(Key.Left);
|
||||
});
|
||||
|
||||
AddAssert("Jumped backwards", () => Player.GameplayClockContainer.CurrentTime - lastTime < 0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSeekForwards()
|
||||
{
|
||||
double? lastTime = null;
|
||||
|
||||
AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0);
|
||||
|
||||
AddStep("Seek forwards", () =>
|
||||
{
|
||||
lastTime = Player.GameplayClockContainer.CurrentTime;
|
||||
InputManager.Key(Key.Right);
|
||||
});
|
||||
|
||||
AddAssert("Jumped forwards", () => Player.GameplayClockContainer.CurrentTime - lastTime > 500);
|
||||
}
|
||||
|
||||
protected TestReplayPlayer CreatePlayer(Ruleset ruleset)
|
||||
{
|
||||
Beatmap.Value = CreateWorkingBeatmap(ruleset.RulesetInfo);
|
||||
SelectedMods.Value = new[] { ruleset.GetAutoplayMod() };
|
||||
|
||||
return new TestReplayPlayer(false);
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Add(new DirectorySelector { RelativeSizeAxes = Axes.Both });
|
||||
Add(new OsuDirectorySelector { RelativeSizeAxes = Axes.Both });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,13 +12,13 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
[Test]
|
||||
public void TestAllFiles()
|
||||
{
|
||||
AddStep("create", () => Child = new FileSelector { RelativeSizeAxes = Axes.Both });
|
||||
AddStep("create", () => Child = new OsuFileSelector { RelativeSizeAxes = Axes.Both });
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestJpgFilesOnly()
|
||||
{
|
||||
AddStep("create", () => Child = new FileSelector(validFileExtensions: new[] { ".jpg" }) { RelativeSizeAxes = Axes.Both });
|
||||
AddStep("create", () => Child = new OsuFileSelector(validFileExtensions: new[] { ".jpg" }) { RelativeSizeAxes = Axes.Both });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.Mods;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mania;
|
||||
using osu.Game.Rulesets.Mania.Mods;
|
||||
@ -50,6 +51,38 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
AddStep("show", () => modSelect.Show());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure that two mod overlays are not cross polluting via central settings instances.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestSettingsNotCrossPolluting()
|
||||
{
|
||||
Bindable<IReadOnlyList<Mod>> selectedMods2 = null;
|
||||
|
||||
AddStep("select diff adjust", () => SelectedMods.Value = new Mod[] { new OsuModDifficultyAdjust() });
|
||||
|
||||
AddStep("set setting", () => modSelect.ChildrenOfType<SettingsSlider<float>>().First().Current.Value = 8);
|
||||
|
||||
AddAssert("ensure setting is propagated", () => SelectedMods.Value.OfType<OsuModDifficultyAdjust>().Single().CircleSize.Value == 8);
|
||||
|
||||
AddStep("create second bindable", () => selectedMods2 = new Bindable<IReadOnlyList<Mod>>(new Mod[] { new OsuModDifficultyAdjust() }));
|
||||
|
||||
AddStep("create second overlay", () =>
|
||||
{
|
||||
Add(modSelect = new TestModSelectOverlay().With(d =>
|
||||
{
|
||||
d.Origin = Anchor.TopCentre;
|
||||
d.Anchor = Anchor.TopCentre;
|
||||
d.SelectedMods.BindTarget = selectedMods2;
|
||||
}));
|
||||
});
|
||||
|
||||
AddStep("show", () => modSelect.Show());
|
||||
|
||||
AddAssert("ensure first is unchanged", () => SelectedMods.Value.OfType<OsuModDifficultyAdjust>().Single().CircleSize.Value == 8);
|
||||
AddAssert("ensure second is default", () => selectedMods2.Value.OfType<OsuModDifficultyAdjust>().Single().CircleSize.Value == 5);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSettingsResetOnDeselection()
|
||||
{
|
||||
|
@ -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.Overlays;
|
||||
using osu.Game.Overlays.Volume;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
public class TestSceneVolumeOverlay : OsuTestScene
|
||||
{
|
||||
private VolumeOverlay volume;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
volume = new VolumeOverlay(),
|
||||
new VolumeControlReceptor
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ActionRequested = action => volume.Adjust(action),
|
||||
ScrollActionRequested = (action, amount, isPrecise) => volume.Adjust(action, amount, isPrecise),
|
||||
},
|
||||
});
|
||||
|
||||
AddStep("show controls", () => volume.Show());
|
||||
}
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ namespace osu.Game.Tournament.Screens.Setup
|
||||
[Resolved]
|
||||
private MatchIPCInfo ipc { get; set; }
|
||||
|
||||
private DirectorySelector directorySelector;
|
||||
private OsuDirectorySelector directorySelector;
|
||||
private DialogOverlay overlay;
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
@ -79,7 +79,7 @@ namespace osu.Game.Tournament.Screens.Setup
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
directorySelector = new DirectorySelector(initialPath)
|
||||
directorySelector = new OsuDirectorySelector(initialPath)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Graphics.Containers
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
protected virtual HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet);
|
||||
protected virtual HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet);
|
||||
|
||||
public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Default)
|
||||
{
|
||||
@ -39,7 +39,7 @@ namespace osu.Game.Graphics.Containers
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
content,
|
||||
CreateHoverClickSounds(sampleSet)
|
||||
CreateHoverSounds(sampleSet)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,87 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Graphics.Containers
|
||||
{
|
||||
/// <summary>
|
||||
/// A FillFlowContainer that provides functionality to cycle selection between children
|
||||
/// The selection wraps around when overflowing past the first or last child.
|
||||
/// </summary>
|
||||
public class SelectionCycleFillFlowContainer<T> : FillFlowContainer<T> where T : Drawable, IStateful<SelectionState>
|
||||
{
|
||||
public T Selected => (selectedIndex >= 0 && selectedIndex < Count) ? this[selectedIndex.Value] : null;
|
||||
|
||||
private int? selectedIndex;
|
||||
|
||||
public void SelectNext()
|
||||
{
|
||||
if (!selectedIndex.HasValue || selectedIndex == Count - 1)
|
||||
setSelected(0);
|
||||
else
|
||||
setSelected(selectedIndex.Value + 1);
|
||||
}
|
||||
|
||||
public void SelectPrevious()
|
||||
{
|
||||
if (!selectedIndex.HasValue || selectedIndex == 0)
|
||||
setSelected(Count - 1);
|
||||
else
|
||||
setSelected(selectedIndex.Value - 1);
|
||||
}
|
||||
|
||||
public void Deselect() => setSelected(null);
|
||||
|
||||
public void Select(T item)
|
||||
{
|
||||
var newIndex = IndexOf(item);
|
||||
|
||||
if (newIndex < 0)
|
||||
setSelected(null);
|
||||
else
|
||||
setSelected(IndexOf(item));
|
||||
}
|
||||
|
||||
public override void Add(T drawable)
|
||||
{
|
||||
base.Add(drawable);
|
||||
|
||||
Debug.Assert(drawable != null);
|
||||
|
||||
drawable.StateChanged += state => selectionChanged(drawable, state);
|
||||
}
|
||||
|
||||
public override bool Remove(T drawable)
|
||||
=> throw new NotSupportedException($"Cannot remove drawables from {nameof(SelectionCycleFillFlowContainer<T>)}");
|
||||
|
||||
private void setSelected(int? value)
|
||||
{
|
||||
if (selectedIndex == value)
|
||||
return;
|
||||
|
||||
// Deselect the previously-selected button
|
||||
if (selectedIndex.HasValue)
|
||||
this[selectedIndex.Value].State = SelectionState.NotSelected;
|
||||
|
||||
selectedIndex = value;
|
||||
|
||||
// Select the newly-selected button
|
||||
if (selectedIndex.HasValue)
|
||||
this[selectedIndex.Value].State = SelectionState.Selected;
|
||||
}
|
||||
|
||||
private void selectionChanged(T drawable, SelectionState state)
|
||||
{
|
||||
if (state == SelectionState.NotSelected)
|
||||
Deselect();
|
||||
else
|
||||
Select(drawable);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +1,26 @@
|
||||
// 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.Bindables;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using System;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class DialogButton : OsuClickableContainer
|
||||
public class DialogButton : OsuClickableContainer, IStateful<SelectionState>
|
||||
{
|
||||
private const float idle_width = 0.8f;
|
||||
private const float hover_width = 0.9f;
|
||||
@ -27,7 +28,22 @@ namespace osu.Game.Graphics.UserInterface
|
||||
private const float hover_duration = 500;
|
||||
private const float click_duration = 200;
|
||||
|
||||
public readonly BindableBool Selected = new BindableBool();
|
||||
public event Action<SelectionState> StateChanged;
|
||||
|
||||
private SelectionState state;
|
||||
|
||||
public SelectionState State
|
||||
{
|
||||
get => state;
|
||||
set
|
||||
{
|
||||
if (state == value)
|
||||
return;
|
||||
|
||||
state = value;
|
||||
StateChanged?.Invoke(value);
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Container backgroundContainer;
|
||||
private readonly Container colourContainer;
|
||||
@ -153,7 +169,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
updateGlow();
|
||||
|
||||
Selected.ValueChanged += selectionChanged;
|
||||
StateChanged += selectionChanged;
|
||||
}
|
||||
|
||||
private Color4 buttonColour;
|
||||
@ -221,7 +237,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
.OnComplete(_ =>
|
||||
{
|
||||
clickAnimating = false;
|
||||
Selected.TriggerChange();
|
||||
StateChanged?.Invoke(State);
|
||||
});
|
||||
|
||||
return base.OnClick(e);
|
||||
@ -235,7 +251,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
protected override void OnMouseUp(MouseUpEvent e)
|
||||
{
|
||||
if (Selected.Value)
|
||||
if (State == SelectionState.Selected)
|
||||
colourContainer.ResizeWidthTo(hover_width, click_duration, Easing.In);
|
||||
base.OnMouseUp(e);
|
||||
}
|
||||
@ -243,7 +259,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
base.OnHover(e);
|
||||
Selected.Value = true;
|
||||
State = SelectionState.Selected;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -251,15 +267,15 @@ namespace osu.Game.Graphics.UserInterface
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
base.OnHoverLost(e);
|
||||
Selected.Value = false;
|
||||
State = SelectionState.NotSelected;
|
||||
}
|
||||
|
||||
private void selectionChanged(ValueChangedEvent<bool> args)
|
||||
private void selectionChanged(SelectionState newState)
|
||||
{
|
||||
if (clickAnimating)
|
||||
return;
|
||||
|
||||
if (args.NewValue)
|
||||
if (newState == SelectionState.Selected)
|
||||
{
|
||||
spriteText.TransformSpacingTo(hoverSpacing, hover_duration, Easing.OutElastic);
|
||||
colourContainer.ResizeWidthTo(hover_width, hover_duration, Easing.OutElastic);
|
||||
|
@ -1,297 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Platform;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
public class DirectorySelector : CompositeDrawable
|
||||
{
|
||||
private FillFlowContainer directoryFlow;
|
||||
|
||||
[Resolved]
|
||||
private GameHost host { get; set; }
|
||||
|
||||
[Cached]
|
||||
public readonly Bindable<DirectoryInfo> CurrentPath = new Bindable<DirectoryInfo>();
|
||||
|
||||
public DirectorySelector(string initialPath = null)
|
||||
{
|
||||
CurrentPath.Value = new DirectoryInfo(initialPath ?? Environment.GetFolderPath(Environment.SpecialFolder.UserProfile));
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Padding = new MarginPadding(10);
|
||||
|
||||
InternalChild = new GridContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
RowDimensions = new[]
|
||||
{
|
||||
new Dimension(GridSizeMode.Absolute, 50),
|
||||
new Dimension(),
|
||||
},
|
||||
Content = new[]
|
||||
{
|
||||
new Drawable[]
|
||||
{
|
||||
new CurrentDirectoryDisplay
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
new OsuScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Child = directoryFlow = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Y,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(2),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CurrentPath.BindValueChanged(updateDisplay, true);
|
||||
}
|
||||
|
||||
private void updateDisplay(ValueChangedEvent<DirectoryInfo> directory)
|
||||
{
|
||||
directoryFlow.Clear();
|
||||
|
||||
try
|
||||
{
|
||||
if (directory.NewValue == null)
|
||||
{
|
||||
var drives = DriveInfo.GetDrives();
|
||||
|
||||
foreach (var drive in drives)
|
||||
directoryFlow.Add(new DirectoryPiece(drive.RootDirectory));
|
||||
}
|
||||
else
|
||||
{
|
||||
directoryFlow.Add(new ParentDirectoryPiece(CurrentPath.Value.Parent));
|
||||
|
||||
directoryFlow.AddRange(GetEntriesForPath(CurrentPath.Value));
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
CurrentPath.Value = directory.OldValue;
|
||||
this.FlashColour(Color4.Red, 300);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<DisplayPiece> GetEntriesForPath(DirectoryInfo path)
|
||||
{
|
||||
foreach (var dir in path.GetDirectories().OrderBy(d => d.Name))
|
||||
{
|
||||
if ((dir.Attributes & FileAttributes.Hidden) == 0)
|
||||
yield return new DirectoryPiece(dir);
|
||||
}
|
||||
}
|
||||
|
||||
private class CurrentDirectoryDisplay : CompositeDrawable
|
||||
{
|
||||
[Resolved]
|
||||
private Bindable<DirectoryInfo> currentDirectory { get; set; }
|
||||
|
||||
private FillFlowContainer flow;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
flow = new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Spacing = new Vector2(5),
|
||||
Height = DisplayPiece.HEIGHT,
|
||||
Direction = FillDirection.Horizontal,
|
||||
},
|
||||
};
|
||||
|
||||
currentDirectory.BindValueChanged(updateDisplay, true);
|
||||
}
|
||||
|
||||
private void updateDisplay(ValueChangedEvent<DirectoryInfo> dir)
|
||||
{
|
||||
flow.Clear();
|
||||
|
||||
List<DirectoryPiece> pathPieces = new List<DirectoryPiece>();
|
||||
|
||||
DirectoryInfo ptr = dir.NewValue;
|
||||
|
||||
while (ptr != null)
|
||||
{
|
||||
pathPieces.Insert(0, new CurrentDisplayPiece(ptr));
|
||||
ptr = ptr.Parent;
|
||||
}
|
||||
|
||||
flow.ChildrenEnumerable = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText { Text = "Current Directory: ", Font = OsuFont.Default.With(size: DisplayPiece.HEIGHT), },
|
||||
new ComputerPiece(),
|
||||
}.Concat(pathPieces);
|
||||
}
|
||||
|
||||
private class ComputerPiece : CurrentDisplayPiece
|
||||
{
|
||||
protected override IconUsage? Icon => null;
|
||||
|
||||
public ComputerPiece()
|
||||
: base(null, "Computer")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class CurrentDisplayPiece : DirectoryPiece
|
||||
{
|
||||
public CurrentDisplayPiece(DirectoryInfo directory, string displayName = null)
|
||||
: base(directory, displayName)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Flow.Add(new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Icon = FontAwesome.Solid.ChevronRight,
|
||||
Size = new Vector2(FONT_SIZE / 2)
|
||||
});
|
||||
}
|
||||
|
||||
protected override IconUsage? Icon => Directory.Name.Contains(Path.DirectorySeparatorChar) ? base.Icon : null;
|
||||
}
|
||||
}
|
||||
|
||||
private class ParentDirectoryPiece : DirectoryPiece
|
||||
{
|
||||
protected override IconUsage? Icon => FontAwesome.Solid.Folder;
|
||||
|
||||
public ParentDirectoryPiece(DirectoryInfo directory)
|
||||
: base(directory, "..")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
protected class DirectoryPiece : DisplayPiece
|
||||
{
|
||||
protected readonly DirectoryInfo Directory;
|
||||
|
||||
[Resolved]
|
||||
private Bindable<DirectoryInfo> currentDirectory { get; set; }
|
||||
|
||||
public DirectoryPiece(DirectoryInfo directory, string displayName = null)
|
||||
: base(displayName)
|
||||
{
|
||||
Directory = directory;
|
||||
}
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
currentDirectory.Value = Directory;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override string FallbackName => Directory.Name;
|
||||
|
||||
protected override IconUsage? Icon => Directory.Name.Contains(Path.DirectorySeparatorChar)
|
||||
? FontAwesome.Solid.Database
|
||||
: FontAwesome.Regular.Folder;
|
||||
}
|
||||
|
||||
protected abstract class DisplayPiece : CompositeDrawable
|
||||
{
|
||||
public const float HEIGHT = 20;
|
||||
|
||||
protected const float FONT_SIZE = 16;
|
||||
|
||||
private readonly string displayName;
|
||||
|
||||
protected FillFlowContainer Flow;
|
||||
|
||||
protected DisplayPiece(string displayName = null)
|
||||
{
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 5;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Colour = colours.GreySeafoamDarker,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
Flow = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
Height = 20,
|
||||
Margin = new MarginPadding { Vertical = 2, Horizontal = 5 },
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(5),
|
||||
}
|
||||
};
|
||||
|
||||
if (Icon.HasValue)
|
||||
{
|
||||
Flow.Add(new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Icon = Icon.Value,
|
||||
Size = new Vector2(FONT_SIZE)
|
||||
});
|
||||
}
|
||||
|
||||
Flow.Add(new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Text = displayName ?? FallbackName,
|
||||
Font = OsuFont.Default.With(size: FONT_SIZE)
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract string FallbackName { get; }
|
||||
|
||||
protected abstract IconUsage? Icon { get; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,94 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input.Events;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
public class FileSelector : DirectorySelector
|
||||
{
|
||||
private readonly string[] validFileExtensions;
|
||||
|
||||
[Cached]
|
||||
public readonly Bindable<FileInfo> CurrentFile = new Bindable<FileInfo>();
|
||||
|
||||
public FileSelector(string initialPath = null, string[] validFileExtensions = null)
|
||||
: base(initialPath)
|
||||
{
|
||||
this.validFileExtensions = validFileExtensions ?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
protected override IEnumerable<DisplayPiece> GetEntriesForPath(DirectoryInfo path)
|
||||
{
|
||||
foreach (var dir in base.GetEntriesForPath(path))
|
||||
yield return dir;
|
||||
|
||||
IEnumerable<FileInfo> files = path.GetFiles();
|
||||
|
||||
if (validFileExtensions.Length > 0)
|
||||
files = files.Where(f => validFileExtensions.Contains(f.Extension));
|
||||
|
||||
foreach (var file in files.OrderBy(d => d.Name))
|
||||
{
|
||||
if ((file.Attributes & FileAttributes.Hidden) == 0)
|
||||
yield return new FilePiece(file);
|
||||
}
|
||||
}
|
||||
|
||||
protected class FilePiece : DisplayPiece
|
||||
{
|
||||
private readonly FileInfo file;
|
||||
|
||||
[Resolved]
|
||||
private Bindable<FileInfo> currentFile { get; set; }
|
||||
|
||||
public FilePiece(FileInfo file)
|
||||
{
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
protected override bool OnClick(ClickEvent e)
|
||||
{
|
||||
currentFile.Value = file;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override string FallbackName => file.Name;
|
||||
|
||||
protected override IconUsage? Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (file.Extension)
|
||||
{
|
||||
case ".ogg":
|
||||
case ".mp3":
|
||||
case ".wav":
|
||||
return FontAwesome.Regular.FileAudio;
|
||||
|
||||
case ".jpg":
|
||||
case ".jpeg":
|
||||
case ".png":
|
||||
return FontAwesome.Regular.FileImage;
|
||||
|
||||
case ".mp4":
|
||||
case ".avi":
|
||||
case ".mov":
|
||||
case ".flv":
|
||||
return FontAwesome.Regular.FileVideo;
|
||||
|
||||
default:
|
||||
return FontAwesome.Regular.File;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
38
osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelector.cs
Normal file
38
osu.Game/Graphics/UserInterfaceV2/OsuDirectorySelector.cs
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.IO;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
public class OsuDirectorySelector : DirectorySelector
|
||||
{
|
||||
public const float ITEM_HEIGHT = 20;
|
||||
|
||||
public OsuDirectorySelector(string initialPath = null)
|
||||
: base(initialPath)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Padding = new MarginPadding(10);
|
||||
}
|
||||
|
||||
protected override ScrollContainer<Drawable> CreateScrollContainer() => new OsuScrollContainer();
|
||||
|
||||
protected override DirectorySelectorBreadcrumbDisplay CreateBreadcrumb() => new OsuDirectorySelectorBreadcrumbDisplay();
|
||||
|
||||
protected override DirectorySelectorDirectory CreateParentDirectoryItem(DirectoryInfo directory) => new OsuDirectorySelectorParentDirectory(directory);
|
||||
|
||||
protected override DirectorySelectorDirectory CreateDirectoryItem(DirectoryInfo directory, string displayName = null) => new OsuDirectorySelectorDirectory(directory, displayName);
|
||||
|
||||
protected override void NotifySelectionError() => this.FlashColour(Colour4.Red, 300);
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.IO;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
internal class OsuDirectorySelectorBreadcrumbDisplay : DirectorySelectorBreadcrumbDisplay
|
||||
{
|
||||
protected override Drawable CreateCaption() => new OsuSpriteText
|
||||
{
|
||||
Text = "Current Directory: ",
|
||||
Font = OsuFont.Default.With(size: OsuDirectorySelector.ITEM_HEIGHT),
|
||||
};
|
||||
|
||||
protected override DirectorySelectorDirectory CreateRootDirectoryItem() => new OsuBreadcrumbDisplayComputer();
|
||||
|
||||
protected override DirectorySelectorDirectory CreateDirectoryItem(DirectoryInfo directory, string displayName = null) => new OsuBreadcrumbDisplayDirectory(directory, displayName);
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Height = 50;
|
||||
}
|
||||
|
||||
private class OsuBreadcrumbDisplayComputer : OsuBreadcrumbDisplayDirectory
|
||||
{
|
||||
protected override IconUsage? Icon => null;
|
||||
|
||||
public OsuBreadcrumbDisplayComputer()
|
||||
: base(null, "Computer")
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class OsuBreadcrumbDisplayDirectory : OsuDirectorySelectorDirectory
|
||||
{
|
||||
public OsuBreadcrumbDisplayDirectory(DirectoryInfo directory, string displayName = null)
|
||||
: base(directory, displayName)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Flow.Add(new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Icon = FontAwesome.Solid.ChevronRight,
|
||||
Size = new Vector2(FONT_SIZE / 2)
|
||||
});
|
||||
}
|
||||
|
||||
protected override IconUsage? Icon => Directory.Name.Contains(Path.DirectorySeparatorChar) ? base.Icon : null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.IO;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
internal class OsuDirectorySelectorDirectory : DirectorySelectorDirectory
|
||||
{
|
||||
public OsuDirectorySelectorDirectory(DirectoryInfo directory, string displayName = null)
|
||||
: base(directory, displayName)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Flow.AutoSizeAxes = Axes.X;
|
||||
Flow.Height = OsuDirectorySelector.ITEM_HEIGHT;
|
||||
|
||||
AddInternal(new Background
|
||||
{
|
||||
Depth = 1
|
||||
});
|
||||
}
|
||||
|
||||
protected override SpriteText CreateSpriteText() => new OsuSpriteText();
|
||||
|
||||
protected override IconUsage? Icon => Directory.Name.Contains(Path.DirectorySeparatorChar)
|
||||
? FontAwesome.Solid.Database
|
||||
: FontAwesome.Regular.Folder;
|
||||
|
||||
internal class Background : CompositeDrawable
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 5;
|
||||
|
||||
InternalChild = new Box
|
||||
{
|
||||
Colour = colours.GreySeafoamDarker,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.IO;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
internal class OsuDirectorySelectorParentDirectory : OsuDirectorySelectorDirectory
|
||||
{
|
||||
protected override IconUsage? Icon => FontAwesome.Solid.Folder;
|
||||
|
||||
public OsuDirectorySelectorParentDirectory(DirectoryInfo directory)
|
||||
: base(directory, "..")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
90
osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs
Normal file
90
osu.Game/Graphics/UserInterfaceV2/OsuFileSelector.cs
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System.IO;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterfaceV2
|
||||
{
|
||||
public class OsuFileSelector : FileSelector
|
||||
{
|
||||
public OsuFileSelector(string initialPath = null, string[] validFileExtensions = null)
|
||||
: base(initialPath, validFileExtensions)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Padding = new MarginPadding(10);
|
||||
}
|
||||
|
||||
protected override ScrollContainer<Drawable> CreateScrollContainer() => new OsuScrollContainer();
|
||||
|
||||
protected override DirectorySelectorBreadcrumbDisplay CreateBreadcrumb() => new OsuDirectorySelectorBreadcrumbDisplay();
|
||||
|
||||
protected override DirectorySelectorDirectory CreateParentDirectoryItem(DirectoryInfo directory) => new OsuDirectorySelectorParentDirectory(directory);
|
||||
|
||||
protected override DirectorySelectorDirectory CreateDirectoryItem(DirectoryInfo directory, string displayName = null) => new OsuDirectorySelectorDirectory(directory, displayName);
|
||||
|
||||
protected override DirectoryListingFile CreateFileItem(FileInfo file) => new OsuDirectoryListingFile(file);
|
||||
|
||||
protected override void NotifySelectionError() => this.FlashColour(Colour4.Red, 300);
|
||||
|
||||
protected class OsuDirectoryListingFile : DirectoryListingFile
|
||||
{
|
||||
public OsuDirectoryListingFile(FileInfo file)
|
||||
: base(file)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
Flow.AutoSizeAxes = Axes.X;
|
||||
Flow.Height = OsuDirectorySelector.ITEM_HEIGHT;
|
||||
|
||||
AddInternal(new OsuDirectorySelectorDirectory.Background
|
||||
{
|
||||
Depth = 1
|
||||
});
|
||||
}
|
||||
|
||||
protected override IconUsage? Icon
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (File.Extension)
|
||||
{
|
||||
case @".ogg":
|
||||
case @".mp3":
|
||||
case @".wav":
|
||||
return FontAwesome.Regular.FileAudio;
|
||||
|
||||
case @".jpg":
|
||||
case @".jpeg":
|
||||
case @".png":
|
||||
return FontAwesome.Regular.FileImage;
|
||||
|
||||
case @".mp4":
|
||||
case @".avi":
|
||||
case @".mov":
|
||||
case @".flv":
|
||||
return FontAwesome.Regular.FileVideo;
|
||||
|
||||
default:
|
||||
return FontAwesome.Regular.File;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override SpriteText CreateSpriteText() => new OsuSpriteText();
|
||||
}
|
||||
}
|
||||
}
|
@ -102,8 +102,15 @@ namespace osu.Game.IO
|
||||
|
||||
protected override void ChangeTargetStorage(Storage newStorage)
|
||||
{
|
||||
var lastStorage = UnderlyingStorage;
|
||||
base.ChangeTargetStorage(newStorage);
|
||||
Logger.Storage = UnderlyingStorage.GetStorageForDirectory("logs");
|
||||
|
||||
if (lastStorage != null)
|
||||
{
|
||||
// for now we assume that if there was a previous storage, this is a migration operation.
|
||||
// the logger shouldn't be set during initialisation as it can cause cross-talk in tests (due to being static).
|
||||
Logger.Storage = UnderlyingStorage.GetStorageForDirectory("logs");
|
||||
}
|
||||
}
|
||||
|
||||
public override void Migrate(Storage newStorage)
|
||||
|
@ -87,6 +87,8 @@ namespace osu.Game.Input.Bindings
|
||||
new KeyBinding(new[] { InputKey.Shift, InputKey.Tab }, GlobalAction.ToggleInGameInterface),
|
||||
new KeyBinding(InputKey.MouseMiddle, GlobalAction.PauseGameplay),
|
||||
new KeyBinding(InputKey.Space, GlobalAction.TogglePauseReplay),
|
||||
new KeyBinding(InputKey.Left, GlobalAction.SeekReplayBackward),
|
||||
new KeyBinding(InputKey.Right, GlobalAction.SeekReplayForward),
|
||||
new KeyBinding(InputKey.Control, GlobalAction.HoldForHUD),
|
||||
};
|
||||
|
||||
@ -103,6 +105,9 @@ namespace osu.Game.Input.Bindings
|
||||
new KeyBinding(new[] { InputKey.Alt, InputKey.Up }, GlobalAction.IncreaseVolume),
|
||||
new KeyBinding(new[] { InputKey.Alt, InputKey.Down }, GlobalAction.DecreaseVolume),
|
||||
|
||||
new KeyBinding(new[] { InputKey.Alt, InputKey.Left }, GlobalAction.PreviousVolumeMeter),
|
||||
new KeyBinding(new[] { InputKey.Alt, InputKey.Right }, GlobalAction.NextVolumeMeter),
|
||||
|
||||
new KeyBinding(new[] { InputKey.Control, InputKey.F4 }, GlobalAction.ToggleMute),
|
||||
|
||||
new KeyBinding(InputKey.TrackPrevious, GlobalAction.MusicPrev),
|
||||
@ -263,5 +268,17 @@ namespace osu.Game.Input.Bindings
|
||||
|
||||
[Description("Toggle skin editor")]
|
||||
ToggleSkinEditor,
|
||||
|
||||
[Description("Previous volume meter")]
|
||||
PreviousVolumeMeter,
|
||||
|
||||
[Description("Next volume meter")]
|
||||
NextVolumeMeter,
|
||||
|
||||
[Description("Seek replay forward")]
|
||||
SeekReplayForward,
|
||||
|
||||
[Description("Seek replay backward")]
|
||||
SeekReplayBackward,
|
||||
}
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ namespace osu.Game.Online.Chat
|
||||
|
||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => Parts.Any(d => d.ReceivePositionalInputAt(screenSpacePos));
|
||||
|
||||
protected override HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new LinkHoverSounds(sampleSet, Parts);
|
||||
protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new LinkHoverSounds(sampleSet, Parts);
|
||||
|
||||
public DrawableLinkCompiler(IEnumerable<Drawable> parts)
|
||||
{
|
||||
|
@ -429,7 +429,7 @@ namespace osu.Game.Overlays.Mods
|
||||
if (!Stacked)
|
||||
modEnumeration = ModUtils.FlattenMods(modEnumeration);
|
||||
|
||||
section.Mods = modEnumeration.Select(getValidModOrNull).Where(m => m != null);
|
||||
section.Mods = modEnumeration.Select(getValidModOrNull).Where(m => m != null).Select(m => m.CreateCopy());
|
||||
}
|
||||
|
||||
updateSelectedButtons();
|
||||
|
@ -2,11 +2,14 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osuTK;
|
||||
|
||||
namespace osu.Game.Overlays.Profile.Header.Components
|
||||
@ -18,18 +21,29 @@ namespace osu.Game.Overlays.Profile.Header.Components
|
||||
public override LocalisableString TooltipText => DetailsVisible.Value ? "collapse" : "expand";
|
||||
|
||||
private SpriteIcon icon;
|
||||
private Sample sampleOpen;
|
||||
private Sample sampleClose;
|
||||
|
||||
protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds();
|
||||
|
||||
public ExpandDetailsButton()
|
||||
{
|
||||
Action = () => DetailsVisible.Toggle();
|
||||
Action = () =>
|
||||
{
|
||||
DetailsVisible.Toggle();
|
||||
(DetailsVisible.Value ? sampleOpen : sampleClose)?.Play();
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
private void load(OverlayColourProvider colourProvider, AudioManager audio)
|
||||
{
|
||||
IdleColour = colourProvider.Background2;
|
||||
HoverColour = colourProvider.Background2.Lighten(0.2f);
|
||||
|
||||
sampleOpen = audio.Samples.Get(@"UI/dropdown-open");
|
||||
sampleClose = audio.Samples.Get(@"UI/dropdown-close");
|
||||
|
||||
Child = icon = new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
|
@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Rankings
|
||||
public class CountryFilter : CompositeDrawable, IHasCurrentValue<Country>
|
||||
{
|
||||
private const int duration = 200;
|
||||
private const int height = 50;
|
||||
private const int height = 70;
|
||||
|
||||
private readonly BindableWithCurrent<Country> current = new BindableWithCurrent<Country>();
|
||||
|
||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Overlays.Rankings
|
||||
|
||||
InternalChild = content = new CircularContainer
|
||||
{
|
||||
Height = 25,
|
||||
Height = 30,
|
||||
AutoSizeDuration = duration,
|
||||
AutoSizeEasing = Easing.OutQuint,
|
||||
Masking = true,
|
||||
@ -58,9 +58,9 @@ namespace osu.Game.Overlays.Rankings
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
AutoSizeAxes = Axes.X,
|
||||
Margin = new MarginPadding { Horizontal = 10 },
|
||||
Margin = new MarginPadding { Horizontal = 15 },
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(8, 0),
|
||||
Spacing = new Vector2(15, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
@ -70,14 +70,14 @@ namespace osu.Game.Overlays.Rankings
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(3, 0),
|
||||
Spacing = new Vector2(5, 0),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
flag = new UpdateableFlag
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Size = new Vector2(22, 15)
|
||||
Size = new Vector2(30, 20)
|
||||
},
|
||||
countryName = new OsuSpriteText
|
||||
{
|
||||
@ -148,7 +148,7 @@ namespace osu.Game.Overlays.Rankings
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Add(icon = new SpriteIcon
|
||||
{
|
||||
Size = new Vector2(8),
|
||||
Size = new Vector2(10),
|
||||
Icon = FontAwesome.Solid.Times
|
||||
});
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
@ -46,6 +47,7 @@ namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
InternalChildren = new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
@ -139,7 +141,7 @@ namespace osu.Game.Overlays.Rankings
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Direction = FillDirection.Vertical;
|
||||
Margin = new MarginPadding { Vertical = 10 };
|
||||
Padding = new MarginPadding { Vertical = 15 };
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
@ -150,11 +152,11 @@ namespace osu.Game.Overlays.Rankings
|
||||
new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
Height = 20,
|
||||
Height = 25,
|
||||
Child = valueText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Font = OsuFont.GetFont(size: 20, weight: FontWeight.Light),
|
||||
}
|
||||
}
|
||||
@ -174,11 +176,34 @@ namespace osu.Game.Overlays.Rankings
|
||||
|
||||
protected override DropdownMenu CreateMenu() => menu = base.CreateMenu().With(m => m.MaxHeight = 400);
|
||||
|
||||
protected override DropdownHeader CreateHeader() => new SpotlightsDropdownHeader();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
// osu-web adds a 0.6 opacity container on top of the 0.5 base one when hovering, 0.8 on a single container here matches the resulting colour
|
||||
AccentColour = colourProvider.Background6.Opacity(0.8f);
|
||||
menu.BackgroundColour = colourProvider.Background5;
|
||||
AccentColour = colourProvider.Background6;
|
||||
Padding = new MarginPadding { Vertical = 20 };
|
||||
}
|
||||
|
||||
private class SpotlightsDropdownHeader : OsuDropdownHeader
|
||||
{
|
||||
public SpotlightsDropdownHeader()
|
||||
{
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Text.Font = OsuFont.GetFont(size: 15);
|
||||
Text.Padding = new MarginPadding { Vertical = 1.5f }; // osu-web line-height difference compensation
|
||||
Foreground.Padding = new MarginPadding { Horizontal = 10, Vertical = 15 };
|
||||
Margin = Icon.Margin = new MarginPadding(0);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
BackgroundColour = colourProvider.Background6.Opacity(0.5f);
|
||||
BackgroundColourHover = colourProvider.Background5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,14 @@
|
||||
// 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.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using System;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics.Containers;
|
||||
|
||||
namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
@ -62,35 +61,20 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
}
|
||||
};
|
||||
|
||||
private class CountryName : OsuHoverContainer
|
||||
private class CountryName : LinkFlowContainer
|
||||
{
|
||||
protected override IEnumerable<Drawable> EffectTargets => new[] { text };
|
||||
|
||||
[Resolved(canBeNull: true)]
|
||||
private RankingsOverlay rankings { get; set; }
|
||||
|
||||
private readonly OsuSpriteText text;
|
||||
private readonly Country country;
|
||||
|
||||
public CountryName(Country country)
|
||||
: base(t => t.Font = OsuFont.GetFont(size: 12))
|
||||
{
|
||||
this.country = country;
|
||||
AutoSizeAxes = Axes.X;
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
TextAnchor = Anchor.CentreLeft;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
Add(text = new OsuSpriteText
|
||||
{
|
||||
Font = OsuFont.GetFont(size: 12),
|
||||
Text = country.FullName ?? string.Empty,
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
IdleColour = colourProvider.Light2;
|
||||
HoverColour = colourProvider.Content2;
|
||||
|
||||
Action = () => rankings?.ShowCountry(country);
|
||||
if (!string.IsNullOrEmpty(country.FullName))
|
||||
AddLink(country.FullName, () => rankings?.ShowCountry(country));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
@ -20,7 +20,8 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
protected const int TEXT_SIZE = 12;
|
||||
private const float horizontal_inset = 20;
|
||||
private const float row_height = 25;
|
||||
private const float row_height = 32;
|
||||
private const float row_spacing = 3;
|
||||
private const int items_per_page = 50;
|
||||
|
||||
private readonly int page;
|
||||
@ -35,7 +36,7 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
Padding = new MarginPadding { Horizontal = horizontal_inset };
|
||||
RowSize = new Dimension(GridSizeMode.Absolute, row_height);
|
||||
RowSize = new Dimension(GridSizeMode.Absolute, row_height + row_spacing);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
@ -47,10 +48,11 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Depth = 1f,
|
||||
Margin = new MarginPadding { Top = row_height }
|
||||
Margin = new MarginPadding { Top = row_height + row_spacing },
|
||||
Spacing = new Vector2(0, row_spacing),
|
||||
});
|
||||
|
||||
rankings.ForEach(_ => backgroundFlow.Add(new TableRowBackground()));
|
||||
rankings.ForEach(_ => backgroundFlow.Add(new TableRowBackground { Height = row_height }));
|
||||
|
||||
Columns = mainHeaders.Concat(CreateAdditionalHeaders()).ToArray();
|
||||
Content = rankings.Select((s, i) => createContent((page - 1) * items_per_page + i, s)).ToArray().ToRectangular();
|
||||
@ -68,13 +70,19 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
|
||||
protected abstract Drawable[] CreateAdditionalContent(TModel item);
|
||||
|
||||
protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? string.Empty, HighlightedColumn());
|
||||
protected virtual string HighlightedColumn => @"Performance";
|
||||
|
||||
protected override Drawable CreateHeader(int index, TableColumn column)
|
||||
{
|
||||
var title = column?.Header ?? string.Empty;
|
||||
return new HeaderText(title, title == HighlightedColumn);
|
||||
}
|
||||
|
||||
protected abstract Country GetCountry(TModel item);
|
||||
|
||||
protected abstract Drawable CreateFlagContent(TModel item);
|
||||
|
||||
private OsuSpriteText createIndexDrawable(int index) => new OsuSpriteText
|
||||
private OsuSpriteText createIndexDrawable(int index) => new RowText
|
||||
{
|
||||
Text = $"#{index + 1}",
|
||||
Font = OsuFont.GetFont(size: TEXT_SIZE, weight: FontWeight.SemiBold)
|
||||
@ -84,37 +92,36 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(7, 0),
|
||||
Spacing = new Vector2(10, 0),
|
||||
Margin = new MarginPadding { Bottom = row_spacing },
|
||||
Children = new[]
|
||||
{
|
||||
new UpdateableFlag(GetCountry(item))
|
||||
{
|
||||
Size = new Vector2(20, 13),
|
||||
Size = new Vector2(30, 20),
|
||||
ShowPlaceholderOnNull = false,
|
||||
},
|
||||
CreateFlagContent(item)
|
||||
}
|
||||
};
|
||||
|
||||
protected virtual string HighlightedColumn() => @"Performance";
|
||||
|
||||
private class HeaderText : OsuSpriteText
|
||||
protected class HeaderText : OsuSpriteText
|
||||
{
|
||||
private readonly string highlighted;
|
||||
private readonly bool isHighlighted;
|
||||
|
||||
public HeaderText(string text, string highlighted)
|
||||
public HeaderText(string text, bool isHighlighted)
|
||||
{
|
||||
this.highlighted = highlighted;
|
||||
this.isHighlighted = isHighlighted;
|
||||
|
||||
Text = text;
|
||||
Font = OsuFont.GetFont(size: 12);
|
||||
Margin = new MarginPadding { Horizontal = 10 };
|
||||
Margin = new MarginPadding { Vertical = 5, Horizontal = 10 };
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OverlayColourProvider colourProvider)
|
||||
{
|
||||
if (Text != highlighted)
|
||||
if (!isHighlighted)
|
||||
Colour = colourProvider.Foreground1;
|
||||
}
|
||||
}
|
||||
@ -124,7 +131,7 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
public RowText()
|
||||
{
|
||||
Font = OsuFont.GetFont(size: TEXT_SIZE);
|
||||
Margin = new MarginPadding { Horizontal = 10 };
|
||||
Margin = new MarginPadding { Horizontal = 10, Bottom = row_spacing };
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,6 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
}
|
||||
};
|
||||
|
||||
protected override string HighlightedColumn() => @"Ranked Score";
|
||||
protected override string HighlightedColumn => @"Ranked Score";
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// 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.
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
@ -22,10 +22,10 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
public TableRowBackground()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 25;
|
||||
|
||||
CornerRadius = 3;
|
||||
CornerRadius = 4;
|
||||
Masking = true;
|
||||
MaskingSmoothness = 0.5f;
|
||||
|
||||
InternalChild = background = new Box
|
||||
{
|
||||
|
@ -19,22 +19,32 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
{
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<string> GradeColumns => new List<string> { "SS", "S", "A" };
|
||||
|
||||
protected override TableColumn[] CreateAdditionalHeaders() => new[]
|
||||
{
|
||||
new TableColumn("Accuracy", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
}.Concat(CreateUniqueHeaders())
|
||||
.Concat(GradeColumns.Select(grade => new TableColumn(grade, Anchor.Centre, new Dimension(GridSizeMode.AutoSize))))
|
||||
.ToArray();
|
||||
|
||||
protected override Drawable CreateHeader(int index, TableColumn column)
|
||||
{
|
||||
new TableColumn("Accuracy", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("Play Count", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
}.Concat(CreateUniqueHeaders()).Concat(new[]
|
||||
{
|
||||
new TableColumn("SS", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("S", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
new TableColumn("A", Anchor.Centre, new Dimension(GridSizeMode.AutoSize)),
|
||||
}).ToArray();
|
||||
var title = column?.Header ?? string.Empty;
|
||||
return new UserTableHeaderText(title, HighlightedColumn == title, GradeColumns.Contains(title));
|
||||
}
|
||||
|
||||
protected sealed override Country GetCountry(UserStatistics item) => item.User.Country;
|
||||
|
||||
protected sealed override Drawable CreateFlagContent(UserStatistics item)
|
||||
{
|
||||
var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: TEXT_SIZE, italics: true)) { AutoSizeAxes = Axes.Both };
|
||||
var username = new LinkFlowContainer(t => t.Font = OsuFont.GetFont(size: TEXT_SIZE, italics: true))
|
||||
{
|
||||
AutoSizeAxes = Axes.X,
|
||||
RelativeSizeAxes = Axes.Y,
|
||||
TextAnchor = Anchor.CentreLeft
|
||||
};
|
||||
username.AddUserLink(item.User);
|
||||
return username;
|
||||
}
|
||||
@ -53,5 +63,19 @@ namespace osu.Game.Overlays.Rankings.Tables
|
||||
protected abstract TableColumn[] CreateUniqueHeaders();
|
||||
|
||||
protected abstract Drawable[] CreateUniqueContent(UserStatistics item);
|
||||
|
||||
private class UserTableHeaderText : HeaderText
|
||||
{
|
||||
public UserTableHeaderText(string text, bool isHighlighted, bool isGrade)
|
||||
: base(text, isHighlighted)
|
||||
{
|
||||
Margin = new MarginPadding
|
||||
{
|
||||
// Grade columns have extra horizontal padding for readibility
|
||||
Horizontal = isGrade ? 20 : 10,
|
||||
Vertical = 5
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
{
|
||||
private TriangleButton selectionButton;
|
||||
|
||||
private DirectorySelector directorySelector;
|
||||
private OsuDirectorySelector directorySelector;
|
||||
|
||||
/// <summary>
|
||||
/// Text to display in the header to inform the user of what they are selecting.
|
||||
@ -91,7 +91,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
},
|
||||
new Drawable[]
|
||||
{
|
||||
directorySelector = new DirectorySelector
|
||||
directorySelector = new OsuDirectorySelector
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
}
|
||||
|
@ -30,6 +30,8 @@ namespace osu.Game.Overlays.Volume
|
||||
return true;
|
||||
|
||||
case GlobalAction.ToggleMute:
|
||||
case GlobalAction.NextVolumeMeter:
|
||||
case GlobalAction.PreviousVolumeMeter:
|
||||
ActionRequested?.Invoke(action);
|
||||
return true;
|
||||
}
|
||||
|
@ -3,10 +3,12 @@
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -19,13 +21,14 @@ using osu.Framework.Threading;
|
||||
using osu.Framework.Utils;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Volume
|
||||
{
|
||||
public class VolumeMeter : Container, IKeyBindingHandler<GlobalAction>
|
||||
public class VolumeMeter : Container, IKeyBindingHandler<GlobalAction>, IStateful<SelectionState>
|
||||
{
|
||||
private CircularProgress volumeCircle;
|
||||
private CircularProgress volumeCircleGlow;
|
||||
@ -38,9 +41,33 @@ namespace osu.Game.Overlays.Volume
|
||||
private OsuSpriteText text;
|
||||
private BufferedContainer maxGlow;
|
||||
|
||||
private Sample sample;
|
||||
private Container selectedGlowContainer;
|
||||
|
||||
private Sample hoverSample;
|
||||
private Sample notchSample;
|
||||
private double sampleLastPlaybackTime;
|
||||
|
||||
public event Action<SelectionState> StateChanged;
|
||||
|
||||
private SelectionState state;
|
||||
|
||||
public SelectionState State
|
||||
{
|
||||
get => state;
|
||||
set
|
||||
{
|
||||
if (state == value)
|
||||
return;
|
||||
|
||||
state = value;
|
||||
StateChanged?.Invoke(value);
|
||||
|
||||
updateSelectedState();
|
||||
}
|
||||
}
|
||||
|
||||
private const float transition_length = 500;
|
||||
|
||||
public VolumeMeter(string name, float circleSize, Color4 meterColour)
|
||||
{
|
||||
this.circleSize = circleSize;
|
||||
@ -53,7 +80,8 @@ namespace osu.Game.Overlays.Volume
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, AudioManager audio)
|
||||
{
|
||||
sample = audio.Samples.Get(@"UI/notch-tick");
|
||||
hoverSample = audio.Samples.Get($"UI/{HoverSampleSet.Button.GetDescription()}-hover");
|
||||
notchSample = audio.Samples.Get(@"UI/notch-tick");
|
||||
sampleLastPlaybackTime = Time.Current;
|
||||
|
||||
Color4 backgroundColour = colours.Gray1;
|
||||
@ -75,7 +103,6 @@ namespace osu.Game.Overlays.Volume
|
||||
{
|
||||
new BufferedContainer
|
||||
{
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
@ -147,6 +174,24 @@ namespace osu.Game.Overlays.Volume
|
||||
},
|
||||
},
|
||||
},
|
||||
selectedGlowContainer = new CircularContainer
|
||||
{
|
||||
Masking = true,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
Child = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
AlwaysPresent = true,
|
||||
},
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Glow,
|
||||
Colour = meterColour.Opacity(0.1f),
|
||||
Radius = 10,
|
||||
}
|
||||
},
|
||||
maxGlow = (text = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
@ -171,7 +216,6 @@ namespace osu.Game.Overlays.Volume
|
||||
{
|
||||
new Box
|
||||
{
|
||||
Alpha = 0.9f,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = backgroundColour,
|
||||
},
|
||||
@ -233,7 +277,7 @@ namespace osu.Game.Overlays.Volume
|
||||
if (Time.Current - sampleLastPlaybackTime <= tick_debounce_time)
|
||||
return;
|
||||
|
||||
var channel = sample.GetChannel();
|
||||
var channel = notchSample.GetChannel();
|
||||
|
||||
channel.Frequency.Value = 0.99f + RNG.NextDouble(0.02f) + displayVolume * 0.1f;
|
||||
|
||||
@ -305,17 +349,14 @@ namespace osu.Game.Overlays.Volume
|
||||
return true;
|
||||
}
|
||||
|
||||
private const float transition_length = 500;
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||
{
|
||||
this.ScaleTo(1.04f, transition_length, Easing.OutExpo);
|
||||
return false;
|
||||
State = SelectionState.Selected;
|
||||
return base.OnMouseMove(e);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
this.ScaleTo(1f, transition_length, Easing.OutExpo);
|
||||
}
|
||||
|
||||
public bool OnPressed(GlobalAction action)
|
||||
@ -326,10 +367,12 @@ namespace osu.Game.Overlays.Volume
|
||||
switch (action)
|
||||
{
|
||||
case GlobalAction.SelectPrevious:
|
||||
State = SelectionState.Selected;
|
||||
adjust(1, false);
|
||||
return true;
|
||||
|
||||
case GlobalAction.SelectNext:
|
||||
State = SelectionState.Selected;
|
||||
adjust(-1, false);
|
||||
return true;
|
||||
}
|
||||
@ -340,5 +383,22 @@ namespace osu.Game.Overlays.Volume
|
||||
public void OnReleased(GlobalAction action)
|
||||
{
|
||||
}
|
||||
|
||||
private void updateSelectedState()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case SelectionState.Selected:
|
||||
this.ScaleTo(1.04f, transition_length, Easing.OutExpo);
|
||||
selectedGlowContainer.FadeIn(transition_length, Easing.OutExpo);
|
||||
hoverSample?.Play();
|
||||
break;
|
||||
|
||||
case SelectionState.NotSelected:
|
||||
this.ScaleTo(1f, transition_length, Easing.OutExpo);
|
||||
selectedGlowContainer.FadeOut(transition_length, Easing.OutExpo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Overlays.Volume;
|
||||
using osuTK;
|
||||
@ -32,6 +33,8 @@ namespace osu.Game.Overlays
|
||||
|
||||
public Bindable<bool> IsMuted { get; } = new Bindable<bool>();
|
||||
|
||||
private SelectionCycleFillFlowContainer<VolumeMeter> volumeMeters;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio, OsuColour colours)
|
||||
{
|
||||
@ -53,7 +56,7 @@ namespace osu.Game.Overlays
|
||||
Margin = new MarginPadding(10),
|
||||
Current = { BindTarget = IsMuted }
|
||||
},
|
||||
new FillFlowContainer
|
||||
volumeMeters = new SelectionCycleFillFlowContainer<VolumeMeter>
|
||||
{
|
||||
Direction = FillDirection.Vertical,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
@ -61,7 +64,7 @@ namespace osu.Game.Overlays
|
||||
Origin = Anchor.CentreLeft,
|
||||
Spacing = new Vector2(0, offset),
|
||||
Margin = new MarginPadding { Left = offset },
|
||||
Children = new Drawable[]
|
||||
Children = new[]
|
||||
{
|
||||
volumeMeterEffect = new VolumeMeter("EFFECTS", 125, colours.BlueDarker),
|
||||
volumeMeterMaster = new VolumeMeter("MASTER", 150, colours.PinkDarker),
|
||||
@ -87,9 +90,9 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
volumeMeterMaster.Bindable.ValueChanged += _ => Show();
|
||||
volumeMeterEffect.Bindable.ValueChanged += _ => Show();
|
||||
volumeMeterMusic.Bindable.ValueChanged += _ => Show();
|
||||
foreach (var volumeMeter in volumeMeters)
|
||||
volumeMeter.Bindable.ValueChanged += _ => Show();
|
||||
|
||||
muteButton.Current.ValueChanged += _ => Show();
|
||||
}
|
||||
|
||||
@ -102,23 +105,27 @@ namespace osu.Game.Overlays
|
||||
case GlobalAction.DecreaseVolume:
|
||||
if (State.Value == Visibility.Hidden)
|
||||
Show();
|
||||
else if (volumeMeterMusic.IsHovered)
|
||||
volumeMeterMusic.Decrease(amount, isPrecise);
|
||||
else if (volumeMeterEffect.IsHovered)
|
||||
volumeMeterEffect.Decrease(amount, isPrecise);
|
||||
else
|
||||
volumeMeterMaster.Decrease(amount, isPrecise);
|
||||
volumeMeters.Selected?.Decrease(amount, isPrecise);
|
||||
return true;
|
||||
|
||||
case GlobalAction.IncreaseVolume:
|
||||
if (State.Value == Visibility.Hidden)
|
||||
Show();
|
||||
else if (volumeMeterMusic.IsHovered)
|
||||
volumeMeterMusic.Increase(amount, isPrecise);
|
||||
else if (volumeMeterEffect.IsHovered)
|
||||
volumeMeterEffect.Increase(amount, isPrecise);
|
||||
else
|
||||
volumeMeterMaster.Increase(amount, isPrecise);
|
||||
volumeMeters.Selected?.Increase(amount, isPrecise);
|
||||
return true;
|
||||
|
||||
case GlobalAction.NextVolumeMeter:
|
||||
if (State.Value == Visibility.Visible)
|
||||
volumeMeters.SelectNext();
|
||||
Show();
|
||||
return true;
|
||||
|
||||
case GlobalAction.PreviousVolumeMeter:
|
||||
if (State.Value == Visibility.Visible)
|
||||
volumeMeters.SelectPrevious();
|
||||
Show();
|
||||
return true;
|
||||
|
||||
case GlobalAction.ToggleMute:
|
||||
@ -134,6 +141,10 @@ namespace osu.Game.Overlays
|
||||
|
||||
public override void Show()
|
||||
{
|
||||
// Focus on the master meter as a default if previously hidden
|
||||
if (State.Value == Visibility.Hidden)
|
||||
volumeMeters.Select(volumeMeterMaster);
|
||||
|
||||
if (State.Value == Visibility.Visible)
|
||||
schedulePopOut();
|
||||
|
||||
|
@ -56,9 +56,9 @@ namespace osu.Game.Screens.Edit.Setup
|
||||
|
||||
public void DisplayFileChooser()
|
||||
{
|
||||
FileSelector fileSelector;
|
||||
OsuFileSelector fileSelector;
|
||||
|
||||
Target.Child = fileSelector = new FileSelector(currentFile.Value?.DirectoryName, handledExtensions)
|
||||
Target.Child = fileSelector = new OsuFileSelector(currentFile.Value?.DirectoryName, handledExtensions)
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 400,
|
||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Screens.Import
|
||||
{
|
||||
public override bool HideOverlaysOnEnter => true;
|
||||
|
||||
private FileSelector fileSelector;
|
||||
private OsuFileSelector fileSelector;
|
||||
private Container contentContainer;
|
||||
private TextFlowContainer currentFileText;
|
||||
|
||||
@ -57,7 +57,7 @@ namespace osu.Game.Screens.Import
|
||||
Colour = colours.GreySeafoamDark,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
fileSelector = new FileSelector(validFileExtensions: game.HandledExtensions.ToArray())
|
||||
fileSelector = new OsuFileSelector(validFileExtensions: game.HandledExtensions.ToArray())
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Width = 0.65f
|
||||
|
@ -2,23 +2,24 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Humanizer;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Input.Bindings;
|
||||
using Humanizer;
|
||||
using osu.Framework.Graphics.Effects;
|
||||
using osuTK;
|
||||
using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
@ -46,13 +47,13 @@ namespace osu.Game.Screens.Play
|
||||
/// <summary>
|
||||
/// Action that is invoked when <see cref="GlobalAction.Select"/> is triggered.
|
||||
/// </summary>
|
||||
protected virtual Action SelectAction => () => InternalButtons.Children.FirstOrDefault(f => f.Selected.Value)?.Click();
|
||||
protected virtual Action SelectAction => () => InternalButtons.Selected?.Click();
|
||||
|
||||
public abstract string Header { get; }
|
||||
|
||||
public abstract string Description { get; }
|
||||
|
||||
protected ButtonContainer InternalButtons;
|
||||
protected SelectionCycleFillFlowContainer<DialogButton> InternalButtons;
|
||||
public IReadOnlyList<DialogButton> Buttons => InternalButtons;
|
||||
|
||||
private FillFlowContainer retryCounterContainer;
|
||||
@ -116,7 +117,7 @@ namespace osu.Game.Screens.Play
|
||||
}
|
||||
}
|
||||
},
|
||||
InternalButtons = new ButtonContainer
|
||||
InternalButtons = new SelectionCycleFillFlowContainer<DialogButton>
|
||||
{
|
||||
Origin = Anchor.TopCentre,
|
||||
Anchor = Anchor.TopCentre,
|
||||
@ -183,8 +184,6 @@ namespace osu.Game.Screens.Play
|
||||
}
|
||||
};
|
||||
|
||||
button.Selected.ValueChanged += selected => buttonSelectionChanged(button, selected.NewValue);
|
||||
|
||||
InternalButtons.Add(button);
|
||||
}
|
||||
|
||||
@ -216,14 +215,6 @@ namespace osu.Game.Screens.Play
|
||||
{
|
||||
}
|
||||
|
||||
private void buttonSelectionChanged(DialogButton button, bool isSelected)
|
||||
{
|
||||
if (!isSelected)
|
||||
InternalButtons.Deselect();
|
||||
else
|
||||
InternalButtons.Select(button);
|
||||
}
|
||||
|
||||
private void updateRetryCount()
|
||||
{
|
||||
// "You've retried 1,065 times in this session"
|
||||
@ -255,46 +246,6 @@ namespace osu.Game.Screens.Play
|
||||
};
|
||||
}
|
||||
|
||||
protected class ButtonContainer : FillFlowContainer<DialogButton>
|
||||
{
|
||||
private int selectedIndex = -1;
|
||||
|
||||
private void setSelected(int value)
|
||||
{
|
||||
if (selectedIndex == value)
|
||||
return;
|
||||
|
||||
// Deselect the previously-selected button
|
||||
if (selectedIndex != -1)
|
||||
this[selectedIndex].Selected.Value = false;
|
||||
|
||||
selectedIndex = value;
|
||||
|
||||
// Select the newly-selected button
|
||||
if (selectedIndex != -1)
|
||||
this[selectedIndex].Selected.Value = true;
|
||||
}
|
||||
|
||||
public void SelectNext()
|
||||
{
|
||||
if (selectedIndex == -1 || selectedIndex == Count - 1)
|
||||
setSelected(0);
|
||||
else
|
||||
setSelected(selectedIndex + 1);
|
||||
}
|
||||
|
||||
public void SelectPrevious()
|
||||
{
|
||||
if (selectedIndex == -1 || selectedIndex == 0)
|
||||
setSelected(Count - 1);
|
||||
else
|
||||
setSelected(selectedIndex - 1);
|
||||
}
|
||||
|
||||
public void Deselect() => setSelected(-1);
|
||||
public void Select(DialogButton button) => setSelected(IndexOf(button));
|
||||
}
|
||||
|
||||
private class Button : DialogButton
|
||||
{
|
||||
// required to ensure keyboard navigation always starts from an extremity (unless the cursor is moved)
|
||||
@ -302,7 +253,7 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||
{
|
||||
Selected.Value = true;
|
||||
State = SelectionState.Selected;
|
||||
return base.OnMouseMove(e);
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,15 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Scoring;
|
||||
using osu.Game.Screens.Ranking;
|
||||
|
||||
@ -43,10 +47,24 @@ namespace osu.Game.Screens.Play
|
||||
|
||||
protected override ResultsScreen CreateResults(ScoreInfo score) => new SoloResultsScreen(score, false);
|
||||
|
||||
private ScheduledDelegate keyboardSeekDelegate;
|
||||
|
||||
public bool OnPressed(GlobalAction action)
|
||||
{
|
||||
const double keyboard_seek_amount = 5000;
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case GlobalAction.SeekReplayBackward:
|
||||
keyboardSeekDelegate?.Cancel();
|
||||
keyboardSeekDelegate = this.BeginKeyRepeat(Scheduler, () => keyboardSeek(-1));
|
||||
return true;
|
||||
|
||||
case GlobalAction.SeekReplayForward:
|
||||
keyboardSeekDelegate?.Cancel();
|
||||
keyboardSeekDelegate = this.BeginKeyRepeat(Scheduler, () => keyboardSeek(1));
|
||||
return true;
|
||||
|
||||
case GlobalAction.TogglePauseReplay:
|
||||
if (GameplayClockContainer.IsPaused.Value)
|
||||
GameplayClockContainer.Start();
|
||||
@ -56,10 +74,24 @@ namespace osu.Game.Screens.Play
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
void keyboardSeek(int direction)
|
||||
{
|
||||
double target = Math.Clamp(GameplayClockContainer.CurrentTime + direction * keyboard_seek_amount, 0, GameplayBeatmap.HitObjects.Last().GetEndTime());
|
||||
|
||||
Seek(target);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReleased(GlobalAction action)
|
||||
{
|
||||
switch (action)
|
||||
{
|
||||
case GlobalAction.SeekReplayBackward:
|
||||
case GlobalAction.SeekReplayForward:
|
||||
keyboardSeekDelegate?.Cancel();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,8 +57,6 @@ namespace osu.Game.Screens.Play
|
||||
set => CurrentNumber.Value = value;
|
||||
}
|
||||
|
||||
protected override bool AllowKeyboardInputWhenNotHovered => true;
|
||||
|
||||
public SongProgressBar(float barHeight, float handleBarHeight, Vector2 handleSize)
|
||||
{
|
||||
CurrentNumber.MinValue = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user