mirror of
https://github.com/ppy/osu.git
synced 2025-01-27 00:23:01 +08:00
Merge branch 'master' into fix-wrapped-storage-native-open
This commit is contained in:
commit
f8d9c044df
@ -8,7 +8,7 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Beatmaps.Formats;
|
using osu.Game.Beatmaps.Formats;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
using osu.Game.IO.Archives;
|
using osu.Game.IO.Archives;
|
||||||
using osu.Game.Resources;
|
using osu.Game.Tests.Resources;
|
||||||
|
|
||||||
namespace osu.Game.Benchmarks
|
namespace osu.Game.Benchmarks
|
||||||
{
|
{
|
||||||
@ -18,8 +18,8 @@ namespace osu.Game.Benchmarks
|
|||||||
|
|
||||||
public override void SetUp()
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
using (var resources = new DllResourceStore(OsuResources.ResourceAssembly))
|
using (var resources = new DllResourceStore(typeof(TestResources).Assembly))
|
||||||
using (var archive = resources.GetStream("Beatmaps/241526 Soleily - Renatus.osz"))
|
using (var archive = resources.GetStream("Resources/Archives/241526 Soleily - Renatus.osz"))
|
||||||
using (var reader = new ZipArchiveReader(archive))
|
using (var reader = new ZipArchiveReader(archive))
|
||||||
reader.GetStream("Soleily - Renatus (Gamu) [Insane].osu").CopyTo(beatmapStream);
|
reader.GetStream("Soleily - Renatus (Gamu) [Insane].osu").CopyTo(beatmapStream);
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\osu.Game.Tests\osu.Game.Tests.csproj" />
|
||||||
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
<ProjectReference Include="..\osu.Game\osu.Game.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Caching;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Edit.Tools;
|
using osu.Game.Rulesets.Edit.Tools;
|
||||||
@ -12,6 +16,7 @@ using osu.Game.Rulesets.Objects;
|
|||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.UI;
|
using osu.Game.Rulesets.UI;
|
||||||
using osu.Game.Screens.Edit.Compose.Components;
|
using osu.Game.Screens.Edit.Compose.Components;
|
||||||
|
using osuTK;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit
|
namespace osu.Game.Rulesets.Osu.Edit
|
||||||
{
|
{
|
||||||
@ -32,9 +37,80 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
new SpinnerCompositionTool()
|
new SpinnerCompositionTool()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
LayerBelowRuleset.Add(distanceSnapGridContainer = new Container { RelativeSizeAxes = Axes.Both });
|
||||||
|
|
||||||
|
EditorBeatmap.SelectedHitObjects.CollectionChanged += (_, __) => updateDistanceSnapGrid();
|
||||||
|
EditorBeatmap.PlacementObject.ValueChanged += _ => updateDistanceSnapGrid();
|
||||||
|
}
|
||||||
|
|
||||||
protected override ComposeBlueprintContainer CreateBlueprintContainer() => new OsuBlueprintContainer(HitObjects);
|
protected override ComposeBlueprintContainer CreateBlueprintContainer() => new OsuBlueprintContainer(HitObjects);
|
||||||
|
|
||||||
protected override DistanceSnapGrid CreateDistanceSnapGrid(IEnumerable<HitObject> selectedHitObjects)
|
private DistanceSnapGrid distanceSnapGrid;
|
||||||
|
private Container distanceSnapGridContainer;
|
||||||
|
|
||||||
|
private readonly Cached distanceSnapGridCache = new Cached();
|
||||||
|
private double? lastDistanceSnapGridTime;
|
||||||
|
|
||||||
|
protected override void Update()
|
||||||
|
{
|
||||||
|
base.Update();
|
||||||
|
|
||||||
|
if (!(BlueprintContainer.CurrentTool is SelectTool))
|
||||||
|
{
|
||||||
|
if (EditorClock.CurrentTime != lastDistanceSnapGridTime)
|
||||||
|
{
|
||||||
|
distanceSnapGridCache.Invalidate();
|
||||||
|
lastDistanceSnapGridTime = EditorClock.CurrentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!distanceSnapGridCache.IsValid)
|
||||||
|
updateDistanceSnapGrid();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition)
|
||||||
|
{
|
||||||
|
if (distanceSnapGrid == null)
|
||||||
|
return base.SnapScreenSpacePositionToValidTime(screenSpacePosition);
|
||||||
|
|
||||||
|
(Vector2 pos, double time) = distanceSnapGrid.GetSnappedPosition(distanceSnapGrid.ToLocalSpace(screenSpacePosition));
|
||||||
|
|
||||||
|
return new SnapResult(distanceSnapGrid.ToScreenSpace(pos), time);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateDistanceSnapGrid()
|
||||||
|
{
|
||||||
|
distanceSnapGridContainer.Clear();
|
||||||
|
distanceSnapGridCache.Invalidate();
|
||||||
|
|
||||||
|
switch (BlueprintContainer.CurrentTool)
|
||||||
|
{
|
||||||
|
case SelectTool _:
|
||||||
|
if (!EditorBeatmap.SelectedHitObjects.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
distanceSnapGrid = createDistanceSnapGrid(EditorBeatmap.SelectedHitObjects);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (!CursorInPlacementArea)
|
||||||
|
return;
|
||||||
|
|
||||||
|
distanceSnapGrid = createDistanceSnapGrid(Enumerable.Empty<HitObject>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distanceSnapGrid != null)
|
||||||
|
{
|
||||||
|
distanceSnapGridContainer.Add(distanceSnapGrid);
|
||||||
|
distanceSnapGridCache.Validate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DistanceSnapGrid createDistanceSnapGrid(IEnumerable<HitObject> selectedHitObjects)
|
||||||
{
|
{
|
||||||
if (BlueprintContainer.CurrentTool is SpinnerCompositionTool)
|
if (BlueprintContainer.CurrentTool is SpinnerCompositionTool)
|
||||||
return null;
|
return null;
|
||||||
@ -42,7 +118,8 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
var objects = selectedHitObjects.ToList();
|
var objects = selectedHitObjects.ToList();
|
||||||
|
|
||||||
if (objects.Count == 0)
|
if (objects.Count == 0)
|
||||||
return createGrid(h => h.StartTime <= EditorClock.CurrentTime);
|
// use accurate time value to give more instantaneous feedback to the user.
|
||||||
|
return createGrid(h => h.StartTime <= EditorClock.CurrentTimeAccurate);
|
||||||
|
|
||||||
double minTime = objects.Min(h => h.StartTime);
|
double minTime = objects.Min(h => h.StartTime);
|
||||||
return createGrid(h => h.StartTime < minTime, objects.Count + 1);
|
return createGrid(h => h.StartTime < minTime, objects.Count + 1);
|
||||||
|
@ -4,8 +4,8 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
using osu.Game.Screens.Edit.Components;
|
using osu.Game.Screens.Edit.Components;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -17,9 +17,8 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
var clock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
var clock = new EditorClock { IsCoupled = false };
|
||||||
Dependencies.CacheAs<IAdjustableClock>(clock);
|
Dependencies.CacheAs(clock);
|
||||||
Dependencies.CacheAs<IFrameBasedClock>(clock);
|
|
||||||
|
|
||||||
var playback = new PlaybackControl
|
var playback = new PlaybackControl
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,6 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
@ -69,7 +68,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
private IBindable<WorkingBeatmap> beatmap { get; set; }
|
private IBindable<WorkingBeatmap> beatmap { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IAdjustableClock adjustableClock { get; set; }
|
private EditorClock editorClock { get; set; }
|
||||||
|
|
||||||
public AudioVisualiser()
|
public AudioVisualiser()
|
||||||
{
|
{
|
||||||
@ -96,13 +95,15 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
if (beatmap.Value.Track.IsLoaded)
|
if (beatmap.Value.Track.IsLoaded)
|
||||||
marker.X = (float)(adjustableClock.CurrentTime / beatmap.Value.Track.Length);
|
marker.X = (float)(editorClock.CurrentTime / beatmap.Value.Track.Length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class StartStopButton : OsuButton
|
private class StartStopButton : OsuButton
|
||||||
{
|
{
|
||||||
private IAdjustableClock adjustableClock;
|
[Resolved]
|
||||||
|
private EditorClock editorClock { get; set; }
|
||||||
|
|
||||||
private bool started;
|
private bool started;
|
||||||
|
|
||||||
public StartStopButton()
|
public StartStopButton()
|
||||||
@ -114,22 +115,16 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
Action = onClick;
|
Action = onClick;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load(IAdjustableClock adjustableClock)
|
|
||||||
{
|
|
||||||
this.adjustableClock = adjustableClock;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onClick()
|
private void onClick()
|
||||||
{
|
{
|
||||||
if (started)
|
if (started)
|
||||||
{
|
{
|
||||||
adjustableClock.Stop();
|
editorClock.Stop();
|
||||||
Text = "Start";
|
Text = "Start";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
adjustableClock.Start();
|
editorClock.Start();
|
||||||
Text = "Stop";
|
Text = "Stop";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,6 @@ using osu.Game.Online.API.Requests;
|
|||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using Decoder = osu.Game.Beatmaps.Formats.Decoder;
|
using Decoder = osu.Game.Beatmaps.Formats.Decoder;
|
||||||
using ZipArchive = SharpCompress.Archives.Zip.ZipArchive;
|
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps
|
namespace osu.Game.Beatmaps
|
||||||
{
|
{
|
||||||
@ -66,7 +65,6 @@ namespace osu.Game.Beatmaps
|
|||||||
private readonly AudioManager audioManager;
|
private readonly AudioManager audioManager;
|
||||||
private readonly GameHost host;
|
private readonly GameHost host;
|
||||||
private readonly BeatmapOnlineLookupQueue onlineLookupQueue;
|
private readonly BeatmapOnlineLookupQueue onlineLookupQueue;
|
||||||
private readonly Storage exportStorage;
|
|
||||||
|
|
||||||
public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, AudioManager audioManager, GameHost host = null,
|
public BeatmapManager(Storage storage, IDatabaseContextFactory contextFactory, RulesetStore rulesets, IAPIProvider api, AudioManager audioManager, GameHost host = null,
|
||||||
WorkingBeatmap defaultBeatmap = null)
|
WorkingBeatmap defaultBeatmap = null)
|
||||||
@ -83,7 +81,6 @@ namespace osu.Game.Beatmaps
|
|||||||
beatmaps.BeatmapRestored += b => beatmapRestored.Value = new WeakReference<BeatmapInfo>(b);
|
beatmaps.BeatmapRestored += b => beatmapRestored.Value = new WeakReference<BeatmapInfo>(b);
|
||||||
|
|
||||||
onlineLookupQueue = new BeatmapOnlineLookupQueue(api, storage);
|
onlineLookupQueue = new BeatmapOnlineLookupQueue(api, storage);
|
||||||
exportStorage = storage.GetStorageForDirectory("exports");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) =>
|
protected override ArchiveDownloadRequest<BeatmapSetInfo> CreateDownloadRequest(BeatmapSetInfo set, bool minimiseDownloadSize) =>
|
||||||
@ -214,26 +211,6 @@ namespace osu.Game.Beatmaps
|
|||||||
workingCache.Remove(working);
|
workingCache.Remove(working);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Exports a <see cref="BeatmapSetInfo"/> to an .osz package.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="set">The <see cref="BeatmapSetInfo"/> to export.</param>
|
|
||||||
public void Export(BeatmapSetInfo set)
|
|
||||||
{
|
|
||||||
var localSet = QueryBeatmapSet(s => s.ID == set.ID);
|
|
||||||
|
|
||||||
using (var archive = ZipArchive.Create())
|
|
||||||
{
|
|
||||||
foreach (var file in localSet.Files)
|
|
||||||
archive.AddEntry(file.Filename, Files.Storage.GetStream(file.FileInfo.StoragePath));
|
|
||||||
|
|
||||||
using (var outputStream = exportStorage.GetStream($"{set}.osz", FileAccess.Write, FileMode.Create))
|
|
||||||
archive.SaveTo(outputStream);
|
|
||||||
|
|
||||||
exportStorage.OpenInNativeExplorer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly WeakList<WorkingBeatmap> workingCache = new WeakList<WorkingBeatmap>();
|
private readonly WeakList<WorkingBeatmap> workingCache = new WeakList<WorkingBeatmap>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -22,6 +22,7 @@ using osu.Game.IO.Archives;
|
|||||||
using osu.Game.IPC;
|
using osu.Game.IPC;
|
||||||
using osu.Game.Overlays.Notifications;
|
using osu.Game.Overlays.Notifications;
|
||||||
using osu.Game.Utils;
|
using osu.Game.Utils;
|
||||||
|
using SharpCompress.Archives.Zip;
|
||||||
using SharpCompress.Common;
|
using SharpCompress.Common;
|
||||||
using FileInfo = osu.Game.IO.FileInfo;
|
using FileInfo = osu.Game.IO.FileInfo;
|
||||||
|
|
||||||
@ -82,6 +83,8 @@ namespace osu.Game.Database
|
|||||||
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
|
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
|
||||||
private ArchiveImportIPCChannel ipc;
|
private ArchiveImportIPCChannel ipc;
|
||||||
|
|
||||||
|
private readonly Storage exportStorage;
|
||||||
|
|
||||||
protected ArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, MutableDatabaseBackedStoreWithFileIncludes<TModel, TFileModel> modelStore, IIpcHost importHost = null)
|
protected ArchiveModelManager(Storage storage, IDatabaseContextFactory contextFactory, MutableDatabaseBackedStoreWithFileIncludes<TModel, TFileModel> modelStore, IIpcHost importHost = null)
|
||||||
{
|
{
|
||||||
ContextFactory = contextFactory;
|
ContextFactory = contextFactory;
|
||||||
@ -90,6 +93,8 @@ namespace osu.Game.Database
|
|||||||
ModelStore.ItemAdded += item => handleEvent(() => itemAdded.Value = new WeakReference<TModel>(item));
|
ModelStore.ItemAdded += item => handleEvent(() => itemAdded.Value = new WeakReference<TModel>(item));
|
||||||
ModelStore.ItemRemoved += item => handleEvent(() => itemRemoved.Value = new WeakReference<TModel>(item));
|
ModelStore.ItemRemoved += item => handleEvent(() => itemRemoved.Value = new WeakReference<TModel>(item));
|
||||||
|
|
||||||
|
exportStorage = storage.GetStorageForDirectory("exports");
|
||||||
|
|
||||||
Files = new FileStore(contextFactory, storage);
|
Files = new FileStore(contextFactory, storage);
|
||||||
|
|
||||||
if (importHost != null)
|
if (importHost != null)
|
||||||
@ -369,6 +374,29 @@ namespace osu.Game.Database
|
|||||||
return item;
|
return item;
|
||||||
}, cancellationToken, TaskCreationOptions.HideScheduler, import_scheduler).Unwrap();
|
}, cancellationToken, TaskCreationOptions.HideScheduler, import_scheduler).Unwrap();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Exports an item to a legacy (.zip based) package.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item to export.</param>
|
||||||
|
public void Export(TModel item)
|
||||||
|
{
|
||||||
|
var retrievedItem = ModelStore.ConsumableItems.FirstOrDefault(s => s.ID == item.ID);
|
||||||
|
|
||||||
|
if (retrievedItem == null)
|
||||||
|
throw new ArgumentException("Specified model could not be found", nameof(item));
|
||||||
|
|
||||||
|
using (var archive = ZipArchive.Create())
|
||||||
|
{
|
||||||
|
foreach (var file in retrievedItem.Files)
|
||||||
|
archive.AddEntry(file.Filename, Files.Storage.GetStream(file.FileInfo.StoragePath));
|
||||||
|
|
||||||
|
using (var outputStream = exportStorage.GetStream($"{getValidFilename(item.ToString())}{HandledExtensions.First()}", FileAccess.Write, FileMode.Create))
|
||||||
|
archive.SaveTo(outputStream);
|
||||||
|
|
||||||
|
exportStorage.OpenInNativeExplorer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateFile(TModel model, TFileModel file, Stream contents)
|
public void UpdateFile(TModel model, TFileModel file, Stream contents)
|
||||||
{
|
{
|
||||||
using (var usage = ContextFactory.GetForWrite())
|
using (var usage = ContextFactory.GetForWrite())
|
||||||
@ -710,5 +738,12 @@ namespace osu.Game.Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private string getValidFilename(string filename)
|
||||||
|
{
|
||||||
|
foreach (char c in Path.GetInvalidFileNameChars())
|
||||||
|
filename = filename.Replace(c, '_');
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Skinning;
|
using osu.Game.Skinning;
|
||||||
@ -38,9 +39,11 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
private void load(OsuConfigManager config)
|
private void load(OsuConfigManager config)
|
||||||
{
|
{
|
||||||
FlowContent.Spacing = new Vector2(0, 5);
|
FlowContent.Spacing = new Vector2(0, 5);
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
skinDropdown = new SkinSettingsDropdown(),
|
skinDropdown = new SkinSettingsDropdown(),
|
||||||
|
new ExportSkinButton(),
|
||||||
new SettingsSlider<float, SizeSlider>
|
new SettingsSlider<float, SizeSlider>
|
||||||
{
|
{
|
||||||
LabelText = "Menu cursor size",
|
LabelText = "Menu cursor size",
|
||||||
@ -117,5 +120,35 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
protected override DropdownMenu CreateMenu() => base.CreateMenu().With(m => m.MaxHeight = 200);
|
protected override DropdownMenu CreateMenu() => base.CreateMenu().With(m => m.MaxHeight = 200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ExportSkinButton : SettingsButton
|
||||||
|
{
|
||||||
|
[Resolved]
|
||||||
|
private SkinManager skins { get; set; }
|
||||||
|
|
||||||
|
private Bindable<Skin> currentSkin;
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Text = "Export selected skin";
|
||||||
|
Action = export;
|
||||||
|
|
||||||
|
currentSkin = skins.CurrentSkin.GetBoundCopy();
|
||||||
|
currentSkin.BindValueChanged(skin => Enabled.Value = skin.NewValue.SkinInfo.ID > 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void export()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
skins.Export(currentSkin.Value.SkinInfo);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Log($"Could not export current skin: {e.Message}", level: LogLevel.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,15 +3,14 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using JetBrains.Annotations;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Configuration;
|
using osu.Game.Rulesets.Configuration;
|
||||||
@ -38,22 +37,20 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
protected readonly Ruleset Ruleset;
|
protected readonly Ruleset Ruleset;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
protected IFrameBasedClock EditorClock { get; private set; }
|
protected EditorClock EditorClock { get; private set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
protected EditorBeatmap EditorBeatmap { get; private set; }
|
protected EditorBeatmap EditorBeatmap { get; private set; }
|
||||||
|
|
||||||
[Resolved]
|
|
||||||
private IAdjustableClock adjustableClock { get; set; }
|
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
protected IBeatSnapProvider BeatSnapProvider { get; private set; }
|
protected IBeatSnapProvider BeatSnapProvider { get; private set; }
|
||||||
|
|
||||||
protected ComposeBlueprintContainer BlueprintContainer { get; private set; }
|
protected ComposeBlueprintContainer BlueprintContainer { get; private set; }
|
||||||
|
|
||||||
private DrawableEditRulesetWrapper<TObject> drawableRulesetWrapper;
|
private DrawableEditRulesetWrapper<TObject> drawableRulesetWrapper;
|
||||||
private Container distanceSnapGridContainer;
|
|
||||||
private DistanceSnapGrid distanceSnapGrid;
|
protected readonly Container LayerBelowRuleset = new Container { RelativeSizeAxes = Axes.Both };
|
||||||
|
|
||||||
private readonly List<Container> layerContainers = new List<Container>();
|
private readonly List<Container> layerContainers = new List<Container>();
|
||||||
|
|
||||||
private InputManager inputManager;
|
private InputManager inputManager;
|
||||||
@ -67,7 +64,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(IFrameBasedClock framedClock)
|
private void load()
|
||||||
{
|
{
|
||||||
Config = Dependencies.Get<RulesetConfigCache>().GetConfigFor(Ruleset);
|
Config = Dependencies.Get<RulesetConfigCache>().GetConfigFor(Ruleset);
|
||||||
|
|
||||||
@ -75,7 +72,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
{
|
{
|
||||||
drawableRulesetWrapper = new DrawableEditRulesetWrapper<TObject>(CreateDrawableRuleset(Ruleset, EditorBeatmap.PlayableBeatmap))
|
drawableRulesetWrapper = new DrawableEditRulesetWrapper<TObject>(CreateDrawableRuleset(Ruleset, EditorBeatmap.PlayableBeatmap))
|
||||||
{
|
{
|
||||||
Clock = framedClock,
|
Clock = EditorClock,
|
||||||
ProcessCustomClock = false
|
ProcessCustomClock = false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -87,7 +84,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
var layerBelowRuleset = drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer().WithChildren(new Drawable[]
|
var layerBelowRuleset = drawableRulesetWrapper.CreatePlayfieldAdjustmentContainer().WithChildren(new Drawable[]
|
||||||
{
|
{
|
||||||
distanceSnapGridContainer = new Container { RelativeSizeAxes = Axes.Both },
|
LayerBelowRuleset,
|
||||||
new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both }
|
new EditorPlayfieldBorder { RelativeSizeAxes = Axes.Both }
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -139,7 +136,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
setSelectTool();
|
setSelectTool();
|
||||||
|
|
||||||
BlueprintContainer.SelectionChanged += selectionChanged;
|
EditorBeatmap.SelectedHitObjects.CollectionChanged += selectionChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
@ -165,16 +162,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
inputManager = GetContainingInputManager();
|
inputManager = GetContainingInputManager();
|
||||||
}
|
}
|
||||||
|
|
||||||
private double lastGridUpdateTime;
|
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
|
|
||||||
if (EditorClock.CurrentTime != lastGridUpdateTime && !(BlueprintContainer.CurrentTool is SelectTool))
|
|
||||||
showGridFor(Enumerable.Empty<HitObject>());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
protected override void UpdateAfterChildren()
|
||||||
{
|
{
|
||||||
base.UpdateAfterChildren();
|
base.UpdateAfterChildren();
|
||||||
@ -188,19 +175,13 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void selectionChanged(IEnumerable<HitObject> selectedHitObjects)
|
private void selectionChanged(object sender, NotifyCollectionChangedEventArgs changedArgs)
|
||||||
{
|
{
|
||||||
var hitObjects = selectedHitObjects.ToArray();
|
if (EditorBeatmap.SelectedHitObjects.Any())
|
||||||
|
|
||||||
if (hitObjects.Any())
|
|
||||||
{
|
{
|
||||||
// ensure in selection mode if a selection is made.
|
// ensure in selection mode if a selection is made.
|
||||||
setSelectTool();
|
setSelectTool();
|
||||||
|
|
||||||
showGridFor(hitObjects);
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
distanceSnapGridContainer.Hide();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setSelectTool() => toolboxCollection.Items.First().Select();
|
private void setSelectTool() => toolboxCollection.Items.First().Select();
|
||||||
@ -209,30 +190,12 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
{
|
{
|
||||||
BlueprintContainer.CurrentTool = tool;
|
BlueprintContainer.CurrentTool = tool;
|
||||||
|
|
||||||
if (tool is SelectTool)
|
if (!(tool is SelectTool))
|
||||||
distanceSnapGridContainer.Hide();
|
|
||||||
else
|
|
||||||
{
|
|
||||||
EditorBeatmap.SelectedHitObjects.Clear();
|
EditorBeatmap.SelectedHitObjects.Clear();
|
||||||
showGridFor(Enumerable.Empty<HitObject>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showGridFor(IEnumerable<HitObject> selectedHitObjects)
|
|
||||||
{
|
|
||||||
distanceSnapGridContainer.Clear();
|
|
||||||
distanceSnapGrid = CreateDistanceSnapGrid(selectedHitObjects);
|
|
||||||
|
|
||||||
if (distanceSnapGrid != null)
|
|
||||||
{
|
|
||||||
distanceSnapGridContainer.Child = distanceSnapGrid;
|
|
||||||
distanceSnapGridContainer.Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
lastGridUpdateTime = EditorClock.CurrentTime;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override IEnumerable<DrawableHitObject> HitObjects => drawableRulesetWrapper.Playfield.AllHitObjects;
|
public override IEnumerable<DrawableHitObject> HitObjects => drawableRulesetWrapper.Playfield.AllHitObjects;
|
||||||
|
|
||||||
public override bool CursorInPlacementArea => drawableRulesetWrapper.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position);
|
public override bool CursorInPlacementArea => drawableRulesetWrapper.Playfield.ReceivePositionalInputAt(inputManager.CurrentState.Mouse.Position);
|
||||||
|
|
||||||
protected abstract IReadOnlyList<HitObjectCompositionTool> CompositionTools { get; }
|
protected abstract IReadOnlyList<HitObjectCompositionTool> CompositionTools { get; }
|
||||||
@ -254,24 +217,14 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
{
|
{
|
||||||
EditorBeatmap.Add(hitObject);
|
EditorBeatmap.Add(hitObject);
|
||||||
|
|
||||||
if (adjustableClock.CurrentTime < hitObject.StartTime)
|
if (EditorClock.CurrentTime < hitObject.StartTime)
|
||||||
adjustableClock.Seek(hitObject.StartTime);
|
EditorClock.SeekTo(hitObject.StartTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
showGridFor(Enumerable.Empty<HitObject>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Delete(HitObject hitObject) => EditorBeatmap.Remove(hitObject);
|
public void Delete(HitObject hitObject) => EditorBeatmap.Remove(hitObject);
|
||||||
|
|
||||||
public override SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition)
|
public override SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition) => new SnapResult(screenSpacePosition, null);
|
||||||
{
|
|
||||||
if (distanceSnapGrid == null) return new SnapResult(screenSpacePosition, null);
|
|
||||||
|
|
||||||
// TODO: move distance snap grid to OsuHitObjectComposer.
|
|
||||||
(Vector2 pos, double time) = distanceSnapGrid.GetSnappedPosition(distanceSnapGrid.ToLocalSpace(screenSpacePosition));
|
|
||||||
|
|
||||||
return new SnapResult(distanceSnapGrid.ToScreenSpace(pos), time);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override float GetBeatSnapDistanceAt(double referenceTime)
|
public override float GetBeatSnapDistanceAt(double referenceTime)
|
||||||
{
|
{
|
||||||
@ -321,14 +274,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract bool CursorInPlacementArea { get; }
|
public abstract bool CursorInPlacementArea { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates the <see cref="DistanceSnapGrid"/> applicable for a <see cref="HitObject"/> selection.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="selectedHitObjects">The <see cref="HitObject"/> selection.</param>
|
|
||||||
/// <returns>The <see cref="DistanceSnapGrid"/> for <paramref name="selectedHitObjects"/>. If empty, a grid is returned for the current point in time.</returns>
|
|
||||||
[CanBeNull]
|
|
||||||
protected virtual DistanceSnapGrid CreateDistanceSnapGrid([NotNull] IEnumerable<HitObject> selectedHitObjects) => null;
|
|
||||||
|
|
||||||
public abstract SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition);
|
public abstract SnapResult SnapScreenSpacePositionToValidTime(Vector2 screenSpacePosition);
|
||||||
|
|
||||||
public abstract float GetBeatSnapDistanceAt(double referenceTime);
|
public abstract float GetBeatSnapDistanceAt(double referenceTime);
|
||||||
|
@ -6,10 +6,10 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
using osu.Game.Screens.Edit.Compose;
|
using osu.Game.Screens.Edit.Compose;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
|
||||||
@ -30,10 +30,13 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected readonly HitObject HitObject;
|
protected readonly HitObject HitObject;
|
||||||
|
|
||||||
protected IClock EditorClock { get; private set; }
|
[Resolved(canBeNull: true)]
|
||||||
|
protected EditorClock EditorClock { get; private set; }
|
||||||
|
|
||||||
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
private readonly IBindable<WorkingBeatmap> beatmap = new Bindable<WorkingBeatmap>();
|
||||||
|
|
||||||
|
private Bindable<double> startTimeBindable;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IPlacementHandler placementHandler { get; set; }
|
private IPlacementHandler placementHandler { get; set; }
|
||||||
|
|
||||||
@ -49,13 +52,12 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(IBindable<WorkingBeatmap> beatmap, IAdjustableClock clock)
|
private void load(IBindable<WorkingBeatmap> beatmap)
|
||||||
{
|
{
|
||||||
this.beatmap.BindTo(beatmap);
|
this.beatmap.BindTo(beatmap);
|
||||||
|
|
||||||
EditorClock = clock;
|
startTimeBindable = HitObject.StartTimeBindable.GetBoundCopy();
|
||||||
|
startTimeBindable.BindValueChanged(_ => ApplyDefaultsToHitObject(), true);
|
||||||
ApplyDefaultsToHitObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -81,9 +83,6 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
PlacementActive = false;
|
PlacementActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Resolved(canBeNull: true)]
|
|
||||||
private IFrameBasedClock editorClock { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the position of this <see cref="PlacementBlueprint"/> to a new screen-space position.
|
/// Updates the position of this <see cref="PlacementBlueprint"/> to a new screen-space position.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -91,7 +90,7 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
public virtual void UpdatePosition(SnapResult snapResult)
|
public virtual void UpdatePosition(SnapResult snapResult)
|
||||||
{
|
{
|
||||||
if (!PlacementActive)
|
if (!PlacementActive)
|
||||||
HitObject.StartTime = snapResult.Time ?? editorClock?.CurrentTime ?? Time.Current;
|
HitObject.StartTime = snapResult.Time ?? EditorClock?.CurrentTime ?? Time.Current;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -13,7 +13,6 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.UserInterface;
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
@ -26,7 +25,7 @@ namespace osu.Game.Screens.Edit.Components
|
|||||||
private IconButton playButton;
|
private IconButton playButton;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IAdjustableClock adjustableClock { get; set; }
|
private EditorClock editorClock { get; set; }
|
||||||
|
|
||||||
private readonly BindableNumber<double> tempo = new BindableDouble(1);
|
private readonly BindableNumber<double> tempo = new BindableDouble(1);
|
||||||
|
|
||||||
@ -87,17 +86,17 @@ namespace osu.Game.Screens.Edit.Components
|
|||||||
|
|
||||||
private void togglePause()
|
private void togglePause()
|
||||||
{
|
{
|
||||||
if (adjustableClock.IsRunning)
|
if (editorClock.IsRunning)
|
||||||
adjustableClock.Stop();
|
editorClock.Stop();
|
||||||
else
|
else
|
||||||
adjustableClock.Start();
|
editorClock.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
playButton.Icon = adjustableClock.IsRunning ? FontAwesome.Regular.PauseCircle : FontAwesome.Regular.PlayCircle;
|
playButton.Icon = editorClock.IsRunning ? FontAwesome.Regular.PauseCircle : FontAwesome.Regular.PlayCircle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PlaybackTabControl : OsuTabControl<double>
|
private class PlaybackTabControl : OsuTabControl<double>
|
||||||
|
@ -5,7 +5,6 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Game.Graphics.Sprites;
|
using osu.Game.Graphics.Sprites;
|
||||||
using System;
|
using System;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Components
|
namespace osu.Game.Screens.Edit.Components
|
||||||
@ -15,7 +14,7 @@ namespace osu.Game.Screens.Edit.Components
|
|||||||
private readonly OsuSpriteText trackTimer;
|
private readonly OsuSpriteText trackTimer;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IAdjustableClock adjustableClock { get; set; }
|
private EditorClock editorClock { get; set; }
|
||||||
|
|
||||||
public TimeInfoContainer()
|
public TimeInfoContainer()
|
||||||
{
|
{
|
||||||
@ -35,7 +34,7 @@ namespace osu.Game.Screens.Edit.Components
|
|||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
|
|
||||||
trackTimer.Text = TimeSpan.FromMilliseconds(adjustableClock.CurrentTime).ToString(@"mm\:ss\:fff");
|
trackTimer.Text = TimeSpan.FromMilliseconds(editorClock.CurrentTime).ToString(@"mm\:ss\:fff");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Threading;
|
using osu.Framework.Threading;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
|
||||||
@ -20,14 +19,14 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class MarkerPart : TimelinePart
|
public class MarkerPart : TimelinePart
|
||||||
{
|
{
|
||||||
private readonly Drawable marker;
|
private Drawable marker;
|
||||||
|
|
||||||
private readonly IAdjustableClock adjustableClock;
|
[Resolved]
|
||||||
|
private EditorClock editorClock { get; set; }
|
||||||
|
|
||||||
public MarkerPart(IAdjustableClock adjustableClock)
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
{
|
{
|
||||||
this.adjustableClock = adjustableClock;
|
|
||||||
|
|
||||||
Add(marker = new MarkerVisualisation());
|
Add(marker = new MarkerVisualisation());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,14 +58,14 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary.Parts
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
float markerPos = Math.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth);
|
float markerPos = Math.Clamp(ToLocalSpace(screenPosition).X, 0, DrawWidth);
|
||||||
adjustableClock.Seek(markerPos / DrawWidth * Beatmap.Value.Track.Length);
|
editorClock.SeekTo(markerPos / DrawWidth * editorClock.TrackLength);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
marker.X = (float)adjustableClock.CurrentTime;
|
marker.X = (float)editorClock.CurrentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadBeatmap(WorkingBeatmap beatmap)
|
protected override void LoadBeatmap(WorkingBeatmap beatmap)
|
||||||
|
@ -6,7 +6,6 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts;
|
using osu.Game.Screens.Edit.Components.Timelines.Summary.Parts;
|
||||||
|
|
||||||
@ -18,11 +17,11 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary
|
|||||||
public class SummaryTimeline : BottomBarContainer
|
public class SummaryTimeline : BottomBarContainer
|
||||||
{
|
{
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OsuColour colours, IAdjustableClock adjustableClock)
|
private void load(OsuColour colours)
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new MarkerPart(adjustableClock) { RelativeSizeAxes = Axes.Both },
|
new MarkerPart { RelativeSizeAxes = Axes.Both },
|
||||||
new ControlPointPart
|
new ControlPointPart
|
||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
// 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 System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -14,7 +13,6 @@ using osu.Framework.Graphics.Primitives;
|
|||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -29,8 +27,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class BlueprintContainer : CompositeDrawable, IKeyBindingHandler<PlatformAction>
|
public abstract class BlueprintContainer : CompositeDrawable, IKeyBindingHandler<PlatformAction>
|
||||||
{
|
{
|
||||||
public event Action<IEnumerable<HitObject>> SelectionChanged;
|
|
||||||
|
|
||||||
protected DragBox DragBox { get; private set; }
|
protected DragBox DragBox { get; private set; }
|
||||||
|
|
||||||
protected Container<SelectionBlueprint> SelectionBlueprints { get; private set; }
|
protected Container<SelectionBlueprint> SelectionBlueprints { get; private set; }
|
||||||
@ -41,7 +37,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
private IEditorChangeHandler changeHandler { get; set; }
|
private IEditorChangeHandler changeHandler { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IAdjustableClock adjustableClock { get; set; }
|
private EditorClock editorClock { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private EditorBeatmap beatmap { get; set; }
|
private EditorBeatmap beatmap { get; set; }
|
||||||
@ -88,8 +84,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
SelectionBlueprints.FirstOrDefault(b => b.HitObject == o)?.Deselect();
|
SelectionBlueprints.FirstOrDefault(b => b.HitObject == o)?.Deselect();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectionChanged?.Invoke(selectedHitObjects);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +143,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
if (clickedBlueprint == null)
|
if (clickedBlueprint == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
adjustableClock?.Seek(clickedBlueprint.HitObject.StartTime);
|
editorClock?.SeekTo(clickedBlueprint.HitObject.StartTime);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ using osu.Framework.Extensions.Color4Extensions;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Audio;
|
using osu.Framework.Graphics.Audio;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
@ -25,7 +24,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
public readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
|
public readonly IBindable<WorkingBeatmap> Beatmap = new Bindable<WorkingBeatmap>();
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IAdjustableClock adjustableClock { get; set; }
|
private EditorClock editorClock { get; set; }
|
||||||
|
|
||||||
public Timeline()
|
public Timeline()
|
||||||
{
|
{
|
||||||
@ -101,7 +100,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 };
|
Content.Margin = new MarginPadding { Horizontal = DrawWidth / 2 };
|
||||||
|
|
||||||
// This needs to happen after transforms are updated, but before the scroll position is updated in base.UpdateAfterChildren
|
// This needs to happen after transforms are updated, but before the scroll position is updated in base.UpdateAfterChildren
|
||||||
if (adjustableClock.IsRunning)
|
if (editorClock.IsRunning)
|
||||||
scrollToTrackTime();
|
scrollToTrackTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,21 +110,21 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
|
|
||||||
if (handlingDragInput)
|
if (handlingDragInput)
|
||||||
seekTrackToCurrent();
|
seekTrackToCurrent();
|
||||||
else if (!adjustableClock.IsRunning)
|
else if (!editorClock.IsRunning)
|
||||||
{
|
{
|
||||||
// The track isn't running. There are two cases we have to be wary of:
|
// The track isn't running. There are two cases we have to be wary of:
|
||||||
// 1) The user flick-drags on this timeline: We want the track to follow us
|
// 1) The user flick-drags on this timeline: We want the track to follow us
|
||||||
// 2) The user changes the track time through some other means (scrolling in the editor or overview timeline): We want to follow the track time
|
// 2) The user changes the track time through some other means (scrolling in the editor or overview timeline): We want to follow the track time
|
||||||
|
|
||||||
// The simplest way to cover both cases is by checking whether the scroll position has changed and the audio hasn't been changed externally
|
// The simplest way to cover both cases is by checking whether the scroll position has changed and the audio hasn't been changed externally
|
||||||
if (Current != lastScrollPosition && adjustableClock.CurrentTime == lastTrackTime)
|
if (Current != lastScrollPosition && editorClock.CurrentTime == lastTrackTime)
|
||||||
seekTrackToCurrent();
|
seekTrackToCurrent();
|
||||||
else
|
else
|
||||||
scrollToTrackTime();
|
scrollToTrackTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
lastScrollPosition = Current;
|
lastScrollPosition = Current;
|
||||||
lastTrackTime = adjustableClock.CurrentTime;
|
lastTrackTime = editorClock.CurrentTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void seekTrackToCurrent()
|
private void seekTrackToCurrent()
|
||||||
@ -133,7 +132,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
if (!track.IsLoaded)
|
if (!track.IsLoaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
adjustableClock.Seek(Current / Content.DrawWidth * track.Length);
|
editorClock.Seek(Current / Content.DrawWidth * track.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scrollToTrackTime()
|
private void scrollToTrackTime()
|
||||||
@ -141,7 +140,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
if (!track.IsLoaded || track.Length == 0)
|
if (!track.IsLoaded || track.Length == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ScrollTo((float)(adjustableClock.CurrentTime / track.Length) * Content.DrawWidth, false);
|
ScrollTo((float)(editorClock.CurrentTime / track.Length) * Content.DrawWidth, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseDown(MouseDownEvent e)
|
protected override bool OnMouseDown(MouseDownEvent e)
|
||||||
@ -164,15 +163,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
private void beginUserDrag()
|
private void beginUserDrag()
|
||||||
{
|
{
|
||||||
handlingDragInput = true;
|
handlingDragInput = true;
|
||||||
trackWasPlaying = adjustableClock.IsRunning;
|
trackWasPlaying = editorClock.IsRunning;
|
||||||
adjustableClock.Stop();
|
editorClock.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void endUserDrag()
|
private void endUserDrag()
|
||||||
{
|
{
|
||||||
handlingDragInput = false;
|
handlingDragInput = false;
|
||||||
if (trackWasPlaying)
|
if (trackWasPlaying)
|
||||||
adjustableClock.Start();
|
editorClock.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
|
@ -83,8 +83,8 @@ namespace osu.Game.Screens.Edit
|
|||||||
clock = new EditorClock(Beatmap.Value, beatDivisor) { IsCoupled = false };
|
clock = new EditorClock(Beatmap.Value, beatDivisor) { IsCoupled = false };
|
||||||
clock.ChangeSource(sourceClock);
|
clock.ChangeSource(sourceClock);
|
||||||
|
|
||||||
dependencies.CacheAs<IFrameBasedClock>(clock);
|
dependencies.CacheAs(clock);
|
||||||
dependencies.CacheAs<IAdjustableClock>(clock);
|
AddInternal(clock);
|
||||||
|
|
||||||
// todo: remove caching of this and consume via editorBeatmap?
|
// todo: remove caching of this and consume via editorBeatmap?
|
||||||
dependencies.Cache(beatDivisor);
|
dependencies.Cache(beatDivisor);
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Transforms;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -13,7 +15,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A decoupled clock which adds editor-specific functionality, such as snapping to a user-defined beat divisor.
|
/// A decoupled clock which adds editor-specific functionality, such as snapping to a user-defined beat divisor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class EditorClock : DecoupleableInterpolatingFramedClock
|
public class EditorClock : Component, IFrameBasedClock, IAdjustableClock, ISourceChangeableClock
|
||||||
{
|
{
|
||||||
public readonly double TrackLength;
|
public readonly double TrackLength;
|
||||||
|
|
||||||
@ -21,12 +23,11 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private readonly BindableBeatDivisor beatDivisor;
|
private readonly BindableBeatDivisor beatDivisor;
|
||||||
|
|
||||||
public EditorClock(WorkingBeatmap beatmap, BindableBeatDivisor beatDivisor)
|
private readonly DecoupleableInterpolatingFramedClock underlyingClock;
|
||||||
{
|
|
||||||
this.beatDivisor = beatDivisor;
|
|
||||||
|
|
||||||
ControlPointInfo = beatmap.Beatmap.ControlPointInfo;
|
public EditorClock(WorkingBeatmap beatmap, BindableBeatDivisor beatDivisor)
|
||||||
TrackLength = beatmap.Track.Length;
|
: this(beatmap.Beatmap.ControlPointInfo, beatmap.Track.Length, beatDivisor)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public EditorClock(ControlPointInfo controlPointInfo, double trackLength, BindableBeatDivisor beatDivisor)
|
public EditorClock(ControlPointInfo controlPointInfo, double trackLength, BindableBeatDivisor beatDivisor)
|
||||||
@ -35,6 +36,13 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
ControlPointInfo = controlPointInfo;
|
ControlPointInfo = controlPointInfo;
|
||||||
TrackLength = trackLength;
|
TrackLength = trackLength;
|
||||||
|
|
||||||
|
underlyingClock = new DecoupleableInterpolatingFramedClock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public EditorClock()
|
||||||
|
: this(new ControlPointInfo(), 1000, new BindableBeatDivisor())
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -79,20 +87,22 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
private void seek(int direction, bool snapped, double amount = 1)
|
private void seek(int direction, bool snapped, double amount = 1)
|
||||||
{
|
{
|
||||||
|
double current = CurrentTimeAccurate;
|
||||||
|
|
||||||
if (amount <= 0) throw new ArgumentException("Value should be greater than zero", nameof(amount));
|
if (amount <= 0) throw new ArgumentException("Value should be greater than zero", nameof(amount));
|
||||||
|
|
||||||
var timingPoint = ControlPointInfo.TimingPointAt(CurrentTime);
|
var timingPoint = ControlPointInfo.TimingPointAt(current);
|
||||||
|
|
||||||
if (direction < 0 && timingPoint.Time == CurrentTime)
|
if (direction < 0 && timingPoint.Time == current)
|
||||||
// When going backwards and we're at the boundary of two timing points, we compute the seek distance with the timing point which we are seeking into
|
// When going backwards and we're at the boundary of two timing points, we compute the seek distance with the timing point which we are seeking into
|
||||||
timingPoint = ControlPointInfo.TimingPointAt(CurrentTime - 1);
|
timingPoint = ControlPointInfo.TimingPointAt(current - 1);
|
||||||
|
|
||||||
double seekAmount = timingPoint.BeatLength / beatDivisor.Value * amount;
|
double seekAmount = timingPoint.BeatLength / beatDivisor.Value * amount;
|
||||||
double seekTime = CurrentTime + seekAmount * direction;
|
double seekTime = current + seekAmount * direction;
|
||||||
|
|
||||||
if (!snapped || ControlPointInfo.TimingPoints.Count == 0)
|
if (!snapped || ControlPointInfo.TimingPoints.Count == 0)
|
||||||
{
|
{
|
||||||
Seek(seekTime);
|
SeekTo(seekTime);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +120,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
// Due to the rounding above, we may end up on the current beat. This will effectively cause 0 seeking to happen, but we don't want this.
|
// Due to the rounding above, we may end up on the current beat. This will effectively cause 0 seeking to happen, but we don't want this.
|
||||||
// Instead, we'll go to the next beat in the direction when this is the case
|
// Instead, we'll go to the next beat in the direction when this is the case
|
||||||
if (Precision.AlmostEquals(CurrentTime, seekTime))
|
if (Precision.AlmostEquals(current, seekTime))
|
||||||
{
|
{
|
||||||
closestBeat += direction > 0 ? 1 : -1;
|
closestBeat += direction > 0 ? 1 : -1;
|
||||||
seekTime = timingPoint.Time + closestBeat * seekAmount;
|
seekTime = timingPoint.Time + closestBeat * seekAmount;
|
||||||
@ -125,7 +135,97 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
// Ensure the sought point is within the boundaries
|
// Ensure the sought point is within the boundaries
|
||||||
seekTime = Math.Clamp(seekTime, 0, TrackLength);
|
seekTime = Math.Clamp(seekTime, 0, TrackLength);
|
||||||
Seek(seekTime);
|
SeekTo(seekTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current time of this clock, include any active transform seeks performed via <see cref="SeekTo"/>.
|
||||||
|
/// </summary>
|
||||||
|
public double CurrentTimeAccurate =>
|
||||||
|
Transforms.OfType<TransformSeek>().FirstOrDefault()?.EndValue ?? CurrentTime;
|
||||||
|
|
||||||
|
public double CurrentTime => underlyingClock.CurrentTime;
|
||||||
|
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
ClearTransforms();
|
||||||
|
underlyingClock.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start()
|
||||||
|
{
|
||||||
|
ClearTransforms();
|
||||||
|
underlyingClock.Start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
underlyingClock.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Seek(double position)
|
||||||
|
{
|
||||||
|
ClearTransforms();
|
||||||
|
return underlyingClock.Seek(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetSpeedAdjustments() => underlyingClock.ResetSpeedAdjustments();
|
||||||
|
|
||||||
|
double IAdjustableClock.Rate
|
||||||
|
{
|
||||||
|
get => underlyingClock.Rate;
|
||||||
|
set => underlyingClock.Rate = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
double IClock.Rate => underlyingClock.Rate;
|
||||||
|
|
||||||
|
public bool IsRunning => underlyingClock.IsRunning;
|
||||||
|
|
||||||
|
public void ProcessFrame() => underlyingClock.ProcessFrame();
|
||||||
|
|
||||||
|
public double ElapsedFrameTime => underlyingClock.ElapsedFrameTime;
|
||||||
|
|
||||||
|
public double FramesPerSecond => underlyingClock.FramesPerSecond;
|
||||||
|
|
||||||
|
public FrameTimeInfo TimeInfo => underlyingClock.TimeInfo;
|
||||||
|
|
||||||
|
public void ChangeSource(IClock source) => underlyingClock.ChangeSource(source);
|
||||||
|
|
||||||
|
public IClock Source => underlyingClock.Source;
|
||||||
|
|
||||||
|
public bool IsCoupled
|
||||||
|
{
|
||||||
|
get => underlyingClock.IsCoupled;
|
||||||
|
set => underlyingClock.IsCoupled = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private const double transform_time = 300;
|
||||||
|
|
||||||
|
public void SeekTo(double seekDestination)
|
||||||
|
{
|
||||||
|
if (IsRunning)
|
||||||
|
Seek(seekDestination);
|
||||||
|
else
|
||||||
|
transformSeekTo(seekDestination, transform_time, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void transformSeekTo(double seek, double duration = 0, Easing easing = Easing.None)
|
||||||
|
=> this.TransformTo(this.PopulateTransform(new TransformSeek(), seek, duration, easing));
|
||||||
|
|
||||||
|
private double currentTime
|
||||||
|
{
|
||||||
|
get => underlyingClock.CurrentTime;
|
||||||
|
set => underlyingClock.Seek(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private class TransformSeek : Transform<double, EditorClock>
|
||||||
|
{
|
||||||
|
public override string TargetMember => nameof(currentTime);
|
||||||
|
|
||||||
|
protected override void Apply(EditorClock clock, double time) =>
|
||||||
|
clock.currentTime = Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing);
|
||||||
|
|
||||||
|
protected override void ReadIntoStartValue(EditorClock clock) => StartValue = clock.currentTime;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ using osu.Framework.Bindables;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Framework.Timing;
|
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
@ -23,7 +22,7 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
private Bindable<ControlPointGroup> selectedGroup = new Bindable<ControlPointGroup>();
|
private Bindable<ControlPointGroup> selectedGroup = new Bindable<ControlPointGroup>();
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IAdjustableClock clock { get; set; }
|
private EditorClock clock { get; set; }
|
||||||
|
|
||||||
protected override Drawable CreateMainContent() => new GridContainer
|
protected override Drawable CreateMainContent() => new GridContainer
|
||||||
{
|
{
|
||||||
@ -50,7 +49,7 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
selectedGroup.BindValueChanged(selected =>
|
selectedGroup.BindValueChanged(selected =>
|
||||||
{
|
{
|
||||||
if (selected.NewValue != null)
|
if (selected.NewValue != null)
|
||||||
clock.Seek(selected.NewValue.Time);
|
clock.SeekTo(selected.NewValue.Time);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +61,7 @@ namespace osu.Game.Screens.Edit.Timing
|
|||||||
private IBindableList<ControlPointGroup> controlGroups;
|
private IBindableList<ControlPointGroup> controlGroups;
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IFrameBasedClock clock { get; set; }
|
private EditorClock clock { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
protected IBindable<WorkingBeatmap> Beatmap { get; private set; }
|
protected IBindable<WorkingBeatmap> Beatmap { get; private set; }
|
||||||
|
@ -24,8 +24,6 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public bool DeletePending { get; set; }
|
public bool DeletePending { get; set; }
|
||||||
|
|
||||||
public string FullName => $"\"{Name}\" by {Creator}";
|
|
||||||
|
|
||||||
public static SkinInfo Default { get; } = new SkinInfo
|
public static SkinInfo Default { get; } = new SkinInfo
|
||||||
{
|
{
|
||||||
Name = "osu!lazer",
|
Name = "osu!lazer",
|
||||||
@ -34,6 +32,10 @@ namespace osu.Game.Skinning
|
|||||||
|
|
||||||
public bool Equals(SkinInfo other) => other != null && ID == other.ID;
|
public bool Equals(SkinInfo other) => other != null && ID == other.ID;
|
||||||
|
|
||||||
public override string ToString() => FullName;
|
public override string ToString()
|
||||||
|
{
|
||||||
|
string author = Creator == null ? string.Empty : $"({Creator})";
|
||||||
|
return $"{Name} {author}".Trim();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
|
|
||||||
dependencies.Cache(BeatDivisor);
|
dependencies.Cache(BeatDivisor);
|
||||||
dependencies.CacheAs<IFrameBasedClock>(Clock);
|
dependencies.CacheAs(Clock);
|
||||||
dependencies.CacheAs<IAdjustableClock>(Clock);
|
|
||||||
|
|
||||||
return dependencies;
|
return dependencies;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using osu.Framework.Timing;
|
|||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
|
using osu.Game.Screens.Edit;
|
||||||
using osu.Game.Screens.Edit.Compose;
|
using osu.Game.Screens.Edit.Compose;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual
|
namespace osu.Game.Tests.Visual
|
||||||
@ -32,7 +33,7 @@ namespace osu.Game.Tests.Visual
|
|||||||
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
|
||||||
{
|
{
|
||||||
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
var dependencies = new DependencyContainer(base.CreateChildDependencies(parent));
|
||||||
dependencies.CacheAs<IAdjustableClock>(new StopwatchClock());
|
dependencies.CacheAs(new EditorClock());
|
||||||
|
|
||||||
return dependencies;
|
return dependencies;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="Dapper" Version="2.0.35" />
|
<PackageReference Include="Dapper" Version="2.0.35" />
|
||||||
<PackageReference Include="DiffPlex" Version="1.6.1" />
|
<PackageReference Include="DiffPlex" Version="1.6.2" />
|
||||||
<PackageReference Include="Humanizer" Version="2.8.11" />
|
<PackageReference Include="Humanizer" Version="2.8.11" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
@ -27,7 +27,7 @@
|
|||||||
<PackageReference Include="ppy.osu.Framework" Version="2020.519.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2020.519.0" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.512.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.512.0" />
|
||||||
<PackageReference Include="Sentry" Version="2.1.1" />
|
<PackageReference Include="Sentry" Version="2.1.1" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.25.0" />
|
<PackageReference Include="SharpCompress" Version="0.25.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -75,13 +75,13 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
|
||||||
<ItemGroup Label="Transitive Dependencies">
|
<ItemGroup Label="Transitive Dependencies">
|
||||||
<PackageReference Include="DiffPlex" Version="1.6.1" />
|
<PackageReference Include="DiffPlex" Version="1.6.2" />
|
||||||
<PackageReference Include="Humanizer" Version="2.8.11" />
|
<PackageReference Include="Humanizer" Version="2.8.11" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2020.519.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2020.519.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.25.0" />
|
<PackageReference Include="SharpCompress" Version="0.25.1" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
|
<PackageReference Include="System.ComponentModel.Annotations" Version="4.7.0" />
|
||||||
|
Loading…
Reference in New Issue
Block a user