diff --git a/osu-framework b/osu-framework index 5a9ca94fc3..96daf2053a 160000 --- a/osu-framework +++ b/osu-framework @@ -1 +1 @@ -Subproject commit 5a9ca94fc31bc796b45572eb3d0b27b46556c586 +Subproject commit 96daf2053a8a19fe221fef2557674ca5bee808fb diff --git a/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs b/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs index cbb2775234..292e31de75 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseMusicController.cs @@ -1,11 +1,15 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Testing; +using osu.Framework.Allocation; +using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Framework.Timing; -using osu.Game.Overlays; using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Framework.Timing; +using osu.Game; +using osu.Game.Beatmaps; +using osu.Game.Overlays; namespace osu.Desktop.VisualTests.Tests { @@ -13,6 +17,8 @@ namespace osu.Desktop.VisualTests.Tests { public override string Description => @"Tests music controller ui."; + private readonly Bindable beatmapBacking = new Bindable(); + public TestCaseMusicController() { Clock = new FramedClock(); @@ -26,6 +32,13 @@ namespace osu.Desktop.VisualTests.Tests AddToggleStep(@"toggle visibility", state => mc.State = state ? Visibility.Visible : Visibility.Hidden); AddStep(@"show", () => mc.State = Visibility.Visible); + AddToggleStep(@"toggle beatmap lock", state => beatmapBacking.Disabled = state); + } + + [BackgroundDependencyLoader] + private void load(OsuGameBase game) + { + beatmapBacking.BindTo(game.Beatmap); } } } diff --git a/osu.Desktop.VisualTests/Tests/TestCaseTextAwesome.cs b/osu.Desktop.VisualTests/Tests/TestCaseTextAwesome.cs index 2824c0416f..504b59f007 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseTextAwesome.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseTextAwesome.cs @@ -31,10 +31,10 @@ namespace osu.Desktop.VisualTests.Tests int i = 50; foreach (FontAwesome fa in Enum.GetValues(typeof(FontAwesome))) { - flow.Add(new TextAwesome + flow.Add(new SpriteIcon { Icon = fa, - TextSize = 60, + Size = new Vector2(60), Colour = new Color4( Math.Max(0.5f, RNG.NextSingle()), Math.Max(0.5f, RNG.NextSingle()), diff --git a/osu.Desktop/OsuGameDesktop.cs b/osu.Desktop/OsuGameDesktop.cs index bd5c6c6790..88c8a206c8 100644 --- a/osu.Desktop/OsuGameDesktop.cs +++ b/osu.Desktop/OsuGameDesktop.cs @@ -1,6 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Game; using System.Linq; using System.Windows.Forms; @@ -11,6 +12,7 @@ using System.Reflection; using System.Drawing; using System.IO; using System.Threading.Tasks; +using Microsoft.Win32; using osu.Framework.Graphics.Containers; using osu.Game.Screens.Menu; @@ -30,6 +32,58 @@ namespace osu.Desktop }; } + public override Storage GetStorageForStableInstall() + { + try + { + return new StableStorage(); + } + catch + { + return null; + } + } + + /// + /// A method of accessing an osu-stable install in a controlled fashion. + /// + private class StableStorage : DesktopStorage + { + protected override string LocateBasePath() + { + Func checkExists = p => Directory.Exists(Path.Combine(p, "Songs")); + + string stableInstallPath; + + try + { + using (RegistryKey key = Registry.ClassesRoot.OpenSubKey("osu")) + stableInstallPath = key?.OpenSubKey(@"shell\open\command")?.GetValue(String.Empty).ToString().Split('"')[1].Replace("osu!.exe", ""); + + if (checkExists(stableInstallPath)) + return stableInstallPath; + } + catch + { + } + + stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), @"osu!"); + if (checkExists(stableInstallPath)) + return stableInstallPath; + + stableInstallPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".osu"); + if (checkExists(stableInstallPath)) + return stableInstallPath; + + return null; + } + + public StableStorage() + : base(string.Empty) + { + } + } + protected override void LoadComplete() { base.LoadComplete(); diff --git a/osu.Desktop/Overlays/VersionManager.cs b/osu.Desktop/Overlays/VersionManager.cs index 6983c51c7d..18fa43ab5c 100644 --- a/osu.Desktop/Overlays/VersionManager.cs +++ b/osu.Desktop/Overlays/VersionManager.cs @@ -209,13 +209,13 @@ namespace osu.Desktop.Overlays RelativeSizeAxes = Axes.Both, Colour = ColourInfo.GradientVertical(colours.YellowDark, colours.Yellow) }, - new TextAwesome + new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = FontAwesome.fa_upload, Colour = Color4.White, - TextSize = 20 + Size = new Vector2(20), } }); } diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs index 2902455808..dc13329bde 100644 --- a/osu.Game.Rulesets.Catch/CatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using System.Collections.Generic; +using osu.Framework.Graphics; using osu.Game.Rulesets.Catch.Scoring; using osu.Game.Rulesets.Scoring; @@ -87,7 +88,7 @@ namespace osu.Game.Rulesets.Catch public override string Description => "osu!catch"; - public override FontAwesome Icon => FontAwesome.fa_osu_fruits_o; + public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o }; public override IEnumerable CreateGameplayKeys() => new KeyCounter[] { diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs index 1b50b8809c..a8a89a57e0 100644 --- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs @@ -2,13 +2,14 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.Beatmaps; -using osu.Game.Graphics; using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Game.Graphics; using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Scoring; @@ -108,7 +109,7 @@ namespace osu.Game.Rulesets.Mania public override string Description => "osu!mania"; - public override FontAwesome Icon => FontAwesome.fa_osu_mania_o; + public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o }; public override IEnumerable CreateGameplayKeys() => new KeyCounter[] { /* Todo: Should be keymod specific */ }; diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs index 2aae1bb24e..4a0b8422f1 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs @@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables private readonly CirclePiece circle; private readonly GlowPiece glow; - private readonly TextAwesome symbol; + private readonly SpriteIcon symbol; private readonly Color4 baseColour = OsuColour.FromHex(@"002c3c"); private readonly Color4 fillColour = OsuColour.FromHex(@"005b7c"); @@ -64,12 +64,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables Anchor = Anchor.Centre, }, new RingPiece(), - symbol = new TextAwesome + symbol = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - UseFullGlyphHeight = true, - TextSize = 48, + Size = new Vector2(48), Icon = FontAwesome.fa_asterisk, Shadow = false, }, diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs index 10d14b5485..942f166241 100644 --- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs +++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBouncer.cs @@ -4,6 +4,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; +using OpenTK; namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { @@ -11,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces { private readonly Slider slider; private readonly bool isEnd; - private readonly TextAwesome icon; + private readonly SpriteIcon icon; public SliderBouncer(Slider slider, bool isEnd) { @@ -24,12 +25,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces Children = new Drawable[] { - icon = new TextAwesome + icon = new SpriteIcon { Icon = FontAwesome.fa_eercast, Anchor = Anchor.Centre, Origin = Anchor.Centre, - TextSize = 48, + Size = new Vector2(48), } }; } diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs index efa6ae75d4..9a1971d791 100644 --- a/osu.Game.Rulesets.Osu/OsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using System.Collections.Generic; using System.Linq; +using osu.Framework.Graphics; using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Scoring; using osu.Game.Overlays.Settings; @@ -106,7 +107,7 @@ namespace osu.Game.Rulesets.Osu public override Mod GetAutoplayMod() => new OsuModAutoplay(); - public override FontAwesome Icon => FontAwesome.fa_osu_osu_o; + public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o }; public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new OsuDifficultyCalculator(beatmap); diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/SwellSymbolPiece.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/SwellSymbolPiece.cs index 0f703837a9..5a9ee36021 100644 --- a/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/SwellSymbolPiece.cs +++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/Pieces/SwellSymbolPiece.cs @@ -3,20 +3,20 @@ using osu.Framework.Graphics; using osu.Game.Graphics; +using OpenTK; namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces { /// /// The symbol used for swell pieces. /// - public class SwellSymbolPiece : TextAwesome + public class SwellSymbolPiece : SpriteIcon { public SwellSymbolPiece() { Anchor = Anchor.Centre; Origin = Anchor.Centre; - UseFullGlyphHeight = true; - TextSize = CirclePiece.SYMBOL_INNER_SIZE; + Size = new Vector2(CirclePiece.SYMBOL_INNER_SIZE); Icon = FontAwesome.fa_asterisk; Shadow = false; } diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs index c244616d47..83db9b35af 100644 --- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs @@ -10,6 +10,7 @@ using osu.Game.Rulesets.Taiko.UI; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using System.Collections.Generic; +using osu.Framework.Graphics; using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Taiko.Scoring; @@ -87,7 +88,7 @@ namespace osu.Game.Rulesets.Taiko public override string Description => "osu!taiko"; - public override FontAwesome Icon => FontAwesome.fa_osu_taiko_o; + public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o }; public override IEnumerable CreateGameplayKeys() => new KeyCounter[] { diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index 99117afe35..bbb6c975d0 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -17,9 +17,9 @@ using osu.Game.Beatmaps.Formats; using osu.Game.Beatmaps.IO; using osu.Game.IO; using osu.Game.IPC; +using osu.Game.Overlays.Notifications; using osu.Game.Rulesets; using SQLite.Net; -using FileInfo = osu.Game.IO.FileInfo; namespace osu.Game.Beatmaps { @@ -47,6 +47,8 @@ namespace osu.Game.Beatmaps private readonly FileStore files; + private readonly SQLiteConnection connection; + private readonly RulesetStore rulesets; private readonly BeatmapStore beatmaps; @@ -54,6 +56,16 @@ namespace osu.Game.Beatmaps // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised) private BeatmapIPCChannel ipc; + /// + /// Set an endpoint for notifications to be posted to. + /// + public Action PostNotification { private get; set; } + + /// + /// Set a storage with access to an osu-stable install for import purposes. + /// + public Func GetStableStorage { private get; set; } + public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, IIpcHost importHost = null) { beatmaps = new BeatmapStore(connection); @@ -62,6 +74,7 @@ namespace osu.Game.Beatmaps this.storage = storage; this.files = files; + this.connection = connection; this.rulesets = rulesets; if (importHost != null) @@ -69,29 +82,48 @@ namespace osu.Game.Beatmaps } /// - /// Import multiple from filesystem . + /// Import one or more from filesystem . + /// This will post a notification tracking import progress. /// - /// Multiple locations on disk. + /// One or more beatmap locations on disk. public void Import(params string[] paths) { + var notification = new ProgressNotification + { + Text = "Beatmap import is initialising...", + Progress = 0, + State = ProgressNotificationState.Active, + }; + + PostNotification?.Invoke(notification); + + int i = 0; foreach (string path in paths) { + if (notification.State == ProgressNotificationState.Cancelled) + // user requested abort + return; + try { + notification.Text = $"Importing ({i} of {paths.Length})\n{Path.GetFileName(path)}"; using (ArchiveReader reader = getReaderFrom(path)) Import(reader); + notification.Progress = (float)++i / paths.Length; + // We may or may not want to delete the file depending on where it is stored. // e.g. reconstructing/repairing database with beatmaps from default storage. // Also, not always a single file, i.e. for LegacyFilesystemReader // TODO: Add a check to prevent files from storage to be deleted. try { - File.Delete(path); + if (File.Exists(path)) + File.Delete(path); } catch (Exception e) { - Logger.Error(e, $@"Could not delete file at {path}"); + Logger.Error(e, $@"Could not delete original file after import ({Path.GetFileName(path)})"); } } catch (Exception e) @@ -100,16 +132,24 @@ namespace osu.Game.Beatmaps Logger.Error(e, @"Could not import beatmap set"); } } + + notification.State = ProgressNotificationState.Completed; } + private readonly object importLock = new object(); + /// /// Import a beatmap from an . /// /// The beatmap to be imported. public BeatmapSetInfo Import(ArchiveReader archiveReader) { - BeatmapSetInfo set = importToStorage(archiveReader); - Import(set); + BeatmapSetInfo set = null; + + // let's only allow one concurrent import at a time for now. + lock (importLock) + connection.RunInTransaction(() => Import(set = importToStorage(archiveReader))); + return set; } @@ -122,7 +162,8 @@ namespace osu.Game.Beatmaps // If we have an ID then we already exist in the database. if (beatmapSetInfo.ID != 0) return; - beatmaps.Add(beatmapSetInfo); + lock (beatmaps) + beatmaps.Add(beatmapSetInfo); } /// @@ -132,10 +173,11 @@ namespace osu.Game.Beatmaps /// The beatmap to delete. public void Delete(BeatmapSetInfo beatmapSet) { - if (!beatmaps.Delete(beatmapSet)) return; + lock (beatmaps) + if (!beatmaps.Delete(beatmapSet)) return; if (!beatmapSet.Protected) - files.Dereference(beatmapSet.Files); + files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); } /// @@ -145,9 +187,11 @@ namespace osu.Game.Beatmaps /// The beatmap to restore. public void Undelete(BeatmapSetInfo beatmapSet) { - if (!beatmaps.Undelete(beatmapSet)) return; + lock (beatmaps) + if (!beatmaps.Undelete(beatmapSet)) return; - files.Reference(beatmapSet.Files); + if (!beatmapSet.Protected) + files.Reference(beatmapSet.Files.Select(f => f.FileInfo).ToArray()); } /// @@ -161,7 +205,8 @@ namespace osu.Game.Beatmaps if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) return DefaultBeatmap; - beatmaps.Populate(beatmapInfo); + lock (beatmaps) + beatmaps.Populate(beatmapInfo); if (beatmapInfo.BeatmapSet == null) throw new InvalidOperationException($@"Beatmap set {beatmapInfo.BeatmapSetInfoID} is not in the local database."); @@ -181,7 +226,8 @@ namespace osu.Game.Beatmaps /// public void Reset() { - beatmaps.Reset(); + lock (beatmaps) + beatmaps.Reset(); } /// @@ -191,12 +237,15 @@ namespace osu.Game.Beatmaps /// The first result for the provided query, or null if no results were found. public BeatmapSetInfo QueryBeatmapSet(Func query) { - BeatmapSetInfo set = beatmaps.Query().FirstOrDefault(query); + lock (beatmaps) + { + BeatmapSetInfo set = beatmaps.Query().FirstOrDefault(query); - if (set != null) - beatmaps.Populate(set); + if (set != null) + beatmaps.Populate(set); - return set; + return set; + } } /// @@ -204,7 +253,10 @@ namespace osu.Game.Beatmaps /// /// The query. /// Results from the provided query. - public List QueryBeatmapSets(Expression> query) => beatmaps.QueryAndPopulate(query); + public List QueryBeatmapSets(Expression> query) + { + lock (beatmaps) return beatmaps.QueryAndPopulate(query); + } /// /// Perform a lookup query on available s. @@ -213,12 +265,15 @@ namespace osu.Game.Beatmaps /// The first result for the provided query, or null if no results were found. public BeatmapInfo QueryBeatmap(Func query) { - BeatmapInfo set = beatmaps.Query().FirstOrDefault(query); + lock (beatmaps) + { + BeatmapInfo set = beatmaps.Query().FirstOrDefault(query); - if (set != null) - beatmaps.Populate(set); + if (set != null) + beatmaps.Populate(set); - return set; + return set; + } } /// @@ -226,7 +281,10 @@ namespace osu.Game.Beatmaps /// /// The query. /// Results from the provided query. - public List QueryBeatmaps(Expression> query) => beatmaps.QueryAndPopulate(query); + public List QueryBeatmaps(Expression> query) + { + lock (beatmaps) return beatmaps.QueryAndPopulate(query); + } /// /// Creates an from a valid storage path. @@ -258,19 +316,26 @@ namespace osu.Game.Beatmaps var hash = hashable.ComputeSHA2Hash(); // check if this beatmap has already been imported and exit early if so. - var beatmapSet = beatmaps.QueryAndPopulate().FirstOrDefault(b => b.Hash == hash); + BeatmapSetInfo beatmapSet; + lock (beatmaps) + beatmapSet = beatmaps.QueryAndPopulate(b => b.Hash == hash).FirstOrDefault(); + if (beatmapSet != null) { Undelete(beatmapSet); return beatmapSet; } - List fileInfos = new List(); + List fileInfos = new List(); // import files to manager foreach (string file in reader.Filenames) using (Stream s = reader.GetStream(file)) - fileInfos.Add(files.Add(s, file)); + fileInfos.Add(new BeatmapSetFileInfo + { + Filename = file, + FileInfo = files.Add(s) + }); BeatmapMetadata metadata; @@ -325,10 +390,13 @@ namespace osu.Game.Beatmaps /// A list of available . public List GetAllUsableBeatmapSets(bool populate = true) { - if (populate) - return beatmaps.QueryAndPopulate(b => !b.DeletePending).ToList(); - else - return beatmaps.Query(b => !b.DeletePending).ToList(); + lock (beatmaps) + { + if (populate) + return beatmaps.QueryAndPopulate(b => !b.DeletePending).ToList(); + else + return beatmaps.Query(b => !b.DeletePending).ToList(); + } } protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap @@ -366,7 +434,7 @@ namespace osu.Game.Beatmaps catch { return null; } } - private string getPathForFile(string filename) => BeatmapSetInfo.Files.First(f => f.Filename == filename).StoragePath; + private string getPathForFile(string filename) => BeatmapSetInfo.Files.First(f => f.Filename == filename).FileInfo.StoragePath; protected override Texture GetBackground() { @@ -390,5 +458,51 @@ namespace osu.Game.Beatmaps catch { return new TrackVirtual(); } } } + + /// + /// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future. + /// + public void ImportFromStable() + { + var stable = GetStableStorage?.Invoke(); + + if (stable == null) + { + Logger.Log("No osu!stable installation available!", LoggingTarget.Information, LogLevel.Error); + return; + } + + Import(stable.GetDirectories("Songs")); + } + + public void DeleteAll() + { + var maps = GetAllUsableBeatmapSets().ToArray(); + + if (maps.Length == 0) return; + + var notification = new ProgressNotification + { + Progress = 0, + State = ProgressNotificationState.Active, + }; + + PostNotification?.Invoke(notification); + + int i = 0; + + foreach (var b in maps) + { + if (notification.State == ProgressNotificationState.Cancelled) + // user requested abort + return; + + notification.Text = $"Deleting ({i} of {maps.Length})"; + notification.Progress = (float)++i / maps.Length; + Delete(b); + } + + notification.State = ProgressNotificationState.Completed; + } } } diff --git a/osu.Game/Beatmaps/BeatmapSetFileInfo.cs b/osu.Game/Beatmaps/BeatmapSetFileInfo.cs index d18b1e833b..a05362b32d 100644 --- a/osu.Game/Beatmaps/BeatmapSetFileInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetFileInfo.cs @@ -2,16 +2,26 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Game.IO; +using SQLite.Net.Attributes; using SQLiteNetExtensions.Attributes; namespace osu.Game.Beatmaps { public class BeatmapSetFileInfo { - [ForeignKey(typeof(BeatmapSetInfo))] + [PrimaryKey, AutoIncrement] + public int ID { get; set; } + + [ForeignKey(typeof(BeatmapSetInfo)), NotNull] public int BeatmapSetInfoID { get; set; } - [ForeignKey(typeof(FileInfo))] + [ForeignKey(typeof(FileInfo)), NotNull] public int FileInfoID { get; set; } + + [OneToOne(CascadeOperations = CascadeOperation.CascadeRead)] + public FileInfo FileInfo { get; set; } + + [NotNull] + public string Filename { get; set; } } } \ No newline at end of file diff --git a/osu.Game/Beatmaps/BeatmapSetInfo.cs b/osu.Game/Beatmaps/BeatmapSetInfo.cs index a99ba94e9a..f47affcab8 100644 --- a/osu.Game/Beatmaps/BeatmapSetInfo.cs +++ b/osu.Game/Beatmaps/BeatmapSetInfo.cs @@ -3,7 +3,6 @@ using System.Collections.Generic; using System.Linq; -using osu.Game.IO; using SQLite.Net.Attributes; using SQLiteNetExtensions.Attributes; @@ -37,8 +36,8 @@ namespace osu.Game.Beatmaps public string StoryboardFile => Files.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename; - [ManyToMany(typeof(BeatmapSetFileInfo), CascadeOperations = CascadeOperation.CascadeRead)] - public List Files { get; set; } + [OneToMany(CascadeOperations = CascadeOperation.All)] + public List Files { get; set; } public bool Protected { get; set; } } diff --git a/osu.Game/Beatmaps/BeatmapStore.cs b/osu.Game/Beatmaps/BeatmapStore.cs index 102900ae81..2ec9a7d759 100644 --- a/osu.Game/Beatmaps/BeatmapStore.cs +++ b/osu.Game/Beatmaps/BeatmapStore.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using osu.Framework.Logging; using osu.Game.Database; using SQLite.Net; using SQLiteNetExtensions.Extensions; @@ -21,7 +20,7 @@ namespace osu.Game.Beatmaps /// The current version of this store. Used for migrations (see ). /// The initial version is 1. /// - protected override int StoreVersion => 1; + protected override int StoreVersion => 2; public BeatmapStore(SQLiteConnection connection) : base(connection) @@ -52,7 +51,11 @@ namespace osu.Game.Beatmaps Connection.CreateTable(); Connection.CreateTable(); Connection.CreateTable(); + } + protected override void StartupTasks() + { + base.StartupTasks(); cleanupPendingDeletions(); } @@ -60,24 +63,19 @@ namespace osu.Game.Beatmaps /// Perform migrations between two store versions. /// /// The current store version. This will be zero on a fresh database initialisation. - /// The target version which we are migrating to (equal to the current ). - protected override void PerformMigration(int currentVersion, int newVersion) + /// The target version which we are migrating to (equal to the current ). + protected override void PerformMigration(int currentVersion, int targetVersion) { - base.PerformMigration(currentVersion, newVersion); + base.PerformMigration(currentVersion, targetVersion); - while (currentVersion++ < newVersion) + while (currentVersion++ < targetVersion) { switch (currentVersion) { case 1: - // initialising from a version before we had versioning (or a fresh install). - - // force adding of Protected column (not automatically migrated). - Connection.MigrateTable(); - - // remove all existing beatmaps. - foreach (var b in Connection.GetAllWithChildren(null, true)) - Connection.Delete(b, true); + case 2: + // cannot migrate; breaking underlying changes. + Reset(); break; } } @@ -131,23 +129,11 @@ namespace osu.Game.Beatmaps private void cleanupPendingDeletions() { - foreach (var b in QueryAndPopulate(b => b.DeletePending && !b.Protected)) + Connection.RunInTransaction(() => { - try - { - // many-to-many join table entries are not automatically tidied. - Connection.Table().Delete(f => f.BeatmapSetInfoID == b.ID); + foreach (var b in QueryAndPopulate(b => b.DeletePending && !b.Protected)) Connection.Delete(b, true); - } - catch (Exception e) - { - Logger.Error(e, $@"Could not delete beatmap {b}"); - } - } - - //this is required because sqlite migrations don't work, initially inserting nulls into this field. - //see https://github.com/praeclarum/sqlite-net/issues/326 - Connection.Query("UPDATE BeatmapSetInfo SET DeletePending = 0 WHERE DeletePending IS NULL"); + }); } } } diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index f61380bfb8..42db025a40 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -4,8 +4,8 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using OpenTK; -using OpenTK.Graphics; namespace osu.Game.Beatmaps.Drawables { @@ -22,23 +22,20 @@ namespace osu.Game.Beatmaps.Drawables [BackgroundDependencyLoader] private void load() { - Children = new[] + Children = new Drawable[] { - new TextAwesome + new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - TextSize = Size.X, + RelativeSizeAxes = Axes.Both, Colour = AccentColour, Icon = FontAwesome.fa_circle }, - new TextAwesome + new ConstrainedIconContainer { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - TextSize = Size.X, - Colour = Color4.White, - Icon = beatmap.Ruleset.CreateInstance().Icon + RelativeSizeAxes = Axes.Both, + Icon = beatmap.Ruleset.CreateInstance().CreateIcon() } }; } diff --git a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs index 4c540fa8cf..433c23284f 100644 --- a/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs +++ b/osu.Game/Beatmaps/Formats/OsuLegacyDecoder.cs @@ -456,6 +456,11 @@ namespace osu.Game.Beatmaps.Formats handleColours(beatmap, line, ref hasCustomColours); break; case Section.HitObjects: + + // If the ruleset wasn't specified, assume the osu!standard ruleset. + if (parser == null) + parser = new Rulesets.Objects.Legacy.Osu.ConvertHitObjectParser(); + var obj = parser.Parse(line); if (obj != null) diff --git a/osu.Game/Database/DatabaseBackedStore.cs b/osu.Game/Database/DatabaseBackedStore.cs index bb61fc1870..d8e2e35bd7 100644 --- a/osu.Game/Database/DatabaseBackedStore.cs +++ b/osu.Game/Database/DatabaseBackedStore.cs @@ -41,7 +41,7 @@ namespace osu.Game.Database { var storeName = GetType().Name; - var reportedVersion = Connection.Table().FirstOrDefault(s => s.StoreName == storeName) ?? new StoreVersion + var reportedVersion = Connection.Table().Where(s => s.StoreName == storeName).FirstOrDefault() ?? new StoreVersion { StoreName = storeName, Version = 0 @@ -51,14 +51,30 @@ namespace osu.Game.Database PerformMigration(reportedVersion.Version, reportedVersion.Version = StoreVersion); Connection.InsertOrReplace(reportedVersion); + + StartupTasks(); } - protected virtual void PerformMigration(int currentVersion, int newVersion) + /// + /// Called when the database version of this store doesn't match the local version. + /// Any manual migration operations should be performed in this. + /// + /// The current store version. This will be zero on a fresh database initialisation. + /// The target version which we are migrating to (equal to the current ). + protected virtual void PerformMigration(int currentVersion, int targetVersion) { } /// - /// Prepare this database for use. + /// Perform any common startup tasks. Runs after and . + /// + protected virtual void StartupTasks() + { + + } + + /// + /// Prepare this database for use. Tables should be created here. /// protected abstract void Prepare(bool reset = false); @@ -83,9 +99,9 @@ namespace osu.Game.Database /// /// Query and populate results. /// - /// An optional filter to refine results. + /// An filter to refine results. /// - public List QueryAndPopulate(Expression> filter = null) + public List QueryAndPopulate(Expression> filter) where T : class { checkType(typeof(T)); @@ -101,7 +117,6 @@ namespace osu.Game.Database public void Populate(T item, bool recursive = true) { checkType(item.GetType()); - Connection.GetChildren(item, recursive); } diff --git a/osu.Game/Graphics/Containers/ConstrainedIconContainer.cs b/osu.Game/Graphics/Containers/ConstrainedIconContainer.cs new file mode 100644 index 0000000000..dd2a265a0f --- /dev/null +++ b/osu.Game/Graphics/Containers/ConstrainedIconContainer.cs @@ -0,0 +1,62 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using OpenTK; + +namespace osu.Game.Graphics.Containers +{ + /// + /// Display an icon that is forced to scale to the size of this container. + /// + public class ConstrainedIconContainer : CompositeDrawable + { + public Drawable Icon + { + get + { + return InternalChild; + } + + set + { + InternalChild = value; + } + } + + /// + /// Determines an edge effect of this . + /// Edge effects are e.g. glow or a shadow. + /// Only has an effect when is true. + /// + public new EdgeEffectParameters EdgeEffect + { + get { return base.EdgeEffect; } + set { base.EdgeEffect = value; } + } + + protected override void Update() + { + base.Update(); + if (InternalChildren.Count > 0 && InternalChild.DrawSize.X > 0) + { + // We're modifying scale here for a few reasons + // - Guarantees correctness if BorderWidth is being used + // - If we were to use RelativeSize/FillMode, we'd need to set the Icon's RelativeSizeAxes directly. + // We can't do this because we would need access to AutoSizeAxes to set it to none. + // Other issues come up along the way too, so it's not a good solution. + var fitScale = Math.Min(DrawSize.X / InternalChild.DrawSize.X, DrawSize.Y / InternalChild.DrawSize.Y); + InternalChild.Scale = new Vector2(fitScale); + InternalChild.Anchor = Anchor.Centre; + InternalChild.Origin = Anchor.Centre; + } + } + + public ConstrainedIconContainer() + { + Masking = true; + } + } +} diff --git a/osu.Game/Graphics/TextAwesome.cs b/osu.Game/Graphics/SpriteIcon.cs similarity index 90% rename from osu.Game/Graphics/TextAwesome.cs rename to osu.Game/Graphics/SpriteIcon.cs index 69b0217444..345c6e7639 100644 --- a/osu.Game/Graphics/TextAwesome.cs +++ b/osu.Game/Graphics/SpriteIcon.cs @@ -1,13 +1,70 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Game.Graphics.Sprites; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics; +using osu.Framework.IO.Stores; +using OpenTK; +using OpenTK.Graphics; namespace osu.Game.Graphics { - public class TextAwesome : OsuSpriteText + public class SpriteIcon : CompositeDrawable { - //public override FontFace FontFace => (int)Icon < 0xf000 ? FontFace.OsuFont : FontFace.FontAwesome; + private readonly Sprite spriteShadow; + private readonly Sprite spriteMain; + + public SpriteIcon() + { + InternalChildren = new[] + { + spriteShadow = new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit, + Position = new Vector2(0, 0.06f), + Colour = new Color4(0f, 0f, 0f, 0.2f), + Alpha = 0 + }, + spriteMain = new Sprite + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + FillMode = FillMode.Fit + }, + }; + } + + private FontStore store; + + [BackgroundDependencyLoader] + private void load(FontStore store) + { + this.store = store; + updateTexture(); + } + + private void updateTexture() + { + var texture = store?.Get(((char)icon).ToString()); + + spriteMain.Texture = texture; + spriteShadow.Texture = texture; + + if (Size == Vector2.Zero) + Size = new Vector2(texture?.DisplayWidth ?? 0, texture?.DisplayHeight ?? 0); + } + + public bool Shadow + { + get { return spriteShadow.IsPresent; } + set { spriteShadow.Alpha = value ? 1 : 0; } + } private FontAwesome icon; @@ -23,7 +80,8 @@ namespace osu.Game.Graphics if (icon == value) return; icon = value; - Text = ((char)icon).ToString(); + if (IsLoaded) + updateTexture(); } } } diff --git a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs index f61192a1a6..b3e53280fb 100644 --- a/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs +++ b/osu.Game/Graphics/UserInterface/BreadcrumbControl.cs @@ -35,7 +35,7 @@ namespace osu.Game.Graphics.UserInterface private class BreadcrumbTabItem : OsuTabItem, IStateful { - public readonly TextAwesome Chevron; + public readonly SpriteIcon Chevron; //don't allow clicking between transitions and don't make the chevron clickable public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Alpha == 1f && Text.ReceiveMouseInputAt(screenSpacePos); @@ -69,11 +69,11 @@ namespace osu.Game.Graphics.UserInterface { Text.TextSize = 16; Padding = new MarginPadding { Right = padding + 8 }; //padding + chevron width - Add(Chevron = new TextAwesome + Add(Chevron = new SpriteIcon { Anchor = Anchor.CentreRight, Origin = Anchor.CentreLeft, - TextSize = 12, + Size = new Vector2(12), Icon = FontAwesome.fa_chevron_right, Margin = new MarginPadding { Left = padding }, Alpha = 0f, diff --git a/osu.Game/Graphics/UserInterface/IconButton.cs b/osu.Game/Graphics/UserInterface/IconButton.cs index 1598ace9df..1808dc4b6c 100644 --- a/osu.Game/Graphics/UserInterface/IconButton.cs +++ b/osu.Game/Graphics/UserInterface/IconButton.cs @@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterface { public class IconButton : OsuClickableContainer { - private readonly TextAwesome icon; + private readonly SpriteIcon icon; private readonly Box hover; private readonly Container content; @@ -47,7 +47,7 @@ namespace osu.Game.Graphics.UserInterface { Origin = Anchor.Centre, Anchor = Anchor.Centre, - Size = new Vector2 (button_size), + Size = new Vector2(button_size), CornerRadius = 5, Masking = true, @@ -64,11 +64,11 @@ namespace osu.Game.Graphics.UserInterface RelativeSizeAxes = Axes.Both, Alpha = 0, }, - icon = new TextAwesome + icon = new SpriteIcon { Origin = Anchor.Centre, Anchor = Anchor.Centre, - TextSize = 18, + Size = new Vector2(18), } } } @@ -80,6 +80,8 @@ namespace osu.Game.Graphics.UserInterface { hover.Colour = colours.Yellow.Opacity(0.6f); flashColour = colours.Yellow; + + Enabled.ValueChanged += enabled => this.FadeColour(enabled ? Color4.White : colours.Gray9, 200, Easing.OutQuint); } protected override bool OnHover(InputState state) diff --git a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs b/osu.Game/Graphics/UserInterface/LoadingAnimation.cs index 56ee47a7e6..eb8ff5be86 100644 --- a/osu.Game/Graphics/UserInterface/LoadingAnimation.cs +++ b/osu.Game/Graphics/UserInterface/LoadingAnimation.cs @@ -9,7 +9,7 @@ namespace osu.Game.Graphics.UserInterface { public class LoadingAnimation : VisibilityContainer { - private readonly TextAwesome spinner; + private readonly SpriteIcon spinner; public LoadingAnimation() { @@ -20,9 +20,9 @@ namespace osu.Game.Graphics.UserInterface Children = new Drawable[] { - spinner = new TextAwesome + spinner = new SpriteIcon { - TextSize = 20, + Size = new Vector2(20), Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = FontAwesome.fa_spinner diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs index 6dadd63ac4..f5a4219707 100644 --- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs +++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.Sprites; +using OpenTK; namespace osu.Game.Graphics.UserInterface { @@ -60,14 +61,13 @@ namespace osu.Game.Graphics.UserInterface AutoSizeAxes = Axes.Y, Children = new Drawable[] { - Chevron = new TextAwesome + Chevron = new SpriteIcon { AlwaysPresent = true, Icon = FontAwesome.fa_chevron_right, - UseFullGlyphHeight = false, Colour = Color4.Black, Alpha = 0.5f, - TextSize = 8, + Size = new Vector2(8), Margin = new MarginPadding { Left = 3, Right = 3 }, Origin = Anchor.CentreLeft, Anchor = Anchor.CentreLeft, @@ -84,7 +84,7 @@ namespace osu.Game.Graphics.UserInterface private Color4? accentColour; - protected readonly TextAwesome Chevron; + protected readonly SpriteIcon Chevron; protected readonly OsuSpriteText Label; protected override void FormatForeground(bool hover = false) @@ -123,7 +123,7 @@ namespace osu.Game.Graphics.UserInterface set { Text.Text = value; } } - protected readonly TextAwesome Icon; + protected readonly SpriteIcon Icon; private Color4? accentColour; public virtual Color4 AccentColour @@ -152,13 +152,13 @@ namespace osu.Game.Graphics.UserInterface Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, }, - Icon = new TextAwesome + Icon = new SpriteIcon { Icon = FontAwesome.fa_chevron_down, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, Margin = new MarginPadding { Right = 4 }, - TextSize = 20 + Size = new Vector2(20), } }; } diff --git a/osu.Game/Graphics/UserInterface/OsuTabControl.cs b/osu.Game/Graphics/UserInterface/OsuTabControl.cs index 8c16c048ea..5ad412965c 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControl.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControl.cs @@ -209,10 +209,10 @@ namespace osu.Game.Graphics.UserInterface Foreground.Children = new Drawable[] { - new TextAwesome + new SpriteIcon { Icon = FontAwesome.fa_ellipsis_h, - TextSize = 14, + Size = new Vector2(14), Origin = Anchor.Centre, Anchor = Anchor.Centre, } diff --git a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs index 57a87dc74b..a0d48e5ebe 100644 --- a/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs +++ b/osu.Game/Graphics/UserInterface/OsuTabControlCheckbox.cs @@ -21,7 +21,7 @@ namespace osu.Game.Graphics.UserInterface { private readonly Box box; private readonly SpriteText text; - private readonly TextAwesome icon; + private readonly SpriteIcon icon; private Color4? accentColour; public Color4 AccentColour @@ -99,9 +99,9 @@ namespace osu.Game.Graphics.UserInterface TextSize = 14, Font = @"Exo2.0-Bold", }, - icon = new TextAwesome + icon = new SpriteIcon { - TextSize = 14, + Size = new Vector2(14), Icon = FontAwesome.fa_circle_o, Shadow = true, }, diff --git a/osu.Game/Graphics/UserInterface/SearchTextBox.cs b/osu.Game/Graphics/UserInterface/SearchTextBox.cs index a2cd2ba5ea..ee5d3baf66 100644 --- a/osu.Game/Graphics/UserInterface/SearchTextBox.cs +++ b/osu.Game/Graphics/UserInterface/SearchTextBox.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Framework.Input; +using OpenTK; using OpenTK.Input; namespace osu.Game.Graphics.UserInterface @@ -16,13 +17,13 @@ namespace osu.Game.Graphics.UserInterface Height = 35; AddRange(new Drawable[] { - new TextAwesome + new SpriteIcon { Icon = FontAwesome.fa_search, Origin = Anchor.CentreRight, Anchor = Anchor.CentreRight, Margin = new MarginPadding { Right = 10 }, - TextSize = 20 + Size = new Vector2(20), } }); diff --git a/osu.Game/Graphics/UserInterface/StarCounter.cs b/osu.Game/Graphics/UserInterface/StarCounter.cs index 6c5204fed4..e581d19d54 100644 --- a/osu.Game/Graphics/UserInterface/StarCounter.cs +++ b/osu.Game/Graphics/UserInterface/StarCounter.cs @@ -142,16 +142,16 @@ namespace osu.Game.Graphics.UserInterface private class Star : Container { - public readonly TextAwesome Icon; + public readonly SpriteIcon Icon; public Star() { Size = new Vector2(star_size); Children = new[] { - Icon = new TextAwesome + Icon = new SpriteIcon { - TextSize = star_size, + Size = new Vector2(star_size), Icon = FontAwesome.fa_star, Anchor = Anchor.Centre, Origin = Anchor.Centre, diff --git a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs index f290f4fadd..f17b307826 100644 --- a/osu.Game/Graphics/UserInterface/TwoLayerButton.cs +++ b/osu.Game/Graphics/UserInterface/TwoLayerButton.cs @@ -215,7 +215,7 @@ namespace osu.Game.Graphics.UserInterface { private const double beat_in_time = 60; - private readonly TextAwesome icon; + private readonly SpriteIcon icon; public FontAwesome Icon { set { icon.Icon = value; } } @@ -226,11 +226,11 @@ namespace osu.Game.Graphics.UserInterface Children = new Drawable[] { - icon = new TextAwesome + icon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - TextSize = 25 + Size = new Vector2(25), } }; } diff --git a/osu.Game/IO/FileInfo.cs b/osu.Game/IO/FileInfo.cs index 6f4c4b26e8..367fd68f7b 100644 --- a/osu.Game/IO/FileInfo.cs +++ b/osu.Game/IO/FileInfo.cs @@ -11,8 +11,6 @@ namespace osu.Game.IO [PrimaryKey, AutoIncrement] public int ID { get; set; } - public string Filename { get; set; } - [Indexed(Unique = true)] public string Hash { get; set; } diff --git a/osu.Game/IO/FileStore.cs b/osu.Game/IO/FileStore.cs index e8cabafe17..1011fa3236 100644 --- a/osu.Game/IO/FileStore.cs +++ b/osu.Game/IO/FileStore.cs @@ -2,7 +2,6 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System; -using System.Collections.Generic; using System.IO; using System.Linq; using osu.Framework.Extensions; @@ -23,6 +22,8 @@ namespace osu.Game.IO public readonly ResourceStore Store; + protected override int StoreVersion => 2; + public FileStore(SQLiteConnection connection, Storage storage) : base(connection, storage) { Store = new NamespacedResourceStore(new StorageBackedResourceStore(storage), prefix); @@ -35,25 +36,55 @@ namespace osu.Game.IO protected override void Prepare(bool reset = false) { if (reset) + { + // in earlier versions we stored beatmaps as solid archives, but not any more. + if (Storage.ExistsDirectory("beatmaps")) + Storage.DeleteDirectory("beatmaps"); + + if (Storage.ExistsDirectory(prefix)) + Storage.DeleteDirectory(prefix); + Connection.DropTable(); + } Connection.CreateTable(); + } + protected override void StartupTasks() + { + base.StartupTasks(); deletePending(); } - public FileInfo Add(Stream data, string filename = null) + /// + /// Perform migrations between two store versions. + /// + /// The current store version. This will be zero on a fresh database initialisation. + /// The target version which we are migrating to (equal to the current ). + protected override void PerformMigration(int currentVersion, int targetVersion) + { + base.PerformMigration(currentVersion, targetVersion); + + while (currentVersion++ < targetVersion) + { + switch (currentVersion) + { + case 1: + case 2: + // cannot migrate; breaking underlying changes. + Reset(); + break; + } + } + } + + public FileInfo Add(Stream data) { string hash = data.ComputeSHA2Hash(); - var info = new FileInfo - { - Filename = filename, - Hash = hash, - }; - - var existing = Connection.Table().FirstOrDefault(f => f.Hash == info.Hash); + var existing = Connection.Table().Where(f => f.Hash == hash).FirstOrDefault(); + var info = existing ?? new FileInfo { Hash = hash }; if (existing != null) { info = existing; @@ -73,42 +104,57 @@ namespace osu.Game.IO Connection.Insert(info); } - Reference(new[] { info }); + Reference(info); return info; } - public void Reference(IEnumerable files) + public void Reference(params FileInfo[] files) { - foreach (var f in files) + Connection.RunInTransaction(() => { - f.ReferenceCount++; - Connection.Update(f); - } + var incrementedFiles = files.GroupBy(f => f.ID).Select(f => + { + var accurateRefCount = Connection.Get(f.First().ID); + accurateRefCount.ReferenceCount += f.Count(); + return accurateRefCount; + }); + + Connection.UpdateAll(incrementedFiles); + }); } - public void Dereference(IEnumerable files) + public void Dereference(params FileInfo[] files) { - foreach (var f in files) + Connection.RunInTransaction(() => { - f.ReferenceCount--; - Connection.Update(f); - } + var incrementedFiles = files.GroupBy(f => f.ID).Select(f => + { + var accurateRefCount = Connection.Get(f.First().ID); + accurateRefCount.ReferenceCount -= f.Count(); + return accurateRefCount; + }); + + Connection.UpdateAll(incrementedFiles); + }); } private void deletePending() { - foreach (var f in QueryAndPopulate(f => f.ReferenceCount < 1)) + Connection.RunInTransaction(() => { - try + foreach (var f in Query(f => f.ReferenceCount < 1)) { - Connection.Delete(f); - Storage.Delete(Path.Combine(prefix, f.Hash)); + try + { + Storage.Delete(Path.Combine(prefix, f.StoragePath)); + Connection.Delete(f); + } + catch (Exception e) + { + Logger.Error(e, $@"Could not delete beatmap {f}"); + } } - catch (Exception e) - { - Logger.Error(e, $@"Could not delete beatmap {f}"); - } - } + }); } } } \ No newline at end of file diff --git a/osu.Game/Online/Multiplayer/GameType.cs b/osu.Game/Online/Multiplayer/GameType.cs index 22e2ffac31..c94b409d1b 100644 --- a/osu.Game/Online/Multiplayer/GameType.cs +++ b/osu.Game/Online/Multiplayer/GameType.cs @@ -21,15 +21,14 @@ namespace osu.Game.Online.Multiplayer public override string Name => "Tag"; public override Drawable GetIcon(OsuColour colours, float size) { - return new TextAwesome + return new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = FontAwesome.fa_refresh, - TextSize = size, + Size = new Vector2(size), Colour = colours.Blue, Shadow = false, - UseFullGlyphHeight = false, }; } } @@ -61,21 +60,19 @@ namespace osu.Game.Online.Multiplayer Spacing = new Vector2(2f), Children = new[] { - new TextAwesome + new SpriteIcon { Icon = FontAwesome.fa_refresh, - TextSize = size * 0.75f, + Size = new Vector2(size * 0.75f), Colour = colours.Blue, Shadow = false, - UseFullGlyphHeight = false, }, - new TextAwesome + new SpriteIcon { Icon = FontAwesome.fa_refresh, - TextSize = size * 0.75f, + Size = new Vector2(size * 0.75f), Colour = colours.Pink, Shadow = false, - UseFullGlyphHeight = false, }, }, }; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 2b1396ac71..5fd04a92ab 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -20,6 +20,7 @@ using osu.Game.Screens.Menu; using OpenTK; using System.Linq; using System.Threading.Tasks; +using osu.Framework.Platform; using osu.Framework.Threading; using osu.Game.Graphics; using osu.Game.Rulesets.Scoring; @@ -47,6 +48,8 @@ namespace osu.Game private UserProfileOverlay userProfile; + public virtual Storage GetStorageForStableInstall() => null; + private Intro intro { get @@ -149,6 +152,10 @@ namespace osu.Game { base.LoadComplete(); + // hook up notifications to components. + BeatmapManager.PostNotification = n => notificationOverlay?.Post(n); + BeatmapManager.GetStableStorage = GetStorageForStableInstall; + AddRange(new Drawable[] { new VolumeControlReceptor { @@ -332,6 +339,7 @@ namespace osu.Game direct.State = Visibility.Hidden; social.State = Visibility.Hidden; userProfile.State = Visibility.Hidden; + notificationOverlay.State = Visibility.Hidden; } else { diff --git a/osu.Game/Overlays/Chat/ChannelListItem.cs b/osu.Game/Overlays/Chat/ChannelListItem.cs index 791377187b..f43154ea20 100644 --- a/osu.Game/Overlays/Chat/ChannelListItem.cs +++ b/osu.Game/Overlays/Chat/ChannelListItem.cs @@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Chat private readonly Bindable joinedBind = new Bindable(); private readonly OsuSpriteText name; private readonly OsuSpriteText topic; - private readonly TextAwesome joinedCheckmark; + private readonly SpriteIcon joinedCheckmark; private Color4 joinedColour; private Color4 topicColour; @@ -68,12 +68,12 @@ namespace osu.Game.Overlays.Chat { Children = new[] { - joinedCheckmark = new TextAwesome + joinedCheckmark = new SpriteIcon { Anchor = Anchor.TopRight, Origin = Anchor.TopRight, Icon = FontAwesome.fa_check_circle, - TextSize = text_size, + Size = new Vector2(text_size), Shadow = false, Margin = new MarginPadding { Right = 10f }, Alpha = 0f, @@ -121,10 +121,10 @@ namespace osu.Game.Overlays.Chat Spacing = new Vector2(3f, 0f), Children = new Drawable[] { - new TextAwesome + new SpriteIcon { Icon = FontAwesome.fa_user, - TextSize = text_size - 2, + Size = new Vector2(text_size - 2), Shadow = false, Margin = new MarginPadding { Top = 1 }, }, diff --git a/osu.Game/Overlays/Chat/ChatTabControl.cs b/osu.Game/Overlays/Chat/ChatTabControl.cs index c3c930eba0..4ff9169877 100644 --- a/osu.Game/Overlays/Chat/ChatTabControl.cs +++ b/osu.Game/Overlays/Chat/ChatTabControl.cs @@ -35,13 +35,13 @@ namespace osu.Game.Overlays.Chat TabContainer.Spacing = new Vector2(-shear_width, 0); TabContainer.Masking = false; - AddInternal(new TextAwesome + AddInternal(new SpriteIcon { Icon = FontAwesome.fa_comments, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, - TextSize = 20, - Padding = new MarginPadding(10), + Size = new Vector2(20), + Margin = new MarginPadding(10), }); AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" })); @@ -72,7 +72,7 @@ namespace osu.Game.Overlays.Chat private readonly SpriteText textBold; private readonly Box box; private readonly Box highlightBox; - private readonly TextAwesome icon; + private readonly SpriteIcon icon; private void updateState() { @@ -176,7 +176,7 @@ namespace osu.Game.Overlays.Chat RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - icon = new TextAwesome + icon = new SpriteIcon { Icon = FontAwesome.fa_hashtag, Anchor = Anchor.CentreLeft, @@ -184,7 +184,7 @@ namespace osu.Game.Overlays.Chat Colour = Color4.Black, X = -10, Alpha = 0.2f, - TextSize = ChatOverlay.TAB_AREA_HEIGHT, + Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT), }, text = new OsuSpriteText { diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs index 97aae2f49c..9b19b8150e 100644 --- a/osu.Game/Overlays/Dialog/PopupDialog.cs +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -30,14 +30,14 @@ namespace osu.Game.Overlays.Dialog private readonly Container content; private readonly Container ring; private readonly FillFlowContainer buttonsContainer; - private readonly TextAwesome iconText; + private readonly SpriteIcon icon; private readonly SpriteText header; private readonly SpriteText body; public FontAwesome Icon { - get { return iconText.Icon; } - set { iconText.Icon = value; } + get { return icon.Icon; } + set { icon.Icon = value; } } public string HeaderText @@ -205,12 +205,12 @@ namespace osu.Game.Overlays.Dialog RelativeSizeAxes = Axes.Both, Colour = Color4.Black.Opacity(0), }, - iconText = new TextAwesome + icon = new SpriteIcon { Origin = Anchor.Centre, Anchor = Anchor.Centre, Icon = FontAwesome.fa_close, - TextSize = 50, + Size = new Vector2(50), }, }, }, diff --git a/osu.Game/Overlays/Direct/DirectListPanel.cs b/osu.Game/Overlays/Direct/DirectListPanel.cs index b9063a5c82..5b45fc7725 100644 --- a/osu.Game/Overlays/Direct/DirectListPanel.cs +++ b/osu.Game/Overlays/Direct/DirectListPanel.cs @@ -152,18 +152,17 @@ namespace osu.Game.Overlays.Direct private class DownloadButton : OsuClickableContainer { - private readonly TextAwesome icon; + private readonly SpriteIcon icon; public DownloadButton() { Children = new Drawable[] { - icon = new TextAwesome + icon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - UseFullGlyphHeight = false, - TextSize = 30, + Size = new Vector2(30), Icon = FontAwesome.fa_osu_chevron_down_o, }, }; diff --git a/osu.Game/Overlays/Direct/DirectPanel.cs b/osu.Game/Overlays/Direct/DirectPanel.cs index 75619d9ba4..2f048b0e3d 100644 --- a/osu.Game/Overlays/Direct/DirectPanel.cs +++ b/osu.Game/Overlays/Direct/DirectPanel.cs @@ -75,11 +75,11 @@ namespace osu.Game.Overlays.Direct { Font = @"Exo2.0-SemiBoldItalic", }, - new TextAwesome + new SpriteIcon { Icon = icon, Shadow = true, - TextSize = 14, + Size = new Vector2(14), Margin = new MarginPadding { Top = 1 }, }, }; diff --git a/osu.Game/Overlays/Direct/FilterControl.cs b/osu.Game/Overlays/Direct/FilterControl.cs index 4f815f220c..28d26d0641 100644 --- a/osu.Game/Overlays/Direct/FilterControl.cs +++ b/osu.Game/Overlays/Direct/FilterControl.cs @@ -47,7 +47,11 @@ namespace osu.Game.Overlays.Direct private class RulesetToggleButton : OsuClickableContainer { - private readonly TextAwesome icon; + private Drawable icon + { + get { return iconContainer.Icon; } + set { iconContainer.Icon = value; } + } private RulesetInfo ruleset; public RulesetInfo Ruleset @@ -56,15 +60,17 @@ namespace osu.Game.Overlays.Direct set { ruleset = value; - icon.Icon = Ruleset.CreateInstance().Icon; + icon = Ruleset.CreateInstance().CreateIcon(); } } private readonly Bindable bindable; + private readonly ConstrainedIconContainer iconContainer; + private void Bindable_ValueChanged(RulesetInfo obj) { - icon.FadeTo(Ruleset.ID == obj?.ID ? 1f : 0.5f, 100); + iconContainer.FadeTo(Ruleset.ID == obj?.ID ? 1f : 0.5f, 100); } public RulesetToggleButton(Bindable bindable, RulesetInfo ruleset) @@ -74,11 +80,11 @@ namespace osu.Game.Overlays.Direct Children = new[] { - icon = new TextAwesome + iconContainer = new ConstrainedIconContainer { Origin = Anchor.TopLeft, Anchor = Anchor.TopLeft, - TextSize = 32, + Size = new Vector2(32), } }; diff --git a/osu.Game/Overlays/Music/CollectionsDropdown.cs b/osu.Game/Overlays/Music/CollectionsDropdown.cs index f6016fd1db..0c0a636be8 100644 --- a/osu.Game/Overlays/Music/CollectionsDropdown.cs +++ b/osu.Game/Overlays/Music/CollectionsDropdown.cs @@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Music { CornerRadius = 5; Height = 30; - Icon.TextSize = 14; + Icon.Size = new Vector2(14); Icon.Margin = new MarginPadding(0); Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 10, Right = 10 }; EdgeEffect = new EdgeEffectParameters diff --git a/osu.Game/Overlays/Music/PlaylistItem.cs b/osu.Game/Overlays/Music/PlaylistItem.cs index 1e3e48b17a..4145a8d1f0 100644 --- a/osu.Game/Overlays/Music/PlaylistItem.cs +++ b/osu.Game/Overlays/Music/PlaylistItem.cs @@ -12,6 +12,7 @@ using osu.Framework.Localisation; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using OpenTK; namespace osu.Game.Overlays.Music { @@ -22,7 +23,7 @@ namespace osu.Game.Overlays.Music private Color4 hoverColour; private Color4 artistColour; - private TextAwesome handle; + private SpriteIcon handle; private TextFlowContainer text; private IEnumerable titleSprites; private UnicodeBindableString titleBind; @@ -67,16 +68,15 @@ namespace osu.Game.Overlays.Music Children = new Drawable[] { - handle = new TextAwesome + handle = new SpriteIcon { Anchor = Anchor.TopLeft, Origin = Anchor.TopLeft, - TextSize = 12, + Size = new Vector2(12), Colour = colours.Gray5, Icon = FontAwesome.fa_bars, Alpha = 0f, - Margin = new MarginPadding { Left = 5 }, - Padding = new MarginPadding { Top = 2 }, + Margin = new MarginPadding { Left = 5, Top = 2 }, }, text = new OsuTextFlowContainer { diff --git a/osu.Game/Overlays/Music/PlaylistList.cs b/osu.Game/Overlays/Music/PlaylistList.cs index 88f499f9a6..3dd514edeb 100644 --- a/osu.Game/Overlays/Music/PlaylistList.cs +++ b/osu.Game/Overlays/Music/PlaylistList.cs @@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Music public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) { - PlaylistItem itemToRemove = items.Children.FirstOrDefault(item => item.BeatmapSetInfo == beatmapSet); + PlaylistItem itemToRemove = items.Children.FirstOrDefault(item => item.BeatmapSetInfo.ID == beatmapSet.ID); if (itemToRemove != null) items.Remove(itemToRemove); } diff --git a/osu.Game/Overlays/Music/PlaylistOverlay.cs b/osu.Game/Overlays/Music/PlaylistOverlay.cs index 31fe755d2b..942633b35e 100644 --- a/osu.Game/Overlays/Music/PlaylistOverlay.cs +++ b/osu.Game/Overlays/Music/PlaylistOverlay.cs @@ -6,14 +6,14 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Input; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Game.Beatmaps; using osu.Game.Graphics; using OpenTK; using OpenTK.Graphics; -using osu.Framework.Input; -using osu.Framework.Graphics.Shapes; namespace osu.Game.Overlays.Music { @@ -77,11 +77,11 @@ namespace osu.Game.Overlays.Music }, }; + beatmaps.BeatmapSetAdded += s => Schedule(() => list.AddBeatmapSet(s)); + beatmaps.BeatmapSetRemoved += s => Schedule(() => list.RemoveBeatmapSet(s)); + list.BeatmapSets = BeatmapSets = beatmaps.GetAllUsableBeatmapSets(); - // todo: these should probably be above the query. - beatmaps.BeatmapSetAdded += s => list.AddBeatmapSet(s); - beatmaps.BeatmapSetRemoved += s => list.RemoveBeatmapSet(s); beatmapBacking.BindTo(game.Beatmap); diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs index 2807a02543..d970089942 100644 --- a/osu.Game/Overlays/MusicController.cs +++ b/osu.Game/Overlays/MusicController.cs @@ -12,18 +12,18 @@ using osu.Framework.Configuration; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input; using osu.Framework.Localisation; +using osu.Framework.Threading; using osu.Game.Beatmaps; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Framework.Threading; using osu.Game.Overlays.Music; using osu.Game.Graphics.UserInterface; -using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Containers; namespace osu.Game.Overlays @@ -41,7 +41,9 @@ namespace osu.Game.Overlays private Drawable currentBackground; private ProgressBar progressBar; + private IconButton prevButton; private IconButton playButton; + private IconButton nextButton; private IconButton playlistButton; private SpriteText title, artist; @@ -158,7 +160,7 @@ namespace osu.Game.Overlays Anchor = Anchor.Centre, Children = new[] { - new IconButton + prevButton = new IconButton { Action = prev, Icon = FontAwesome.fa_step_backward, @@ -170,7 +172,7 @@ namespace osu.Game.Overlays Action = play, Icon = FontAwesome.fa_play_circle_o, }, - new IconButton + nextButton = new IconButton { Action = next, Icon = FontAwesome.fa_step_forward, @@ -209,11 +211,22 @@ namespace osu.Game.Overlays protected override void LoadComplete() { beatmapBacking.ValueChanged += beatmapChanged; + beatmapBacking.DisabledChanged += beatmapDisabledChanged; beatmapBacking.TriggerChange(); base.LoadComplete(); } + private void beatmapDisabledChanged(bool disabled) + { + if (disabled) + playlist.Hide(); + + prevButton.Enabled.Value = !disabled; + nextButton.Enabled.Value = !disabled; + playlistButton.Enabled.Value = !disabled; + } + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); @@ -233,7 +246,8 @@ namespace osu.Game.Overlays playButton.Icon = track.IsRunning ? FontAwesome.fa_pause_circle_o : FontAwesome.fa_play_circle_o; - if (track.HasCompleted && !track.Looping) next(); + if (track.HasCompleted && !track.Looping && !beatmapBacking.Disabled) + next(); } else playButton.Icon = FontAwesome.fa_play_circle_o; @@ -245,7 +259,8 @@ namespace osu.Game.Overlays if (track == null) { - playlist.PlayNext(); + if (!beatmapBacking.Disabled) + playlist.PlayNext(); return; } @@ -257,16 +272,12 @@ namespace osu.Game.Overlays private void prev() { - if (beatmapBacking.Disabled) return; - queuedDirection = TransformDirection.Prev; playlist.PlayPrevious(); } private void next() { - if (beatmapBacking.Disabled) return; - queuedDirection = TransformDirection.Next; playlist.PlayNext(); } diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs index 49b2823531..14446a468c 100644 --- a/osu.Game/Overlays/Notifications/Notification.cs +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -165,12 +165,12 @@ namespace osu.Game.Overlays.Notifications Children = new[] { - new TextAwesome + new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = FontAwesome.fa_times_circle, - TextSize = 20 + Size = new Vector2(20), } }; } diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs index 44e6d92aef..e10cc26546 100644 --- a/osu.Game/Overlays/Notifications/SimpleNotification.cs +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -8,6 +8,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; +using OpenTK; namespace osu.Game.Overlays.Notifications { @@ -36,7 +37,7 @@ namespace osu.Game.Overlays.Notifications } private readonly SpriteText textDrawable; - private readonly TextAwesome iconDrawable; + private readonly SpriteIcon iconDrawable; protected Box IconBackgound; @@ -49,12 +50,12 @@ namespace osu.Game.Overlays.Notifications RelativeSizeAxes = Axes.Both, Colour = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.6f)) }, - iconDrawable = new TextAwesome + iconDrawable = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = icon, - TextSize = 20 + Size = new Vector2(20), } }); diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs index 93044315cc..77a3449b9c 100644 --- a/osu.Game/Overlays/Profile/ProfileHeader.cs +++ b/osu.Game/Overlays/Profile/ProfileHeader.cs @@ -110,12 +110,12 @@ namespace osu.Game.Overlays.Profile Alpha = 0, AlwaysPresent = true }, - new TextAwesome + new SpriteIcon { Icon = FontAwesome.fa_heart, Anchor = Anchor.Centre, Origin = Anchor.Centre, - TextSize = 12 + Size = new Vector2(12), } } }, diff --git a/osu.Game/Overlays/SearchableList/DisplayStyleControl.cs b/osu.Game/Overlays/SearchableList/DisplayStyleControl.cs index 7157861632..9fa266c5fe 100644 --- a/osu.Game/Overlays/SearchableList/DisplayStyleControl.cs +++ b/osu.Game/Overlays/SearchableList/DisplayStyleControl.cs @@ -55,7 +55,7 @@ namespace osu.Game.Overlays.SearchableList private class DisplayStyleToggleButton : OsuClickableContainer { - private readonly TextAwesome icon; + private readonly SpriteIcon icon; private readonly PanelDisplayStyle style; private readonly Bindable bindable; @@ -67,13 +67,12 @@ namespace osu.Game.Overlays.SearchableList Children = new Drawable[] { - this.icon = new TextAwesome + this.icon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, Icon = icon, - TextSize = 18, - UseFullGlyphHeight = false, + Size = new Vector2(18), Alpha = 0.5f, }, }; diff --git a/osu.Game/Overlays/SearchableList/SearchableListHeader.cs b/osu.Game/Overlays/SearchableList/SearchableListHeader.cs index af99a39cc4..4239a123b8 100644 --- a/osu.Game/Overlays/SearchableList/SearchableListHeader.cs +++ b/osu.Game/Overlays/SearchableList/SearchableListHeader.cs @@ -55,9 +55,9 @@ namespace osu.Game.Overlays.SearchableList Spacing = new Vector2(10f, 0f), Children = new[] { - new TextAwesome + new SpriteIcon { - TextSize = 25, + Size = new Vector2(25), Icon = Icon, }, CreateHeaderText(), diff --git a/osu.Game/Overlays/SearchableList/SlimEnumDropdown.cs b/osu.Game/Overlays/SearchableList/SlimEnumDropdown.cs index e2eec0214f..38e3e44911 100644 --- a/osu.Game/Overlays/SearchableList/SlimEnumDropdown.cs +++ b/osu.Game/Overlays/SearchableList/SlimEnumDropdown.cs @@ -6,6 +6,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; +using OpenTK; namespace osu.Game.Overlays.SearchableList { @@ -19,7 +20,7 @@ namespace osu.Game.Overlays.SearchableList public SlimDropdownHeader() { Height = 25; - Icon.TextSize = 16; + Icon.Size = new Vector2(16); Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 8, Right = 4 }; } diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs index 6268a9753a..d07f156673 100644 --- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs @@ -286,7 +286,7 @@ namespace osu.Game.Overlays.Settings.Sections.General { public const float LABEL_LEFT_MARGIN = 20; - private readonly TextAwesome statusIcon; + private readonly SpriteIcon statusIcon; public Color4 StatusColour { set @@ -308,15 +308,15 @@ namespace osu.Game.Overlays.Settings.Sections.General Radius = 4, }; - Icon.TextSize = 14; + Icon.Size = new Vector2(14); Icon.Margin = new MarginPadding(0); - Foreground.Add(statusIcon = new TextAwesome + Foreground.Add(statusIcon = new SpriteIcon { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Icon = FontAwesome.fa_circle_o, - TextSize = 14, + Size = new Vector2(14), }); Text.Margin = new MarginPadding { Left = LABEL_LEFT_MARGIN }; diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs new file mode 100644 index 0000000000..9d13a2ae2f --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Maintenance/GeneralSettings.cs @@ -0,0 +1,47 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Threading.Tasks; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Settings.Sections.Maintenance +{ + public class GeneralSettings : SettingsSubsection + { + private OsuButton importButton; + private OsuButton deleteButton; + + protected override string Header => "General"; + + [BackgroundDependencyLoader] + private void load(BeatmapManager beatmaps) + { + Children = new Drawable[] + { + importButton = new OsuButton + { + RelativeSizeAxes = Axes.X, + Text = "Import beatmaps from stable", + Action = () => + { + importButton.Enabled.Value = false; + Task.Run(() => beatmaps.ImportFromStable()).ContinueWith(t => Schedule(() => importButton.Enabled.Value = true)); + } + }, + deleteButton = new OsuButton + { + RelativeSizeAxes = Axes.X, + Text = "Delete ALL beatmaps", + Action = () => + { + deleteButton.Enabled.Value = false; + Task.Run(() => beatmaps.DeleteAll()).ContinueWith(t => Schedule(() => deleteButton.Enabled.Value = true)); + } + }, + }; + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs index 529cec79c1..b42c64d324 100644 --- a/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs +++ b/osu.Game/Overlays/Settings/Sections/MaintenanceSection.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Game.Graphics; +using osu.Game.Overlays.Settings.Sections.Maintenance; using OpenTK; namespace osu.Game.Overlays.Settings.Sections @@ -17,6 +18,7 @@ namespace osu.Game.Overlays.Settings.Sections FlowContent.Spacing = new Vector2(0, 5); Children = new Drawable[] { + new GeneralSettings() }; } } diff --git a/osu.Game/Overlays/Settings/SettingsFooter.cs b/osu.Game/Overlays/Settings/SettingsFooter.cs index 6c25b146a1..aef9f071db 100644 --- a/osu.Game/Overlays/Settings/SettingsFooter.cs +++ b/osu.Game/Overlays/Settings/SettingsFooter.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets; using OpenTK; @@ -27,12 +28,14 @@ namespace osu.Game.Overlays.Settings foreach (var ruleset in rulesets.AllRulesets) { - modes.Add(new TextAwesome + var icon = new ConstrainedIconContainer { - Icon = ruleset.CreateInstance().Icon, + Icon = ruleset.CreateInstance().CreateIcon(), Colour = Color4.Gray, - TextSize = 20 - }); + Size = new Vector2(20), + }; + + modes.Add(icon); } Children = new Drawable[] diff --git a/osu.Game/Overlays/Settings/SidebarButton.cs b/osu.Game/Overlays/Settings/SidebarButton.cs index 309216dd91..7af7363dda 100644 --- a/osu.Game/Overlays/Settings/SidebarButton.cs +++ b/osu.Game/Overlays/Settings/SidebarButton.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Settings { public class SidebarButton : Container { - private readonly TextAwesome drawableIcon; + private readonly SpriteIcon drawableIcon; private readonly SpriteText headerText; private readonly Box backgroundBox; private readonly Box selectionIndicator; @@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Settings Width = Sidebar.DEFAULT_WIDTH, RelativeSizeAxes = Axes.Y, Colour = OsuColour.Gray(0.6f), - Children = new[] + Children = new Drawable[] { headerText = new OsuSpriteText { @@ -85,11 +85,11 @@ namespace osu.Game.Overlays.Settings Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, }, - drawableIcon = new TextAwesome + drawableIcon = new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, - TextSize = 20 + Size = new Vector2(20), }, } }, diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index b5e832d381..f2df2721d3 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -20,10 +20,21 @@ namespace osu.Game.Overlays.Toolbar { public const float WIDTH = Toolbar.HEIGHT * 1.4f; + public void SetIcon(Drawable icon) + { + IconContainer.Icon = icon; + IconContainer.Show(); + } + + public void SetIcon(FontAwesome icon) => SetIcon(new SpriteIcon + { + Size = new Vector2(20), + Icon = icon + }); + public FontAwesome Icon { - get { return DrawableIcon.Icon; } - set { DrawableIcon.Icon = value; } + set { SetIcon(value); } } public string Text @@ -55,7 +66,7 @@ namespace osu.Game.Overlays.Toolbar protected virtual Anchor TooltipAnchor => Anchor.TopLeft; - protected TextAwesome DrawableIcon; + protected ConstrainedIconContainer IconContainer; protected SpriteText DrawableText; protected Box HoverBackground; private readonly FillFlowContainer tooltipContainer; @@ -88,11 +99,12 @@ namespace osu.Game.Overlays.Toolbar AutoSizeAxes = Axes.X, Children = new Drawable[] { - DrawableIcon = new TextAwesome + IconContainer = new ConstrainedIconContainer { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - TextSize = 20 + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Size = new Vector2(20), + Alpha = 0, }, DrawableText = new OsuSpriteText { diff --git a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs index 39909b8d5b..2e2786851c 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs @@ -10,7 +10,7 @@ namespace osu.Game.Overlays.Toolbar { public ToolbarChatButton() { - Icon = FontAwesome.fa_comments; + SetIcon(FontAwesome.fa_comments); } [BackgroundDependencyLoader] diff --git a/osu.Game/Overlays/Toolbar/ToolbarModeButton.cs b/osu.Game/Overlays/Toolbar/ToolbarModeButton.cs index 2c50897e1f..b615cd3303 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarModeButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarModeButton.cs @@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Toolbar TooltipMain = rInstance.Description; TooltipSub = $"Play some {rInstance.Description}"; - Icon = rInstance.Icon; + SetIcon(rInstance.CreateIcon()); } } @@ -31,9 +31,8 @@ namespace osu.Game.Overlays.Toolbar { if (value) { - DrawableIcon.Colour = Color4.White; - DrawableIcon.Masking = true; - DrawableIcon.EdgeEffect = new EdgeEffectParameters + IconContainer.Colour = Color4.White; + IconContainer.EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Glow, Colour = new Color4(255, 194, 224, 100), @@ -43,8 +42,8 @@ namespace osu.Game.Overlays.Toolbar } else { - DrawableIcon.Masking = false; - DrawableIcon.Colour = new Color4(255, 194, 224, 255); + IconContainer.Colour = new Color4(255, 194, 224, 255); + IconContainer.EdgeEffect = new EdgeEffectParameters(); } } } @@ -52,7 +51,7 @@ namespace osu.Game.Overlays.Toolbar protected override void LoadComplete() { base.LoadComplete(); - DrawableIcon.TextSize *= 1.4f; + IconContainer.Scale *= 1.4f; } } } diff --git a/osu.Game/Rulesets/Ruleset.cs b/osu.Game/Rulesets/Ruleset.cs index 316b3ad276..b3be36a983 100644 --- a/osu.Game/Rulesets/Ruleset.cs +++ b/osu.Game/Rulesets/Ruleset.cs @@ -7,6 +7,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.UI; using osu.Game.Screens.Play; using System.Collections.Generic; +using osu.Framework.Graphics; using osu.Game.Rulesets.Scoring; using osu.Game.Overlays.Settings; @@ -33,7 +34,7 @@ namespace osu.Game.Rulesets public abstract ScoreProcessor CreateScoreProcessor(); - public virtual FontAwesome Icon => FontAwesome.fa_question_circle; + public virtual Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_question_circle }; public abstract string Description { get; } diff --git a/osu.Game/Rulesets/RulesetStore.cs b/osu.Game/Rulesets/RulesetStore.cs index 88aee2bffc..1564df1366 100644 --- a/osu.Game/Rulesets/RulesetStore.cs +++ b/osu.Game/Rulesets/RulesetStore.cs @@ -62,7 +62,7 @@ namespace osu.Game.Rulesets { var us = createRulesetInfo(r); - var existing = Query().FirstOrDefault(ri => ri.InstantiationInfo == us.InstantiationInfo); + var existing = Query().Where(ri => ri.InstantiationInfo == us.InstantiationInfo).FirstOrDefault(); if (existing == null) Connection.Insert(us); diff --git a/osu.Game/Rulesets/UI/ModIcon.cs b/osu.Game/Rulesets/UI/ModIcon.cs index b23028098f..03705c19e6 100644 --- a/osu.Game/Rulesets/UI/ModIcon.cs +++ b/osu.Game/Rulesets/UI/ModIcon.cs @@ -8,13 +8,14 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Rulesets.Mods; +using OpenTK; namespace osu.Game.Rulesets.UI { public class ModIcon : Container { - private readonly TextAwesome modIcon; - private readonly TextAwesome background; + private readonly SpriteIcon modIcon; + private readonly SpriteIcon background; private const float icon_size = 80; @@ -34,20 +35,20 @@ namespace osu.Game.Rulesets.UI Children = new Drawable[] { - background = new TextAwesome + background = new SpriteIcon { Origin = Anchor.Centre, Anchor = Anchor.Centre, - TextSize = icon_size, + Size = new Vector2(icon_size), Icon = FontAwesome.fa_osu_mod_bg, Shadow = true, }, - modIcon = new TextAwesome + modIcon = new SpriteIcon { Origin = Anchor.Centre, Anchor = Anchor.Centre, Colour = OsuColour.Gray(84), - TextSize = icon_size - 35, + Size = new Vector2(icon_size - 35), Icon = mod.Icon }, }; diff --git a/osu.Game/Screens/Menu/Button.cs b/osu.Game/Screens/Menu/Button.cs index e55c4ef4fe..0898c079ce 100644 --- a/osu.Game/Screens/Menu/Button.cs +++ b/osu.Game/Screens/Menu/Button.cs @@ -31,7 +31,7 @@ namespace osu.Game.Screens.Menu private readonly Container iconText; private readonly Container box; private readonly Box boxHoverLayer; - private readonly TextAwesome icon; + private readonly SpriteIcon icon; private readonly string sampleName; private readonly Action clickAction; private readonly Key triggerKey; @@ -95,12 +95,12 @@ namespace osu.Game.Screens.Menu Origin = Anchor.Centre, Children = new Drawable[] { - icon = new TextAwesome + icon = new SpriteIcon { Shadow = true, Anchor = Anchor.Centre, Origin = Anchor.Centre, - TextSize = 30, + Size = new Vector2(30), Position = new Vector2(0, 0), Icon = symbol }, diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 6a176898a2..1ac5823ec4 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -15,7 +15,7 @@ namespace osu.Game.Screens.Menu internal class Disclaimer : OsuScreen { private Intro intro; - private readonly TextAwesome icon; + private readonly SpriteIcon icon; private Color4 iconColour; internal override bool ShowOverlays => false; @@ -37,12 +37,12 @@ namespace osu.Game.Screens.Menu Spacing = new Vector2(0, 2), Children = new Drawable[] { - icon = new TextAwesome + icon = new SpriteIcon { Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, Icon = FontAwesome.fa_warning, - TextSize = 30, + Size = new Vector2(30), }, new OsuSpriteText { diff --git a/osu.Game/Screens/Play/SkipButton.cs b/osu.Game/Screens/Play/SkipButton.cs index b2d5abe71a..a67cf4e5ea 100644 --- a/osu.Game/Screens/Play/SkipButton.cs +++ b/osu.Game/Screens/Play/SkipButton.cs @@ -227,9 +227,9 @@ namespace osu.Game.Screens.Play Direction = FillDirection.Horizontal, Children = new[] { - new TextAwesome { Icon = FontAwesome.fa_chevron_right }, - new TextAwesome { Icon = FontAwesome.fa_chevron_right }, - new TextAwesome { Icon = FontAwesome.fa_chevron_right }, + new SpriteIcon { Icon = FontAwesome.fa_chevron_right }, + new SpriteIcon { Icon = FontAwesome.fa_chevron_right }, + new SpriteIcon { Icon = FontAwesome.fa_chevron_right }, } }, new OsuSpriteText diff --git a/osu.Game/Screens/Ranking/ResultModeButton.cs b/osu.Game/Screens/Ranking/ResultModeButton.cs index 50be5c8d00..d38611c45a 100644 --- a/osu.Game/Screens/Ranking/ResultModeButton.cs +++ b/osu.Game/Screens/Ranking/ResultModeButton.cs @@ -78,14 +78,14 @@ namespace osu.Game.Screens.Ranking RelativeSizeAxes = Axes.Both, Colour = Color4.Transparent, }, - new TextAwesome + new SpriteIcon { Anchor = Anchor.Centre, Origin = Anchor.Centre, Shadow = false, Colour = OsuColour.Gray(0.95f), Icon = icon, - TextSize = 20, + Size = new Vector2(20), } } } diff --git a/osu.Game/Screens/ScreenWhiteBox.cs b/osu.Game/Screens/ScreenWhiteBox.cs index 5596f345d5..408dbd8f16 100644 --- a/osu.Game/Screens/ScreenWhiteBox.cs +++ b/osu.Game/Screens/ScreenWhiteBox.cs @@ -108,14 +108,14 @@ namespace osu.Game.Screens Anchor = Anchor.Centre, Origin = Anchor.Centre, Direction = FillDirection.Vertical, - Children = new[] + Children = new Drawable[] { - new TextAwesome + new SpriteIcon { Icon = FontAwesome.fa_universal_access, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, - TextSize = 50, + Size = new Vector2(50), }, new OsuSpriteText { diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 743a0a0f63..264636b258 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -107,6 +107,14 @@ namespace osu.Game.Screens.Select }); } + public void RemoveBeatmap(BeatmapSetInfo beatmapSet) + { + Schedule(delegate + { + removeGroup(groups.Find(b => b.BeatmapSet.ID == beatmapSet.ID)); + }); + } + public void SelectBeatmap(BeatmapInfo beatmap, bool animated = true) { if (beatmap == null) @@ -128,8 +136,6 @@ namespace osu.Game.Screens.Select } } - public void RemoveBeatmap(BeatmapSetInfo info) => removeGroup(groups.Find(b => b.BeatmapSet.ID == info.ID)); - public Action SelectionChanged; public Action StartRequested; @@ -181,12 +187,12 @@ namespace osu.Game.Screens.Select if (groups.Count == 0) return; - randomSelectedBeatmaps.Push(new KeyValuePair(selectedGroup, selectedGroup.SelectedPanel)); - var visibleGroups = getVisibleGroups(); if (!visibleGroups.Any()) return; + randomSelectedBeatmaps.Push(new KeyValuePair(selectedGroup, selectedGroup.SelectedPanel)); + BeatmapGroup group; if (randomType == SelectionRandomType.RandomPermutation) @@ -281,6 +287,12 @@ namespace osu.Game.Screens.Select perform(); } + public void ScrollToSelected(bool animated = true) + { + float selectedY = computeYPositions(animated); + ScrollTo(selectedY, animated); + } + private BeatmapGroup createGroup(BeatmapSetInfo beatmapSet) { foreach (var b in beatmapSet.Beatmaps) @@ -420,8 +432,7 @@ namespace osu.Game.Screens.Select } finally { - float selectedY = computeYPositions(animated); - ScrollTo(selectedY, animated); + ScrollToSelected(animated); } } diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs index 385492980f..1fb9c707f0 100644 --- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs +++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs @@ -247,21 +247,21 @@ namespace osu.Game.Screens.Select AutoSizeAxes = Axes.Both; Children = new Drawable[] { - new TextAwesome + new SpriteIcon { Icon = FontAwesome.fa_square, Origin = Anchor.Centre, Colour = new Color4(68, 17, 136, 255), Rotation = 45, - TextSize = 20 + Size = new Vector2(20), }, - new TextAwesome + new SpriteIcon { Icon = statistic.Icon, Origin = Anchor.Centre, Colour = new Color4(255, 221, 85, 255), Scale = new Vector2(0.8f), - TextSize = 20 + Size = new Vector2(20), }, new OsuSpriteText { diff --git a/osu.Game/Screens/Select/FilterControl.cs b/osu.Game/Screens/Select/FilterControl.cs index c406e7c44d..838e6f7123 100644 --- a/osu.Game/Screens/Select/FilterControl.cs +++ b/osu.Game/Screens/Select/FilterControl.cs @@ -121,7 +121,7 @@ namespace osu.Game.Screens.Select //{ // Font = @"Exo2.0-Bold", // Text = "Sort results by", - // TextSize = 14, + // Size = 14, // Margin = new MarginPadding // { // Top = 5, diff --git a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs index 39c948f8d3..ac3b0b5c3b 100644 --- a/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Screens/Select/Leaderboards/LeaderboardScore.cs @@ -334,25 +334,23 @@ namespace osu.Game.Screens.Select.Leaderboards Children = new[] { - new TextAwesome + new SpriteIcon { Origin = Anchor.Centre, Anchor = Anchor.Centre, Icon = FontAwesome.fa_osu_mod_bg, Colour = colour, Shadow = true, - TextSize = 30, - UseFullGlyphHeight = false, + Size = new Vector2(30), }, - new TextAwesome + new SpriteIcon { Origin = Anchor.Centre, Anchor = Anchor.Centre, Icon = icon, Colour = OsuColour.Gray(84), - TextSize = 18, + Size = new Vector2(18), Position = new Vector2(0f, 2f), - UseFullGlyphHeight = false, }, }; } @@ -369,7 +367,7 @@ namespace osu.Game.Screens.Select.Leaderboards Children = new Drawable[] { - new TextAwesome + new SpriteIcon { Origin = Anchor.Centre, Icon = FontAwesome.fa_square, @@ -377,7 +375,7 @@ namespace osu.Game.Screens.Select.Leaderboards Rotation = 45, Shadow = true, }, - new TextAwesome + new SpriteIcon { Origin = Anchor.Centre, Icon = icon, diff --git a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs index ab02e8678f..306e7fb3dc 100644 --- a/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs +++ b/osu.Game/Screens/Select/Options/BeatmapOptionsButton.cs @@ -21,7 +21,7 @@ namespace osu.Game.Screens.Select.Options private readonly Box background; private readonly Box flash; - private readonly TextAwesome iconText; + private readonly SpriteIcon iconText; private readonly OsuSpriteText firstLine; private readonly OsuSpriteText secondLine; private readonly Container box; @@ -134,11 +134,11 @@ namespace osu.Game.Screens.Select.Options Direction = FillDirection.Vertical, Children = new Drawable[] { - iconText = new TextAwesome + iconText = new SpriteIcon { Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, - TextSize = 30, + Size = new Vector2(30), Shadow = true, Icon = FontAwesome.fa_close, Margin = new MarginPadding diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index cd5082bd11..8f545240c8 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -126,6 +126,11 @@ namespace osu.Game.Screens.Select Right = left_area_padding, }, }); + Add(new ResetScrollContainer(() => carousel.ScrollToSelected()) + { + RelativeSizeAxes = Axes.Y, + Width = 250, + }); if (ShowFooter) { @@ -277,7 +282,7 @@ namespace osu.Game.Screens.Select carousel.Filter(criteria, debounce); } - private void onBeatmapSetAdded(BeatmapSetInfo s) => carousel.AddBeatmap(s); + private void onBeatmapSetAdded(BeatmapSetInfo s) => Schedule(() => addBeatmapSet(s)); private void onBeatmapSetRemoved(BeatmapSetInfo s) => Schedule(() => removeBeatmapSet(s)); @@ -372,6 +377,11 @@ namespace osu.Game.Screens.Select } } + private void addBeatmapSet(BeatmapSetInfo beatmapSet) + { + carousel.AddBeatmap(beatmapSet); + } + private void removeBeatmapSet(BeatmapSetInfo beatmapSet) { carousel.RemoveBeatmap(beatmapSet); @@ -406,5 +416,21 @@ namespace osu.Game.Screens.Select return base.OnKeyDown(state, args); } + + private class ResetScrollContainer : Container + { + private readonly Action onHoverAction; + + public ResetScrollContainer(Action onHoverAction) + { + this.onHoverAction = onHoverAction; + } + + protected override bool OnHover(InputState state) + { + onHoverAction?.Invoke(); + return base.OnHover(state); + } + } } } diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs index cd9ca582fc..89bd4b68d2 100644 --- a/osu.Game/Users/UserPanel.cs +++ b/osu.Game/Users/UserPanel.cs @@ -142,15 +142,15 @@ namespace osu.Game.Users Origin = Anchor.Centre, AutoSizeAxes = Axes.Both, Spacing = new Vector2(5f, 0f), - Children = new[] + Children = new Drawable[] { - new TextAwesome + new SpriteIcon { Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Icon = FontAwesome.fa_circle_o, Shadow = true, - TextSize = 14, + Size = new Vector2(14), }, statusMessage = new OsuSpriteText { diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index fa4665fd7d..3f475a34c8 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -104,6 +104,7 @@ + @@ -115,6 +116,7 @@ + @@ -348,7 +350,7 @@ - + diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index e3eae96ca8..06d160ad31 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -115,7 +115,7 @@ WARNING WARNING WARNING - WARNING + HINT WARNING WARNING WARNING