1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-18 22:37:20 +08:00

Merge branch 'master' into taiko-visual-update

This commit is contained in:
Dean Herbert 2017-05-24 17:18:08 +09:00 committed by GitHub
commit 1c776511df
30 changed files with 1949 additions and 55 deletions

View File

@ -0,0 +1,199 @@
// 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.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Testing;
using osu.Game.Database;
using osu.Game.Overlays;
namespace osu.Desktop.VisualTests.Tests
{
public class TestCaseDirect : TestCase
{
public override string Description => @"osu!direct overlay";
private DirectOverlay direct;
private RulesetDatabase rulesets;
public override void Reset()
{
base.Reset();
Add(direct = new DirectOverlay());
newBeatmaps();
AddStep(@"toggle", direct.ToggleVisibility);
AddStep(@"result counts", () => direct.ResultAmounts = new DirectOverlay.ResultCounts(1, 4, 13));
}
[BackgroundDependencyLoader]
private void load(RulesetDatabase rulesets)
{
this.rulesets = rulesets;
}
private void newBeatmaps()
{
var ruleset = rulesets.GetRuleset(0);
direct.BeatmapSets = new[]
{
new BeatmapSetInfo
{
Metadata = new BeatmapMetadata
{
Title = @"OrVid",
Artist = @"An",
Author = @"RLC",
Source = @"",
},
Beatmaps = new List<BeatmapInfo>
{
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 5.35f,
Metadata = new BeatmapMetadata(),
OnlineInfo = new BeatmapOnlineInfo
{
Covers = new[] { @"https://assets.ppy.sh//beatmaps/578332/covers/cover.jpg?1494591390" },
Preview = @"https://b.ppy.sh/preview/578332.mp3",
PlayCount = 97,
FavouriteCount = 72,
},
},
},
},
new BeatmapSetInfo
{
Metadata = new BeatmapMetadata
{
Title = @"tiny lamp",
Artist = @"fhana",
Author = @"Sotarks",
Source = @"ぎんぎつね",
},
Beatmaps = new List<BeatmapInfo>
{
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 5.81f,
Metadata = new BeatmapMetadata(),
OnlineInfo = new BeatmapOnlineInfo
{
Covers = new[] { @"https://assets.ppy.sh//beatmaps/599627/covers/cover.jpg?1494539318" },
Preview = @"https//b.ppy.sh/preview/599627.mp3",
PlayCount = 3082,
FavouriteCount = 14,
},
},
},
},
new BeatmapSetInfo
{
Metadata = new BeatmapMetadata
{
Title = @"At Gwanghwamun",
Artist = @"KYUHYUN",
Author = @"Cerulean Veyron",
Source = @"",
},
Beatmaps = new List<BeatmapInfo>
{
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 0.9f,
Metadata = new BeatmapMetadata(),
OnlineInfo = new BeatmapOnlineInfo
{
Covers = new[] { @"https://assets.ppy.sh//beatmaps/513268/covers/cover.jpg?1494502863" },
Preview = @"https//b.ppy.sh/preview/513268.mp3",
PlayCount = 2762,
FavouriteCount = 15,
},
},
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 1.1f,
},
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 2.02f,
},
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 3.49f,
},
},
},
new BeatmapSetInfo
{
Metadata = new BeatmapMetadata
{
Title = @"RHAPSODY OF BLUE SKY",
Artist = @"fhana",
Author = @"[Kamiya]",
Source = @"小林さんちのメイドラゴン",
},
Beatmaps = new List<BeatmapInfo>
{
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 1.26f,
Metadata = new BeatmapMetadata(),
OnlineInfo = new BeatmapOnlineInfo
{
Covers = new[] { @"https://assets.ppy.sh//beatmaps/586841/covers/cover.jpg?1494052741" },
Preview = @"https//b.ppy.sh/preview/586841.mp3",
PlayCount = 62317,
FavouriteCount = 161,
},
},
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 2.01f,
},
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 2.87f,
},
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 3.76f,
},
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 3.93f,
},
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 4.37f,
},
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 5.13f,
},
new BeatmapInfo
{
Ruleset = ruleset,
StarDifficulty = 5.42f,
},
},
},
};
}
}
}

View File

@ -0,0 +1,57 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Testing;
using osu.Framework.Graphics;
using osu.Game.Users;
using osu.Framework.Graphics.Containers;
using OpenTK;
namespace osu.Desktop.VisualTests.Tests
{
internal class TestCaseUserPanel : TestCase
{
public override string Description => @"Panels for displaying a user's status";
public override void Reset()
{
base.Reset();
UserPanel flyte;
UserPanel peppy;
Add(new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Spacing = new Vector2(10f),
Children = new[]
{
flyte = new UserPanel(new User
{
Username = @"flyte",
Id = 3103765,
Country = new Country { FlagName = @"JP" },
CoverUrl = @"https://assets.ppy.sh/user-profile-covers/3103765/5b012e13611d5761caa7e24fecb3d3a16e1cf48fc2a3032cfd43dd444af83d82.jpeg"
}) { Width = 300 },
peppy = new UserPanel(new User
{
Username = @"peppy",
Id = 2,
Country = new Country { FlagName = @"AU" },
CoverUrl = @"https://assets.ppy.sh/user-profile-covers/2/08cad88747c235a64fca5f1b770e100f120827ded1ffe3b66bfcd19c940afa65.jpeg"
}) { Width = 300 },
},
});
flyte.Status.Value = new UserStatusOnline();
peppy.Status.Value = new UserStatusSoloGame();
AddStep(@"spectating", () => { flyte.Status.Value = new UserStatusSpectating(); });
AddStep(@"multiplaying", () => { flyte.Status.Value = new UserStatusMultiplayerGame(); });
AddStep(@"modding", () => { flyte.Status.Value = new UserStatusModding(); });
AddStep(@"offline", () => { flyte.Status.Value = new UserStatusOffline(); });
AddStep(@"null status", () => { flyte.Status.Value = null; });
}
}
}

View File

@ -220,6 +220,8 @@
<Compile Include="Tests\TestCaseLeaderboard.cs" />
<Compile Include="Beatmaps\TestWorkingBeatmap.cs" />
<Compile Include="Tests\TestCaseBeatmapDetailArea.cs" />
<Compile Include="Tests\TestCaseUserPanel.cs" />
<Compile Include="Tests\TestCaseDirect.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup />

View File

@ -9,7 +9,7 @@ using OpenTK.Graphics;
namespace osu.Game.Beatmaps.Drawables
{
internal class DifficultyColouredContainer : Container, IHasAccentColour
public class DifficultyColouredContainer : Container, IHasAccentColour
{
public Color4 AccentColour { get; set; }

View File

@ -11,7 +11,7 @@ using OpenTK.Graphics;
namespace osu.Game.Beatmaps.Drawables
{
internal class DifficultyIcon : DifficultyColouredContainer
public class DifficultyIcon : DifficultyColouredContainer
{
private readonly BeatmapInfo beatmap;

View File

@ -43,6 +43,9 @@ namespace osu.Game.Database
[Ignore]
public BeatmapMetrics Metrics { get; set; }
[Ignore]
public BeatmapOnlineInfo OnlineInfo { get; set; }
public string Path { get; set; }
[JsonProperty("file_md5")]

View File

@ -0,0 +1,38 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using Newtonsoft.Json;
using System.Collections.Generic;
namespace osu.Game.Database
{
/// <summary>
/// Beatmap info retrieved for previewing locally without having the beatmap downloaded.
/// </summary>
public class BeatmapOnlineInfo
{
/// <summary>
/// The different sizes of cover art for this beatmap: cover, cover@2x, card, card@2x, list, list@2x.
/// </summary>
[JsonProperty(@"covers")]
public IEnumerable<string> Covers { get; set; }
/// <summary>
/// A small sample clip of this beatmap's song.
/// </summary>
[JsonProperty(@"previewUrl")]
public string Preview { get; set; }
/// <summary>
/// The amount of plays this beatmap has.
/// </summary>
[JsonProperty(@"play_count")]
public int PlayCount { get; set; }
/// <summary>
/// The amount of people who have favourited this map.
/// </summary>
[JsonProperty(@"favourite_count")]
public int FavouriteCount { get; set; }
}
}

View File

@ -0,0 +1,37 @@
// 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.Linq;
using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps;
namespace osu.Game.Database
{
internal class OnlineWorkingBeatmap : WorkingBeatmap
{
private readonly TextureStore textures;
private readonly TrackManager tracks;
public OnlineWorkingBeatmap(BeatmapInfo beatmapInfo, TextureStore textures, TrackManager tracks) : base(beatmapInfo)
{
this.textures = textures;
this.tracks = tracks;
}
protected override Beatmap GetBeatmap()
{
return new Beatmap();
}
protected override Texture GetBackground()
{
return textures.Get(BeatmapInfo.OnlineInfo.Covers.FirstOrDefault());
}
protected override Track GetTrack()
{
return tracks.Get(BeatmapInfo.OnlineInfo.Preview);
}
}
}

View File

@ -0,0 +1,23 @@
// 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.ComponentModel;
namespace osu.Game.Database
{
public enum RankStatus
{
Any = 7,
[Description("Ranked & Approved")]
RankedApproved = 0,
Approved = 1,
Loved = 8,
Favourites = 2,
[Description("Mod Requests")]
ModRequests = 3,
Pending = 4,
Graveyard = 5,
[Description("My Maps")]
MyMaps = 6,
}
}

View File

@ -0,0 +1,16 @@
// 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.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Graphics.Containers
{
public class ReverseDepthFillFlowContainer<T> : FillFlowContainer<T> where T : Drawable
{
protected override IComparer<Drawable> DepthComparer => new ReverseCreationOrderDepthComparer();
protected override IEnumerable<T> FlowingChildren => base.FlowingChildren.Reverse();
}
}

View File

@ -113,7 +113,7 @@ namespace osu.Game.Graphics.UserInterface
}
}
protected class OsuDropdownHeader : DropdownHeader
public class OsuDropdownHeader : DropdownHeader
{
private readonly SpriteText label;
protected override string Label

View File

@ -0,0 +1,32 @@
// 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 System.ComponentModel;
using System.Reflection;
using System.Collections.Generic;
namespace osu.Game.Graphics.UserInterface
{
public class OsuEnumDropdown<T> : OsuDropdown<T>
{
public OsuEnumDropdown()
{
if (!typeof(T).IsEnum)
throw new InvalidOperationException("OsuEnumDropdown only supports enums as the generic type argument");
List<KeyValuePair<string, T>> items = new List<KeyValuePair<string, T>>();
foreach(var val in (T[])Enum.GetValues(typeof(T)))
{
var field = typeof(T).GetField(Enum.GetName(typeof(T), val));
items.Add(
new KeyValuePair<string, T>(
field.GetCustomAttribute<DescriptionAttribute>()?.Description ?? Enum.GetName(typeof(T), val),
val
)
);
}
Items = items;
}
}
}

View File

@ -57,9 +57,9 @@ namespace osu.Game.Graphics.UserInterface
}
}
private class OsuTabItem : TabItem<T>
public class OsuTabItem : TabItem<T>
{
private readonly SpriteText text;
protected readonly SpriteText Text;
private readonly Box box;
private Color4? accentColour;
@ -70,7 +70,7 @@ namespace osu.Game.Graphics.UserInterface
{
accentColour = value;
if (!Active)
text.Colour = value;
Text.Colour = value;
}
}
@ -94,13 +94,13 @@ namespace osu.Game.Graphics.UserInterface
private void fadeActive()
{
box.FadeIn(transition_length, EasingTypes.OutQuint);
text.FadeColour(Color4.White, transition_length, EasingTypes.OutQuint);
Text.FadeColour(Color4.White, transition_length, EasingTypes.OutQuint);
}
private void fadeInactive()
{
box.FadeOut(transition_length, EasingTypes.OutQuint);
text.FadeColour(AccentColour, transition_length, EasingTypes.OutQuint);
Text.FadeColour(AccentColour, transition_length, EasingTypes.OutQuint);
}
protected override bool OnHover(InputState state)
@ -130,7 +130,7 @@ namespace osu.Game.Graphics.UserInterface
Children = new Drawable[]
{
text = new OsuSpriteText
Text = new OsuSpriteText
{
Margin = new MarginPadding { Top = 5, Bottom = 5 },
Origin = Anchor.BottomLeft,

View File

@ -41,6 +41,8 @@ namespace osu.Game
private DialogOverlay dialogOverlay;
private DirectOverlay direct;
private Intro intro
{
get
@ -70,6 +72,8 @@ namespace osu.Game
public void ToggleSettings() => settings.ToggleVisibility();
public void ToggleDirect() => direct.ToggleVisibility();
[BackgroundDependencyLoader]
private void load()
{
@ -160,6 +164,7 @@ namespace osu.Game
});
//overlay elements
LoadComponentAsync(direct = new DirectOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(chat = new ChatOverlay { Depth = -1 }, mainContent.Add);
LoadComponentAsync(settings = new SettingsOverlay { Depth = -1 }, overlayContent.Add);
LoadComponentAsync(musicController = new MusicController
@ -249,6 +254,9 @@ namespace osu.Game
case Key.O:
settings.ToggleVisibility();
return true;
case Key.D:
direct.ToggleVisibility();
return true;
}
}
@ -280,6 +288,7 @@ namespace osu.Game
Toolbar.State = Visibility.Hidden;
musicController.State = Visibility.Hidden;
chat.State = Visibility.Hidden;
direct.State = Visibility.Hidden;
}
else
{

View File

@ -0,0 +1,193 @@
// 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.Linq;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Localisation;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Direct
{
public class DirectGridPanel : DirectPanel
{
private const float horizontal_padding = 10;
private const float vertical_padding = 5;
private FillFlowContainer bottomPanel;
public DirectGridPanel(BeatmapSetInfo beatmap) : base(beatmap)
{
Height = 140 + vertical_padding; //full height of all the elements plus vertical padding (autosize uses the image)
CornerRadius = 4;
Masking = true;
EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Shadow,
Offset = new Vector2(0f, 1f),
Radius = 3f,
Colour = Color4.Black.Opacity(0.25f),
};
}
protected override void LoadComplete()
{
base.LoadComplete();
FadeInFromZero(200, EasingTypes.Out);
bottomPanel.LayoutDuration = 200;
bottomPanel.LayoutEasing = EasingTypes.Out;
bottomPanel.Origin = Anchor.BottomLeft;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours, LocalisationEngine localisation, TextureStore textures)
{
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
},
GetBackground(textures),
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black.Opacity(0.5f),
},
bottomPanel = new FillFlowContainer
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.TopLeft,
Direction = FillDirection.Vertical,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(0f, vertical_padding),
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = horizontal_padding, Right = horizontal_padding },
Direction = FillDirection.Vertical,
Children = new[]
{
new OsuSpriteText
{
Text = localisation.GetUnicodePreference(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title),
TextSize = 18,
Font = @"Exo2.0-BoldItalic",
},
new OsuSpriteText
{
Text = localisation.GetUnicodePreference(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
Font = @"Exo2.0-BoldItalic",
},
},
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Padding = new MarginPadding
{
Top = vertical_padding,
Bottom = vertical_padding,
Left = horizontal_padding,
Right = horizontal_padding,
},
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new[]
{
new OsuSpriteText
{
Text = "mapped by ",
TextSize = 14,
Shadow = false,
Colour = colours.Gray5,
},
new OsuSpriteText
{
Text = SetInfo.Metadata.Author,
TextSize = 14,
Font = @"Exo2.0-SemiBoldItalic",
Shadow = false,
Colour = colours.BlueDark,
},
},
},
new Container
{
AutoSizeAxes = Axes.X,
Height = 14,
Children = new[]
{
new OsuSpriteText
{
Text = $"from {SetInfo.Metadata.Source}",
TextSize = 14,
Shadow = false,
Colour = colours.Gray5,
Alpha = string.IsNullOrEmpty(SetInfo.Metadata.Source) ? 0f : 1f,
},
},
},
new FillFlowContainer
{
AutoSizeAxes = Axes.X,
Height = 20,
Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding },
Children = GetDifficultyIcons(),
},
},
},
},
},
},
},
new FillFlowContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Margin = new MarginPadding { Top = vertical_padding, Right = vertical_padding },
Children = new[]
{
new Statistic(FontAwesome.fa_play_circle, SetInfo.Beatmaps.FirstOrDefault()?.OnlineInfo.PlayCount ?? 0)
{
Margin = new MarginPadding { Right = 1 },
},
new Statistic(FontAwesome.fa_heart, SetInfo.Beatmaps.FirstOrDefault()?.OnlineInfo.FavouriteCount ?? 0),
},
},
};
}
}
}

View File

@ -0,0 +1,197 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Colour;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Database;
using osu.Framework.Allocation;
using osu.Framework.Localisation;
using osu.Framework.Graphics.Textures;
using System.Linq;
using osu.Framework.Input;
namespace osu.Game.Overlays.Direct
{
public class DirectListPanel : DirectPanel
{
private const float horizontal_padding = 10;
private const float vertical_padding = 5;
private const float height = 70;
public DirectListPanel(BeatmapSetInfo beatmap) : base(beatmap)
{
RelativeSizeAxes = Axes.X;
Height = height;
CornerRadius = 5;
Masking = true;
EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Shadow,
Offset = new Vector2(0f, 1f),
Radius = 3f,
Colour = Color4.Black.Opacity(0.25f),
};
}
protected override void LoadComplete()
{
base.LoadComplete();
FadeInFromZero(200, EasingTypes.Out);
}
[BackgroundDependencyLoader]
private void load(LocalisationEngine localisation, TextureStore textures)
{
Children = new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
},
GetBackground(textures),
new Box
{
RelativeSizeAxes = Axes.Both,
ColourInfo = ColourInfo.GradientHorizontal(Color4.Black.Opacity(0.25f), Color4.Black.Opacity(0.75f)),
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding, Left = horizontal_padding, Right = vertical_padding },
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
new OsuSpriteText
{
Current = localisation.GetUnicodePreference(SetInfo.Metadata.TitleUnicode, SetInfo.Metadata.Title),
TextSize = 18,
Font = @"Exo2.0-BoldItalic",
},
new OsuSpriteText
{
Current = localisation.GetUnicodePreference(SetInfo.Metadata.ArtistUnicode, SetInfo.Metadata.Artist),
Font = @"Exo2.0-BoldItalic",
},
new FillFlowContainer
{
AutoSizeAxes = Axes.X,
Height = 20,
Margin = new MarginPadding { Top = vertical_padding, Bottom = vertical_padding },
Children = GetDifficultyIcons(),
},
},
},
new FillFlowContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
Margin = new MarginPadding { Right = height - vertical_padding * 2 + vertical_padding },
Children = new Drawable[]
{
new Statistic(FontAwesome.fa_play_circle, SetInfo.Beatmaps.FirstOrDefault()?.OnlineInfo.PlayCount ?? 0)
{
Margin = new MarginPadding { Right = 1 },
},
new Statistic(FontAwesome.fa_heart, SetInfo.Beatmaps.FirstOrDefault()?.OnlineInfo.FavouriteCount ?? 0),
new FillFlowContainer
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Children = new[]
{
new OsuSpriteText
{
Text = "mapped by ",
TextSize = 14,
},
new OsuSpriteText
{
Text = SetInfo.Metadata.Author,
TextSize = 14,
Font = @"Exo2.0-SemiBoldItalic",
},
},
},
new OsuSpriteText
{
Text = $"from {SetInfo.Metadata.Source}",
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
TextSize = 14,
Alpha = string.IsNullOrEmpty(SetInfo.Metadata.Source) ? 0f : 1f,
},
},
},
new DownloadButton
{
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Size = new Vector2(height - vertical_padding * 2),
},
},
},
};
}
private class DownloadButton : ClickableContainer
{
private readonly TextAwesome icon;
public DownloadButton()
{
Children = new Drawable[]
{
icon = new TextAwesome
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
UseFullGlyphHeight = false,
TextSize = 30,
Icon = FontAwesome.fa_osu_chevron_down_o,
},
};
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
icon.ScaleTo(0.9f, 1000, EasingTypes.Out);
return base.OnMouseDown(state, args);
}
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
{
icon.ScaleTo(1f, 500, EasingTypes.OutElastic);
return base.OnMouseUp(state, args);
}
protected override bool OnHover(InputState state)
{
icon.ScaleTo(1.1f, 500, EasingTypes.OutElastic);
return base.OnHover(state);
}
protected override void OnHoverLost(InputState state)
{
icon.ScaleTo(1f, 500, EasingTypes.OutElastic);
}
}
}
}

View File

@ -0,0 +1,88 @@
// 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.Collections.Generic;
using System.Linq;
using OpenTK;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Beatmaps.Drawables;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Overlays.Direct
{
public abstract class DirectPanel : Container
{
protected readonly BeatmapSetInfo SetInfo;
protected DirectPanel(BeatmapSetInfo setInfo)
{
SetInfo = setInfo;
}
protected IEnumerable<DifficultyIcon> GetDifficultyIcons()
{
var icons = new List<DifficultyIcon>();
foreach (var b in SetInfo.Beatmaps)
icons.Add(new DifficultyIcon(b));
return icons;
}
protected Drawable GetBackground(TextureStore textures)
{
return new AsyncLoadWrapper(new BeatmapBackgroundSprite(new OnlineWorkingBeatmap(SetInfo.Beatmaps.FirstOrDefault(), textures, null))
{
FillMode = FillMode.Fill,
OnLoadComplete = d => d.FadeInFromZero(400, EasingTypes.Out),
}) { RelativeSizeAxes = Axes.Both };
}
public class Statistic : FillFlowContainer
{
private readonly SpriteText text;
private int value;
public int Value
{
get { return value; }
set
{
this.value = value;
text.Text = Value.ToString(@"N0");
}
}
public Statistic(FontAwesome icon, int value = 0)
{
Anchor = Anchor.TopRight;
Origin = Anchor.TopRight;
AutoSizeAxes = Axes.Both;
Direction = FillDirection.Horizontal;
Spacing = new Vector2(5f, 0f);
Children = new Drawable[]
{
text = new OsuSpriteText
{
Font = @"Exo2.0-SemiBoldItalic",
},
new TextAwesome
{
Icon = icon,
Shadow = true,
TextSize = 14,
Margin = new MarginPadding { Top = 1 },
},
};
Value = value;
}
}
}
}

View File

@ -0,0 +1,233 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Direct
{
public class FilterControl : Container
{
public static readonly float HEIGHT = 35 + 32 + 30 + padding * 2; // search + mode toggle buttons + sort tabs + padding
private const float padding = 10;
private readonly Box tabStrip;
private readonly FillFlowContainer<RulesetToggleButton> modeButtons;
public readonly SearchTextBox Search;
public readonly SortTabControl SortTabs;
public readonly OsuEnumDropdown<RankStatus> RankStatusDropdown;
public readonly Bindable<DirectOverlay.PanelDisplayStyle> DisplayStyle = new Bindable<DirectOverlay.PanelDisplayStyle>();
protected override bool InternalContains(Vector2 screenSpacePos) => base.InternalContains(screenSpacePos) || RankStatusDropdown.Contains(screenSpacePos);
public FilterControl()
{
RelativeSizeAxes = Axes.X;
Height = HEIGHT;
DisplayStyle.Value = DirectOverlay.PanelDisplayStyle.Grid;
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"384552"),
Alpha = 0.9f,
},
tabStrip = new Box
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.TopLeft,
RelativeSizeAxes = Axes.X,
Height = 1,
},
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Left = DirectOverlay.WIDTH_PADDING, Right = DirectOverlay.WIDTH_PADDING },
Children = new Drawable[]
{
Search = new DirectSearchTextBox
{
RelativeSizeAxes = Axes.X,
Margin = new MarginPadding { Top = padding },
},
modeButtons = new FillFlowContainer<RulesetToggleButton>
{
AutoSizeAxes = Axes.Both,
Spacing = new Vector2(padding, 0f),
Margin = new MarginPadding { Top = padding },
},
SortTabs = new SortTabControl
{
RelativeSizeAxes = Axes.X,
},
},
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Spacing = new Vector2(10f, 0f),
Direction = FillDirection.Horizontal,
Margin = new MarginPadding { Top = HEIGHT - SlimEnumDropdown<DirectTab>.HEIGHT - padding, Right = DirectOverlay.WIDTH_PADDING },
Children = new Drawable[]
{
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Spacing = new Vector2(5f, 0f),
Direction = FillDirection.Horizontal,
Children = new[]
{
new DisplayStyleToggleButton(FontAwesome.fa_th_large, DirectOverlay.PanelDisplayStyle.Grid, DisplayStyle),
new DisplayStyleToggleButton(FontAwesome.fa_list_ul, DirectOverlay.PanelDisplayStyle.List, DisplayStyle),
},
},
RankStatusDropdown = new SlimEnumDropdown<RankStatus>
{
RelativeSizeAxes = Axes.None,
Width = 160f,
},
},
},
};
RankStatusDropdown.Current.Value = RankStatus.RankedApproved;
SortTabs.Current.Value = SortCriteria.Title;
SortTabs.Current.TriggerChange();
}
[BackgroundDependencyLoader(true)]
private void load(OsuGame game, RulesetDatabase rulesets, OsuColour colours)
{
tabStrip.Colour = colours.Yellow;
RankStatusDropdown.AccentColour = colours.BlueDark;
var b = new Bindable<RulesetInfo>(); //backup bindable incase the game is null
foreach (var r in rulesets.AllRulesets)
{
modeButtons.Add(new RulesetToggleButton(game?.Ruleset ?? b, r));
}
}
private class DirectSearchTextBox : SearchTextBox
{
protected override Color4 BackgroundUnfocused => backgroundColour;
protected override Color4 BackgroundFocused => backgroundColour;
private Color4 backgroundColour;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
backgroundColour = colours.Gray2.Opacity(0.9f);
}
}
private class RulesetToggleButton : ClickableContainer
{
private readonly TextAwesome icon;
private RulesetInfo ruleset;
public RulesetInfo Ruleset
{
get { return ruleset; }
set
{
ruleset = value;
icon.Icon = Ruleset.CreateInstance().Icon;
}
}
private readonly Bindable<RulesetInfo> bindable;
private void Bindable_ValueChanged(RulesetInfo obj)
{
icon.FadeTo(Ruleset.ID == obj?.ID ? 1f : 0.5f, 100);
}
public RulesetToggleButton(Bindable<RulesetInfo> bindable, RulesetInfo ruleset)
{
this.bindable = bindable;
AutoSizeAxes = Axes.Both;
Children = new[]
{
icon = new TextAwesome
{
Origin = Anchor.TopLeft,
Anchor = Anchor.TopLeft,
TextSize = 32,
}
};
Ruleset = ruleset;
bindable.ValueChanged += Bindable_ValueChanged;
Bindable_ValueChanged(bindable.Value);
Action = () => bindable.Value = Ruleset;
}
protected override void Dispose(bool isDisposing)
{
if (bindable != null)
bindable.ValueChanged -= Bindable_ValueChanged;
base.Dispose(isDisposing);
}
}
private class DisplayStyleToggleButton : ClickableContainer
{
private readonly TextAwesome icon;
private readonly DirectOverlay.PanelDisplayStyle style;
private readonly Bindable<DirectOverlay.PanelDisplayStyle> bindable;
public DisplayStyleToggleButton(FontAwesome icon, DirectOverlay.PanelDisplayStyle style, Bindable<DirectOverlay.PanelDisplayStyle> bindable)
{
this.bindable = bindable;
this.style = style;
Size = new Vector2(SlimEnumDropdown<DirectTab>.HEIGHT);
Children = new Drawable[]
{
this.icon = new TextAwesome
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Icon = icon,
TextSize = 18,
UseFullGlyphHeight = false,
Alpha = 0.5f,
},
};
bindable.ValueChanged += Bindable_ValueChanged;
Bindable_ValueChanged(bindable.Value);
Action = () => bindable.Value = this.style;
}
private void Bindable_ValueChanged(DirectOverlay.PanelDisplayStyle style)
{
icon.FadeTo(style == this.style ? 1.0f : 0.5f, 100);
}
protected override void Dispose(bool isDisposing)
{
bindable.ValueChanged -= Bindable_ValueChanged;
}
}
}
}

View File

@ -0,0 +1,124 @@
// 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.ComponentModel;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using Container = osu.Framework.Graphics.Containers.Container;
namespace osu.Game.Overlays.Direct
{
public class Header : Container
{
public static readonly float HEIGHT = 90;
private readonly Box tabStrip;
public readonly OsuTabControl<DirectTab> Tabs;
public Header()
{
Height = HEIGHT;
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"252f3a"),
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = DirectOverlay.WIDTH_PADDING, Right = DirectOverlay.WIDTH_PADDING },
Children = new Drawable[]
{
new FillFlowContainer
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.BottomLeft,
Position = new Vector2(-35f, 5f),
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10f, 0f),
Children = new Drawable[]
{
new TextAwesome
{
TextSize = 25,
Icon = FontAwesome.fa_osu_chevron_down_o,
},
new OsuSpriteText
{
TextSize = 25,
Text = @"osu!direct",
},
},
},
tabStrip = new Box
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
Width = 282, //todo: make this actually match the tab control's width instead of hardcoding
Height = 1,
},
Tabs = new DirectTabControl
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
},
},
},
};
Tabs.Current.Value = DirectTab.Search;
Tabs.Current.TriggerChange();
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
tabStrip.Colour = colours.Green;
}
private class DirectTabControl : OsuTabControl<DirectTab>
{
protected override TabItem<DirectTab> CreateTabItem(DirectTab value) => new DirectTabItem(value);
public DirectTabControl()
{
Height = 25;
AccentColour = Color4.White;
}
private class DirectTabItem : OsuTabItem
{
public DirectTabItem(DirectTab value) : base(value)
{
Text.TextSize = 15;
}
}
}
}
public enum DirectTab
{
Search,
[Description("Newest Maps")]
NewestMaps,
[Description("Top Rated")]
TopRated,
[Description("Most Played")]
MostPlayed
}
}

View File

@ -0,0 +1,43 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Direct
{
public class SlimEnumDropdown<T> : OsuEnumDropdown<T>
{
public const float HEIGHT = 25;
protected override DropdownHeader CreateHeader() => new SlimDropdownHeader { AccentColour = AccentColour };
protected override Menu CreateMenu() => new SlimMenu();
private class SlimDropdownHeader : OsuDropdownHeader
{
public SlimDropdownHeader()
{
Height = HEIGHT;
Icon.TextSize = 16;
Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 8, Right = 4 };
}
protected override void LoadComplete()
{
base.LoadComplete();
BackgroundColour = Color4.Black.Opacity(0.25f);
}
}
private class SlimMenu : OsuMenu
{
public SlimMenu()
{
Background.Colour = Color4.Black.Opacity(0.25f);
}
}
}
}

View File

@ -0,0 +1,117 @@
// 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 OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Direct
{
public class SortTabControl : OsuTabControl<SortCriteria>
{
protected override TabItem<SortCriteria> CreateTabItem(SortCriteria value) => new SortTabItem(value);
public SortTabControl()
{
Height = 30;
}
private class SortTabItem : TabItem<SortCriteria>
{
private const float transition_duration = 100;
private readonly Box box;
public override bool Active
{
get { return base.Active; }
set
{
if (Active == value) return;
if (value)
slideActive();
else
slideInactive();
base.Active = value;
}
}
public SortTabItem(SortCriteria value) : base(value)
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
{
new OsuSpriteText
{
Margin = new MarginPadding { Top = 8, Bottom = 8 },
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
Text = (value as Enum).GetDescription() ?? value.ToString(),
TextSize = 14,
Font = @"Exo2.0-Bold",
},
box = new Box
{
RelativeSizeAxes = Axes.X,
Height = 5,
Scale = new Vector2(1f, 0f),
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
},
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
box.Colour = colours.Yellow;
}
protected override bool OnHover(InputState state)
{
if (!Active)
slideActive();
return true;
}
protected override void OnHoverLost(InputState state)
{
if (!Active)
slideInactive();
}
private void slideActive()
{
box.ScaleTo(new Vector2(1f), transition_duration);
}
private void slideInactive()
{
box.ScaleTo(new Vector2(1f, 0f), transition_duration);
}
}
}
public enum SortCriteria
{
Title,
Artist,
Creator,
Difficulty,
Ranked,
Rating,
}
}

View File

@ -0,0 +1,230 @@
// 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.Collections.Generic;
using System.Linq;
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays.Direct;
using Container = osu.Framework.Graphics.Containers.Container;
namespace osu.Game.Overlays
{
public class DirectOverlay : WaveOverlayContainer
{
public static readonly int WIDTH_PADDING = 80;
private const float panel_padding = 10f;
private readonly FilterControl filter;
private readonly FillFlowContainer resultCountsContainer;
private readonly OsuSpriteText resultCountsText;
private readonly FillFlowContainer<DirectPanel> panels;
private IEnumerable<BeatmapSetInfo> beatmapSets;
public IEnumerable<BeatmapSetInfo> BeatmapSets
{
get { return beatmapSets; }
set
{
if (beatmapSets?.Equals(value) ?? false) return;
beatmapSets = value;
recreatePanels(filter.DisplayStyle.Value);
}
}
private ResultCounts resultAmounts;
public ResultCounts ResultAmounts
{
get { return resultAmounts; }
set
{
if (value == ResultAmounts) return;
resultAmounts = value;
updateResultCounts();
}
}
public DirectOverlay()
{
RelativeSizeAxes = Axes.Both;
// osu!direct colours are not part of the standard palette
FirstWaveColour = OsuColour.FromHex(@"19b0e2");
SecondWaveColour = OsuColour.FromHex(@"2280a2");
ThirdWaveColour = OsuColour.FromHex(@"005774");
FourthWaveColour = OsuColour.FromHex(@"003a4e");
Header header;
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"485e74"),
},
new Container
{
RelativeSizeAxes = Axes.Both,
Masking = true,
Children = new[]
{
new Triangles
{
RelativeSizeAxes = Axes.Both,
TriangleScale = 5,
ColourLight = OsuColour.FromHex(@"465b71"),
ColourDark = OsuColour.FromHex(@"3f5265"),
},
},
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Top = Header.HEIGHT + FilterControl.HEIGHT },
Children = new[]
{
new ScrollContainer
{
RelativeSizeAxes = Axes.Both,
ScrollDraggerVisible = false,
Children = new Drawable[]
{
new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
resultCountsContainer = new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Margin = new MarginPadding { Left = WIDTH_PADDING, Top = 6 },
Children = new Drawable[]
{
new OsuSpriteText
{
Text = "Found ",
TextSize = 15,
},
resultCountsText = new OsuSpriteText
{
TextSize = 15,
Font = @"Exo2.0-Bold",
},
}
},
panels = new FillFlowContainer<DirectPanel>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Top = panel_padding, Bottom = panel_padding, Left = WIDTH_PADDING, Right = WIDTH_PADDING },
Spacing = new Vector2(panel_padding),
},
},
},
},
},
},
},
filter = new FilterControl
{
RelativeSizeAxes = Axes.X,
Margin = new MarginPadding { Top = Header.HEIGHT },
},
header = new Header
{
RelativeSizeAxes = Axes.X,
},
};
header.Tabs.Current.ValueChanged += tab => { if (tab != DirectTab.Search) filter.Search.Current.Value = string.Empty; };
filter.Search.Exit = Hide;
filter.Search.Current.ValueChanged += text => { if (text != string.Empty) header.Tabs.Current.Value = DirectTab.Search; };
filter.DisplayStyle.ValueChanged += recreatePanels;
updateResultCounts();
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
resultCountsContainer.Colour = colours.Yellow;
}
private void updateResultCounts()
{
resultCountsContainer.FadeTo(ResultAmounts == null ? 0f : 1f, 200, EasingTypes.Out);
if (ResultAmounts == null) return;
resultCountsText.Text = pluralize("Artist", ResultAmounts.Artists) + ", " +
pluralize("Song", ResultAmounts.Songs) + ", " +
pluralize("Tag", ResultAmounts.Tags);
}
private string pluralize(string prefix, int value)
{
return $@"{value} {prefix}" + (value == 1 ? string.Empty : @"s");
}
private void recreatePanels(PanelDisplayStyle displayStyle)
{
if (BeatmapSets == null) return;
panels.Children = BeatmapSets.Select(b => displayStyle == PanelDisplayStyle.Grid ? (DirectPanel)new DirectGridPanel(b) { Width = 400 } : new DirectListPanel(b));
}
protected override bool OnFocus(InputState state)
{
filter.Search.TriggerFocus();
return false;
}
protected override void PopIn()
{
base.PopIn();
filter.Search.HoldFocus = true;
}
protected override void PopOut()
{
base.PopOut();
filter.Search.HoldFocus = false;
}
public class ResultCounts
{
public readonly int Artists;
public readonly int Songs;
public readonly int Tags;
public ResultCounts(int artists, int songs, int tags)
{
Artists = artists;
Songs = songs;
Tags = tags;
}
}
public enum PanelDisplayStyle
{
Grid,
List,
}
}
}

View File

@ -12,6 +12,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using OpenTK;
using osu.Framework.Input;
using osu.Game.Users;
namespace osu.Game.Overlays.Settings.Sections.General
{
@ -73,9 +74,9 @@ namespace osu.Game.Overlays.Settings.Sections.General
case APIState.Online:
Children = new Drawable[]
{
new OsuSpriteText
new UserPanel(api.LocalUser.Value)
{
Text = $"Connected as {api.Username}!",
RelativeSizeAxes = Axes.X,
},
new OsuButton
{

View File

@ -1,32 +1,17 @@
// 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 System.Reflection;
using System.ComponentModel;
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Settings
{
public class SettingsEnumDropdown<T> : SettingsDropdown<T>
{
public SettingsEnumDropdown()
protected override Drawable CreateControl() => new OsuEnumDropdown<T>
{
if (!typeof(T).IsEnum)
throw new InvalidOperationException("SettingsDropdown only supports enums as the generic type argument");
List<KeyValuePair<string, T>> items = new List<KeyValuePair<string, T>>();
foreach(var val in (T[])Enum.GetValues(typeof(T)))
{
var field = typeof(T).GetField(Enum.GetName(typeof(T), val));
items.Add(
new KeyValuePair<string, T>(
field.GetCustomAttribute<DescriptionAttribute>()?.Description ?? Enum.GetName(typeof(T), val),
val
)
);
}
Items = items;
}
Margin = new MarginPadding { Top = 5 },
RelativeSizeAxes = Axes.X,
};
}
}

View File

@ -61,6 +61,7 @@ namespace osu.Game.Screens.Menu
LoadComponentAsync(background);
buttons.OnSettings = game.ToggleSettings;
buttons.OnDirect = game.ToggleDirect;
preloadSongSelect();
}

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -12,6 +11,7 @@ using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI;
using OpenTK;
using osu.Framework.Input;
using osu.Game.Graphics.Containers;
namespace osu.Game.Screens.Play.HUD
{
@ -27,7 +27,7 @@ namespace osu.Game.Screens.Play.HUD
{
Children = new Drawable[]
{
iconsContainer = new IconFlow
iconsContainer = new ReverseDepthFillFlowContainer<ModIcon>
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
@ -93,12 +93,5 @@ namespace osu.Game.Screens.Play.HUD
contract();
base.OnHoverLost(state);
}
private class IconFlow : FillFlowContainer<ModIcon>
{
// just reverses the depth of flow contents.
protected override IComparer<Drawable> DepthComparer => new ReverseCreationOrderDepthComparer();
protected override IEnumerable<ModIcon> FlowingChildren => base.FlowingChildren.Reverse();
}
}
}

View File

@ -2,8 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@ -12,6 +10,7 @@ using osu.Game.Graphics;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
using osu.Game.Graphics.Containers;
namespace osu.Game.Screens.Select.Options
{
@ -71,7 +70,7 @@ namespace osu.Game.Screens.Select.Options
Scale = new Vector2(1, 0),
Colour = Color4.Black.Opacity(0.5f),
},
buttonsContainer = new ButtonFlow
buttonsContainer = new ReverseDepthFillFlowContainer<BeatmapOptionsButton>
{
Height = height,
RelativePositionAxes = Axes.X,
@ -109,16 +108,5 @@ namespace osu.Game.Screens.Select.Options
HotKey = hotkey
});
}
private class ButtonFlow : FillFlowContainer<BeatmapOptionsButton>
{
protected override IComparer<Drawable> DepthComparer => new ReverseCreationOrderDepthComparer();
protected override IEnumerable<BeatmapOptionsButton> FlowingChildren => base.FlowingChildren.Reverse();
public ButtonFlow()
{
Direction = FillDirection.Horizontal;
}
}
}
}

209
osu.Game/Users/UserPanel.cs Normal file
View File

@ -0,0 +1,209 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Users
{
public class UserPanel : Container
{
private const float height = 100;
private const float content_padding = 10;
private const float status_height = 30;
private OsuColour colours;
private readonly Container statusBar;
private readonly Box statusBg;
private readonly OsuSpriteText statusMessage;
public readonly Bindable<UserStatus> Status = new Bindable<UserStatus>();
public UserPanel(User user)
{
Height = height - status_height;
Masking = true;
CornerRadius = 5;
EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.25f),
Radius = 4,
};
Children = new Drawable[]
{
new AsyncLoadWrapper(new CoverBackgroundSprite(user)
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
FillMode = FillMode.Fill,
OnLoadComplete = d => d.FadeInFromZero(200),
}) { RelativeSizeAxes = Axes.Both },
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black.Opacity(0.7f),
},
new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Padding = new MarginPadding { Top = content_padding, Left = content_padding, Right = content_padding },
Children = new Drawable[]
{
new UpdateableAvatar
{
Size = new Vector2(height - status_height - content_padding * 2),
User = user,
Masking = true,
CornerRadius = 5,
EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.25f),
Radius = 4,
},
},
new Container
{
RelativeSizeAxes = Axes.Both,
Padding = new MarginPadding { Left = height - status_height - content_padding },
Children = new Drawable[]
{
new OsuSpriteText
{
Text = user.Username,
TextSize = 18,
Font = @"Exo2.0-SemiBoldItalic",
},
new FillFlowContainer
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
AutoSizeAxes = Axes.X,
Height = 20f,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(5f, 0f),
Children = new Drawable[]
{
new DrawableFlag(user.Country?.FlagName ?? @"__")
{
Width = 30f,
RelativeSizeAxes = Axes.Y,
},
new Container
{
Width = 40f,
RelativeSizeAxes = Axes.Y,
},
new CircularContainer
{
Width = 20f,
RelativeSizeAxes = Axes.Y,
},
},
},
},
},
},
},
statusBar = new Container
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
Alpha = 0f,
Children = new Drawable[]
{
statusBg = new Box
{
RelativeSizeAxes = Axes.Both,
Alpha = 0.5f,
},
new FillFlowContainer
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
AutoSizeAxes = Axes.Both,
Spacing = new Vector2(5f, 0f),
Children = new[]
{
new TextAwesome
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Icon = FontAwesome.fa_circle_o,
Shadow = true,
TextSize = 14,
},
statusMessage = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Font = @"Exo2.0-Semibold",
},
},
},
},
},
};
Status.ValueChanged += displayStatus;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
this.colours = colours;
}
private void displayStatus(UserStatus status)
{
const float transition_duration = 500;
if (status == null)
{
statusBar.ResizeHeightTo(0f, transition_duration, EasingTypes.OutQuint);
statusBar.FadeOut(transition_duration, EasingTypes.OutQuint);
ResizeHeightTo(height - status_height, transition_duration, EasingTypes.OutQuint);
}
else
{
statusBar.ResizeHeightTo(status_height, transition_duration, EasingTypes.OutQuint);
statusBar.FadeIn(transition_duration, EasingTypes.OutQuint);
ResizeHeightTo(height, transition_duration, EasingTypes.OutQuint);
statusBg.FadeColour(status.GetAppropriateColour(colours), 500, EasingTypes.OutQuint);
statusMessage.Text = status.Message;
}
}
private class CoverBackgroundSprite : Sprite
{
private readonly User user;
public CoverBackgroundSprite(User user)
{
this.user = user;
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
{
if (!string.IsNullOrEmpty(user.CoverUrl))
Texture = textures.Get(user.CoverUrl);
}
}
}
}

View File

@ -0,0 +1,61 @@
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Graphics;
using osu.Game.Graphics;
namespace osu.Game.Users
{
public abstract class UserStatus
{
public abstract string Message { get; }
public abstract Color4 GetAppropriateColour(OsuColour colours);
}
public abstract class UserStatusAvailable : UserStatus
{
public override Color4 GetAppropriateColour(OsuColour colours) => colours.BlueDarker;
}
public abstract class UserStatusBusy : UserStatus
{
public override Color4 GetAppropriateColour(OsuColour colours) => colours.YellowDark;
}
public class UserStatusOffline : UserStatus
{
public override string Message => @"Offline";
public override Color4 GetAppropriateColour(OsuColour colours) => colours.Gray7;
}
public class UserStatusOnline : UserStatusAvailable
{
public override string Message => @"Online";
}
public class UserStatusSpectating : UserStatusAvailable
{
public override string Message => @"Spectating a game";
}
public class UserStatusInLobby : UserStatusAvailable
{
public override string Message => @"in Multiplayer Lobby";
}
public class UserStatusSoloGame : UserStatusBusy
{
public override string Message => @"Solo Game";
}
public class UserStatusMultiplayerGame: UserStatusBusy
{
public override string Message => @"Multiplaying";
}
public class UserStatusModding : UserStatus
{
public override string Message => @"Modding a map";
public override Color4 GetAppropriateColour(OsuColour colours) => colours.PurpleDark;
}
}

View File

@ -432,6 +432,21 @@
<Compile Include="Overlays\Music\PlaylistOverlay.cs" />
<Compile Include="Rulesets\Replays\IAutoGenerator.cs" />
<Compile Include="Rulesets\Replays\AutoGenerator.cs" />
<Compile Include="Users\UserPanel.cs" />
<Compile Include="Users\UserStatus.cs" />
<Compile Include="Overlays\DirectOverlay.cs" />
<Compile Include="Overlays\Direct\FilterControl.cs" />
<Compile Include="Overlays\Direct\Header.cs" />
<Compile Include="Overlays\Direct\SortTabControl.cs" />
<Compile Include="Graphics\UserInterface\OsuEnumDropdown.cs" />
<Compile Include="Overlays\Direct\DirectPanel.cs" />
<Compile Include="Overlays\Direct\DirectGridPanel.cs" />
<Compile Include="Overlays\Direct\DirectListPanel.cs" />
<Compile Include="Database\OnlineWorkingBeatmap.cs" />
<Compile Include="Database\BeatmapOnlineInfo.cs" />
<Compile Include="Overlays\Direct\SlimEnumDropdown.cs" />
<Compile Include="Graphics\Containers\ReverseDepthFillFlowContainer.cs" />
<Compile Include="Database\RankStatus.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\osu-framework\osu.Framework\osu.Framework.csproj">