1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 01:27:29 +08:00

Merge branch 'master' into skin-editor-dont-show-save-on-no-change

This commit is contained in:
Bartłomiej Dach 2023-02-03 19:08:33 +01:00 committed by GitHub
commit 59656a7286
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 551 additions and 57 deletions

View File

@ -0,0 +1,63 @@
// 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 System.Threading.Tasks;
using Android.Content;
using Android.Net;
using Android.Provider;
using osu.Game.Database;
namespace osu.Android
{
public class AndroidImportTask : ImportTask
{
private readonly ContentResolver contentResolver;
private readonly Uri uri;
private AndroidImportTask(Stream stream, string filename, ContentResolver contentResolver, Uri uri)
: base(stream, filename)
{
this.contentResolver = contentResolver;
this.uri = uri;
}
public override void DeleteFile()
{
contentResolver.Delete(uri, null, null);
}
public static async Task<AndroidImportTask?> Create(ContentResolver contentResolver, Uri uri)
{
// there are more performant overloads of this method, but this one is the most backwards-compatible
// (dates back to API 1).
var cursor = contentResolver.Query(uri, null, null, null, null);
if (cursor == null)
return null;
if (!cursor.MoveToFirst())
return null;
int filenameColumn = cursor.GetColumnIndex(IOpenableColumns.DisplayName);
string filename = cursor.GetString(filenameColumn) ?? uri.Path ?? string.Empty;
// SharpCompress requires archive streams to be seekable, which the stream opened by
// OpenInputStream() seems to not necessarily be.
// copy to an arbitrary-access memory stream to be able to proceed with the import.
var copy = new MemoryStream();
using (var stream = contentResolver.OpenInputStream(uri))
{
if (stream == null)
return null;
await stream.CopyToAsync(copy).ConfigureAwait(false);
}
return new AndroidImportTask(copy, filename, contentResolver, uri);
}
}
}

View File

@ -5,7 +5,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
@ -14,7 +13,6 @@ using Android.Content;
using Android.Content.PM;
using Android.Graphics;
using Android.OS;
using Android.Provider;
using Android.Views;
using osu.Framework.Android;
using osu.Game.Database;
@ -131,28 +129,14 @@ namespace osu.Android
await Task.WhenAll(uris.Select(async uri =>
{
// there are more performant overloads of this method, but this one is the most backwards-compatible
// (dates back to API 1).
var cursor = ContentResolver?.Query(uri, null, null, null, null);
var task = await AndroidImportTask.Create(ContentResolver!, uri).ConfigureAwait(false);
if (cursor == null)
return;
cursor.MoveToFirst();
int filenameColumn = cursor.GetColumnIndex(IOpenableColumns.DisplayName);
string filename = cursor.GetString(filenameColumn);
// SharpCompress requires archive streams to be seekable, which the stream opened by
// OpenInputStream() seems to not necessarily be.
// copy to an arbitrary-access memory stream to be able to proceed with the import.
var copy = new MemoryStream();
using (var stream = ContentResolver.OpenInputStream(uri))
await stream.CopyToAsync(copy).ConfigureAwait(false);
lock (tasks)
if (task != null)
{
tasks.Add(new ImportTask(copy, filename));
lock (tasks)
{
tasks.Add(task);
}
}
})).ConfigureAwait(false);

View File

@ -4,6 +4,7 @@
#nullable disable
using NUnit.Framework;
using osu.Framework.Screens;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osuTK.Input;
@ -24,13 +25,40 @@ namespace osu.Game.Tests.Visual.Gameplay
}
[Test]
public void TestPause()
public void TestPauseViaSpace()
{
double? lastTime = null;
AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0);
AddStep("Pause playback", () => InputManager.Key(Key.Space));
AddStep("Pause playback with space", () => InputManager.Key(Key.Space));
AddAssert("player not exited", () => Player.IsCurrentScreen());
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 TestPauseViaMiddleMouse()
{
double? lastTime = null;
AddUntilStep("wait for first hit", () => Player.ScoreProcessor.TotalScore.Value > 0);
AddStep("Pause playback with middle mouse", () => InputManager.Click(MouseButton.Middle));
AddAssert("player not exited", () => Player.IsCurrentScreen());
AddUntilStep("Time stopped progressing", () =>
{

View File

@ -51,6 +51,15 @@ namespace osu.Game.Database
: getReaderFrom(Path);
}
/// <summary>
/// Deletes the file that is encapsulated by this <see cref="ImportTask"/>.
/// </summary>
public virtual void DeleteFile()
{
if (File.Exists(Path))
File.Delete(Path);
}
/// <summary>
/// Creates an <see cref="ArchiveReader"/> from a stream.
/// </summary>

View File

@ -201,8 +201,8 @@ namespace osu.Game.Database
// TODO: Add a check to prevent files from storage to be deleted.
try
{
if (import != null && File.Exists(task.Path) && ShouldDeleteArchive(task.Path))
File.Delete(task.Path);
if (import != null && ShouldDeleteArchive(task.Path))
task.DeleteFile();
}
catch (Exception e)
{

View File

@ -35,6 +35,7 @@ namespace osu.Game.Input.Bindings
// It is used to decide the order of precedence, with the earlier items having higher precedence.
public override IEnumerable<IKeyBinding> DefaultKeyBindings => GlobalKeyBindings
.Concat(EditorKeyBindings)
.Concat(ReplayKeyBindings)
.Concat(InGameKeyBindings)
.Concat(SongSelectKeyBindings)
.Concat(AudioControlKeyBindings)
@ -112,13 +113,18 @@ namespace osu.Game.Input.Bindings
new KeyBinding(new[] { InputKey.F4 }, GlobalAction.IncreaseScrollSpeed),
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),
new KeyBinding(InputKey.Tab, GlobalAction.ToggleChatFocus),
};
public IEnumerable<KeyBinding> ReplayKeyBindings => new[]
{
new KeyBinding(InputKey.Space, GlobalAction.TogglePauseReplay),
new KeyBinding(InputKey.MouseMiddle, GlobalAction.TogglePauseReplay),
new KeyBinding(InputKey.Left, GlobalAction.SeekReplayBackward),
new KeyBinding(InputKey.Right, GlobalAction.SeekReplayForward),
};
public IEnumerable<KeyBinding> SongSelectKeyBindings => new[]
{
new KeyBinding(InputKey.F1, GlobalAction.ToggleModSelection),

View File

@ -0,0 +1,89 @@
// 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.Localisation;
namespace osu.Game.Localisation.HUD
{
public static class BarHitErrorMeterStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.HUD.BarHitErrorMeter";
/// <summary>
/// "Judgement line thickness"
/// </summary>
public static LocalisableString JudgementLineThickness => new TranslatableString(getKey(@"judgement_line_thickness"), "Judgement line thickness");
/// <summary>
/// "How thick the individual lines should be."
/// </summary>
public static LocalisableString JudgementLineThicknessDescription => new TranslatableString(getKey(@"judgement_line_thickness_description"), "How thick the individual lines should be.");
/// <summary>
/// "Show colour bars"
/// </summary>
public static LocalisableString ColourBarVisibility => new TranslatableString(getKey(@"colour_bar_visibility"), "Show colour bars");
/// <summary>
/// "Show moving average arrow"
/// </summary>
public static LocalisableString ShowMovingAverage => new TranslatableString(getKey(@"show_moving_average"), "Show moving average arrow");
/// <summary>
/// "Whether an arrow should move beneath the bar showing the average error."
/// </summary>
public static LocalisableString ShowMovingAverageDescription => new TranslatableString(getKey(@"show_moving_average_description"), "Whether an arrow should move beneath the bar showing the average error.");
/// <summary>
/// "Centre marker style"
/// </summary>
public static LocalisableString CentreMarkerStyle => new TranslatableString(getKey(@"centre_marker_style"), "Centre marker style");
/// <summary>
/// "How to signify the centre of the display"
/// </summary>
public static LocalisableString CentreMarkerStyleDescription => new TranslatableString(getKey(@"centre_marker_style_description"), "How to signify the centre of the display");
/// <summary>
/// "None"
/// </summary>
public static LocalisableString CentreMarkerStylesNone => new TranslatableString(getKey(@"centre_marker_styles_none"), "None");
/// <summary>
/// "Circle"
/// </summary>
public static LocalisableString CentreMarkerStylesCircle => new TranslatableString(getKey(@"centre_marker_styles_circle"), "Circle");
/// <summary>
/// "Line"
/// </summary>
public static LocalisableString CentreMarkerStylesLine => new TranslatableString(getKey(@"centre_marker_styles_line"), "Line");
/// <summary>
/// "Label style"
/// </summary>
public static LocalisableString LabelStyle => new TranslatableString(getKey(@"label_style"), "Label style");
/// <summary>
/// "How to show early/late extremities"
/// </summary>
public static LocalisableString LabelStyleDescription => new TranslatableString(getKey(@"label_style_description"), "How to show early/late extremities");
/// <summary>
/// "None"
/// </summary>
public static LocalisableString LabelStylesNone => new TranslatableString(getKey(@"label_styles_none"), "None");
/// <summary>
/// "Icons"
/// </summary>
public static LocalisableString LabelStylesIcons => new TranslatableString(getKey(@"label_styles_icons"), "Icons");
/// <summary>
/// "Text"
/// </summary>
public static LocalisableString LabelStylesText => new TranslatableString(getKey(@"label_styles_text"), "Text");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,54 @@
// 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.Localisation;
namespace osu.Game.Localisation.HUD
{
public static class ColourHitErrorMeterStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.HUD.ColourHitError";
/// <summary>
/// "Judgement count"
/// </summary>
public static LocalisableString JudgementCount => new TranslatableString(getKey(@"judgement_count"), "Judgement count");
/// <summary>
/// "The number of displayed judgements"
/// </summary>
public static LocalisableString JudgementCountDescription => new TranslatableString(getKey(@"judgement_count_description"), "The number of displayed judgements");
/// <summary>
/// "Judgement spacing"
/// </summary>
public static LocalisableString JudgementSpacing => new TranslatableString(getKey(@"judgement_spacing"), "Judgement spacing");
/// <summary>
/// "The space between each displayed judgement"
/// </summary>
public static LocalisableString JudgementSpacingDescription => new TranslatableString(getKey(@"judgement_spacing_description"), "The space between each displayed judgement");
/// <summary>
/// "Judgement shape"
/// </summary>
public static LocalisableString JudgementShape => new TranslatableString(getKey(@"judgement_shape"), "Judgement shape");
/// <summary>
/// "The shape of each displayed judgement"
/// </summary>
public static LocalisableString JudgementShapeDescription => new TranslatableString(getKey(@"judgement_shape_description"), "The shape of each displayed judgement");
/// <summary>
/// "Circle"
/// </summary>
public static LocalisableString ShapeStyleCircle => new TranslatableString(getKey(@"shape_style_cricle"), "Circle");
/// <summary>
/// "Square"
/// </summary>
public static LocalisableString ShapeStyleSquare => new TranslatableString(getKey(@"shape_style_square"), "Square");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,39 @@
// 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.Localisation;
namespace osu.Game.Localisation.HUD
{
public static class GameplayAccuracyCounterStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.HUD.GameplayAccuracyCounter";
/// <summary>
/// "Accuracy display mode"
/// </summary>
public static LocalisableString AccuracyDisplay => new TranslatableString(getKey(@"accuracy_display"), "Accuracy display mode");
/// <summary>
/// "Which accuracy mode should be displayed."
/// </summary>
public static LocalisableString AccuracyDisplayDescription => new TranslatableString(getKey(@"accuracy_display_description"), "Which accuracy mode should be displayed.");
/// <summary>
/// "Standard"
/// </summary>
public static LocalisableString AccuracyDisplayModeStandard => new TranslatableString(getKey(@"accuracy_display_mode_standard"), "Standard");
/// <summary>
/// "Maximum achievable"
/// </summary>
public static LocalisableString AccuracyDisplayModeMax => new TranslatableString(getKey(@"accuracy_display_mode_max"), "Maximum achievable");
/// <summary>
/// "Minimum achievable"
/// </summary>
public static LocalisableString AccuracyDisplayModeMin => new TranslatableString(getKey(@"accuracy_display_mode_min"), "Minimum achievable");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,49 @@
// 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.Localisation;
namespace osu.Game.Localisation.HUD
{
public static class JudgementCounterDisplayStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.HUD.JudgementCounterDisplay";
/// <summary>
/// "Display mode"
/// </summary>
public static LocalisableString JudgementDisplayMode => new TranslatableString(getKey(@"judgement_display_mode"), "Display mode");
/// <summary>
/// "Counter direction"
/// </summary>
public static LocalisableString FlowDirection => new TranslatableString(getKey(@"flow_direction"), "Counter direction");
/// <summary>
/// "Show judgement names"
/// </summary>
public static LocalisableString ShowJudgementNames => new TranslatableString(getKey(@"show_judgement_names"), "Show judgement names");
/// <summary>
/// "Show max judgement"
/// </summary>
public static LocalisableString ShowMaxJudgement => new TranslatableString(getKey(@"show_max_judgement"), "Show max judgement");
/// <summary>
/// "Simple"
/// </summary>
public static LocalisableString JudgementDisplayModeSimple => new TranslatableString(getKey(@"judgement_display_mode_simple"), "Simple");
/// <summary>
/// "Normal"
/// </summary>
public static LocalisableString JudgementDisplayModeNormal => new TranslatableString(getKey(@"judgement_display_mode_normal"), "Normal");
/// <summary>
/// "All"
/// </summary>
public static LocalisableString JudgementDisplayModeAll => new TranslatableString(getKey(@"judgement_display_mode_all"), "All");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,24 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Localisation;
namespace osu.Game.Localisation.HUD
{
public static class SongProgressStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.HUD.SongProgress";
/// <summary>
/// "Show difficulty graph"
/// </summary>
public static LocalisableString ShowGraph => new TranslatableString(getKey(@"show_graph"), "Show difficulty graph");
/// <summary>
/// "Whether a graph displaying difficulty throughout the beatmap should be shown"
/// </summary>
public static LocalisableString ShowGraphDescription => new TranslatableString(getKey(@"show_graph_description"), "Whether a graph displaying difficulty throughout the beatmap should be shown");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -34,6 +34,11 @@ namespace osu.Game.Localisation
/// </summary>
public static LocalisableString InGameSection => new TranslatableString(getKey(@"in_game_section"), @"In Game");
/// <summary>
/// "Replay"
/// </summary>
public static LocalisableString ReplaySection => new TranslatableString(getKey(@"replay_section"), @"Replay");
/// <summary>
/// "Audio"
/// </summary>

View File

@ -0,0 +1,34 @@
// 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.Localisation;
namespace osu.Game.Localisation.SkinComponents
{
public static class BeatmapAttributeTextStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.SkinComponents.BeatmapAttributeText";
/// <summary>
/// "Attribute"
/// </summary>
public static LocalisableString Attribute => new TranslatableString(getKey(@"attribute"), "Attribute");
/// <summary>
/// "The attribute to be displayed."
/// </summary>
public static LocalisableString AttributeDescription => new TranslatableString(getKey(@"attribute_description"), "The attribute to be displayed.");
/// <summary>
/// "Template"
/// </summary>
public static LocalisableString Template => new TranslatableString(getKey(@"template"), "Template");
/// <summary>
/// "Supports {{Label}} and {{Value}}, but also including arbitrary attributes like {{StarRating}} (see attribute list for supported values)."
/// </summary>
public static LocalisableString TemplateDescription => new TranslatableString(getKey(@"template_description"), @"Supports {{Label}} and {{Value}}, but also including arbitrary attributes like {{StarRating}} (see attribute list for supported values).");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -0,0 +1,44 @@
// 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.Localisation;
namespace osu.Game.Localisation.SkinComponents
{
public static class SkinnableComponentStrings
{
private const string prefix = @"osu.Game.Resources.Localisation.SkinComponents.SkinnableComponentStrings";
/// <summary>
/// "Sprite name"
/// </summary>
public static LocalisableString SpriteName => new TranslatableString(getKey(@"sprite_name"), "Sprite name");
/// <summary>
/// "The filename of the sprite"
/// </summary>
public static LocalisableString SpriteNameDescription => new TranslatableString(getKey(@"sprite_name_description"), "The filename of the sprite");
/// <summary>
/// "Font"
/// </summary>
public static LocalisableString Font => new TranslatableString(getKey(@"font"), "Font");
/// <summary>
/// "The font to use."
/// </summary>
public static LocalisableString FontDescription => new TranslatableString(getKey(@"font_description"), "The font to use.");
/// <summary>
/// "Text"
/// </summary>
public static LocalisableString TextElementText => new TranslatableString(getKey(@"text_element_text"), "Text");
/// <summary>
/// "The text to be displayed."
/// </summary>
public static LocalisableString TextElementTextDescription => new TranslatableString(getKey(@"text_element_text_description"), "The text to be displayed.");
private static string getKey(string key) => $"{prefix}:{key}";
}
}

View File

@ -39,6 +39,11 @@ namespace osu.Game.Localisation
/// </summary>
public static LocalisableString Settings(string arg0) => new TranslatableString(getKey(@"settings"), @"Settings ({0})", arg0);
/// <summary>
/// "Currently editing"
/// </summary>
public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), "Currently editing");
private static string getKey(string key) => $@"{prefix}:{key}";
}
}

View File

@ -25,6 +25,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
Add(new AudioControlKeyBindingsSubsection(manager));
Add(new SongSelectKeyBindingSubsection(manager));
Add(new InGameKeyBindingsSubsection(manager));
Add(new ReplayKeyBindingsSubsection(manager));
Add(new EditorKeyBindingsSubsection(manager));
}
@ -72,6 +73,17 @@ namespace osu.Game.Overlays.Settings.Sections.Input
}
}
private partial class ReplayKeyBindingsSubsection : KeyBindingsSubsection
{
protected override LocalisableString Header => InputSettingsStrings.ReplaySection;
public ReplayKeyBindingsSubsection(GlobalActionContainer manager)
: base(null)
{
Defaults = manager.ReplayKeyBindings;
}
}
private partial class AudioControlKeyBindingsSubsection : KeyBindingsSubsection
{
protected override LocalisableString Header => InputSettingsStrings.AudioSection;

View File

@ -256,13 +256,13 @@ namespace osu.Game.Overlays.SkinEditor
headerText.AddParagraph(SkinEditorStrings.SkinEditor, cp => cp.Font = OsuFont.Default.With(size: 16));
headerText.NewParagraph();
headerText.AddText("Currently editing ", cp =>
headerText.AddText(SkinEditorStrings.CurrentlyEditing, cp =>
{
cp.Font = OsuFont.Default.With(size: 12);
cp.Colour = colours.Yellow;
});
headerText.AddText($"{currentSkin.Value.SkinInfo}", cp =>
headerText.AddText($" {currentSkin.Value.SkinInfo}", cp =>
{
cp.Font = OsuFont.Default.With(size: 12, weight: FontWeight.Bold);
cp.Colour = colours.Yellow;

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Localisation.HUD;
using osu.Game.Rulesets.Objects;
namespace osu.Game.Screens.Play.HUD
@ -21,7 +22,7 @@ namespace osu.Game.Screens.Play.HUD
private const float bar_height = 10;
[SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")]
[SettingSource(typeof(SongProgressStrings), nameof(SongProgressStrings.ShowGraph), nameof(SongProgressStrings.ShowGraphDescription))]
public Bindable<bool> ShowGraph { get; } = new BindableBool(true);
[Resolved]

View File

@ -7,6 +7,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Localisation.HUD;
using osu.Game.Rulesets.Objects;
using osuTK;
@ -26,7 +27,7 @@ namespace osu.Game.Screens.Play.HUD
private readonly DefaultSongProgressGraph graph;
private readonly SongProgressInfo info;
[SettingSource("Show difficulty graph", "Whether a graph displaying difficulty throughout the beatmap should be shown")]
[SettingSource(typeof(SongProgressStrings), nameof(SongProgressStrings.ShowGraph), nameof(SongProgressStrings.ShowGraphDescription))]
public Bindable<bool> ShowGraph { get; } = new BindableBool(true);
[Resolved]

View File

@ -1,18 +1,19 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.ComponentModel;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics.UserInterface;
using osu.Game.Localisation.HUD;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Screens.Play.HUD
{
public abstract partial class GameplayAccuracyCounter : PercentageCounter
{
[SettingSource("Accuracy display mode", "Which accuracy mode should be displayed.")]
[SettingSource(typeof(GameplayAccuracyCounterStrings), nameof(GameplayAccuracyCounterStrings.AccuracyDisplay), nameof(GameplayAccuracyCounterStrings.AccuracyDisplayDescription))]
public Bindable<AccuracyDisplayMode> AccuracyDisplay { get; } = new Bindable<AccuracyDisplayMode>();
[Resolved]
@ -51,13 +52,13 @@ namespace osu.Game.Screens.Play.HUD
public enum AccuracyDisplayMode
{
[Description("Standard")]
[LocalisableDescription(typeof(GameplayAccuracyCounterStrings), nameof(GameplayAccuracyCounterStrings.AccuracyDisplayModeStandard))]
Standard,
[Description("Maximum achievable")]
[LocalisableDescription(typeof(GameplayAccuracyCounterStrings), nameof(GameplayAccuracyCounterStrings.AccuracyDisplayModeMax))]
MaximumAchievable,
[Description("Minimum achievable")]
[LocalisableDescription(typeof(GameplayAccuracyCounterStrings), nameof(GameplayAccuracyCounterStrings.AccuracyDisplayModeMin))]
MinimumAchievable
}
}

View File

@ -12,10 +12,12 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Localisation.HUD;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osuTK;
@ -25,7 +27,7 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
[Cached]
public partial class BarHitErrorMeter : HitErrorMeter
{
[SettingSource("Judgement line thickness", "How thick the individual lines should be.")]
[SettingSource(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.JudgementLineThickness), nameof(BarHitErrorMeterStrings.JudgementLineThicknessDescription))]
public BindableNumber<float> JudgementLineThickness { get; } = new BindableNumber<float>(4)
{
MinValue = 1,
@ -33,16 +35,16 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
Precision = 0.1f,
};
[SettingSource("Show colour bars")]
[SettingSource(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.ColourBarVisibility))]
public Bindable<bool> ColourBarVisibility { get; } = new Bindable<bool>(true);
[SettingSource("Show moving average arrow", "Whether an arrow should move beneath the bar showing the average error.")]
[SettingSource(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.ShowMovingAverage), nameof(BarHitErrorMeterStrings.ShowMovingAverageDescription))]
public Bindable<bool> ShowMovingAverage { get; } = new BindableBool(true);
[SettingSource("Centre marker style", "How to signify the centre of the display")]
[SettingSource(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.CentreMarkerStyle), nameof(BarHitErrorMeterStrings.CentreMarkerStyleDescription))]
public Bindable<CentreMarkerStyles> CentreMarkerStyle { get; } = new Bindable<CentreMarkerStyles>(CentreMarkerStyles.Circle);
[SettingSource("Label style", "How to show early/late extremities")]
[SettingSource(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.LabelStyle), nameof(BarHitErrorMeterStrings.LabelStyleDescription))]
public Bindable<LabelStyles> LabelStyle { get; } = new Bindable<LabelStyles>(LabelStyles.Icons);
private const int judgement_line_width = 14;
@ -487,15 +489,25 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
public enum CentreMarkerStyles
{
[LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.CentreMarkerStylesNone))]
None,
[LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.CentreMarkerStylesCircle))]
Circle,
[LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.CentreMarkerStylesLine))]
Line
}
public enum LabelStyles
{
[LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.LabelStylesNone))]
None,
[LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.LabelStylesIcons))]
Icons,
[LocalisableDescription(typeof(BarHitErrorMeterStrings), nameof(BarHitErrorMeterStrings.LabelStylesText))]
Text
}
}

View File

@ -9,7 +9,9 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Pooling;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Localisation.HUD;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Scoring;
using osuTK;
@ -23,21 +25,21 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
private const int animation_duration = 200;
private const int drawable_judgement_size = 8;
[SettingSource("Judgement count", "The number of displayed judgements")]
[SettingSource(typeof(ColourHitErrorMeterStrings), nameof(ColourHitErrorMeterStrings.JudgementCount), nameof(ColourHitErrorMeterStrings.JudgementCountDescription))]
public BindableNumber<int> JudgementCount { get; } = new BindableNumber<int>(20)
{
MinValue = 1,
MaxValue = 50,
};
[SettingSource("Judgement spacing", "The space between each displayed judgement")]
[SettingSource(typeof(ColourHitErrorMeterStrings), nameof(ColourHitErrorMeterStrings.JudgementSpacing), nameof(ColourHitErrorMeterStrings.JudgementSpacingDescription))]
public BindableNumber<float> JudgementSpacing { get; } = new BindableNumber<float>(2)
{
MinValue = 0,
MaxValue = 10,
};
[SettingSource("Judgement shape", "The shape of each displayed judgement")]
[SettingSource(typeof(ColourHitErrorMeterStrings), nameof(ColourHitErrorMeterStrings.JudgementShape), nameof(ColourHitErrorMeterStrings.JudgementShapeDescription))]
public Bindable<ShapeStyle> JudgementShape { get; } = new Bindable<ShapeStyle>();
private readonly JudgementFlow judgementsFlow;
@ -192,7 +194,10 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters
public enum ShapeStyle
{
[LocalisableDescription(typeof(ColourHitErrorMeterStrings), nameof(ColourHitErrorMeterStrings.ShapeStyleCircle))]
Circle,
[LocalisableDescription(typeof(ColourHitErrorMeterStrings), nameof(ColourHitErrorMeterStrings.ShapeStyleSquare))]
Square
}
}

View File

@ -31,6 +31,8 @@ namespace osu.Game.Screens.Play.HUD
public readonly Bindable<bool> IsPaused = new Bindable<bool>();
public readonly Bindable<bool> ReplayLoaded = new Bindable<bool>();
private HoldButton button;
public Action Action { get; set; }
@ -60,6 +62,7 @@ namespace osu.Game.Screens.Play.HUD
HoverGained = () => text.FadeIn(500, Easing.OutQuint),
HoverLost = () => text.FadeOut(500, Easing.OutQuint),
IsPaused = { BindTarget = IsPaused },
ReplayLoaded = { BindTarget = ReplayLoaded },
Action = () => Action(),
}
};
@ -110,6 +113,8 @@ namespace osu.Game.Screens.Play.HUD
public readonly Bindable<bool> IsPaused = new Bindable<bool>();
public readonly Bindable<bool> ReplayLoaded = new Bindable<bool>();
protected override bool AllowMultipleFires => true;
public Action HoverGained;
@ -251,7 +256,14 @@ namespace osu.Game.Screens.Play.HUD
switch (e.Action)
{
case GlobalAction.Back:
case GlobalAction.PauseGameplay: // in the future this behaviour will differ for replays etc.
if (!pendingAnimation)
BeginConfirm();
return true;
case GlobalAction.PauseGameplay:
// handled by replay player
if (ReplayLoaded.Value) return false;
if (!pendingAnimation)
BeginConfirm();
return true;
@ -265,7 +277,12 @@ namespace osu.Game.Screens.Play.HUD
switch (e.Action)
{
case GlobalAction.Back:
AbortConfirm();
break;
case GlobalAction.PauseGameplay:
if (ReplayLoaded.Value) return;
AbortConfirm();
break;
}

View File

@ -6,7 +6,9 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Localisation.HUD;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning;
using osuTK;
@ -19,16 +21,16 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter
public bool UsesFixedAnchor { get; set; }
[SettingSource("Display mode")]
[SettingSource(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayMode))]
public Bindable<DisplayMode> Mode { get; set; } = new Bindable<DisplayMode>();
[SettingSource("Counter direction")]
[SettingSource(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.FlowDirection))]
public Bindable<Direction> FlowDirection { get; set; } = new Bindable<Direction>();
[SettingSource("Show judgement names")]
[SettingSource(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.ShowJudgementNames))]
public BindableBool ShowJudgementNames { get; set; } = new BindableBool(true);
[SettingSource("Show max judgement")]
[SettingSource(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.ShowMaxJudgement))]
public BindableBool ShowMaxJudgement { get; set; } = new BindableBool(true);
[Resolved]
@ -130,8 +132,13 @@ namespace osu.Game.Screens.Play.HUD.JudgementCounter
public enum DisplayMode
{
[LocalisableDescription(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayModeSimple))]
Simple,
[LocalisableDescription(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayModeNormal))]
Normal,
[LocalisableDescription(typeof(JudgementCounterDisplayStrings), nameof(JudgementCounterDisplayStrings.JudgementDisplayModeAll))]
All
}
}

View File

@ -435,7 +435,8 @@ namespace osu.Game.Screens.Play
HoldToQuit =
{
Action = () => PerformExit(true),
IsPaused = { BindTarget = GameplayClockContainer.IsPaused }
IsPaused = { BindTarget = GameplayClockContainer.IsPaused },
ReplayLoaded = { BindTarget = DrawableRuleset.HasReplayLoaded },
},
KeyCounter =
{

View File

@ -18,6 +18,7 @@ using osu.Game.Configuration;
using osu.Game.Extensions;
using osu.Game.Graphics.Sprites;
using osu.Game.Localisation;
using osu.Game.Localisation.SkinComponents;
using osu.Game.Resources.Localisation.Web;
namespace osu.Game.Skinning.Components
@ -25,10 +26,10 @@ namespace osu.Game.Skinning.Components
[UsedImplicitly]
public partial class BeatmapAttributeText : FontAdjustableSkinComponent
{
[SettingSource("Attribute", "The attribute to be displayed.")]
[SettingSource(typeof(BeatmapAttributeTextStrings), nameof(BeatmapAttributeTextStrings.Attribute), nameof(BeatmapAttributeTextStrings.AttributeDescription))]
public Bindable<BeatmapAttribute> Attribute { get; } = new Bindable<BeatmapAttribute>(BeatmapAttribute.StarRating);
[SettingSource("Template", "Supports {Label} and {Value}, but also including arbitrary attributes like {StarRating} (see attribute list for supported values).")]
[SettingSource(typeof(BeatmapAttributeTextStrings), nameof(BeatmapAttributeTextStrings.Template), nameof(BeatmapAttributeTextStrings.TemplateDescription))]
public Bindable<string> Template { get; set; } = new Bindable<string>("{Label}: {Value}");
[Resolved]

View File

@ -8,13 +8,14 @@ using osu.Framework.Graphics.Sprites;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Localisation.SkinComponents;
namespace osu.Game.Skinning.Components
{
[UsedImplicitly]
public partial class TextElement : FontAdjustableSkinComponent
{
[SettingSource("Text", "The text to be displayed.")]
[SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.TextElementText), nameof(SkinnableComponentStrings.TextElementTextDescription))]
public Bindable<string> Text { get; } = new Bindable<string>("Circles!");
private readonly OsuSpriteText text;

View File

@ -6,6 +6,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Configuration;
using osu.Game.Graphics;
using osu.Game.Localisation.SkinComponents;
namespace osu.Game.Skinning
{
@ -16,7 +17,7 @@ namespace osu.Game.Skinning
{
public bool UsesFixedAnchor { get; set; }
[SettingSource("Font", "The font to use.")]
[SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.Font), nameof(SkinnableComponentStrings.FontDescription))]
public Bindable<Typeface> Font { get; } = new Bindable<Typeface>(Typeface.Torus);
/// <summary>

View File

@ -12,6 +12,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Configuration;
using osu.Game.Graphics.Sprites;
using osu.Game.Localisation.SkinComponents;
using osu.Game.Overlays.Settings;
using osuTK;
@ -27,7 +28,7 @@ namespace osu.Game.Skinning
[Resolved]
private TextureStore textures { get; set; } = null!;
[SettingSource("Sprite name", "The filename of the sprite", SettingControlType = typeof(SpriteSelectorControl))]
[SettingSource(typeof(SkinnableComponentStrings), nameof(SkinnableComponentStrings.SpriteName), nameof(SkinnableComponentStrings.SpriteNameDescription), SettingControlType = typeof(SpriteSelectorControl))]
public Bindable<string> SpriteName { get; } = new Bindable<string>(string.Empty);
[Resolved]