1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-15 15:12:57 +08:00

Merge branch 'master' into fixes

This commit is contained in:
Huo Yaoyuan 2017-08-04 13:49:03 +08:00
commit 62b3540fd6
76 changed files with 807 additions and 319 deletions

@ -1 +1 @@
Subproject commit 5a9ca94fc31bc796b45572eb3d0b27b46556c586 Subproject commit 96daf2053a8a19fe221fef2557674ca5bee808fb

View File

@ -1,11 +1,15 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // 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.Graphics;
using osu.Framework.Timing;
using osu.Game.Overlays;
using osu.Framework.Graphics.Containers; 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 namespace osu.Desktop.VisualTests.Tests
{ {
@ -13,6 +17,8 @@ namespace osu.Desktop.VisualTests.Tests
{ {
public override string Description => @"Tests music controller ui."; public override string Description => @"Tests music controller ui.";
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
public TestCaseMusicController() public TestCaseMusicController()
{ {
Clock = new FramedClock(); Clock = new FramedClock();
@ -26,6 +32,13 @@ namespace osu.Desktop.VisualTests.Tests
AddToggleStep(@"toggle visibility", state => mc.State = state ? Visibility.Visible : Visibility.Hidden); AddToggleStep(@"toggle visibility", state => mc.State = state ? Visibility.Visible : Visibility.Hidden);
AddStep(@"show", () => mc.State = Visibility.Visible); AddStep(@"show", () => mc.State = Visibility.Visible);
AddToggleStep(@"toggle beatmap lock", state => beatmapBacking.Disabled = state);
}
[BackgroundDependencyLoader]
private void load(OsuGameBase game)
{
beatmapBacking.BindTo(game.Beatmap);
} }
} }
} }

View File

@ -31,10 +31,10 @@ namespace osu.Desktop.VisualTests.Tests
int i = 50; int i = 50;
foreach (FontAwesome fa in Enum.GetValues(typeof(FontAwesome))) foreach (FontAwesome fa in Enum.GetValues(typeof(FontAwesome)))
{ {
flow.Add(new TextAwesome flow.Add(new SpriteIcon
{ {
Icon = fa, Icon = fa,
TextSize = 60, Size = new Vector2(60),
Colour = new Color4( Colour = new Color4(
Math.Max(0.5f, RNG.NextSingle()), Math.Max(0.5f, RNG.NextSingle()),
Math.Max(0.5f, RNG.NextSingle()), Math.Max(0.5f, RNG.NextSingle()),

View File

@ -1,6 +1,7 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Game; using osu.Game;
using System.Linq; using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
@ -11,6 +12,7 @@ using System.Reflection;
using System.Drawing; using System.Drawing;
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Win32;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
@ -30,6 +32,58 @@ namespace osu.Desktop
}; };
} }
public override Storage GetStorageForStableInstall()
{
try
{
return new StableStorage();
}
catch
{
return null;
}
}
/// <summary>
/// A method of accessing an osu-stable install in a controlled fashion.
/// </summary>
private class StableStorage : DesktopStorage
{
protected override string LocateBasePath()
{
Func<string, bool> 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() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();

View File

@ -209,13 +209,13 @@ namespace osu.Desktop.Overlays
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(colours.YellowDark, colours.Yellow) Colour = ColourInfo.GradientVertical(colours.YellowDark, colours.Yellow)
}, },
new TextAwesome new SpriteIcon
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = FontAwesome.fa_upload, Icon = FontAwesome.fa_upload,
Colour = Color4.White, Colour = Color4.White,
TextSize = 20 Size = new Vector2(20),
} }
}); });
} }

View File

@ -10,6 +10,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Catch.Scoring; using osu.Game.Rulesets.Catch.Scoring;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -87,7 +88,7 @@ namespace osu.Game.Rulesets.Catch
public override string Description => "osu!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<KeyCounter> CreateGameplayKeys() => new KeyCounter[] public override IEnumerable<KeyCounter> CreateGameplayKeys() => new KeyCounter[]
{ {

View File

@ -2,13 +2,14 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Mods; using osu.Game.Rulesets.Mania.Mods;
using osu.Game.Rulesets.Mania.UI; using osu.Game.Rulesets.Mania.UI;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Rulesets.Mania.Scoring; using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -108,7 +109,7 @@ namespace osu.Game.Rulesets.Mania
public override string Description => "osu!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<KeyCounter> CreateGameplayKeys() => new KeyCounter[] { /* Todo: Should be keymod specific */ }; public override IEnumerable<KeyCounter> CreateGameplayKeys() => new KeyCounter[] { /* Todo: Should be keymod specific */ };

View File

@ -28,7 +28,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly CirclePiece circle; private readonly CirclePiece circle;
private readonly GlowPiece glow; private readonly GlowPiece glow;
private readonly TextAwesome symbol; private readonly SpriteIcon symbol;
private readonly Color4 baseColour = OsuColour.FromHex(@"002c3c"); private readonly Color4 baseColour = OsuColour.FromHex(@"002c3c");
private readonly Color4 fillColour = OsuColour.FromHex(@"005b7c"); private readonly Color4 fillColour = OsuColour.FromHex(@"005b7c");
@ -64,12 +64,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
}, },
new RingPiece(), new RingPiece(),
symbol = new TextAwesome symbol = new SpriteIcon
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
UseFullGlyphHeight = true, Size = new Vector2(48),
TextSize = 48,
Icon = FontAwesome.fa_asterisk, Icon = FontAwesome.fa_asterisk,
Shadow = false, Shadow = false,
}, },

View File

@ -4,6 +4,7 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces 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 Slider slider;
private readonly bool isEnd; private readonly bool isEnd;
private readonly TextAwesome icon; private readonly SpriteIcon icon;
public SliderBouncer(Slider slider, bool isEnd) public SliderBouncer(Slider slider, bool isEnd)
{ {
@ -24,12 +25,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Children = new Drawable[] Children = new Drawable[]
{ {
icon = new TextAwesome icon = new SpriteIcon
{ {
Icon = FontAwesome.fa_eercast, Icon = FontAwesome.fa_eercast,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
TextSize = 48, Size = new Vector2(48),
} }
}; };
} }

View File

@ -13,6 +13,7 @@ using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Osu.Scoring; using osu.Game.Rulesets.Osu.Scoring;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings;
@ -106,7 +107,7 @@ namespace osu.Game.Rulesets.Osu
public override Mod GetAutoplayMod() => new OsuModAutoplay(); 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); public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new OsuDifficultyCalculator(beatmap);

View File

@ -3,20 +3,20 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces namespace osu.Game.Rulesets.Taiko.Objects.Drawables.Pieces
{ {
/// <summary> /// <summary>
/// The symbol used for swell pieces. /// The symbol used for swell pieces.
/// </summary> /// </summary>
public class SwellSymbolPiece : TextAwesome public class SwellSymbolPiece : SpriteIcon
{ {
public SwellSymbolPiece() public SwellSymbolPiece()
{ {
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
UseFullGlyphHeight = true; Size = new Vector2(CirclePiece.SYMBOL_INNER_SIZE);
TextSize = CirclePiece.SYMBOL_INNER_SIZE;
Icon = FontAwesome.fa_asterisk; Icon = FontAwesome.fa_asterisk;
Shadow = false; Shadow = false;
} }

View File

@ -10,6 +10,7 @@ using osu.Game.Rulesets.Taiko.UI;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Scoring; using osu.Game.Rulesets.Taiko.Scoring;
@ -87,7 +88,7 @@ namespace osu.Game.Rulesets.Taiko
public override string Description => "osu!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<KeyCounter> CreateGameplayKeys() => new KeyCounter[] public override IEnumerable<KeyCounter> CreateGameplayKeys() => new KeyCounter[]
{ {

View File

@ -17,9 +17,9 @@ using osu.Game.Beatmaps.Formats;
using osu.Game.Beatmaps.IO; using osu.Game.Beatmaps.IO;
using osu.Game.IO; using osu.Game.IO;
using osu.Game.IPC; using osu.Game.IPC;
using osu.Game.Overlays.Notifications;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using SQLite.Net; using SQLite.Net;
using FileInfo = osu.Game.IO.FileInfo;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
@ -47,6 +47,8 @@ namespace osu.Game.Beatmaps
private readonly FileStore files; private readonly FileStore files;
private readonly SQLiteConnection connection;
private readonly RulesetStore rulesets; private readonly RulesetStore rulesets;
private readonly BeatmapStore beatmaps; 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) // ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
private BeatmapIPCChannel ipc; private BeatmapIPCChannel ipc;
/// <summary>
/// Set an endpoint for notifications to be posted to.
/// </summary>
public Action<Notification> PostNotification { private get; set; }
/// <summary>
/// Set a storage with access to an osu-stable install for import purposes.
/// </summary>
public Func<Storage> GetStableStorage { private get; set; }
public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, IIpcHost importHost = null) public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, IIpcHost importHost = null)
{ {
beatmaps = new BeatmapStore(connection); beatmaps = new BeatmapStore(connection);
@ -62,6 +74,7 @@ namespace osu.Game.Beatmaps
this.storage = storage; this.storage = storage;
this.files = files; this.files = files;
this.connection = connection;
this.rulesets = rulesets; this.rulesets = rulesets;
if (importHost != null) if (importHost != null)
@ -69,29 +82,48 @@ namespace osu.Game.Beatmaps
} }
/// <summary> /// <summary>
/// Import multiple <see cref="BeatmapSetInfo"/> from filesystem <paramref name="paths"/>. /// Import one or more <see cref="BeatmapSetInfo"/> from filesystem <paramref name="paths"/>.
/// This will post a notification tracking import progress.
/// </summary> /// </summary>
/// <param name="paths">Multiple locations on disk.</param> /// <param name="paths">One or more beatmap locations on disk.</param>
public void Import(params string[] paths) 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) foreach (string path in paths)
{ {
if (notification.State == ProgressNotificationState.Cancelled)
// user requested abort
return;
try try
{ {
notification.Text = $"Importing ({i} of {paths.Length})\n{Path.GetFileName(path)}";
using (ArchiveReader reader = getReaderFrom(path)) using (ArchiveReader reader = getReaderFrom(path))
Import(reader); Import(reader);
notification.Progress = (float)++i / paths.Length;
// We may or may not want to delete the file depending on where it is stored. // 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. // e.g. reconstructing/repairing database with beatmaps from default storage.
// Also, not always a single file, i.e. for LegacyFilesystemReader // Also, not always a single file, i.e. for LegacyFilesystemReader
// TODO: Add a check to prevent files from storage to be deleted. // TODO: Add a check to prevent files from storage to be deleted.
try try
{ {
if (File.Exists(path))
File.Delete(path); File.Delete(path);
} }
catch (Exception e) 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) catch (Exception e)
@ -100,16 +132,24 @@ namespace osu.Game.Beatmaps
Logger.Error(e, @"Could not import beatmap set"); Logger.Error(e, @"Could not import beatmap set");
} }
} }
notification.State = ProgressNotificationState.Completed;
} }
private readonly object importLock = new object();
/// <summary> /// <summary>
/// Import a beatmap from an <see cref="ArchiveReader"/>. /// Import a beatmap from an <see cref="ArchiveReader"/>.
/// </summary> /// </summary>
/// <param name="archiveReader">The beatmap to be imported.</param> /// <param name="archiveReader">The beatmap to be imported.</param>
public BeatmapSetInfo Import(ArchiveReader archiveReader) public BeatmapSetInfo Import(ArchiveReader archiveReader)
{ {
BeatmapSetInfo set = importToStorage(archiveReader); BeatmapSetInfo set = null;
Import(set);
// let's only allow one concurrent import at a time for now.
lock (importLock)
connection.RunInTransaction(() => Import(set = importToStorage(archiveReader)));
return set; return set;
} }
@ -122,6 +162,7 @@ namespace osu.Game.Beatmaps
// If we have an ID then we already exist in the database. // If we have an ID then we already exist in the database.
if (beatmapSetInfo.ID != 0) return; if (beatmapSetInfo.ID != 0) return;
lock (beatmaps)
beatmaps.Add(beatmapSetInfo); beatmaps.Add(beatmapSetInfo);
} }
@ -132,10 +173,11 @@ namespace osu.Game.Beatmaps
/// <param name="beatmapSet">The beatmap to delete.</param> /// <param name="beatmapSet">The beatmap to delete.</param>
public void Delete(BeatmapSetInfo beatmapSet) public void Delete(BeatmapSetInfo beatmapSet)
{ {
lock (beatmaps)
if (!beatmaps.Delete(beatmapSet)) return; if (!beatmaps.Delete(beatmapSet)) return;
if (!beatmapSet.Protected) if (!beatmapSet.Protected)
files.Dereference(beatmapSet.Files); files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray());
} }
/// <summary> /// <summary>
@ -145,9 +187,11 @@ namespace osu.Game.Beatmaps
/// <param name="beatmapSet">The beatmap to restore.</param> /// <param name="beatmapSet">The beatmap to restore.</param>
public void Undelete(BeatmapSetInfo beatmapSet) public void Undelete(BeatmapSetInfo beatmapSet)
{ {
lock (beatmaps)
if (!beatmaps.Undelete(beatmapSet)) return; if (!beatmaps.Undelete(beatmapSet)) return;
files.Reference(beatmapSet.Files); if (!beatmapSet.Protected)
files.Reference(beatmapSet.Files.Select(f => f.FileInfo).ToArray());
} }
/// <summary> /// <summary>
@ -161,6 +205,7 @@ namespace osu.Game.Beatmaps
if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo) if (beatmapInfo == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
return DefaultBeatmap; return DefaultBeatmap;
lock (beatmaps)
beatmaps.Populate(beatmapInfo); beatmaps.Populate(beatmapInfo);
if (beatmapInfo.BeatmapSet == null) if (beatmapInfo.BeatmapSet == null)
@ -181,6 +226,7 @@ namespace osu.Game.Beatmaps
/// </summary> /// </summary>
public void Reset() public void Reset()
{ {
lock (beatmaps)
beatmaps.Reset(); beatmaps.Reset();
} }
@ -190,6 +236,8 @@ namespace osu.Game.Beatmaps
/// <param name="query">The query.</param> /// <param name="query">The query.</param>
/// <returns>The first result for the provided query, or null if no results were found.</returns> /// <returns>The first result for the provided query, or null if no results were found.</returns>
public BeatmapSetInfo QueryBeatmapSet(Func<BeatmapSetInfo, bool> query) public BeatmapSetInfo QueryBeatmapSet(Func<BeatmapSetInfo, bool> query)
{
lock (beatmaps)
{ {
BeatmapSetInfo set = beatmaps.Query<BeatmapSetInfo>().FirstOrDefault(query); BeatmapSetInfo set = beatmaps.Query<BeatmapSetInfo>().FirstOrDefault(query);
@ -198,13 +246,17 @@ namespace osu.Game.Beatmaps
return set; return set;
} }
}
/// <summary> /// <summary>
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s. /// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
/// </summary> /// </summary>
/// <param name="query">The query.</param> /// <param name="query">The query.</param>
/// <returns>Results from the provided query.</returns> /// <returns>Results from the provided query.</returns>
public List<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query) => beatmaps.QueryAndPopulate(query); public List<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query)
{
lock (beatmaps) return beatmaps.QueryAndPopulate(query);
}
/// <summary> /// <summary>
/// Perform a lookup query on available <see cref="BeatmapInfo"/>s. /// Perform a lookup query on available <see cref="BeatmapInfo"/>s.
@ -212,6 +264,8 @@ namespace osu.Game.Beatmaps
/// <param name="query">The query.</param> /// <param name="query">The query.</param>
/// <returns>The first result for the provided query, or null if no results were found.</returns> /// <returns>The first result for the provided query, or null if no results were found.</returns>
public BeatmapInfo QueryBeatmap(Func<BeatmapInfo, bool> query) public BeatmapInfo QueryBeatmap(Func<BeatmapInfo, bool> query)
{
lock (beatmaps)
{ {
BeatmapInfo set = beatmaps.Query<BeatmapInfo>().FirstOrDefault(query); BeatmapInfo set = beatmaps.Query<BeatmapInfo>().FirstOrDefault(query);
@ -220,13 +274,17 @@ namespace osu.Game.Beatmaps
return set; return set;
} }
}
/// <summary> /// <summary>
/// Perform a lookup query on available <see cref="BeatmapInfo"/>s. /// Perform a lookup query on available <see cref="BeatmapInfo"/>s.
/// </summary> /// </summary>
/// <param name="query">The query.</param> /// <param name="query">The query.</param>
/// <returns>Results from the provided query.</returns> /// <returns>Results from the provided query.</returns>
public List<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query) => beatmaps.QueryAndPopulate(query); public List<BeatmapInfo> QueryBeatmaps(Expression<Func<BeatmapInfo, bool>> query)
{
lock (beatmaps) return beatmaps.QueryAndPopulate(query);
}
/// <summary> /// <summary>
/// Creates an <see cref="ArchiveReader"/> from a valid storage path. /// Creates an <see cref="ArchiveReader"/> from a valid storage path.
@ -258,19 +316,26 @@ namespace osu.Game.Beatmaps
var hash = hashable.ComputeSHA2Hash(); var hash = hashable.ComputeSHA2Hash();
// check if this beatmap has already been imported and exit early if so. // check if this beatmap has already been imported and exit early if so.
var beatmapSet = beatmaps.QueryAndPopulate<BeatmapSetInfo>().FirstOrDefault(b => b.Hash == hash); BeatmapSetInfo beatmapSet;
lock (beatmaps)
beatmapSet = beatmaps.QueryAndPopulate<BeatmapSetInfo>(b => b.Hash == hash).FirstOrDefault();
if (beatmapSet != null) if (beatmapSet != null)
{ {
Undelete(beatmapSet); Undelete(beatmapSet);
return beatmapSet; return beatmapSet;
} }
List<FileInfo> fileInfos = new List<FileInfo>(); List<BeatmapSetFileInfo> fileInfos = new List<BeatmapSetFileInfo>();
// import files to manager // import files to manager
foreach (string file in reader.Filenames) foreach (string file in reader.Filenames)
using (Stream s = reader.GetStream(file)) using (Stream s = reader.GetStream(file))
fileInfos.Add(files.Add(s, file)); fileInfos.Add(new BeatmapSetFileInfo
{
Filename = file,
FileInfo = files.Add(s)
});
BeatmapMetadata metadata; BeatmapMetadata metadata;
@ -324,12 +389,15 @@ namespace osu.Game.Beatmaps
/// <param name="populate">Whether returned objects should be pre-populated with all data.</param> /// <param name="populate">Whether returned objects should be pre-populated with all data.</param>
/// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns> /// <returns>A list of available <see cref="BeatmapSetInfo"/>.</returns>
public List<BeatmapSetInfo> GetAllUsableBeatmapSets(bool populate = true) public List<BeatmapSetInfo> GetAllUsableBeatmapSets(bool populate = true)
{
lock (beatmaps)
{ {
if (populate) if (populate)
return beatmaps.QueryAndPopulate<BeatmapSetInfo>(b => !b.DeletePending).ToList(); return beatmaps.QueryAndPopulate<BeatmapSetInfo>(b => !b.DeletePending).ToList();
else else
return beatmaps.Query<BeatmapSetInfo>(b => !b.DeletePending).ToList(); return beatmaps.Query<BeatmapSetInfo>(b => !b.DeletePending).ToList();
} }
}
protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap protected class BeatmapManagerWorkingBeatmap : WorkingBeatmap
{ {
@ -366,7 +434,7 @@ namespace osu.Game.Beatmaps
catch { return null; } 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() protected override Texture GetBackground()
{ {
@ -390,5 +458,51 @@ namespace osu.Game.Beatmaps
catch { return new TrackVirtual(); } catch { return new TrackVirtual(); }
} }
} }
/// <summary>
/// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future.
/// </summary>
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;
}
} }
} }

View File

@ -2,16 +2,26 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Game.IO; using osu.Game.IO;
using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes; using SQLiteNetExtensions.Attributes;
namespace osu.Game.Beatmaps namespace osu.Game.Beatmaps
{ {
public class BeatmapSetFileInfo public class BeatmapSetFileInfo
{ {
[ForeignKey(typeof(BeatmapSetInfo))] [PrimaryKey, AutoIncrement]
public int ID { get; set; }
[ForeignKey(typeof(BeatmapSetInfo)), NotNull]
public int BeatmapSetInfoID { get; set; } public int BeatmapSetInfoID { get; set; }
[ForeignKey(typeof(FileInfo))] [ForeignKey(typeof(FileInfo)), NotNull]
public int FileInfoID { get; set; } public int FileInfoID { get; set; }
[OneToOne(CascadeOperations = CascadeOperation.CascadeRead)]
public FileInfo FileInfo { get; set; }
[NotNull]
public string Filename { get; set; }
} }
} }

View File

@ -3,7 +3,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Game.IO;
using SQLite.Net.Attributes; using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes; using SQLiteNetExtensions.Attributes;
@ -37,8 +36,8 @@ namespace osu.Game.Beatmaps
public string StoryboardFile => Files.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename; public string StoryboardFile => Files.FirstOrDefault(f => f.Filename.EndsWith(".osb"))?.Filename;
[ManyToMany(typeof(BeatmapSetFileInfo), CascadeOperations = CascadeOperation.CascadeRead)] [OneToMany(CascadeOperations = CascadeOperation.All)]
public List<FileInfo> Files { get; set; } public List<BeatmapSetFileInfo> Files { get; set; }
public bool Protected { get; set; } public bool Protected { get; set; }
} }

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using osu.Framework.Logging;
using osu.Game.Database; using osu.Game.Database;
using SQLite.Net; using SQLite.Net;
using SQLiteNetExtensions.Extensions; using SQLiteNetExtensions.Extensions;
@ -21,7 +20,7 @@ namespace osu.Game.Beatmaps
/// The current version of this store. Used for migrations (see <see cref="PerformMigration(int, int)"/>). /// The current version of this store. Used for migrations (see <see cref="PerformMigration(int, int)"/>).
/// The initial version is 1. /// The initial version is 1.
/// </summary> /// </summary>
protected override int StoreVersion => 1; protected override int StoreVersion => 2;
public BeatmapStore(SQLiteConnection connection) public BeatmapStore(SQLiteConnection connection)
: base(connection) : base(connection)
@ -52,7 +51,11 @@ namespace osu.Game.Beatmaps
Connection.CreateTable<BeatmapSetInfo>(); Connection.CreateTable<BeatmapSetInfo>();
Connection.CreateTable<BeatmapSetFileInfo>(); Connection.CreateTable<BeatmapSetFileInfo>();
Connection.CreateTable<BeatmapInfo>(); Connection.CreateTable<BeatmapInfo>();
}
protected override void StartupTasks()
{
base.StartupTasks();
cleanupPendingDeletions(); cleanupPendingDeletions();
} }
@ -60,24 +63,19 @@ namespace osu.Game.Beatmaps
/// Perform migrations between two store versions. /// Perform migrations between two store versions.
/// </summary> /// </summary>
/// <param name="currentVersion">The current store version. This will be zero on a fresh database initialisation.</param> /// <param name="currentVersion">The current store version. This will be zero on a fresh database initialisation.</param>
/// <param name="newVersion">The target version which we are migrating to (equal to the current <see cref="StoreVersion"/>).</param> /// <param name="targetVersion">The target version which we are migrating to (equal to the current <see cref="StoreVersion"/>).</param>
protected override void PerformMigration(int currentVersion, int newVersion) protected override void PerformMigration(int currentVersion, int targetVersion)
{ {
base.PerformMigration(currentVersion, newVersion); base.PerformMigration(currentVersion, targetVersion);
while (currentVersion++ < newVersion) while (currentVersion++ < targetVersion)
{ {
switch (currentVersion) switch (currentVersion)
{ {
case 1: case 1:
// initialising from a version before we had versioning (or a fresh install). case 2:
// cannot migrate; breaking underlying changes.
// force adding of Protected column (not automatically migrated). Reset();
Connection.MigrateTable<BeatmapSetInfo>();
// remove all existing beatmaps.
foreach (var b in Connection.GetAllWithChildren<BeatmapSetInfo>(null, true))
Connection.Delete(b, true);
break; break;
} }
} }
@ -130,24 +128,12 @@ namespace osu.Game.Beatmaps
} }
private void cleanupPendingDeletions() private void cleanupPendingDeletions()
{
Connection.RunInTransaction(() =>
{ {
foreach (var b in QueryAndPopulate<BeatmapSetInfo>(b => b.DeletePending && !b.Protected)) foreach (var b in QueryAndPopulate<BeatmapSetInfo>(b => b.DeletePending && !b.Protected))
{
try
{
// many-to-many join table entries are not automatically tidied.
Connection.Table<BeatmapSetFileInfo>().Delete(f => f.BeatmapSetInfoID == b.ID);
Connection.Delete(b, true); 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<BeatmapSetInfo>("UPDATE BeatmapSetInfo SET DeletePending = 0 WHERE DeletePending IS NULL");
} }
} }
} }

View File

@ -4,8 +4,8 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using OpenTK; using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Beatmaps.Drawables namespace osu.Game.Beatmaps.Drawables
{ {
@ -22,23 +22,20 @@ namespace osu.Game.Beatmaps.Drawables
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
Children = new[] Children = new Drawable[]
{ {
new TextAwesome new SpriteIcon
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
TextSize = Size.X, RelativeSizeAxes = Axes.Both,
Colour = AccentColour, Colour = AccentColour,
Icon = FontAwesome.fa_circle Icon = FontAwesome.fa_circle
}, },
new TextAwesome new ConstrainedIconContainer
{ {
Anchor = Anchor.Centre, RelativeSizeAxes = Axes.Both,
Origin = Anchor.Centre, Icon = beatmap.Ruleset.CreateInstance().CreateIcon()
TextSize = Size.X,
Colour = Color4.White,
Icon = beatmap.Ruleset.CreateInstance().Icon
} }
}; };
} }

View File

@ -456,6 +456,11 @@ namespace osu.Game.Beatmaps.Formats
handleColours(beatmap, line, ref hasCustomColours); handleColours(beatmap, line, ref hasCustomColours);
break; break;
case Section.HitObjects: 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); var obj = parser.Parse(line);
if (obj != null) if (obj != null)

View File

@ -41,7 +41,7 @@ namespace osu.Game.Database
{ {
var storeName = GetType().Name; var storeName = GetType().Name;
var reportedVersion = Connection.Table<StoreVersion>().FirstOrDefault(s => s.StoreName == storeName) ?? new StoreVersion var reportedVersion = Connection.Table<StoreVersion>().Where(s => s.StoreName == storeName).FirstOrDefault() ?? new StoreVersion
{ {
StoreName = storeName, StoreName = storeName,
Version = 0 Version = 0
@ -51,14 +51,30 @@ namespace osu.Game.Database
PerformMigration(reportedVersion.Version, reportedVersion.Version = StoreVersion); PerformMigration(reportedVersion.Version, reportedVersion.Version = StoreVersion);
Connection.InsertOrReplace(reportedVersion); Connection.InsertOrReplace(reportedVersion);
StartupTasks();
} }
protected virtual void PerformMigration(int currentVersion, int newVersion) /// <summary>
/// Called when the database version of this store doesn't match the local version.
/// Any manual migration operations should be performed in this.
/// </summary>
/// <param name="currentVersion">The current store version. This will be zero on a fresh database initialisation.</param>
/// <param name="targetVersion">The target version which we are migrating to (equal to the current <see cref="StoreVersion"/>).</param>
protected virtual void PerformMigration(int currentVersion, int targetVersion)
{ {
} }
/// <summary> /// <summary>
/// Prepare this database for use. /// Perform any common startup tasks. Runs after <see cref="Prepare(bool)"/> and <see cref="PerformMigration(int, int)"/>.
/// </summary>
protected virtual void StartupTasks()
{
}
/// <summary>
/// Prepare this database for use. Tables should be created here.
/// </summary> /// </summary>
protected abstract void Prepare(bool reset = false); protected abstract void Prepare(bool reset = false);
@ -83,9 +99,9 @@ namespace osu.Game.Database
/// <summary> /// <summary>
/// Query and populate results. /// Query and populate results.
/// </summary> /// </summary>
/// <param name="filter">An optional filter to refine results.</param> /// <param name="filter">An filter to refine results.</param>
/// <returns></returns> /// <returns></returns>
public List<T> QueryAndPopulate<T>(Expression<Func<T, bool>> filter = null) public List<T> QueryAndPopulate<T>(Expression<Func<T, bool>> filter)
where T : class where T : class
{ {
checkType(typeof(T)); checkType(typeof(T));
@ -101,7 +117,6 @@ namespace osu.Game.Database
public void Populate<T>(T item, bool recursive = true) public void Populate<T>(T item, bool recursive = true)
{ {
checkType(item.GetType()); checkType(item.GetType());
Connection.GetChildren(item, recursive); Connection.GetChildren(item, recursive);
} }

View File

@ -0,0 +1,62 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// 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
{
/// <summary>
/// Display an icon that is forced to scale to the size of this container.
/// </summary>
public class ConstrainedIconContainer : CompositeDrawable
{
public Drawable Icon
{
get
{
return InternalChild;
}
set
{
InternalChild = value;
}
}
/// <summary>
/// Determines an edge effect of this <see cref="Container"/>.
/// Edge effects are e.g. glow or a shadow.
/// Only has an effect when <see cref="CompositeDrawable.Masking"/> is true.
/// </summary>
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;
}
}
}

View File

@ -1,13 +1,70 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>. // Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // 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 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; private FontAwesome icon;
@ -23,7 +80,8 @@ namespace osu.Game.Graphics
if (icon == value) return; if (icon == value) return;
icon = value; icon = value;
Text = ((char)icon).ToString(); if (IsLoaded)
updateTexture();
} }
} }
} }

View File

@ -35,7 +35,7 @@ namespace osu.Game.Graphics.UserInterface
private class BreadcrumbTabItem : OsuTabItem, IStateful<Visibility> private class BreadcrumbTabItem : OsuTabItem, IStateful<Visibility>
{ {
public readonly TextAwesome Chevron; public readonly SpriteIcon Chevron;
//don't allow clicking between transitions and don't make the chevron clickable //don't allow clicking between transitions and don't make the chevron clickable
public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Alpha == 1f && Text.ReceiveMouseInputAt(screenSpacePos); public override bool ReceiveMouseInputAt(Vector2 screenSpacePos) => Alpha == 1f && Text.ReceiveMouseInputAt(screenSpacePos);
@ -69,11 +69,11 @@ namespace osu.Game.Graphics.UserInterface
{ {
Text.TextSize = 16; Text.TextSize = 16;
Padding = new MarginPadding { Right = padding + 8 }; //padding + chevron width Padding = new MarginPadding { Right = padding + 8 }; //padding + chevron width
Add(Chevron = new TextAwesome Add(Chevron = new SpriteIcon
{ {
Anchor = Anchor.CentreRight, Anchor = Anchor.CentreRight,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
TextSize = 12, Size = new Vector2(12),
Icon = FontAwesome.fa_chevron_right, Icon = FontAwesome.fa_chevron_right,
Margin = new MarginPadding { Left = padding }, Margin = new MarginPadding { Left = padding },
Alpha = 0f, Alpha = 0f,

View File

@ -15,7 +15,7 @@ namespace osu.Game.Graphics.UserInterface
{ {
public class IconButton : OsuClickableContainer public class IconButton : OsuClickableContainer
{ {
private readonly TextAwesome icon; private readonly SpriteIcon icon;
private readonly Box hover; private readonly Box hover;
private readonly Container content; private readonly Container content;
@ -64,11 +64,11 @@ namespace osu.Game.Graphics.UserInterface
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Alpha = 0, Alpha = 0,
}, },
icon = new TextAwesome icon = new SpriteIcon
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Anchor = 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); hover.Colour = colours.Yellow.Opacity(0.6f);
flashColour = colours.Yellow; flashColour = colours.Yellow;
Enabled.ValueChanged += enabled => this.FadeColour(enabled ? Color4.White : colours.Gray9, 200, Easing.OutQuint);
} }
protected override bool OnHover(InputState state) protected override bool OnHover(InputState state)

View File

@ -9,7 +9,7 @@ namespace osu.Game.Graphics.UserInterface
{ {
public class LoadingAnimation : VisibilityContainer public class LoadingAnimation : VisibilityContainer
{ {
private readonly TextAwesome spinner; private readonly SpriteIcon spinner;
public LoadingAnimation() public LoadingAnimation()
{ {
@ -20,9 +20,9 @@ namespace osu.Game.Graphics.UserInterface
Children = new Drawable[] Children = new Drawable[]
{ {
spinner = new TextAwesome spinner = new SpriteIcon
{ {
TextSize = 20, Size = new Vector2(20),
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = FontAwesome.fa_spinner Icon = FontAwesome.fa_spinner

View File

@ -10,6 +10,7 @@ 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.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
{ {
@ -60,14 +61,13 @@ namespace osu.Game.Graphics.UserInterface
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Children = new Drawable[] Children = new Drawable[]
{ {
Chevron = new TextAwesome Chevron = new SpriteIcon
{ {
AlwaysPresent = true, AlwaysPresent = true,
Icon = FontAwesome.fa_chevron_right, Icon = FontAwesome.fa_chevron_right,
UseFullGlyphHeight = false,
Colour = Color4.Black, Colour = Color4.Black,
Alpha = 0.5f, Alpha = 0.5f,
TextSize = 8, Size = new Vector2(8),
Margin = new MarginPadding { Left = 3, Right = 3 }, Margin = new MarginPadding { Left = 3, Right = 3 },
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
@ -84,7 +84,7 @@ namespace osu.Game.Graphics.UserInterface
private Color4? accentColour; private Color4? accentColour;
protected readonly TextAwesome Chevron; protected readonly SpriteIcon Chevron;
protected readonly OsuSpriteText Label; protected readonly OsuSpriteText Label;
protected override void FormatForeground(bool hover = false) protected override void FormatForeground(bool hover = false)
@ -123,7 +123,7 @@ namespace osu.Game.Graphics.UserInterface
set { Text.Text = value; } set { Text.Text = value; }
} }
protected readonly TextAwesome Icon; protected readonly SpriteIcon Icon;
private Color4? accentColour; private Color4? accentColour;
public virtual Color4 AccentColour public virtual Color4 AccentColour
@ -152,13 +152,13 @@ namespace osu.Game.Graphics.UserInterface
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
}, },
Icon = new TextAwesome Icon = new SpriteIcon
{ {
Icon = FontAwesome.fa_chevron_down, Icon = FontAwesome.fa_chevron_down,
Anchor = Anchor.CentreRight, Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
Margin = new MarginPadding { Right = 4 }, Margin = new MarginPadding { Right = 4 },
TextSize = 20 Size = new Vector2(20),
} }
}; };
} }

View File

@ -209,10 +209,10 @@ namespace osu.Game.Graphics.UserInterface
Foreground.Children = new Drawable[] Foreground.Children = new Drawable[]
{ {
new TextAwesome new SpriteIcon
{ {
Icon = FontAwesome.fa_ellipsis_h, Icon = FontAwesome.fa_ellipsis_h,
TextSize = 14, Size = new Vector2(14),
Origin = Anchor.Centre, Origin = Anchor.Centre,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
} }

View File

@ -21,7 +21,7 @@ namespace osu.Game.Graphics.UserInterface
{ {
private readonly Box box; private readonly Box box;
private readonly SpriteText text; private readonly SpriteText text;
private readonly TextAwesome icon; private readonly SpriteIcon icon;
private Color4? accentColour; private Color4? accentColour;
public Color4 AccentColour public Color4 AccentColour
@ -99,9 +99,9 @@ namespace osu.Game.Graphics.UserInterface
TextSize = 14, TextSize = 14,
Font = @"Exo2.0-Bold", Font = @"Exo2.0-Bold",
}, },
icon = new TextAwesome icon = new SpriteIcon
{ {
TextSize = 14, Size = new Vector2(14),
Icon = FontAwesome.fa_circle_o, Icon = FontAwesome.fa_circle_o,
Shadow = true, Shadow = true,
}, },

View File

@ -3,6 +3,7 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Input; using osu.Framework.Input;
using OpenTK;
using OpenTK.Input; using OpenTK.Input;
namespace osu.Game.Graphics.UserInterface namespace osu.Game.Graphics.UserInterface
@ -16,13 +17,13 @@ namespace osu.Game.Graphics.UserInterface
Height = 35; Height = 35;
AddRange(new Drawable[] AddRange(new Drawable[]
{ {
new TextAwesome new SpriteIcon
{ {
Icon = FontAwesome.fa_search, Icon = FontAwesome.fa_search,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
Anchor = Anchor.CentreRight, Anchor = Anchor.CentreRight,
Margin = new MarginPadding { Right = 10 }, Margin = new MarginPadding { Right = 10 },
TextSize = 20 Size = new Vector2(20),
} }
}); });

View File

@ -142,16 +142,16 @@ namespace osu.Game.Graphics.UserInterface
private class Star : Container private class Star : Container
{ {
public readonly TextAwesome Icon; public readonly SpriteIcon Icon;
public Star() public Star()
{ {
Size = new Vector2(star_size); Size = new Vector2(star_size);
Children = new[] Children = new[]
{ {
Icon = new TextAwesome Icon = new SpriteIcon
{ {
TextSize = star_size, Size = new Vector2(star_size),
Icon = FontAwesome.fa_star, Icon = FontAwesome.fa_star,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,

View File

@ -215,7 +215,7 @@ namespace osu.Game.Graphics.UserInterface
{ {
private const double beat_in_time = 60; private const double beat_in_time = 60;
private readonly TextAwesome icon; private readonly SpriteIcon icon;
public FontAwesome Icon { set { icon.Icon = value; } } public FontAwesome Icon { set { icon.Icon = value; } }
@ -226,11 +226,11 @@ namespace osu.Game.Graphics.UserInterface
Children = new Drawable[] Children = new Drawable[]
{ {
icon = new TextAwesome icon = new SpriteIcon
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
TextSize = 25 Size = new Vector2(25),
} }
}; };
} }

View File

@ -11,8 +11,6 @@ namespace osu.Game.IO
[PrimaryKey, AutoIncrement] [PrimaryKey, AutoIncrement]
public int ID { get; set; } public int ID { get; set; }
public string Filename { get; set; }
[Indexed(Unique = true)] [Indexed(Unique = true)]
public string Hash { get; set; } public string Hash { get; set; }

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System; using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using osu.Framework.Extensions; using osu.Framework.Extensions;
@ -23,6 +22,8 @@ namespace osu.Game.IO
public readonly ResourceStore<byte[]> Store; public readonly ResourceStore<byte[]> Store;
protected override int StoreVersion => 2;
public FileStore(SQLiteConnection connection, Storage storage) : base(connection, storage) public FileStore(SQLiteConnection connection, Storage storage) : base(connection, storage)
{ {
Store = new NamespacedResourceStore<byte[]>(new StorageBackedResourceStore(storage), prefix); Store = new NamespacedResourceStore<byte[]>(new StorageBackedResourceStore(storage), prefix);
@ -35,25 +36,55 @@ namespace osu.Game.IO
protected override void Prepare(bool reset = false) protected override void Prepare(bool reset = false)
{ {
if (reset) 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<FileInfo>(); Connection.DropTable<FileInfo>();
}
Connection.CreateTable<FileInfo>(); Connection.CreateTable<FileInfo>();
}
protected override void StartupTasks()
{
base.StartupTasks();
deletePending(); deletePending();
} }
public FileInfo Add(Stream data, string filename = null) /// <summary>
/// Perform migrations between two store versions.
/// </summary>
/// <param name="currentVersion">The current store version. This will be zero on a fresh database initialisation.</param>
/// <param name="targetVersion">The target version which we are migrating to (equal to the current <see cref="StoreVersion"/>).</param>
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(); string hash = data.ComputeSHA2Hash();
var info = new FileInfo var existing = Connection.Table<FileInfo>().Where(f => f.Hash == hash).FirstOrDefault();
{
Filename = filename,
Hash = hash,
};
var existing = Connection.Table<FileInfo>().FirstOrDefault(f => f.Hash == info.Hash);
var info = existing ?? new FileInfo { Hash = hash };
if (existing != null) if (existing != null)
{ {
info = existing; info = existing;
@ -73,42 +104,57 @@ namespace osu.Game.IO
Connection.Insert(info); Connection.Insert(info);
} }
Reference(new[] { info }); Reference(info);
return info; return info;
} }
public void Reference(IEnumerable<FileInfo> files) public void Reference(params FileInfo[] files)
{ {
foreach (var f in files) Connection.RunInTransaction(() =>
{ {
f.ReferenceCount++; var incrementedFiles = files.GroupBy(f => f.ID).Select(f =>
Connection.Update(f); {
} var accurateRefCount = Connection.Get<FileInfo>(f.First().ID);
accurateRefCount.ReferenceCount += f.Count();
return accurateRefCount;
});
Connection.UpdateAll(incrementedFiles);
});
} }
public void Dereference(IEnumerable<FileInfo> files) public void Dereference(params FileInfo[] files)
{ {
foreach (var f in files) Connection.RunInTransaction(() =>
{ {
f.ReferenceCount--; var incrementedFiles = files.GroupBy(f => f.ID).Select(f =>
Connection.Update(f); {
} var accurateRefCount = Connection.Get<FileInfo>(f.First().ID);
accurateRefCount.ReferenceCount -= f.Count();
return accurateRefCount;
});
Connection.UpdateAll(incrementedFiles);
});
} }
private void deletePending() private void deletePending()
{ {
foreach (var f in QueryAndPopulate<FileInfo>(f => f.ReferenceCount < 1)) Connection.RunInTransaction(() =>
{
foreach (var f in Query<FileInfo>(f => f.ReferenceCount < 1))
{ {
try try
{ {
Storage.Delete(Path.Combine(prefix, f.StoragePath));
Connection.Delete(f); Connection.Delete(f);
Storage.Delete(Path.Combine(prefix, f.Hash));
} }
catch (Exception e) catch (Exception e)
{ {
Logger.Error(e, $@"Could not delete beatmap {f}"); Logger.Error(e, $@"Could not delete beatmap {f}");
} }
} }
});
} }
} }
} }

View File

@ -21,15 +21,14 @@ namespace osu.Game.Online.Multiplayer
public override string Name => "Tag"; public override string Name => "Tag";
public override Drawable GetIcon(OsuColour colours, float size) public override Drawable GetIcon(OsuColour colours, float size)
{ {
return new TextAwesome return new SpriteIcon
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = FontAwesome.fa_refresh, Icon = FontAwesome.fa_refresh,
TextSize = size, Size = new Vector2(size),
Colour = colours.Blue, Colour = colours.Blue,
Shadow = false, Shadow = false,
UseFullGlyphHeight = false,
}; };
} }
} }
@ -61,21 +60,19 @@ namespace osu.Game.Online.Multiplayer
Spacing = new Vector2(2f), Spacing = new Vector2(2f),
Children = new[] Children = new[]
{ {
new TextAwesome new SpriteIcon
{ {
Icon = FontAwesome.fa_refresh, Icon = FontAwesome.fa_refresh,
TextSize = size * 0.75f, Size = new Vector2(size * 0.75f),
Colour = colours.Blue, Colour = colours.Blue,
Shadow = false, Shadow = false,
UseFullGlyphHeight = false,
}, },
new TextAwesome new SpriteIcon
{ {
Icon = FontAwesome.fa_refresh, Icon = FontAwesome.fa_refresh,
TextSize = size * 0.75f, Size = new Vector2(size * 0.75f),
Colour = colours.Pink, Colour = colours.Pink,
Shadow = false, Shadow = false,
UseFullGlyphHeight = false,
}, },
}, },
}; };

View File

@ -20,6 +20,7 @@ using osu.Game.Screens.Menu;
using OpenTK; using OpenTK;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using osu.Framework.Platform;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
@ -47,6 +48,8 @@ namespace osu.Game
private UserProfileOverlay userProfile; private UserProfileOverlay userProfile;
public virtual Storage GetStorageForStableInstall() => null;
private Intro intro private Intro intro
{ {
get get
@ -149,6 +152,10 @@ namespace osu.Game
{ {
base.LoadComplete(); base.LoadComplete();
// hook up notifications to components.
BeatmapManager.PostNotification = n => notificationOverlay?.Post(n);
BeatmapManager.GetStableStorage = GetStorageForStableInstall;
AddRange(new Drawable[] { AddRange(new Drawable[] {
new VolumeControlReceptor new VolumeControlReceptor
{ {
@ -332,6 +339,7 @@ namespace osu.Game
direct.State = Visibility.Hidden; direct.State = Visibility.Hidden;
social.State = Visibility.Hidden; social.State = Visibility.Hidden;
userProfile.State = Visibility.Hidden; userProfile.State = Visibility.Hidden;
notificationOverlay.State = Visibility.Hidden;
} }
else else
{ {

View File

@ -28,7 +28,7 @@ namespace osu.Game.Overlays.Chat
private readonly Bindable<bool> joinedBind = new Bindable<bool>(); private readonly Bindable<bool> joinedBind = new Bindable<bool>();
private readonly OsuSpriteText name; private readonly OsuSpriteText name;
private readonly OsuSpriteText topic; private readonly OsuSpriteText topic;
private readonly TextAwesome joinedCheckmark; private readonly SpriteIcon joinedCheckmark;
private Color4 joinedColour; private Color4 joinedColour;
private Color4 topicColour; private Color4 topicColour;
@ -68,12 +68,12 @@ namespace osu.Game.Overlays.Chat
{ {
Children = new[] Children = new[]
{ {
joinedCheckmark = new TextAwesome joinedCheckmark = new SpriteIcon
{ {
Anchor = Anchor.TopRight, Anchor = Anchor.TopRight,
Origin = Anchor.TopRight, Origin = Anchor.TopRight,
Icon = FontAwesome.fa_check_circle, Icon = FontAwesome.fa_check_circle,
TextSize = text_size, Size = new Vector2(text_size),
Shadow = false, Shadow = false,
Margin = new MarginPadding { Right = 10f }, Margin = new MarginPadding { Right = 10f },
Alpha = 0f, Alpha = 0f,
@ -121,10 +121,10 @@ namespace osu.Game.Overlays.Chat
Spacing = new Vector2(3f, 0f), Spacing = new Vector2(3f, 0f),
Children = new Drawable[] Children = new Drawable[]
{ {
new TextAwesome new SpriteIcon
{ {
Icon = FontAwesome.fa_user, Icon = FontAwesome.fa_user,
TextSize = text_size - 2, Size = new Vector2(text_size - 2),
Shadow = false, Shadow = false,
Margin = new MarginPadding { Top = 1 }, Margin = new MarginPadding { Top = 1 },
}, },

View File

@ -35,13 +35,13 @@ namespace osu.Game.Overlays.Chat
TabContainer.Spacing = new Vector2(-shear_width, 0); TabContainer.Spacing = new Vector2(-shear_width, 0);
TabContainer.Masking = false; TabContainer.Masking = false;
AddInternal(new TextAwesome AddInternal(new SpriteIcon
{ {
Icon = FontAwesome.fa_comments, Icon = FontAwesome.fa_comments,
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
TextSize = 20, Size = new Vector2(20),
Padding = new MarginPadding(10), Margin = new MarginPadding(10),
}); });
AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" })); AddTabItem(selectorTab = new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" }));
@ -72,7 +72,7 @@ namespace osu.Game.Overlays.Chat
private readonly SpriteText textBold; private readonly SpriteText textBold;
private readonly Box box; private readonly Box box;
private readonly Box highlightBox; private readonly Box highlightBox;
private readonly TextAwesome icon; private readonly SpriteIcon icon;
private void updateState() private void updateState()
{ {
@ -176,7 +176,7 @@ namespace osu.Game.Overlays.Chat
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Children = new Drawable[] Children = new Drawable[]
{ {
icon = new TextAwesome icon = new SpriteIcon
{ {
Icon = FontAwesome.fa_hashtag, Icon = FontAwesome.fa_hashtag,
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
@ -184,7 +184,7 @@ namespace osu.Game.Overlays.Chat
Colour = Color4.Black, Colour = Color4.Black,
X = -10, X = -10,
Alpha = 0.2f, Alpha = 0.2f,
TextSize = ChatOverlay.TAB_AREA_HEIGHT, Size = new Vector2(ChatOverlay.TAB_AREA_HEIGHT),
}, },
text = new OsuSpriteText text = new OsuSpriteText
{ {

View File

@ -30,14 +30,14 @@ namespace osu.Game.Overlays.Dialog
private readonly Container content; private readonly Container content;
private readonly Container ring; private readonly Container ring;
private readonly FillFlowContainer<PopupDialogButton> buttonsContainer; private readonly FillFlowContainer<PopupDialogButton> buttonsContainer;
private readonly TextAwesome iconText; private readonly SpriteIcon icon;
private readonly SpriteText header; private readonly SpriteText header;
private readonly SpriteText body; private readonly SpriteText body;
public FontAwesome Icon public FontAwesome Icon
{ {
get { return iconText.Icon; } get { return icon.Icon; }
set { iconText.Icon = value; } set { icon.Icon = value; }
} }
public string HeaderText public string HeaderText
@ -205,12 +205,12 @@ namespace osu.Game.Overlays.Dialog
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.Black.Opacity(0), Colour = Color4.Black.Opacity(0),
}, },
iconText = new TextAwesome icon = new SpriteIcon
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Icon = FontAwesome.fa_close, Icon = FontAwesome.fa_close,
TextSize = 50, Size = new Vector2(50),
}, },
}, },
}, },

View File

@ -152,18 +152,17 @@ namespace osu.Game.Overlays.Direct
private class DownloadButton : OsuClickableContainer private class DownloadButton : OsuClickableContainer
{ {
private readonly TextAwesome icon; private readonly SpriteIcon icon;
public DownloadButton() public DownloadButton()
{ {
Children = new Drawable[] Children = new Drawable[]
{ {
icon = new TextAwesome icon = new SpriteIcon
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
UseFullGlyphHeight = false, Size = new Vector2(30),
TextSize = 30,
Icon = FontAwesome.fa_osu_chevron_down_o, Icon = FontAwesome.fa_osu_chevron_down_o,
}, },
}; };

View File

@ -75,11 +75,11 @@ namespace osu.Game.Overlays.Direct
{ {
Font = @"Exo2.0-SemiBoldItalic", Font = @"Exo2.0-SemiBoldItalic",
}, },
new TextAwesome new SpriteIcon
{ {
Icon = icon, Icon = icon,
Shadow = true, Shadow = true,
TextSize = 14, Size = new Vector2(14),
Margin = new MarginPadding { Top = 1 }, Margin = new MarginPadding { Top = 1 },
}, },
}; };

View File

@ -47,7 +47,11 @@ namespace osu.Game.Overlays.Direct
private class RulesetToggleButton : OsuClickableContainer private class RulesetToggleButton : OsuClickableContainer
{ {
private readonly TextAwesome icon; private Drawable icon
{
get { return iconContainer.Icon; }
set { iconContainer.Icon = value; }
}
private RulesetInfo ruleset; private RulesetInfo ruleset;
public RulesetInfo Ruleset public RulesetInfo Ruleset
@ -56,15 +60,17 @@ namespace osu.Game.Overlays.Direct
set set
{ {
ruleset = value; ruleset = value;
icon.Icon = Ruleset.CreateInstance().Icon; icon = Ruleset.CreateInstance().CreateIcon();
} }
} }
private readonly Bindable<RulesetInfo> bindable; private readonly Bindable<RulesetInfo> bindable;
private readonly ConstrainedIconContainer iconContainer;
private void Bindable_ValueChanged(RulesetInfo obj) 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<RulesetInfo> bindable, RulesetInfo ruleset) public RulesetToggleButton(Bindable<RulesetInfo> bindable, RulesetInfo ruleset)
@ -74,11 +80,11 @@ namespace osu.Game.Overlays.Direct
Children = new[] Children = new[]
{ {
icon = new TextAwesome iconContainer = new ConstrainedIconContainer
{ {
Origin = Anchor.TopLeft, Origin = Anchor.TopLeft,
Anchor = Anchor.TopLeft, Anchor = Anchor.TopLeft,
TextSize = 32, Size = new Vector2(32),
} }
}; };

View File

@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Music
{ {
CornerRadius = 5; CornerRadius = 5;
Height = 30; Height = 30;
Icon.TextSize = 14; Icon.Size = new Vector2(14);
Icon.Margin = new MarginPadding(0); Icon.Margin = new MarginPadding(0);
Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 10, Right = 10 }; Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 10, Right = 10 };
EdgeEffect = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters

View File

@ -12,6 +12,7 @@ using osu.Framework.Localisation;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using OpenTK;
namespace osu.Game.Overlays.Music namespace osu.Game.Overlays.Music
{ {
@ -22,7 +23,7 @@ namespace osu.Game.Overlays.Music
private Color4 hoverColour; private Color4 hoverColour;
private Color4 artistColour; private Color4 artistColour;
private TextAwesome handle; private SpriteIcon handle;
private TextFlowContainer text; private TextFlowContainer text;
private IEnumerable<SpriteText> titleSprites; private IEnumerable<SpriteText> titleSprites;
private UnicodeBindableString titleBind; private UnicodeBindableString titleBind;
@ -67,16 +68,15 @@ namespace osu.Game.Overlays.Music
Children = new Drawable[] Children = new Drawable[]
{ {
handle = new TextAwesome handle = new SpriteIcon
{ {
Anchor = Anchor.TopLeft, Anchor = Anchor.TopLeft,
Origin = Anchor.TopLeft, Origin = Anchor.TopLeft,
TextSize = 12, Size = new Vector2(12),
Colour = colours.Gray5, Colour = colours.Gray5,
Icon = FontAwesome.fa_bars, Icon = FontAwesome.fa_bars,
Alpha = 0f, Alpha = 0f,
Margin = new MarginPadding { Left = 5 }, Margin = new MarginPadding { Left = 5, Top = 2 },
Padding = new MarginPadding { Top = 2 },
}, },
text = new OsuTextFlowContainer text = new OsuTextFlowContainer
{ {

View File

@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Music
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) 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); if (itemToRemove != null) items.Remove(itemToRemove);
} }

View File

@ -6,14 +6,14 @@ using System.Linq;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Configuration; using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Input;
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.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using OpenTK; using OpenTK;
using OpenTK.Graphics; using OpenTK.Graphics;
using osu.Framework.Input;
using osu.Framework.Graphics.Shapes;
namespace osu.Game.Overlays.Music 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(); 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); beatmapBacking.BindTo(game.Beatmap);

View File

@ -12,18 +12,18 @@ using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Extensions.Color4Extensions;
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.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures; using osu.Framework.Graphics.Textures;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input; using osu.Framework.Input;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Threading;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Framework.Threading;
using osu.Game.Overlays.Music; using osu.Game.Overlays.Music;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
namespace osu.Game.Overlays namespace osu.Game.Overlays
@ -41,7 +41,9 @@ namespace osu.Game.Overlays
private Drawable currentBackground; private Drawable currentBackground;
private ProgressBar progressBar; private ProgressBar progressBar;
private IconButton prevButton;
private IconButton playButton; private IconButton playButton;
private IconButton nextButton;
private IconButton playlistButton; private IconButton playlistButton;
private SpriteText title, artist; private SpriteText title, artist;
@ -158,7 +160,7 @@ namespace osu.Game.Overlays
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Children = new[] Children = new[]
{ {
new IconButton prevButton = new IconButton
{ {
Action = prev, Action = prev,
Icon = FontAwesome.fa_step_backward, Icon = FontAwesome.fa_step_backward,
@ -170,7 +172,7 @@ namespace osu.Game.Overlays
Action = play, Action = play,
Icon = FontAwesome.fa_play_circle_o, Icon = FontAwesome.fa_play_circle_o,
}, },
new IconButton nextButton = new IconButton
{ {
Action = next, Action = next,
Icon = FontAwesome.fa_step_forward, Icon = FontAwesome.fa_step_forward,
@ -209,11 +211,22 @@ namespace osu.Game.Overlays
protected override void LoadComplete() protected override void LoadComplete()
{ {
beatmapBacking.ValueChanged += beatmapChanged; beatmapBacking.ValueChanged += beatmapChanged;
beatmapBacking.DisabledChanged += beatmapDisabledChanged;
beatmapBacking.TriggerChange(); beatmapBacking.TriggerChange();
base.LoadComplete(); 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() protected override void UpdateAfterChildren()
{ {
base.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; 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 else
playButton.Icon = FontAwesome.fa_play_circle_o; playButton.Icon = FontAwesome.fa_play_circle_o;
@ -245,6 +259,7 @@ namespace osu.Game.Overlays
if (track == null) if (track == null)
{ {
if (!beatmapBacking.Disabled)
playlist.PlayNext(); playlist.PlayNext();
return; return;
} }
@ -257,16 +272,12 @@ namespace osu.Game.Overlays
private void prev() private void prev()
{ {
if (beatmapBacking.Disabled) return;
queuedDirection = TransformDirection.Prev; queuedDirection = TransformDirection.Prev;
playlist.PlayPrevious(); playlist.PlayPrevious();
} }
private void next() private void next()
{ {
if (beatmapBacking.Disabled) return;
queuedDirection = TransformDirection.Next; queuedDirection = TransformDirection.Next;
playlist.PlayNext(); playlist.PlayNext();
} }

View File

@ -165,12 +165,12 @@ namespace osu.Game.Overlays.Notifications
Children = new[] Children = new[]
{ {
new TextAwesome new SpriteIcon
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = FontAwesome.fa_times_circle, Icon = FontAwesome.fa_times_circle,
TextSize = 20 Size = new Vector2(20),
} }
}; };
} }

View File

@ -8,6 +8,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using OpenTK;
namespace osu.Game.Overlays.Notifications namespace osu.Game.Overlays.Notifications
{ {
@ -36,7 +37,7 @@ namespace osu.Game.Overlays.Notifications
} }
private readonly SpriteText textDrawable; private readonly SpriteText textDrawable;
private readonly TextAwesome iconDrawable; private readonly SpriteIcon iconDrawable;
protected Box IconBackgound; protected Box IconBackgound;
@ -49,12 +50,12 @@ namespace osu.Game.Overlays.Notifications
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.6f)) Colour = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.6f))
}, },
iconDrawable = new TextAwesome iconDrawable = new SpriteIcon
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = icon, Icon = icon,
TextSize = 20 Size = new Vector2(20),
} }
}); });

View File

@ -110,12 +110,12 @@ namespace osu.Game.Overlays.Profile
Alpha = 0, Alpha = 0,
AlwaysPresent = true AlwaysPresent = true
}, },
new TextAwesome new SpriteIcon
{ {
Icon = FontAwesome.fa_heart, Icon = FontAwesome.fa_heart,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
TextSize = 12 Size = new Vector2(12),
} }
} }
}, },

View File

@ -55,7 +55,7 @@ namespace osu.Game.Overlays.SearchableList
private class DisplayStyleToggleButton : OsuClickableContainer private class DisplayStyleToggleButton : OsuClickableContainer
{ {
private readonly TextAwesome icon; private readonly SpriteIcon icon;
private readonly PanelDisplayStyle style; private readonly PanelDisplayStyle style;
private readonly Bindable<PanelDisplayStyle> bindable; private readonly Bindable<PanelDisplayStyle> bindable;
@ -67,13 +67,12 @@ namespace osu.Game.Overlays.SearchableList
Children = new Drawable[] Children = new Drawable[]
{ {
this.icon = new TextAwesome this.icon = new SpriteIcon
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = icon, Icon = icon,
TextSize = 18, Size = new Vector2(18),
UseFullGlyphHeight = false,
Alpha = 0.5f, Alpha = 0.5f,
}, },
}; };

View File

@ -55,9 +55,9 @@ namespace osu.Game.Overlays.SearchableList
Spacing = new Vector2(10f, 0f), Spacing = new Vector2(10f, 0f),
Children = new[] Children = new[]
{ {
new TextAwesome new SpriteIcon
{ {
TextSize = 25, Size = new Vector2(25),
Icon = Icon, Icon = Icon,
}, },
CreateHeaderText(), CreateHeaderText(),

View File

@ -6,6 +6,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using OpenTK;
namespace osu.Game.Overlays.SearchableList namespace osu.Game.Overlays.SearchableList
{ {
@ -19,7 +20,7 @@ namespace osu.Game.Overlays.SearchableList
public SlimDropdownHeader() public SlimDropdownHeader()
{ {
Height = 25; Height = 25;
Icon.TextSize = 16; Icon.Size = new Vector2(16);
Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 8, Right = 4 }; Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 8, Right = 4 };
} }

View File

@ -286,7 +286,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
{ {
public const float LABEL_LEFT_MARGIN = 20; public const float LABEL_LEFT_MARGIN = 20;
private readonly TextAwesome statusIcon; private readonly SpriteIcon statusIcon;
public Color4 StatusColour public Color4 StatusColour
{ {
set set
@ -308,15 +308,15 @@ namespace osu.Game.Overlays.Settings.Sections.General
Radius = 4, Radius = 4,
}; };
Icon.TextSize = 14; Icon.Size = new Vector2(14);
Icon.Margin = new MarginPadding(0); Icon.Margin = new MarginPadding(0);
Foreground.Add(statusIcon = new TextAwesome Foreground.Add(statusIcon = new SpriteIcon
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Icon = FontAwesome.fa_circle_o, Icon = FontAwesome.fa_circle_o,
TextSize = 14, Size = new Vector2(14),
}); });
Text.Margin = new MarginPadding { Left = LABEL_LEFT_MARGIN }; Text.Margin = new MarginPadding { Left = LABEL_LEFT_MARGIN };

View File

@ -0,0 +1,47 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// 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));
}
},
};
}
}
}

View File

@ -3,6 +3,7 @@
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Overlays.Settings.Sections.Maintenance;
using OpenTK; using OpenTK;
namespace osu.Game.Overlays.Settings.Sections namespace osu.Game.Overlays.Settings.Sections
@ -17,6 +18,7 @@ namespace osu.Game.Overlays.Settings.Sections
FlowContent.Spacing = new Vector2(0, 5); FlowContent.Spacing = new Vector2(0, 5);
Children = new Drawable[] Children = new Drawable[]
{ {
new GeneralSettings()
}; };
} }
} }

View File

@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using OpenTK; using OpenTK;
@ -27,12 +28,14 @@ namespace osu.Game.Overlays.Settings
foreach (var ruleset in rulesets.AllRulesets) 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, Colour = Color4.Gray,
TextSize = 20 Size = new Vector2(20),
}); };
modes.Add(icon);
} }
Children = new Drawable[] Children = new Drawable[]

View File

@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Settings
{ {
public class SidebarButton : Container public class SidebarButton : Container
{ {
private readonly TextAwesome drawableIcon; private readonly SpriteIcon drawableIcon;
private readonly SpriteText headerText; private readonly SpriteText headerText;
private readonly Box backgroundBox; private readonly Box backgroundBox;
private readonly Box selectionIndicator; private readonly Box selectionIndicator;
@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Settings
Width = Sidebar.DEFAULT_WIDTH, Width = Sidebar.DEFAULT_WIDTH,
RelativeSizeAxes = Axes.Y, RelativeSizeAxes = Axes.Y,
Colour = OsuColour.Gray(0.6f), Colour = OsuColour.Gray(0.6f),
Children = new[] Children = new Drawable[]
{ {
headerText = new OsuSpriteText headerText = new OsuSpriteText
{ {
@ -85,11 +85,11 @@ namespace osu.Game.Overlays.Settings
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
}, },
drawableIcon = new TextAwesome drawableIcon = new SpriteIcon
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
TextSize = 20 Size = new Vector2(20),
}, },
} }
}, },

View File

@ -20,10 +20,21 @@ namespace osu.Game.Overlays.Toolbar
{ {
public const float WIDTH = Toolbar.HEIGHT * 1.4f; 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 public FontAwesome Icon
{ {
get { return DrawableIcon.Icon; } set { SetIcon(value); }
set { DrawableIcon.Icon = value; }
} }
public string Text public string Text
@ -55,7 +66,7 @@ namespace osu.Game.Overlays.Toolbar
protected virtual Anchor TooltipAnchor => Anchor.TopLeft; protected virtual Anchor TooltipAnchor => Anchor.TopLeft;
protected TextAwesome DrawableIcon; protected ConstrainedIconContainer IconContainer;
protected SpriteText DrawableText; protected SpriteText DrawableText;
protected Box HoverBackground; protected Box HoverBackground;
private readonly FillFlowContainer tooltipContainer; private readonly FillFlowContainer tooltipContainer;
@ -88,11 +99,12 @@ namespace osu.Game.Overlays.Toolbar
AutoSizeAxes = Axes.X, AutoSizeAxes = Axes.X,
Children = new Drawable[] Children = new Drawable[]
{ {
DrawableIcon = new TextAwesome IconContainer = new ConstrainedIconContainer
{ {
Anchor = Anchor.Centre, Anchor = Anchor.CentreLeft,
Origin = Anchor.Centre, Origin = Anchor.CentreLeft,
TextSize = 20 Size = new Vector2(20),
Alpha = 0,
}, },
DrawableText = new OsuSpriteText DrawableText = new OsuSpriteText
{ {

View File

@ -10,7 +10,7 @@ namespace osu.Game.Overlays.Toolbar
{ {
public ToolbarChatButton() public ToolbarChatButton()
{ {
Icon = FontAwesome.fa_comments; SetIcon(FontAwesome.fa_comments);
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]

View File

@ -21,7 +21,7 @@ namespace osu.Game.Overlays.Toolbar
TooltipMain = rInstance.Description; TooltipMain = rInstance.Description;
TooltipSub = $"Play some {rInstance.Description}"; TooltipSub = $"Play some {rInstance.Description}";
Icon = rInstance.Icon; SetIcon(rInstance.CreateIcon());
} }
} }
@ -31,9 +31,8 @@ namespace osu.Game.Overlays.Toolbar
{ {
if (value) if (value)
{ {
DrawableIcon.Colour = Color4.White; IconContainer.Colour = Color4.White;
DrawableIcon.Masking = true; IconContainer.EdgeEffect = new EdgeEffectParameters
DrawableIcon.EdgeEffect = new EdgeEffectParameters
{ {
Type = EdgeEffectType.Glow, Type = EdgeEffectType.Glow,
Colour = new Color4(255, 194, 224, 100), Colour = new Color4(255, 194, 224, 100),
@ -43,8 +42,8 @@ namespace osu.Game.Overlays.Toolbar
} }
else else
{ {
DrawableIcon.Masking = false; IconContainer.Colour = new Color4(255, 194, 224, 255);
DrawableIcon.Colour = new Color4(255, 194, 224, 255); IconContainer.EdgeEffect = new EdgeEffectParameters();
} }
} }
} }
@ -52,7 +51,7 @@ namespace osu.Game.Overlays.Toolbar
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
DrawableIcon.TextSize *= 1.4f; IconContainer.Scale *= 1.4f;
} }
} }
} }

View File

@ -7,6 +7,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Scoring; using osu.Game.Rulesets.Scoring;
using osu.Game.Overlays.Settings; using osu.Game.Overlays.Settings;
@ -33,7 +34,7 @@ namespace osu.Game.Rulesets
public abstract ScoreProcessor CreateScoreProcessor(); 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; } public abstract string Description { get; }

View File

@ -62,7 +62,7 @@ namespace osu.Game.Rulesets
{ {
var us = createRulesetInfo(r); var us = createRulesetInfo(r);
var existing = Query<RulesetInfo>().FirstOrDefault(ri => ri.InstantiationInfo == us.InstantiationInfo); var existing = Query<RulesetInfo>().Where(ri => ri.InstantiationInfo == us.InstantiationInfo).FirstOrDefault();
if (existing == null) if (existing == null)
Connection.Insert(us); Connection.Insert(us);

View File

@ -8,13 +8,14 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using OpenTK;
namespace osu.Game.Rulesets.UI namespace osu.Game.Rulesets.UI
{ {
public class ModIcon : Container public class ModIcon : Container
{ {
private readonly TextAwesome modIcon; private readonly SpriteIcon modIcon;
private readonly TextAwesome background; private readonly SpriteIcon background;
private const float icon_size = 80; private const float icon_size = 80;
@ -34,20 +35,20 @@ namespace osu.Game.Rulesets.UI
Children = new Drawable[] Children = new Drawable[]
{ {
background = new TextAwesome background = new SpriteIcon
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
TextSize = icon_size, Size = new Vector2(icon_size),
Icon = FontAwesome.fa_osu_mod_bg, Icon = FontAwesome.fa_osu_mod_bg,
Shadow = true, Shadow = true,
}, },
modIcon = new TextAwesome modIcon = new SpriteIcon
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Colour = OsuColour.Gray(84), Colour = OsuColour.Gray(84),
TextSize = icon_size - 35, Size = new Vector2(icon_size - 35),
Icon = mod.Icon Icon = mod.Icon
}, },
}; };

View File

@ -31,7 +31,7 @@ namespace osu.Game.Screens.Menu
private readonly Container iconText; private readonly Container iconText;
private readonly Container box; private readonly Container box;
private readonly Box boxHoverLayer; private readonly Box boxHoverLayer;
private readonly TextAwesome icon; private readonly SpriteIcon icon;
private readonly string sampleName; private readonly string sampleName;
private readonly Action clickAction; private readonly Action clickAction;
private readonly Key triggerKey; private readonly Key triggerKey;
@ -95,12 +95,12 @@ namespace osu.Game.Screens.Menu
Origin = Anchor.Centre, Origin = Anchor.Centre,
Children = new Drawable[] Children = new Drawable[]
{ {
icon = new TextAwesome icon = new SpriteIcon
{ {
Shadow = true, Shadow = true,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
TextSize = 30, Size = new Vector2(30),
Position = new Vector2(0, 0), Position = new Vector2(0, 0),
Icon = symbol Icon = symbol
}, },

View File

@ -15,7 +15,7 @@ namespace osu.Game.Screens.Menu
internal class Disclaimer : OsuScreen internal class Disclaimer : OsuScreen
{ {
private Intro intro; private Intro intro;
private readonly TextAwesome icon; private readonly SpriteIcon icon;
private Color4 iconColour; private Color4 iconColour;
internal override bool ShowOverlays => false; internal override bool ShowOverlays => false;
@ -37,12 +37,12 @@ namespace osu.Game.Screens.Menu
Spacing = new Vector2(0, 2), Spacing = new Vector2(0, 2),
Children = new Drawable[] Children = new Drawable[]
{ {
icon = new TextAwesome icon = new SpriteIcon
{ {
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Icon = FontAwesome.fa_warning, Icon = FontAwesome.fa_warning,
TextSize = 30, Size = new Vector2(30),
}, },
new OsuSpriteText new OsuSpriteText
{ {

View File

@ -227,9 +227,9 @@ namespace osu.Game.Screens.Play
Direction = FillDirection.Horizontal, Direction = FillDirection.Horizontal,
Children = new[] Children = new[]
{ {
new TextAwesome { Icon = FontAwesome.fa_chevron_right }, new SpriteIcon { Icon = FontAwesome.fa_chevron_right },
new TextAwesome { Icon = FontAwesome.fa_chevron_right }, new SpriteIcon { Icon = FontAwesome.fa_chevron_right },
new TextAwesome { Icon = FontAwesome.fa_chevron_right }, new SpriteIcon { Icon = FontAwesome.fa_chevron_right },
} }
}, },
new OsuSpriteText new OsuSpriteText

View File

@ -78,14 +78,14 @@ namespace osu.Game.Screens.Ranking
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = Color4.Transparent, Colour = Color4.Transparent,
}, },
new TextAwesome new SpriteIcon
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Shadow = false, Shadow = false,
Colour = OsuColour.Gray(0.95f), Colour = OsuColour.Gray(0.95f),
Icon = icon, Icon = icon,
TextSize = 20, Size = new Vector2(20),
} }
} }
} }

View File

@ -108,14 +108,14 @@ namespace osu.Game.Screens
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Children = new[] Children = new Drawable[]
{ {
new TextAwesome new SpriteIcon
{ {
Icon = FontAwesome.fa_universal_access, Icon = FontAwesome.fa_universal_access,
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
TextSize = 50, Size = new Vector2(50),
}, },
new OsuSpriteText new OsuSpriteText
{ {

View File

@ -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) public void SelectBeatmap(BeatmapInfo beatmap, bool animated = true)
{ {
if (beatmap == null) 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<BeatmapInfo> SelectionChanged; public Action<BeatmapInfo> SelectionChanged;
public Action StartRequested; public Action StartRequested;
@ -181,12 +187,12 @@ namespace osu.Game.Screens.Select
if (groups.Count == 0) if (groups.Count == 0)
return; return;
randomSelectedBeatmaps.Push(new KeyValuePair<BeatmapGroup, BeatmapPanel>(selectedGroup, selectedGroup.SelectedPanel));
var visibleGroups = getVisibleGroups(); var visibleGroups = getVisibleGroups();
if (!visibleGroups.Any()) if (!visibleGroups.Any())
return; return;
randomSelectedBeatmaps.Push(new KeyValuePair<BeatmapGroup, BeatmapPanel>(selectedGroup, selectedGroup.SelectedPanel));
BeatmapGroup group; BeatmapGroup group;
if (randomType == SelectionRandomType.RandomPermutation) if (randomType == SelectionRandomType.RandomPermutation)
@ -281,6 +287,12 @@ namespace osu.Game.Screens.Select
perform(); perform();
} }
public void ScrollToSelected(bool animated = true)
{
float selectedY = computeYPositions(animated);
ScrollTo(selectedY, animated);
}
private BeatmapGroup createGroup(BeatmapSetInfo beatmapSet) private BeatmapGroup createGroup(BeatmapSetInfo beatmapSet)
{ {
foreach (var b in beatmapSet.Beatmaps) foreach (var b in beatmapSet.Beatmaps)
@ -420,8 +432,7 @@ namespace osu.Game.Screens.Select
} }
finally finally
{ {
float selectedY = computeYPositions(animated); ScrollToSelected(animated);
ScrollTo(selectedY, animated);
} }
} }

View File

@ -247,21 +247,21 @@ namespace osu.Game.Screens.Select
AutoSizeAxes = Axes.Both; AutoSizeAxes = Axes.Both;
Children = new Drawable[] Children = new Drawable[]
{ {
new TextAwesome new SpriteIcon
{ {
Icon = FontAwesome.fa_square, Icon = FontAwesome.fa_square,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Colour = new Color4(68, 17, 136, 255), Colour = new Color4(68, 17, 136, 255),
Rotation = 45, Rotation = 45,
TextSize = 20 Size = new Vector2(20),
}, },
new TextAwesome new SpriteIcon
{ {
Icon = statistic.Icon, Icon = statistic.Icon,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Colour = new Color4(255, 221, 85, 255), Colour = new Color4(255, 221, 85, 255),
Scale = new Vector2(0.8f), Scale = new Vector2(0.8f),
TextSize = 20 Size = new Vector2(20),
}, },
new OsuSpriteText new OsuSpriteText
{ {

View File

@ -121,7 +121,7 @@ namespace osu.Game.Screens.Select
//{ //{
// Font = @"Exo2.0-Bold", // Font = @"Exo2.0-Bold",
// Text = "Sort results by", // Text = "Sort results by",
// TextSize = 14, // Size = 14,
// Margin = new MarginPadding // Margin = new MarginPadding
// { // {
// Top = 5, // Top = 5,

View File

@ -334,25 +334,23 @@ namespace osu.Game.Screens.Select.Leaderboards
Children = new[] Children = new[]
{ {
new TextAwesome new SpriteIcon
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Icon = FontAwesome.fa_osu_mod_bg, Icon = FontAwesome.fa_osu_mod_bg,
Colour = colour, Colour = colour,
Shadow = true, Shadow = true,
TextSize = 30, Size = new Vector2(30),
UseFullGlyphHeight = false,
}, },
new TextAwesome new SpriteIcon
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Icon = icon, Icon = icon,
Colour = OsuColour.Gray(84), Colour = OsuColour.Gray(84),
TextSize = 18, Size = new Vector2(18),
Position = new Vector2(0f, 2f), Position = new Vector2(0f, 2f),
UseFullGlyphHeight = false,
}, },
}; };
} }
@ -369,7 +367,7 @@ namespace osu.Game.Screens.Select.Leaderboards
Children = new Drawable[] Children = new Drawable[]
{ {
new TextAwesome new SpriteIcon
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = FontAwesome.fa_square, Icon = FontAwesome.fa_square,
@ -377,7 +375,7 @@ namespace osu.Game.Screens.Select.Leaderboards
Rotation = 45, Rotation = 45,
Shadow = true, Shadow = true,
}, },
new TextAwesome new SpriteIcon
{ {
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = icon, Icon = icon,

View File

@ -21,7 +21,7 @@ namespace osu.Game.Screens.Select.Options
private readonly Box background; private readonly Box background;
private readonly Box flash; private readonly Box flash;
private readonly TextAwesome iconText; private readonly SpriteIcon iconText;
private readonly OsuSpriteText firstLine; private readonly OsuSpriteText firstLine;
private readonly OsuSpriteText secondLine; private readonly OsuSpriteText secondLine;
private readonly Container box; private readonly Container box;
@ -134,11 +134,11 @@ namespace osu.Game.Screens.Select.Options
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Children = new Drawable[] Children = new Drawable[]
{ {
iconText = new TextAwesome iconText = new SpriteIcon
{ {
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
TextSize = 30, Size = new Vector2(30),
Shadow = true, Shadow = true,
Icon = FontAwesome.fa_close, Icon = FontAwesome.fa_close,
Margin = new MarginPadding Margin = new MarginPadding

View File

@ -126,6 +126,11 @@ namespace osu.Game.Screens.Select
Right = left_area_padding, Right = left_area_padding,
}, },
}); });
Add(new ResetScrollContainer(() => carousel.ScrollToSelected())
{
RelativeSizeAxes = Axes.Y,
Width = 250,
});
if (ShowFooter) if (ShowFooter)
{ {
@ -277,7 +282,7 @@ namespace osu.Game.Screens.Select
carousel.Filter(criteria, debounce); 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)); 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) private void removeBeatmapSet(BeatmapSetInfo beatmapSet)
{ {
carousel.RemoveBeatmap(beatmapSet); carousel.RemoveBeatmap(beatmapSet);
@ -406,5 +416,21 @@ namespace osu.Game.Screens.Select
return base.OnKeyDown(state, args); 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);
}
}
} }
} }

View File

@ -142,15 +142,15 @@ namespace osu.Game.Users
Origin = Anchor.Centre, Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both, AutoSizeAxes = Axes.Both,
Spacing = new Vector2(5f, 0f), Spacing = new Vector2(5f, 0f),
Children = new[] Children = new Drawable[]
{ {
new TextAwesome new SpriteIcon
{ {
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Icon = FontAwesome.fa_circle_o, Icon = FontAwesome.fa_circle_o,
Shadow = true, Shadow = true,
TextSize = 14, Size = new Vector2(14),
}, },
statusMessage = new OsuSpriteText statusMessage = new OsuSpriteText
{ {

View File

@ -104,6 +104,7 @@
<Compile Include="Overlays\Music\PlaylistList.cs" /> <Compile Include="Overlays\Music\PlaylistList.cs" />
<Compile Include="Overlays\OnScreenDisplay.cs" /> <Compile Include="Overlays\OnScreenDisplay.cs" />
<Compile Include="Graphics\Containers\SectionsContainer.cs" /> <Compile Include="Graphics\Containers\SectionsContainer.cs" />
<Compile Include="Overlays\Settings\Sections\Maintenance\GeneralSettings.cs" />
<Compile Include="Overlays\Settings\SettingsHeader.cs" /> <Compile Include="Overlays\Settings\SettingsHeader.cs" />
<Compile Include="Overlays\Settings\Sections\Audio\MainMenuSettings.cs" /> <Compile Include="Overlays\Settings\Sections\Audio\MainMenuSettings.cs" />
<Compile Include="Overlays\Toolbar\ToolbarChatButton.cs" /> <Compile Include="Overlays\Toolbar\ToolbarChatButton.cs" />
@ -115,6 +116,7 @@
<Compile Include="Overlays\Profile\RankChart.cs" /> <Compile Include="Overlays\Profile\RankChart.cs" />
<Compile Include="Overlays\Profile\Sections\RanksSection.cs" /> <Compile Include="Overlays\Profile\Sections\RanksSection.cs" />
<Compile Include="Overlays\Profile\Sections\RecentSection.cs" /> <Compile Include="Overlays\Profile\Sections\RecentSection.cs" />
<Compile Include="Graphics\Containers\ConstrainedIconContainer.cs" />
<Compile Include="Users\UserCoverBackground.cs" /> <Compile Include="Users\UserCoverBackground.cs" />
<Compile Include="Overlays\UserProfileOverlay.cs" /> <Compile Include="Overlays\UserProfileOverlay.cs" />
<Compile Include="Overlays\Profile\ProfileHeader.cs" /> <Compile Include="Overlays\Profile\ProfileHeader.cs" />
@ -348,7 +350,7 @@
<Compile Include="Graphics\Containers\ParallaxContainer.cs" /> <Compile Include="Graphics\Containers\ParallaxContainer.cs" />
<Compile Include="Graphics\Cursor\MenuCursor.cs" /> <Compile Include="Graphics\Cursor\MenuCursor.cs" />
<Compile Include="Graphics\Processing\RatioAdjust.cs" /> <Compile Include="Graphics\Processing\RatioAdjust.cs" />
<Compile Include="Graphics\TextAwesome.cs" /> <Compile Include="Graphics\SpriteIcon.cs" />
<Compile Include="Screens\Play\KeyCounter.cs" /> <Compile Include="Screens\Play\KeyCounter.cs" />
<Compile Include="Screens\Play\KeyCounterKeyboard.cs" /> <Compile Include="Screens\Play\KeyCounterKeyboard.cs" />
<Compile Include="Screens\Play\KeyCounterCollection.cs" /> <Compile Include="Screens\Play\KeyCounterCollection.cs" />

View File

@ -115,7 +115,7 @@
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToAny/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToAny/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToCount/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToCount/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToFirst/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToFirst/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToFirstOrDefault/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToFirstOrDefault/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToLast/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToLast/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToLastOrDefault/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToLastOrDefault/@EntryIndexedValue">WARNING</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToSingle/@EntryIndexedValue">WARNING</s:String> <s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ReplaceWithSingleCallToSingle/@EntryIndexedValue">WARNING</s:String>