mirror of
https://github.com/ppy/osu.git
synced 2025-02-05 15:13:21 +08:00
Merge branch 'master' into fix-section-container-scroll-attempt-2
This commit is contained in:
commit
b3ce7f7b43
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -2,7 +2,7 @@ blank_issues_enabled: false
|
|||||||
contact_links:
|
contact_links:
|
||||||
- name: Help
|
- name: Help
|
||||||
url: https://github.com/ppy/osu/discussions/categories/q-a
|
url: https://github.com/ppy/osu/discussions/categories/q-a
|
||||||
about: osu! not working as you'd expect? Not sure it's a bug? Check the Q&A section!
|
about: osu! not working or performing as you'd expect? Not sure it's a bug? Check the Q&A section!
|
||||||
- name: Suggestions or feature request
|
- name: Suggestions or feature request
|
||||||
url: https://github.com/ppy/osu/discussions/categories/ideas
|
url: https://github.com/ppy/osu/discussions/categories/ideas
|
||||||
about: Got something you think should change or be added? Search for or start a new discussion!
|
about: Got something you think should change or be added? Search for or start a new discussion!
|
||||||
|
180
osu.Game.Rulesets.Catch/Edit/CatchBeatSnapGrid.cs
Normal file
180
osu.Game.Rulesets.Catch/Edit/CatchBeatSnapGrid.cs
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
// 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.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Caching;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Rulesets.Catch.UI;
|
||||||
|
using osu.Game.Rulesets.Edit;
|
||||||
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Rulesets.UI.Scrolling;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Catch.Edit
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A grid which displays coloured beat divisor lines in proximity to the selection or placement cursor.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This class heavily borrows from osu!mania's implementation (ManiaBeatSnapGrid).
|
||||||
|
/// If further changes are to be made, they should also be applied there.
|
||||||
|
/// If the scale of the changes are large enough, abstracting may be a good path.
|
||||||
|
/// </remarks>
|
||||||
|
public partial class CatchBeatSnapGrid : Component
|
||||||
|
{
|
||||||
|
private const double visible_range = 750;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The range of time values of the current selection.
|
||||||
|
/// </summary>
|
||||||
|
public (double start, double end)? SelectionTimeRange
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == selectionTimeRange)
|
||||||
|
return;
|
||||||
|
|
||||||
|
selectionTimeRange = value;
|
||||||
|
lineCache.Invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private EditorBeatmap beatmap { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private OsuColour colours { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private BindableBeatDivisor beatDivisor { get; set; } = null!;
|
||||||
|
|
||||||
|
private readonly Cached lineCache = new Cached();
|
||||||
|
|
||||||
|
private (double start, double end)? selectionTimeRange;
|
||||||
|
|
||||||
|
private ScrollingHitObjectContainer lineContainer = null!;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(HitObjectComposer composer)
|
||||||
|
{
|
||||||
|
lineContainer = new ScrollingHitObjectContainer();
|
||||||
|
|
||||||
|
((CatchPlayfield)composer.Playfield).UnderlayElements.Add(lineContainer);
|
||||||
|
|
||||||
|
beatDivisor.BindValueChanged(_ => createLines(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (!lineCache.IsValid)
|
||||||
|
{
|
||||||
|
lineCache.Validate();
|
||||||
|
createLines();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Stack<DrawableGridLine> availableLines = new Stack<DrawableGridLine>();
|
||||||
|
|
||||||
|
private void createLines()
|
||||||
|
{
|
||||||
|
foreach (var line in lineContainer.Objects.OfType<DrawableGridLine>())
|
||||||
|
availableLines.Push(line);
|
||||||
|
|
||||||
|
lineContainer.Clear();
|
||||||
|
|
||||||
|
if (selectionTimeRange == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var range = selectionTimeRange.Value;
|
||||||
|
|
||||||
|
var timingPoint = beatmap.ControlPointInfo.TimingPointAt(range.start - visible_range);
|
||||||
|
|
||||||
|
double time = timingPoint.Time;
|
||||||
|
int beat = 0;
|
||||||
|
|
||||||
|
// progress time until in the visible range.
|
||||||
|
while (time < range.start - visible_range)
|
||||||
|
{
|
||||||
|
time += timingPoint.BeatLength / beatDivisor.Value;
|
||||||
|
beat++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (time < range.end + visible_range)
|
||||||
|
{
|
||||||
|
var nextTimingPoint = beatmap.ControlPointInfo.TimingPointAt(time);
|
||||||
|
|
||||||
|
// switch to the next timing point if we have reached it.
|
||||||
|
if (nextTimingPoint.Time > timingPoint.Time)
|
||||||
|
{
|
||||||
|
beat = 0;
|
||||||
|
time = nextTimingPoint.Time;
|
||||||
|
timingPoint = nextTimingPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color4 colour = BindableBeatDivisor.GetColourFor(
|
||||||
|
BindableBeatDivisor.GetDivisorForBeatIndex(beat, beatDivisor.Value), colours);
|
||||||
|
|
||||||
|
if (!availableLines.TryPop(out var line))
|
||||||
|
line = new DrawableGridLine();
|
||||||
|
|
||||||
|
line.HitObject.StartTime = time;
|
||||||
|
line.Colour = colour;
|
||||||
|
|
||||||
|
lineContainer.Add(line);
|
||||||
|
|
||||||
|
beat++;
|
||||||
|
time += timingPoint.BeatLength / beatDivisor.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// required to update ScrollingHitObjectContainer's cache.
|
||||||
|
lineContainer.UpdateSubTree();
|
||||||
|
|
||||||
|
foreach (var line in lineContainer.Objects.OfType<DrawableGridLine>())
|
||||||
|
{
|
||||||
|
time = line.HitObject.StartTime;
|
||||||
|
|
||||||
|
if (time >= range.start && time <= range.end)
|
||||||
|
line.Alpha = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
double timeSeparation = time < range.start ? range.start - time : time - range.end;
|
||||||
|
line.Alpha = (float)Math.Max(0, 1 - timeSeparation / visible_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private partial class DrawableGridLine : DrawableHitObject
|
||||||
|
{
|
||||||
|
public DrawableGridLine()
|
||||||
|
: base(new HitObject())
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X;
|
||||||
|
Height = 2;
|
||||||
|
|
||||||
|
AddInternal(new Box { RelativeSizeAxes = Axes.Both });
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Origin = Anchor.BottomLeft;
|
||||||
|
Anchor = Anchor.BottomLeft;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateInitialTransforms()
|
||||||
|
{
|
||||||
|
// don't perform any fading – we are handling that ourselves.
|
||||||
|
LifetimeEnd = HitObject.StartTime + visible_range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,8 @@ namespace osu.Game.Rulesets.Catch.Edit
|
|||||||
|
|
||||||
private InputManager inputManager = null!;
|
private InputManager inputManager = null!;
|
||||||
|
|
||||||
|
private CatchBeatSnapGrid beatSnapGrid = null!;
|
||||||
|
|
||||||
private readonly BindableDouble timeRangeMultiplier = new BindableDouble(1)
|
private readonly BindableDouble timeRangeMultiplier = new BindableDouble(1)
|
||||||
{
|
{
|
||||||
MinValue = 1,
|
MinValue = 1,
|
||||||
@ -65,6 +67,8 @@ namespace osu.Game.Rulesets.Catch.Edit
|
|||||||
Catcher.BASE_DASH_SPEED, -Catcher.BASE_DASH_SPEED,
|
Catcher.BASE_DASH_SPEED, -Catcher.BASE_DASH_SPEED,
|
||||||
Catcher.BASE_WALK_SPEED, -Catcher.BASE_WALK_SPEED,
|
Catcher.BASE_WALK_SPEED, -Catcher.BASE_WALK_SPEED,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
AddInternal(beatSnapGrid = new CatchBeatSnapGrid());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -74,6 +78,29 @@ namespace osu.Game.Rulesets.Catch.Edit
|
|||||||
inputManager = GetContainingInputManager();
|
inputManager = GetContainingInputManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void UpdateAfterChildren()
|
||||||
|
{
|
||||||
|
base.UpdateAfterChildren();
|
||||||
|
|
||||||
|
if (BlueprintContainer.CurrentTool is SelectTool)
|
||||||
|
{
|
||||||
|
if (EditorBeatmap.SelectedHitObjects.Any())
|
||||||
|
{
|
||||||
|
beatSnapGrid.SelectionTimeRange = (EditorBeatmap.SelectedHitObjects.Min(h => h.StartTime), EditorBeatmap.SelectedHitObjects.Max(h => h.GetEndTime()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
beatSnapGrid.SelectionTimeRange = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var result = FindSnappedPositionAndTime(inputManager.CurrentState.Mouse.Position);
|
||||||
|
if (result.Time is double time)
|
||||||
|
beatSnapGrid.SelectionTimeRange = (time, time);
|
||||||
|
else
|
||||||
|
beatSnapGrid.SelectionTimeRange = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override double ReadCurrentDistanceSnap(HitObject before, HitObject after)
|
protected override double ReadCurrentDistanceSnap(HitObject before, HitObject after)
|
||||||
{
|
{
|
||||||
// osu!catch's distance snap implementation is limited, in that a custom spacing cannot be specified.
|
// osu!catch's distance snap implementation is limited, in that a custom spacing cannot be specified.
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Catch.Objects;
|
using osu.Game.Rulesets.Catch.Objects;
|
||||||
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
using osu.Game.Rulesets.Catch.Objects.Drawables;
|
||||||
@ -41,6 +42,8 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
internal CatcherArea CatcherArea { get; private set; } = null!;
|
internal CatcherArea CatcherArea { get; private set; } = null!;
|
||||||
|
|
||||||
|
public Container UnderlayElements { get; private set; } = null!;
|
||||||
|
|
||||||
private readonly IBeatmapDifficultyInfo difficulty;
|
private readonly IBeatmapDifficultyInfo difficulty;
|
||||||
|
|
||||||
public CatchPlayfield(IBeatmapDifficultyInfo difficulty)
|
public CatchPlayfield(IBeatmapDifficultyInfo difficulty)
|
||||||
@ -62,6 +65,10 @@ namespace osu.Game.Rulesets.Catch.UI
|
|||||||
|
|
||||||
AddRangeInternal(new[]
|
AddRangeInternal(new[]
|
||||||
{
|
{
|
||||||
|
UnderlayElements = new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
droppedObjectContainer,
|
droppedObjectContainer,
|
||||||
Catcher.CreateProxiedContent(),
|
Catcher.CreateProxiedContent(),
|
||||||
HitObjectContainer.CreateProxy(),
|
HitObjectContainer.CreateProxy(),
|
||||||
|
@ -129,7 +129,7 @@ namespace osu.Game.Rulesets.Mania.Edit
|
|||||||
}
|
}
|
||||||
|
|
||||||
Color4 colour = BindableBeatDivisor.GetColourFor(
|
Color4 colour = BindableBeatDivisor.GetColourFor(
|
||||||
BindableBeatDivisor.GetDivisorForBeatIndex(Math.Max(1, beat), beatDivisor.Value), colours);
|
BindableBeatDivisor.GetDivisorForBeatIndex(beat, beatDivisor.Value), colours);
|
||||||
|
|
||||||
foreach (var grid in grids)
|
foreach (var grid in grids)
|
||||||
{
|
{
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
|
||||||
|
@ -139,11 +139,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
|
|||||||
case 3:
|
case 3:
|
||||||
switch (columnIndex)
|
switch (columnIndex)
|
||||||
{
|
{
|
||||||
case 0: return colour_pink;
|
case 0: return colour_green;
|
||||||
|
|
||||||
case 1: return colour_orange;
|
case 1: return colour_special_column;
|
||||||
|
|
||||||
case 2: return colour_yellow;
|
case 2: return colour_cyan;
|
||||||
|
|
||||||
default: throw new ArgumentOutOfRangeException();
|
default: throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
@ -185,11 +185,11 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
|
|||||||
|
|
||||||
case 1: return colour_orange;
|
case 1: return colour_orange;
|
||||||
|
|
||||||
case 2: return colour_yellow;
|
case 2: return colour_green;
|
||||||
|
|
||||||
case 3: return colour_cyan;
|
case 3: return colour_cyan;
|
||||||
|
|
||||||
case 4: return colour_purple;
|
case 4: return colour_orange;
|
||||||
|
|
||||||
case 5: return colour_pink;
|
case 5: return colour_pink;
|
||||||
|
|
||||||
@ -201,17 +201,17 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
|
|||||||
{
|
{
|
||||||
case 0: return colour_pink;
|
case 0: return colour_pink;
|
||||||
|
|
||||||
case 1: return colour_cyan;
|
case 1: return colour_orange;
|
||||||
|
|
||||||
case 2: return colour_pink;
|
case 2: return colour_pink;
|
||||||
|
|
||||||
case 3: return colour_special_column;
|
case 3: return colour_special_column;
|
||||||
|
|
||||||
case 4: return colour_green;
|
case 4: return colour_pink;
|
||||||
|
|
||||||
case 5: return colour_cyan;
|
case 5: return colour_orange;
|
||||||
|
|
||||||
case 6: return colour_green;
|
case 6: return colour_pink;
|
||||||
|
|
||||||
default: throw new ArgumentOutOfRangeException();
|
default: throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
@ -225,9 +225,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
|
|||||||
|
|
||||||
case 2: return colour_orange;
|
case 2: return colour_orange;
|
||||||
|
|
||||||
case 3: return colour_yellow;
|
case 3: return colour_green;
|
||||||
|
|
||||||
case 4: return colour_yellow;
|
case 4: return colour_cyan;
|
||||||
|
|
||||||
case 5: return colour_orange;
|
case 5: return colour_orange;
|
||||||
|
|
||||||
@ -273,9 +273,9 @@ namespace osu.Game.Rulesets.Mania.Skinning.Argon
|
|||||||
|
|
||||||
case 3: return colour_yellow;
|
case 3: return colour_yellow;
|
||||||
|
|
||||||
case 4: return colour_cyan;
|
case 4: return colour_green;
|
||||||
|
|
||||||
case 5: return colour_green;
|
case 5: return colour_cyan;
|
||||||
|
|
||||||
case 6: return colour_yellow;
|
case 6: return colour_yellow;
|
||||||
|
|
||||||
|
@ -40,7 +40,11 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
|
public readonly Bindable<ManiaAction> Action = new Bindable<ManiaAction>();
|
||||||
|
|
||||||
public readonly ColumnHitObjectArea HitObjectArea;
|
public readonly ColumnHitObjectArea HitObjectArea;
|
||||||
|
|
||||||
|
internal readonly Container BackgroundContainer = new Container { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
internal readonly Container TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both };
|
internal readonly Container TopLevelContainer = new Container { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
private DrawablePool<PoolableHitExplosion> hitExplosionPool;
|
private DrawablePool<PoolableHitExplosion> hitExplosionPool;
|
||||||
private readonly OrderedHitPolicy hitPolicy;
|
private readonly OrderedHitPolicy hitPolicy;
|
||||||
public Container UnderlayElements => HitObjectArea.UnderlayElements;
|
public Container UnderlayElements => HitObjectArea.UnderlayElements;
|
||||||
@ -77,30 +81,31 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
skin.SourceChanged += onSourceChanged;
|
skin.SourceChanged += onSourceChanged;
|
||||||
onSourceChanged();
|
onSourceChanged();
|
||||||
|
|
||||||
Drawable background = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground())
|
InternalChildren = new Drawable[]
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
};
|
|
||||||
|
|
||||||
InternalChildren = new[]
|
|
||||||
{
|
{
|
||||||
hitExplosionPool = new DrawablePool<PoolableHitExplosion>(5),
|
hitExplosionPool = new DrawablePool<PoolableHitExplosion>(5),
|
||||||
sampleTriggerSource = new GameplaySampleTriggerSource(HitObjectContainer),
|
sampleTriggerSource = new GameplaySampleTriggerSource(HitObjectContainer),
|
||||||
// For input purposes, the background is added at the highest depth, but is then proxied back below all other elements
|
|
||||||
background.CreateProxy(),
|
|
||||||
HitObjectArea,
|
HitObjectArea,
|
||||||
keyArea = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea())
|
keyArea = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.KeyArea), _ => new DefaultKeyArea())
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
background,
|
// For input purposes, the background is added at the highest depth, but is then proxied back below all other elements externally
|
||||||
|
// (see `Stage.columnBackgrounds`).
|
||||||
|
BackgroundContainer,
|
||||||
TopLevelContainer,
|
TopLevelContainer,
|
||||||
new ColumnTouchInputArea(this)
|
new ColumnTouchInputArea(this)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var background = new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.ColumnBackground), _ => new DefaultColumnBackground())
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
};
|
||||||
|
|
||||||
background.ApplyGameWideClock(host);
|
background.ApplyGameWideClock(host);
|
||||||
keyArea.ApplyGameWideClock(host);
|
keyArea.ApplyGameWideClock(host);
|
||||||
|
|
||||||
|
BackgroundContainer.Add(background);
|
||||||
TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy());
|
TopLevelContainer.Add(HitObjectArea.Explosions.CreateProxy());
|
||||||
|
|
||||||
RegisterPool<Note, DrawableNote>(10, 50);
|
RegisterPool<Note, DrawableNote>(10, 50);
|
||||||
|
@ -60,6 +60,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
RelativeSizeAxes = Axes.Y;
|
RelativeSizeAxes = Axes.Y;
|
||||||
AutoSizeAxes = Axes.X;
|
AutoSizeAxes = Axes.X;
|
||||||
|
|
||||||
|
Container columnBackgrounds;
|
||||||
Container topLevelContainer;
|
Container topLevelContainer;
|
||||||
|
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
@ -77,9 +78,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
},
|
},
|
||||||
columnFlow = new ColumnFlow<Column>(definition)
|
columnBackgrounds = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Y,
|
Name = "Column backgrounds",
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
},
|
},
|
||||||
new Container
|
new Container
|
||||||
{
|
{
|
||||||
@ -98,6 +100,10 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
RelativeSizeAxes = Axes.Y,
|
RelativeSizeAxes = Axes.Y,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
columnFlow = new ColumnFlow<Column>(definition)
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Y,
|
||||||
|
},
|
||||||
new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.StageForeground), _ => null)
|
new SkinnableDrawable(new ManiaSkinComponentLookup(ManiaSkinComponents.StageForeground), _ => null)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
@ -126,6 +132,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
|||||||
};
|
};
|
||||||
|
|
||||||
topLevelContainer.Add(column.TopLevelContainer.CreateProxy());
|
topLevelContainer.Add(column.TopLevelContainer.CreateProxy());
|
||||||
|
columnBackgrounds.Add(column.BackgroundContainer.CreateProxy());
|
||||||
columnFlow.SetContentForColumn(i, column);
|
columnFlow.SetContentForColumn(i, column);
|
||||||
AddNested(column);
|
AddNested(column);
|
||||||
}
|
}
|
||||||
|
@ -51,9 +51,9 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestBindableBeatDivisor()
|
public void TestBindableBeatDivisor()
|
||||||
{
|
{
|
||||||
AddRepeatStep("move previous", () => bindableBeatDivisor.Previous(), 2);
|
AddRepeatStep("move previous", () => bindableBeatDivisor.SelectPrevious(), 2);
|
||||||
AddAssert("divisor is 4", () => bindableBeatDivisor.Value == 4);
|
AddAssert("divisor is 4", () => bindableBeatDivisor.Value == 4);
|
||||||
AddRepeatStep("move next", () => bindableBeatDivisor.Next(), 1);
|
AddRepeatStep("move next", () => bindableBeatDivisor.SelectNext(), 1);
|
||||||
AddAssert("divisor is 12", () => bindableBeatDivisor.Value == 8);
|
AddAssert("divisor is 12", () => bindableBeatDivisor.Value == 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,16 +101,22 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
public void TestBeatChevronNavigation()
|
public void TestBeatChevronNavigation()
|
||||||
{
|
{
|
||||||
switchBeatSnap(1);
|
switchBeatSnap(1);
|
||||||
|
assertBeatSnap(16);
|
||||||
|
|
||||||
|
switchBeatSnap(-4);
|
||||||
assertBeatSnap(1);
|
assertBeatSnap(1);
|
||||||
|
|
||||||
switchBeatSnap(3);
|
switchBeatSnap(3);
|
||||||
assertBeatSnap(8);
|
assertBeatSnap(8);
|
||||||
|
|
||||||
switchBeatSnap(-1);
|
switchBeatSnap(3);
|
||||||
|
assertBeatSnap(16);
|
||||||
|
|
||||||
|
switchBeatSnap(-2);
|
||||||
assertBeatSnap(4);
|
assertBeatSnap(4);
|
||||||
|
|
||||||
switchBeatSnap(-3);
|
switchBeatSnap(-3);
|
||||||
assertBeatSnap(16);
|
assertBeatSnap(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -207,7 +213,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
}, Math.Abs(direction));
|
}, Math.Abs(direction));
|
||||||
|
|
||||||
private void assertBeatSnap(int expected) => AddAssert($"beat snap is {expected}",
|
private void assertBeatSnap(int expected) => AddAssert($"beat snap is {expected}",
|
||||||
() => bindableBeatDivisor.Value == expected);
|
() => bindableBeatDivisor.Value, () => Is.EqualTo(expected));
|
||||||
|
|
||||||
private void switchPresets(int direction) => AddRepeatStep($"move presets {(direction > 0 ? "forward" : "backward")}", () =>
|
private void switchPresets(int direction) => AddRepeatStep($"move presets {(direction > 0 ? "forward" : "backward")}", () =>
|
||||||
{
|
{
|
||||||
|
@ -209,10 +209,14 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
public override void TearDownSteps()
|
public override void TearDownSteps()
|
||||||
{
|
{
|
||||||
base.TearDownSteps();
|
base.TearDownSteps();
|
||||||
AddStep("delete imported", () =>
|
AddStep("delete imported", () => Realm.Write(r =>
|
||||||
{
|
{
|
||||||
beatmaps.Delete(importedBeatmapSet);
|
// delete from realm directly rather than via `BeatmapManager` to avoid cross-test pollution
|
||||||
});
|
// (`BeatmapManager.Delete()` uses soft deletion, which can lead to beatmap reuse between test cases).
|
||||||
|
r.RemoveAll<BeatmapMetadata>();
|
||||||
|
r.RemoveAll<BeatmapInfo>();
|
||||||
|
r.RemoveAll<BeatmapSetInfo>();
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
|
|
||||||
AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0)));
|
AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0)));
|
||||||
AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.ReadyForUse);
|
AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.ReadyForUse);
|
||||||
AddStep("test gameplay", () => ((Editor)Game.ScreenStack.CurrentScreen).TestGameplay());
|
AddStep("test gameplay", () => getEditor().TestGameplay());
|
||||||
|
|
||||||
AddUntilStep("wait for player", () =>
|
AddUntilStep("wait for player", () =>
|
||||||
{
|
{
|
||||||
@ -141,6 +141,37 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddUntilStep("wait for editor exit", () => Game.ScreenStack.CurrentScreen is not Editor);
|
AddUntilStep("wait for editor exit", () => Game.ScreenStack.CurrentScreen is not Editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private EditorBeatmap getEditorBeatmap() => ((Editor)Game.ScreenStack.CurrentScreen).ChildrenOfType<EditorBeatmap>().Single();
|
[Test]
|
||||||
|
public void TestLastTimestampRememberedOnExit()
|
||||||
|
{
|
||||||
|
BeatmapSetInfo beatmapSet = null!;
|
||||||
|
|
||||||
|
AddStep("import test beatmap", () => Game.BeatmapManager.Import(TestResources.GetTestBeatmapForImport()).WaitSafely());
|
||||||
|
AddStep("retrieve beatmap", () => beatmapSet = Game.BeatmapManager.QueryBeatmapSet(set => !set.Protected).AsNonNull().Value.Detach());
|
||||||
|
|
||||||
|
AddStep("present beatmap", () => Game.PresentBeatmap(beatmapSet));
|
||||||
|
AddUntilStep("wait for song select",
|
||||||
|
() => Game.Beatmap.Value.BeatmapSetInfo.Equals(beatmapSet)
|
||||||
|
&& Game.ScreenStack.CurrentScreen is PlaySongSelect songSelect
|
||||||
|
&& songSelect.IsLoaded);
|
||||||
|
|
||||||
|
AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit(beatmapSet.Beatmaps.First(beatmap => beatmap.Ruleset.OnlineID == 0)));
|
||||||
|
AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.ReadyForUse);
|
||||||
|
|
||||||
|
AddStep("seek to arbitrary time", () => getEditor().ChildrenOfType<EditorClock>().First().Seek(1234));
|
||||||
|
AddUntilStep("time is correct", () => getEditor().ChildrenOfType<EditorClock>().First().CurrentTime, () => Is.EqualTo(1234));
|
||||||
|
|
||||||
|
AddStep("exit editor", () => InputManager.Key(Key.Escape));
|
||||||
|
AddUntilStep("wait for editor exit", () => Game.ScreenStack.CurrentScreen is not Editor);
|
||||||
|
|
||||||
|
AddStep("open editor", () => ((PlaySongSelect)Game.ScreenStack.CurrentScreen).Edit());
|
||||||
|
|
||||||
|
AddUntilStep("wait for editor open", () => Game.ScreenStack.CurrentScreen is Editor editor && editor.ReadyForUse);
|
||||||
|
AddUntilStep("time is correct", () => getEditor().ChildrenOfType<EditorClock>().First().CurrentTime, () => Is.EqualTo(1234));
|
||||||
|
}
|
||||||
|
|
||||||
|
private EditorBeatmap getEditorBeatmap() => getEditor().ChildrenOfType<EditorBeatmap>().Single();
|
||||||
|
|
||||||
|
private Editor getEditor() => (Editor)Game.ScreenStack.CurrentScreen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,6 +171,11 @@ namespace osu.Game.Beatmaps
|
|||||||
|
|
||||||
public double TimelineZoom { get; set; } = 1.0;
|
public double TimelineZoom { get; set; } = 1.0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time in milliseconds when last exiting the editor with this beatmap loaded.
|
||||||
|
/// </summary>
|
||||||
|
public double? EditorTimestamp { get; set; }
|
||||||
|
|
||||||
[Ignored]
|
[Ignored]
|
||||||
public CountdownType Countdown { get; set; } = CountdownType.Normal;
|
public CountdownType Countdown { get; set; } = CountdownType.Normal;
|
||||||
|
|
||||||
|
@ -71,8 +71,9 @@ namespace osu.Game.Database
|
|||||||
/// 24 2022-08-22 Added MaximumStatistics to ScoreInfo.
|
/// 24 2022-08-22 Added MaximumStatistics to ScoreInfo.
|
||||||
/// 25 2022-09-18 Remove skins to add with new naming.
|
/// 25 2022-09-18 Remove skins to add with new naming.
|
||||||
/// 26 2023-02-05 Added BeatmapHash to ScoreInfo.
|
/// 26 2023-02-05 Added BeatmapHash to ScoreInfo.
|
||||||
|
/// 27 2023-06-06 Added EditorTimestamp to BeatmapInfo.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int schema_version = 26;
|
private const int schema_version = 27;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking realm retrieval during blocking periods.
|
/// Lock object which is held during <see cref="BlockAllOperations"/> sections, blocking realm retrieval during blocking periods.
|
||||||
|
@ -21,7 +21,12 @@ namespace osu.Game.Extensions
|
|||||||
/// This is required as enum member names are not allowed to contain hyphens.
|
/// This is required as enum member names are not allowed to contain hyphens.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public static string ToCultureCode(this Language language)
|
public static string ToCultureCode(this Language language)
|
||||||
=> language.ToString().Replace("_", "-");
|
{
|
||||||
|
if (language == Language.zh_hant)
|
||||||
|
return @"zh-tw";
|
||||||
|
|
||||||
|
return language.ToString().Replace("_", "-");
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to parse the supplied <paramref name="cultureCode"/> to a <see cref="Language"/> value.
|
/// Attempts to parse the supplied <paramref name="cultureCode"/> to a <see cref="Language"/> value.
|
||||||
@ -30,7 +35,15 @@ namespace osu.Game.Extensions
|
|||||||
/// <param name="language">The parsed <see cref="Language"/>. Valid only if the return value of the method is <see langword="true" />.</param>
|
/// <param name="language">The parsed <see cref="Language"/>. Valid only if the return value of the method is <see langword="true" />.</param>
|
||||||
/// <returns>Whether the parsing succeeded.</returns>
|
/// <returns>Whether the parsing succeeded.</returns>
|
||||||
public static bool TryParseCultureCode(string cultureCode, out Language language)
|
public static bool TryParseCultureCode(string cultureCode, out Language language)
|
||||||
=> Enum.TryParse(cultureCode.Replace("-", "_"), out language);
|
{
|
||||||
|
if (cultureCode == @"zh-tw")
|
||||||
|
{
|
||||||
|
language = Language.zh_hant;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Enum.TryParse(cultureCode.Replace("-", "_"), out language);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Parses the <see cref="Language"/> that is specified in <paramref name="frameworkLocale"/>,
|
/// Parses the <see cref="Language"/> that is specified in <paramref name="frameworkLocale"/>,
|
||||||
|
@ -101,6 +101,10 @@ namespace osu.Game.Input.Bindings
|
|||||||
new KeyBinding(new[] { InputKey.Control, InputKey.J }, GlobalAction.EditorFlipVertically),
|
new KeyBinding(new[] { InputKey.Control, InputKey.J }, GlobalAction.EditorFlipVertically),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.MouseWheelDown }, GlobalAction.EditorDecreaseDistanceSpacing),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.MouseWheelDown }, GlobalAction.EditorDecreaseDistanceSpacing),
|
||||||
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.MouseWheelUp }, GlobalAction.EditorIncreaseDistanceSpacing),
|
new KeyBinding(new[] { InputKey.Control, InputKey.Alt, InputKey.MouseWheelUp }, GlobalAction.EditorIncreaseDistanceSpacing),
|
||||||
|
// Framework automatically converts wheel up/down to left/right when shift is held.
|
||||||
|
// See https://github.com/ppy/osu-framework/blob/master/osu.Framework/Input/StateChanges/MouseScrollRelativeInput.cs#L37-L38.
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.MouseWheelRight }, GlobalAction.EditorCyclePreviousBeatSnapDivisor),
|
||||||
|
new KeyBinding(new[] { InputKey.Control, InputKey.Shift, InputKey.MouseWheelLeft }, GlobalAction.EditorCycleNextBeatSnapDivisor),
|
||||||
};
|
};
|
||||||
|
|
||||||
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
public IEnumerable<KeyBinding> InGameKeyBindings => new[]
|
||||||
@ -355,6 +359,12 @@ namespace osu.Game.Input.Bindings
|
|||||||
ToggleProfile,
|
ToggleProfile,
|
||||||
|
|
||||||
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorCloneSelection))]
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorCloneSelection))]
|
||||||
EditorCloneSelection
|
EditorCloneSelection,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorCyclePreviousBeatSnapDivisor))]
|
||||||
|
EditorCyclePreviousBeatSnapDivisor,
|
||||||
|
|
||||||
|
[LocalisableDescription(typeof(GlobalActionKeyBindingStrings), nameof(GlobalActionKeyBindingStrings.EditorCycleNextBeatSnapDivisor))]
|
||||||
|
EditorCycleNextBeatSnapDivisor,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,6 +279,16 @@ namespace osu.Game.Localisation
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static LocalisableString EditorDecreaseDistanceSpacing => new TranslatableString(getKey(@"editor_decrease_distance_spacing"), @"Decrease distance spacing");
|
public static LocalisableString EditorDecreaseDistanceSpacing => new TranslatableString(getKey(@"editor_decrease_distance_spacing"), @"Decrease distance spacing");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Cycle previous beat snap divisor"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString EditorCyclePreviousBeatSnapDivisor => new TranslatableString(getKey(@"editor_cycle_previous_beat_snap_divisor"), @"Cycle previous beat snap divisor");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// "Cycle next beat snap divisor"
|
||||||
|
/// </summary>
|
||||||
|
public static LocalisableString EditorCycleNextBeatSnapDivisor => new TranslatableString(getKey(@"editor_cycle_next_snap_divisor"), @"Cycle next beat snap divisor");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// "Toggle skin editor"
|
/// "Toggle skin editor"
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -18,6 +18,7 @@ using osu.Framework.Extensions.ObjectExtensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.Notifications;
|
using osu.Game.Online.Notifications;
|
||||||
@ -28,6 +29,7 @@ namespace osu.Game.Online.API
|
|||||||
{
|
{
|
||||||
public partial class APIAccess : Component, IAPIProvider
|
public partial class APIAccess : Component, IAPIProvider
|
||||||
{
|
{
|
||||||
|
private readonly OsuGameBase game;
|
||||||
private readonly OsuConfigManager config;
|
private readonly OsuConfigManager config;
|
||||||
|
|
||||||
private readonly string versionHash;
|
private readonly string versionHash;
|
||||||
@ -52,6 +54,8 @@ namespace osu.Game.Online.API
|
|||||||
public IBindableList<APIUser> Friends => friends;
|
public IBindableList<APIUser> Friends => friends;
|
||||||
public IBindable<UserActivity> Activity => activity;
|
public IBindable<UserActivity> Activity => activity;
|
||||||
|
|
||||||
|
public Language Language => game.CurrentLanguage.Value;
|
||||||
|
|
||||||
private Bindable<APIUser> localUser { get; } = new Bindable<APIUser>(createGuestUser());
|
private Bindable<APIUser> localUser { get; } = new Bindable<APIUser>(createGuestUser());
|
||||||
|
|
||||||
private BindableList<APIUser> friends { get; } = new BindableList<APIUser>();
|
private BindableList<APIUser> friends { get; } = new BindableList<APIUser>();
|
||||||
@ -64,8 +68,9 @@ namespace osu.Game.Online.API
|
|||||||
|
|
||||||
private readonly Logger log;
|
private readonly Logger log;
|
||||||
|
|
||||||
public APIAccess(OsuConfigManager config, EndpointConfiguration endpointConfiguration, string versionHash)
|
public APIAccess(OsuGameBase game, OsuConfigManager config, EndpointConfiguration endpointConfiguration, string versionHash)
|
||||||
{
|
{
|
||||||
|
this.game = game;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.versionHash = versionHash;
|
this.versionHash = versionHash;
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ using JetBrains.Annotations;
|
|||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Framework.IO.Network;
|
using osu.Framework.IO.Network;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
|
||||||
namespace osu.Game.Online.API
|
namespace osu.Game.Online.API
|
||||||
@ -116,10 +117,11 @@ namespace osu.Game.Online.API
|
|||||||
WebRequest.Failed += Fail;
|
WebRequest.Failed += Fail;
|
||||||
WebRequest.AllowRetryOnTimeout = false;
|
WebRequest.AllowRetryOnTimeout = false;
|
||||||
|
|
||||||
WebRequest.AddHeader("x-api-version", API.APIVersion.ToString(CultureInfo.InvariantCulture));
|
WebRequest.AddHeader(@"Accept-Language", API.Language.ToCultureCode());
|
||||||
|
WebRequest.AddHeader(@"x-api-version", API.APIVersion.ToString(CultureInfo.InvariantCulture));
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(API.AccessToken))
|
if (!string.IsNullOrEmpty(API.AccessToken))
|
||||||
WebRequest.AddHeader("Authorization", $"Bearer {API.AccessToken}");
|
WebRequest.AddHeader(@"Authorization", $@"Bearer {API.AccessToken}");
|
||||||
|
|
||||||
if (isFailing) return;
|
if (isFailing) return;
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.Notifications;
|
using osu.Game.Online.Notifications;
|
||||||
using osu.Game.Tests;
|
using osu.Game.Tests;
|
||||||
@ -29,6 +30,8 @@ namespace osu.Game.Online.API
|
|||||||
|
|
||||||
public Bindable<UserActivity> Activity { get; } = new Bindable<UserActivity>();
|
public Bindable<UserActivity> Activity { get; } = new Bindable<UserActivity>();
|
||||||
|
|
||||||
|
public Language Language => Language.en;
|
||||||
|
|
||||||
public string AccessToken => "token";
|
public string AccessToken => "token";
|
||||||
|
|
||||||
public bool IsLoggedIn => State.Value == APIState.Online;
|
public bool IsLoggedIn => State.Value == APIState.Online;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
using osu.Game.Online.Notifications;
|
using osu.Game.Online.Notifications;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
@ -27,6 +28,11 @@ namespace osu.Game.Online.API
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
IBindable<UserActivity> Activity { get; }
|
IBindable<UserActivity> Activity { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The language supplied by this provider to API requests.
|
||||||
|
/// </summary>
|
||||||
|
Language Language { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieve the OAuth access token.
|
/// Retrieve the OAuth access token.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -14,6 +14,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Development;
|
using osu.Framework.Development;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
@ -27,6 +28,7 @@ using osu.Framework.Input.Handlers.Mouse;
|
|||||||
using osu.Framework.Input.Handlers.Tablet;
|
using osu.Framework.Input.Handlers.Tablet;
|
||||||
using osu.Framework.Input.Handlers.Touch;
|
using osu.Framework.Input.Handlers.Touch;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
@ -36,11 +38,13 @@ using osu.Game.Beatmaps.ControlPoints;
|
|||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Input;
|
using osu.Game.Input;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
|
using osu.Game.Localisation;
|
||||||
using osu.Game.Online;
|
using osu.Game.Online;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Chat;
|
using osu.Game.Online.Chat;
|
||||||
@ -157,6 +161,11 @@ namespace osu.Game
|
|||||||
|
|
||||||
protected Storage Storage { get; set; }
|
protected Storage Storage { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The language in which the game is currently displayed in.
|
||||||
|
/// </summary>
|
||||||
|
public Bindable<Language> CurrentLanguage { get; } = new Bindable<Language>();
|
||||||
|
|
||||||
protected Bindable<WorkingBeatmap> Beatmap { get; private set; } // cached via load() method
|
protected Bindable<WorkingBeatmap> Beatmap { get; private set; } // cached via load() method
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -216,6 +225,10 @@ namespace osu.Game
|
|||||||
|
|
||||||
private readonly BindableNumber<double> globalTrackVolumeAdjust = new BindableNumber<double>(global_track_volume_adjust);
|
private readonly BindableNumber<double> globalTrackVolumeAdjust = new BindableNumber<double>(global_track_volume_adjust);
|
||||||
|
|
||||||
|
private Bindable<string> frameworkLocale = null!;
|
||||||
|
|
||||||
|
private IBindable<LocalisationParameters> localisationParameters = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Number of unhandled exceptions to allow before aborting execution.
|
/// Number of unhandled exceptions to allow before aborting execution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -238,7 +251,7 @@ namespace osu.Game
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ReadableKeyCombinationProvider keyCombinationProvider)
|
private void load(ReadableKeyCombinationProvider keyCombinationProvider, FrameworkConfigManager frameworkConfig)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -283,7 +296,15 @@ namespace osu.Game
|
|||||||
|
|
||||||
MessageFormatter.WebsiteRootUrl = endpoints.WebsiteRootUrl;
|
MessageFormatter.WebsiteRootUrl = endpoints.WebsiteRootUrl;
|
||||||
|
|
||||||
dependencies.CacheAs(API ??= new APIAccess(LocalConfig, endpoints, VersionHash));
|
frameworkLocale = frameworkConfig.GetBindable<string>(FrameworkSetting.Locale);
|
||||||
|
frameworkLocale.BindValueChanged(_ => updateLanguage());
|
||||||
|
|
||||||
|
localisationParameters = Localisation.CurrentParameters.GetBoundCopy();
|
||||||
|
localisationParameters.BindValueChanged(_ => updateLanguage(), true);
|
||||||
|
|
||||||
|
CurrentLanguage.BindValueChanged(val => frameworkLocale.Value = val.NewValue.ToCultureCode());
|
||||||
|
|
||||||
|
dependencies.CacheAs(API ??= new APIAccess(this, LocalConfig, endpoints, VersionHash));
|
||||||
|
|
||||||
var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures);
|
var defaultBeatmap = new DummyWorkingBeatmap(Audio, Textures);
|
||||||
|
|
||||||
@ -394,6 +415,8 @@ namespace osu.Game
|
|||||||
Beatmap.BindValueChanged(onBeatmapChanged);
|
Beatmap.BindValueChanged(onBeatmapChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateLanguage() => CurrentLanguage.Value = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, localisationParameters.Value);
|
||||||
|
|
||||||
private void addFilesWarning()
|
private void addFilesWarning()
|
||||||
{
|
{
|
||||||
var realmStore = new RealmFileStore(realm, Storage);
|
var realmStore = new RealmFileStore(realm, Storage);
|
||||||
|
@ -56,11 +56,11 @@ namespace osu.Game.Overlays.Chat
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private OverlayColourProvider? colourProvider { get; set; }
|
private OverlayColourProvider? colourProvider { get; set; }
|
||||||
|
|
||||||
private readonly OsuSpriteText drawableTimestamp;
|
private OsuSpriteText drawableTimestamp = null!;
|
||||||
|
|
||||||
private readonly DrawableChatUsername drawableUsername;
|
private DrawableChatUsername drawableUsername = null!;
|
||||||
|
|
||||||
private readonly LinkFlowContainer drawableContentFlow;
|
private LinkFlowContainer drawableContentFlow = null!;
|
||||||
|
|
||||||
private readonly Bindable<bool> prefer24HourTime = new Bindable<bool>();
|
private readonly Bindable<bool> prefer24HourTime = new Bindable<bool>();
|
||||||
|
|
||||||
@ -69,8 +69,16 @@ namespace osu.Game.Overlays.Chat
|
|||||||
public ChatLine(Message message)
|
public ChatLine(Message message)
|
||||||
{
|
{
|
||||||
Message = message;
|
Message = message;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
AutoSizeAxes = Axes.Y;
|
AutoSizeAxes = Axes.Y;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load(OsuConfigManager configManager)
|
||||||
|
{
|
||||||
|
configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime);
|
||||||
|
prefer24HourTime.BindValueChanged(_ => updateTimestamp());
|
||||||
|
|
||||||
InternalChild = new GridContainer
|
InternalChild = new GridContainer
|
||||||
{
|
{
|
||||||
@ -103,7 +111,6 @@ namespace osu.Game.Overlays.Chat
|
|||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Margin = new MarginPadding { Horizontal = Spacing },
|
Margin = new MarginPadding { Horizontal = Spacing },
|
||||||
ReportRequested = this.ShowPopover,
|
|
||||||
},
|
},
|
||||||
drawableContentFlow = new LinkFlowContainer(styleMessageContent)
|
drawableContentFlow = new LinkFlowContainer(styleMessageContent)
|
||||||
{
|
{
|
||||||
@ -115,13 +122,6 @@ namespace osu.Game.Overlays.Chat
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(OsuConfigManager configManager)
|
|
||||||
{
|
|
||||||
configManager.BindWith(OsuSetting.Prefer24HourTime, prefer24HourTime);
|
|
||||||
prefer24HourTime.BindValueChanged(_ => updateTimestamp());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
@ -130,6 +130,17 @@ namespace osu.Game.Overlays.Chat
|
|||||||
|
|
||||||
updateMessageContent();
|
updateMessageContent();
|
||||||
FinishTransforms(true);
|
FinishTransforms(true);
|
||||||
|
|
||||||
|
if (this.FindClosestParent<PopoverContainer>() != null)
|
||||||
|
{
|
||||||
|
// This guards against cases like in-game chat where there's no available popover container.
|
||||||
|
// There may be a future where a global one becomes available, at which point this code may be unnecessary.
|
||||||
|
//
|
||||||
|
// See:
|
||||||
|
// https://github.com/ppy/osu/pull/23698
|
||||||
|
// https://github.com/ppy/osu/pull/14554
|
||||||
|
drawableUsername.ReportRequested = this.ShowPopover;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Popover GetPopover() => new ReportChatPopover(message);
|
public Popover GetPopover() => new ReportChatPopover(message);
|
||||||
|
@ -13,7 +13,6 @@ using osu.Framework.Graphics.Shapes;
|
|||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Game.Extensions;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
@ -68,13 +67,12 @@ namespace osu.Game.Overlays.FirstRunSetup
|
|||||||
|
|
||||||
private partial class LanguageSelectionFlow : FillFlowContainer
|
private partial class LanguageSelectionFlow : FillFlowContainer
|
||||||
{
|
{
|
||||||
private Bindable<string> frameworkLocale = null!;
|
private Bindable<Language> language = null!;
|
||||||
private IBindable<LocalisationParameters> localisationParameters = null!;
|
|
||||||
|
|
||||||
private ScheduledDelegate? updateSelectedDelegate;
|
private ScheduledDelegate? updateSelectedDelegate;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(FrameworkConfigManager frameworkConfig, LocalisationManager localisation)
|
private void load(OsuGameBase game)
|
||||||
{
|
{
|
||||||
Direction = FillDirection.Full;
|
Direction = FillDirection.Full;
|
||||||
Spacing = new Vector2(5);
|
Spacing = new Vector2(5);
|
||||||
@ -82,25 +80,18 @@ namespace osu.Game.Overlays.FirstRunSetup
|
|||||||
ChildrenEnumerable = Enum.GetValues<Language>()
|
ChildrenEnumerable = Enum.GetValues<Language>()
|
||||||
.Select(l => new LanguageButton(l)
|
.Select(l => new LanguageButton(l)
|
||||||
{
|
{
|
||||||
Action = () => frameworkLocale.Value = l.ToCultureCode()
|
Action = () => language.Value = l,
|
||||||
});
|
});
|
||||||
|
|
||||||
frameworkLocale = frameworkConfig.GetBindable<string>(FrameworkSetting.Locale);
|
language = game.CurrentLanguage.GetBoundCopy();
|
||||||
frameworkLocale.BindValueChanged(_ => onLanguageChange());
|
language.BindValueChanged(v =>
|
||||||
|
{
|
||||||
localisationParameters = localisation.CurrentParameters.GetBoundCopy();
|
// Changing language may cause a short period of blocking the UI thread while the new glyphs are loaded.
|
||||||
localisationParameters.BindValueChanged(_ => onLanguageChange(), true);
|
// Scheduling ensures the button animation plays smoothly after any blocking operation completes.
|
||||||
}
|
// Note that a delay is required (the alternative would be a double-schedule; delay feels better).
|
||||||
|
updateSelectedDelegate?.Cancel();
|
||||||
private void onLanguageChange()
|
updateSelectedDelegate = Scheduler.AddDelayed(() => updateSelectedStates(v.NewValue), 50);
|
||||||
{
|
}, true);
|
||||||
var language = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, localisationParameters.Value);
|
|
||||||
|
|
||||||
// Changing language may cause a short period of blocking the UI thread while the new glyphs are loaded.
|
|
||||||
// Scheduling ensures the button animation plays smoothly after any blocking operation completes.
|
|
||||||
// Note that a delay is required (the alternative would be a double-schedule; delay feels better).
|
|
||||||
updateSelectedDelegate?.Cancel();
|
|
||||||
updateSelectedDelegate = Scheduler.AddDelayed(() => updateSelectedStates(language), 50);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSelectedStates(Language language)
|
private void updateSelectedStates(Language language)
|
||||||
|
@ -2,35 +2,27 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
|
||||||
using osu.Framework.Configuration;
|
using osu.Framework.Configuration;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Extensions;
|
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
|
|
||||||
namespace osu.Game.Overlays.Settings.Sections.General
|
namespace osu.Game.Overlays.Settings.Sections.General
|
||||||
{
|
{
|
||||||
public partial class LanguageSettings : SettingsSubsection
|
public partial class LanguageSettings : SettingsSubsection
|
||||||
{
|
{
|
||||||
private SettingsDropdown<Language> languageSelection = null!;
|
|
||||||
private Bindable<string> frameworkLocale = null!;
|
|
||||||
private IBindable<LocalisationParameters> localisationParameters = null!;
|
|
||||||
|
|
||||||
protected override LocalisableString Header => GeneralSettingsStrings.LanguageHeader;
|
protected override LocalisableString Header => GeneralSettingsStrings.LanguageHeader;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(FrameworkConfigManager frameworkConfig, OsuConfigManager config, LocalisationManager localisation)
|
private void load(OsuGameBase game, OsuConfigManager config, FrameworkConfigManager frameworkConfig)
|
||||||
{
|
{
|
||||||
frameworkLocale = frameworkConfig.GetBindable<string>(FrameworkSetting.Locale);
|
|
||||||
localisationParameters = localisation.CurrentParameters.GetBoundCopy();
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
languageSelection = new SettingsEnumDropdown<Language>
|
new SettingsEnumDropdown<Language>
|
||||||
{
|
{
|
||||||
LabelText = GeneralSettingsStrings.LanguageDropdown,
|
LabelText = GeneralSettingsStrings.LanguageDropdown,
|
||||||
|
Current = game.CurrentLanguage,
|
||||||
},
|
},
|
||||||
new SettingsCheckbox
|
new SettingsCheckbox
|
||||||
{
|
{
|
||||||
@ -43,14 +35,6 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
|||||||
Current = config.GetBindable<bool>(OsuSetting.Prefer24HourTime)
|
Current = config.GetBindable<bool>(OsuSetting.Prefer24HourTime)
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
frameworkLocale.BindValueChanged(_ => updateSelection());
|
|
||||||
localisationParameters.BindValueChanged(_ => updateSelection(), true);
|
|
||||||
|
|
||||||
languageSelection.Current.BindValueChanged(val => frameworkLocale.Value = val.NewValue.ToCultureCode());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateSelection() =>
|
|
||||||
languageSelection.Current.Value = LanguageExtensions.GetLanguageFor(frameworkLocale.Value, localisationParameters.Value);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,16 +59,18 @@ namespace osu.Game.Screens.Edit
|
|||||||
Value = 1;
|
Value = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Next()
|
public void SelectNext()
|
||||||
{
|
{
|
||||||
var presets = ValidDivisors.Value.Presets;
|
var presets = ValidDivisors.Value.Presets;
|
||||||
Value = presets.Cast<int?>().SkipWhile(preset => preset != Value).ElementAtOrDefault(1) ?? presets[0];
|
if (presets.Cast<int?>().SkipWhile(preset => preset != Value).ElementAtOrDefault(1) is int newValue)
|
||||||
|
Value = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Previous()
|
public void SelectPrevious()
|
||||||
{
|
{
|
||||||
var presets = ValidDivisors.Value.Presets;
|
var presets = ValidDivisors.Value.Presets;
|
||||||
Value = presets.Cast<int?>().TakeWhile(preset => preset != Value).LastOrDefault() ?? presets[^1];
|
if (presets.Cast<int?>().TakeWhile(preset => preset != Value).LastOrDefault() is int newValue)
|
||||||
|
Value = newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override int DefaultPrecision => 1;
|
protected override int DefaultPrecision => 1;
|
||||||
|
@ -16,12 +16,14 @@ using osu.Framework.Graphics.Cursor;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Containers;
|
using osu.Game.Graphics.Containers;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics.UserInterfaceV2;
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -29,7 +31,7 @@ using osuTK.Input;
|
|||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Compose.Components
|
namespace osu.Game.Screens.Edit.Compose.Components
|
||||||
{
|
{
|
||||||
public partial class BeatDivisorControl : CompositeDrawable
|
public partial class BeatDivisorControl : CompositeDrawable, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor();
|
private readonly BindableBeatDivisor beatDivisor = new BindableBeatDivisor();
|
||||||
|
|
||||||
@ -101,13 +103,13 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
new ChevronButton
|
new ChevronButton
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.Solid.ChevronLeft,
|
Icon = FontAwesome.Solid.ChevronLeft,
|
||||||
Action = beatDivisor.Previous
|
Action = beatDivisor.SelectPrevious
|
||||||
},
|
},
|
||||||
new DivisorDisplay { BeatDivisor = { BindTarget = beatDivisor } },
|
new DivisorDisplay { BeatDivisor = { BindTarget = beatDivisor } },
|
||||||
new ChevronButton
|
new ChevronButton
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.Solid.ChevronRight,
|
Icon = FontAwesome.Solid.ChevronRight,
|
||||||
Action = beatDivisor.Next
|
Action = beatDivisor.SelectNext
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -220,6 +222,26 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
return base.OnKeyDown(e);
|
return base.OnKeyDown(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||||
|
{
|
||||||
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
case GlobalAction.EditorCycleNextBeatSnapDivisor:
|
||||||
|
beatDivisor.SelectNext();
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case GlobalAction.EditorCyclePreviousBeatSnapDivisor:
|
||||||
|
beatDivisor.SelectPrevious();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
internal partial class DivisorDisplay : OsuAnimatedButton, IHasPopover
|
internal partial class DivisorDisplay : OsuAnimatedButton, IHasPopover
|
||||||
{
|
{
|
||||||
public BindableBeatDivisor BeatDivisor { get; } = new BindableBeatDivisor();
|
public BindableBeatDivisor BeatDivisor { get; } = new BindableBeatDivisor();
|
||||||
@ -442,12 +464,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
switch (e.Key)
|
switch (e.Key)
|
||||||
{
|
{
|
||||||
case Key.Right:
|
case Key.Right:
|
||||||
beatDivisor.Next();
|
beatDivisor.SelectNext();
|
||||||
OnUserChange(Current.Value);
|
OnUserChange(Current.Value);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case Key.Left:
|
case Key.Left:
|
||||||
beatDivisor.Previous();
|
beatDivisor.SelectPrevious();
|
||||||
OnUserChange(Current.Value);
|
OnUserChange(Current.Value);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -28,6 +28,7 @@ using osu.Game.Audio;
|
|||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Database;
|
||||||
using osu.Game.Graphics.Cursor;
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
@ -92,6 +93,9 @@ namespace osu.Game.Screens.Edit
|
|||||||
[Resolved(canBeNull: true)]
|
[Resolved(canBeNull: true)]
|
||||||
private INotificationOverlay notifications { get; set; }
|
private INotificationOverlay notifications { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private RealmAccess realm { get; set; }
|
||||||
|
|
||||||
public readonly Bindable<EditorScreenMode> Mode = new Bindable<EditorScreenMode>();
|
public readonly Bindable<EditorScreenMode> Mode = new Bindable<EditorScreenMode>();
|
||||||
|
|
||||||
public IBindable<bool> SamplePlaybackDisabled => samplePlaybackDisabled;
|
public IBindable<bool> SamplePlaybackDisabled => samplePlaybackDisabled;
|
||||||
@ -700,6 +704,13 @@ namespace osu.Game.Screens.Edit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
realm.Write(r =>
|
||||||
|
{
|
||||||
|
var beatmap = r.Find<BeatmapInfo>(editorBeatmap.BeatmapInfo.ID);
|
||||||
|
if (beatmap != null)
|
||||||
|
beatmap.EditorTimestamp = clock.CurrentTime;
|
||||||
|
});
|
||||||
|
|
||||||
ApplyToBackground(b =>
|
ApplyToBackground(b =>
|
||||||
{
|
{
|
||||||
b.DimWhenUserSettingsIgnored.Value = 0;
|
b.DimWhenUserSettingsIgnored.Value = 0;
|
||||||
@ -833,7 +844,11 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
double targetTime = 0;
|
double targetTime = 0;
|
||||||
|
|
||||||
if (Beatmap.Value.Beatmap.HitObjects.Count > 0)
|
if (editorBeatmap.BeatmapInfo.EditorTimestamp != null)
|
||||||
|
{
|
||||||
|
targetTime = editorBeatmap.BeatmapInfo.EditorTimestamp.Value;
|
||||||
|
}
|
||||||
|
else if (Beatmap.Value.Beatmap.HitObjects.Count > 0)
|
||||||
{
|
{
|
||||||
// seek to one beat length before the first hitobject
|
// seek to one beat length before the first hitobject
|
||||||
targetTime = Beatmap.Value.Beatmap.HitObjects[0].StartTime;
|
targetTime = Beatmap.Value.Beatmap.HitObjects[0].StartTime;
|
||||||
|
Loading…
Reference in New Issue
Block a user