diff --git a/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs b/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs new file mode 100644 index 0000000000..cc9201c1fd --- /dev/null +++ b/osu.Desktop.VisualTests/Tests/TestCaseNotificationManager.cs @@ -0,0 +1,121 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using osu.Framework.Graphics; +using osu.Framework.GameModes.Testing; +using osu.Framework.MathUtils; +using osu.Framework.Timing; +using osu.Game.Overlays; +using System.Linq; +using osu.Game.Overlays.Notifications; +using osu.Game.Screens.Backgrounds; + +namespace osu.Desktop.VisualTests.Tests +{ + class TestCaseNotificationManager : TestCase + { + public override string Name => @"Notification Manager"; + public override string Description => @"I handle notifications"; + + NotificationManager manager; + + public override void Reset() + { + base.Reset(); + + progressingNotifications.Clear(); + + AddInternal(new BackgroundModeDefault() { Depth = 10 }); + + Content.Add(manager = new NotificationManager + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }); + + AddToggle(@"show", manager.ToggleVisibility); + + AddButton(@"simple #1", sendNotification1); + AddButton(@"simple #2", sendNotification2); + AddButton(@"progress #1", sendProgress1); + AddButton(@"progress #2", sendProgress2); + AddButton(@"barrage", () => sendBarrage()); + } + + private void sendBarrage(int remaining = 100) + { + switch (RNG.Next(0, 4)) + { + case 0: + sendNotification1(); + break; + case 1: + sendNotification2(); + break; + case 2: + sendProgress1(); + break; + case 3: + sendProgress2(); + break; + } + + if (remaining > 0) + { + Delay(80); + Schedule(() => sendBarrage(remaining - 1)); + } + } + + protected override void Update() + { + base.Update(); + + progressingNotifications.RemoveAll(n => n.State == ProgressNotificationState.Completed); + + while (progressingNotifications.Count(n => n.State == ProgressNotificationState.Active) < 3) + { + var p = progressingNotifications.FirstOrDefault(n => n.IsLoaded && n.State == ProgressNotificationState.Queued); + if (p == null) + break; + + p.State = ProgressNotificationState.Active; + } + + foreach (var n in progressingNotifications.FindAll(n => n.State == ProgressNotificationState.Active)) + { + if (n.Progress < 1) + n.Progress += (float)(Time.Elapsed / 2000) * RNG.NextSingle(); + else + n.Complete(); + } + } + + private void sendProgress2() + { + var n = new ProgressNotification(@"Downloading Haitai..."); + manager.Post(n); + progressingNotifications.Add(n); + } + + List progressingNotifications = new List(); + + private void sendProgress1() + { + var n = new ProgressNotification(@"Uploading to BSS..."); + manager.Post(n); + progressingNotifications.Add(n); + } + + private void sendNotification2() + { + manager.Post(new SimpleNotification(@"You are amazing")); + } + + private void sendNotification1() + { + manager.Post(new SimpleNotification(@"Welcome to osu!. Enjoy your stay!")); + } + } +} diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index 69df007013..6fa9ab604e 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -176,6 +176,7 @@ + diff --git a/osu.Game/Graphics/Sprites/OsuSpriteText.cs b/osu.Game/Graphics/Sprites/OsuSpriteText.cs index 5bc76b74b4..f5749846be 100644 --- a/osu.Game/Graphics/Sprites/OsuSpriteText.cs +++ b/osu.Game/Graphics/Sprites/OsuSpriteText.cs @@ -9,7 +9,7 @@ using OpenTK.Graphics; namespace osu.Game.Graphics.Sprites { - class OsuSpriteText : SpriteText + public class OsuSpriteText : SpriteText { public const float FONT_SIZE = 16; diff --git a/osu.Game/Graphics/UserInterface/Nub.cs b/osu.Game/Graphics/UserInterface/Nub.cs index c8174ef546..61b59d6b51 100644 --- a/osu.Game/Graphics/UserInterface/Nub.cs +++ b/osu.Game/Graphics/UserInterface/Nub.cs @@ -13,7 +13,7 @@ using osu.Framework.Graphics.UserInterface; namespace osu.Game.Graphics.UserInterface { - class Nub : CircularContainer, IStateful + public class Nub : CircularContainer, IStateful { public const float COLLAPSED_SIZE = 20; public const float EXPANDED_SIZE = 40; diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 97c9dbb2e0..e8233366d9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -35,6 +35,8 @@ namespace osu.Game private MusicController musicController; + private NotificationManager notificationManager; + private MainMenu mainMenu => modeStack?.ChildGameMode as MainMenu; private Intro intro => modeStack as Intro; @@ -117,8 +119,16 @@ namespace osu.Game Origin = Anchor.TopRight, }).Preload(this, overlayContent.Add); + (notificationManager = new NotificationManager + { + Depth = -2, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }).Preload(this, overlayContent.Add); + Dependencies.Cache(options); Dependencies.Cache(musicController); + Dependencies.Cache(notificationManager); (Toolbar = new Toolbar { diff --git a/osu.Game/Overlays/NotificationManager.cs b/osu.Game/Overlays/NotificationManager.cs new file mode 100644 index 0000000000..e4eb718639 --- /dev/null +++ b/osu.Game/Overlays/NotificationManager.cs @@ -0,0 +1,111 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transformations; +using osu.Game.Graphics; +using osu.Game.Overlays.Notifications; +using OpenTK.Graphics; + +namespace osu.Game.Overlays +{ + public class NotificationManager : FocusedOverlayContainer + { + private const float width = 320; + + public const float TRANSITION_LENGTH = 600; + + private ScrollContainer scrollContainer; + private FlowContainer sections; + + [BackgroundDependencyLoader(permitNulls: true)] + private void load(OsuColour colours) + { + Width = width; + RelativeSizeAxes = Axes.Y; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.6f, + }, + scrollContainer = new ScrollContainer() + { + Margin = new MarginPadding { Top = Toolbar.Toolbar.HEIGHT }, + Children = new[] + { + sections = new FlowContainer + { + Direction = FlowDirection.VerticalOnly, + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Children = new [] + { + new NotificationSection + { + Title = @"Notifications", + ClearText = @"Clear All", + AcceptTypes = new [] { typeof(SimpleNotification) }, + }, + new NotificationSection + { + Title = @"Running Tasks", + ClearText = @"Cancel All", + AcceptTypes = new [] { typeof(ProgressNotification) }, + }, + } + } + } + } + }; + } + + int runningDepth = 0; + + public void Post(Notification notification) + { + ++runningDepth; + notification.Depth = notification.DisplayOnTop ? runningDepth : -runningDepth; + + var hasCompletionTarget = notification as IHasCompletionTarget; + if (hasCompletionTarget != null) + hasCompletionTarget.CompletionTarget = Post; + + var ourType = notification.GetType(); + sections.Children.FirstOrDefault(s => s.AcceptTypes.Any(accept => ourType == accept || ourType.IsSubclassOf(accept)))?.Add(notification); + } + + protected override void PopIn() + { + base.PopIn(); + + scrollContainer.MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint); + MoveToX(0, TRANSITION_LENGTH, EasingTypes.OutQuint); + FadeTo(1, TRANSITION_LENGTH / 2); + } + + private void markAllRead() + { + sections.Children.ForEach(s => s.MarkAllRead()); + } + + protected override void PopOut() + { + base.PopOut(); + + markAllRead(); + + MoveToX(width, TRANSITION_LENGTH, EasingTypes.OutQuint); + FadeTo(0, TRANSITION_LENGTH / 2); + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/IHasCompletionTarget.cs b/osu.Game/Overlays/Notifications/IHasCompletionTarget.cs new file mode 100644 index 0000000000..7fba75c4fc --- /dev/null +++ b/osu.Game/Overlays/Notifications/IHasCompletionTarget.cs @@ -0,0 +1,12 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; + +namespace osu.Game.Overlays.Notifications +{ + public interface IHasCompletionTarget + { + Action CompletionTarget { get; set; } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/Notification.cs b/osu.Game/Overlays/Notifications/Notification.cs new file mode 100644 index 0000000000..9270e4e792 --- /dev/null +++ b/osu.Game/Overlays/Notifications/Notification.cs @@ -0,0 +1,285 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transformations; +using osu.Framework.Input; +using osu.Game.Graphics; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Overlays.Notifications +{ + public abstract class Notification : Container + { + /// + /// Use requested close. + /// + public Action Closed; + + /// + /// Run on user activating the notification. Return true to close. + /// + public Func Activated; + + /// + /// Should we show at the top of our section on display? + /// + public virtual bool DisplayOnTop => true; + + protected NotificationLight Light; + private CloseButton closeButton; + protected Container IconContent; + private Container content; + + protected override Container Content => content; + + protected Container NotificationContent; + + private bool read; + + public virtual bool Read + { + get { return read; } + set + { + read = value; + } + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + AddInternal(new Drawable[] + { + Light = new NotificationLight + { + Margin = new MarginPadding { Right = 5 }, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreRight, + }, + NotificationContent = new Container + { + CornerRadius = 8, + Masking = true, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + }, + new Container + { + RelativeSizeAxes = Axes.X, + Padding = new MarginPadding(5), + Height = 60, + Children = new Drawable[] + { + IconContent = new Container + { + Size = new Vector2(40), + Colour = Color4.DarkGray, + Masking = true, + CornerRadius = 5, + }, + content = new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding + { + Top = 5, + Left = 45, + Right = 30 + }, + } + } + }, + closeButton = new CloseButton + { + Alpha = 0, + Action = Close, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Margin = new MarginPadding + { + Right = 5 + }, + } + } + } + }); + } + + protected override bool OnHover(InputState state) + { + closeButton.FadeIn(75); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + closeButton.FadeOut(75); + base.OnHoverLost(state); + } + + protected override bool OnClick(InputState state) + { + if (Activated?.Invoke() ?? true) + Close(); + + return true; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + FadeInFromZero(200); + NotificationContent.MoveToX(DrawSize.X); + NotificationContent.MoveToX(0, 500, EasingTypes.OutQuint); + } + + private bool wasClosed; + + public virtual void Close() + { + if (wasClosed) return; + wasClosed = true; + + Closed?.Invoke(); + FadeOut(100); + Expire(); + } + + class CloseButton : ClickableContainer + { + private Color4 hoverColour; + + public CloseButton() + { + Colour = OsuColour.Gray(0.2f); + AutoSizeAxes = Axes.Both; + + Children = new[] + { + new TextAwesome + { + Anchor = Anchor.Centre, + Icon = FontAwesome.fa_times_circle, + } + }; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + hoverColour = colours.Yellow; + } + + protected override bool OnHover(InputState state) + { + FadeColour(hoverColour, 200); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + FadeColour(OsuColour.Gray(0.2f), 200); + base.OnHoverLost(state); + } + } + + public class NotificationLight : Container + { + private bool pulsate; + private Container pulsateLayer; + + public bool Pulsate + { + get { return pulsate; } + set + { + pulsate = value; + + pulsateLayer.ClearTransformations(); + pulsateLayer.Alpha = 1; + + if (pulsate) + { + const float length = 1000; + pulsateLayer.Transforms.Add(new TransformAlpha + { + StartTime = Time.Current, + EndTime = Time.Current + length, + StartValue = 1, + EndValue = 0.4f, + Easing = EasingTypes.In + }); + pulsateLayer.Transforms.Add(new TransformAlpha + { + StartTime = Time.Current + length, + EndTime = Time.Current + length * 2, + StartValue = 0.4f, + EndValue = 1, + Easing = EasingTypes.Out + }); + + //todo: figure why we can't add arbitrary delays at the end of loop. + pulsateLayer.Loop(length * 2); + } + } + } + + public new SRGBColour Colour + { + set + { + base.Colour = value; + pulsateLayer.EdgeEffect = new EdgeEffect + { + Colour = ((Color4)value).Opacity(0.5f), //todo: avoid cast + Type = EdgeEffectType.Glow, + Radius = 12, + Roundness = 12, + }; + } + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + Size = new Vector2(6, 15); + + Children = new[] + { + pulsateLayer = new CircularContainer + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Masking = true, + RelativeSizeAxes = Axes.Both, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + }, + } + } + }; + } + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs new file mode 100644 index 0000000000..ec286302b8 --- /dev/null +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -0,0 +1,162 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// 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.Allocation; +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Transformations; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using OpenTK; + +namespace osu.Game.Overlays.Notifications +{ + public class NotificationSection : FlowContainer + { + private OsuSpriteText titleText; + private OsuSpriteText countText; + + private ClearAllButton clearButton; + + private FlowContainer notifications; + + public void Add(Notification notification) + { + notifications.Add(notification); + } + + public IEnumerable AcceptTypes; + + private string clearText; + public string ClearText + { + get { return clearText; } + set + { + clearText = value; + if (clearButton != null) clearButton.Text = clearText; + } + } + + private string title; + + public string Title + { + get { return title; } + set + { + title = value; + if (titleText != null) titleText.Text = title.ToUpper(); + } + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Direction = FlowDirection.VerticalOnly; + + Padding = new MarginPadding + { + Top = 10, + Bottom = 5, + Right = 20, + Left = 20, + }; + + AddInternal(new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + clearButton = new ClearAllButton + { + Text = clearText, + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + Action = clearAll + }, + new FlowContainer + { + Margin = new MarginPadding + { + Bottom = 5 + }, + Spacing = new Vector2(5, 0), + AutoSizeAxes = Axes.Both, + Children = new Drawable[] + { + titleText = new OsuSpriteText + { + Text = title.ToUpper(), + Font = @"Exo2.0-Black", + }, + countText = new OsuSpriteText + { + Text = "3", + Colour = colours.Yellow, + Font = @"Exo2.0-Black", + }, + } + }, + }, + }, + notifications = new FlowContainer + { + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + LayoutDuration = 150, + LayoutEasing = EasingTypes.OutQuart, + Spacing = new Vector2(3), + } + }); + } + + private void clearAll() + { + notifications.Children.ForEach(c => c.Close()); + } + + protected override void Update() + { + base.Update(); + + countText.Text = notifications.Children.Count(c => c.Alpha > 0.99f).ToString(); + } + + class ClearAllButton : ClickableContainer + { + private OsuSpriteText text; + + public ClearAllButton() + { + AutoSizeAxes = Axes.Both; + + Children = new[] + { + text = new OsuSpriteText() + }; + } + + public string Text + { + get { return text.Text; } + set { text.Text = value.ToUpper(); } + } + } + + public void MarkAllRead() + { + notifications.Children.ForEach(n => n.Read = true); + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs new file mode 100644 index 0000000000..1861e410d2 --- /dev/null +++ b/osu.Game/Overlays/Notifications/ProgressCompletionNotification.cs @@ -0,0 +1,16 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Overlays.Notifications +{ + public class ProgressCompletionNotification : SimpleNotification + { + private ProgressNotification progressNotification; + + public ProgressCompletionNotification(ProgressNotification progressNotification) + : base(@"Task has completed!") + { + this.progressNotification = progressNotification; + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/ProgressNotification.cs b/osu.Game/Overlays/Notifications/ProgressNotification.cs new file mode 100644 index 0000000000..4cb1557c32 --- /dev/null +++ b/osu.Game/Overlays/Notifications/ProgressNotification.cs @@ -0,0 +1,200 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System; +using System.Diagnostics; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Transformations; +using osu.Game.Graphics; +using OpenTK; +using OpenTK.Graphics; + +namespace osu.Game.Overlays.Notifications +{ + public class ProgressNotification : Notification, IHasCompletionTarget + { + private string text; + + private float progress; + public float Progress + { + get { return progress; } + set + { + Debug.Assert(state == ProgressNotificationState.Active); + progress = value; + progressBar.Progress = progress; + } + } + + public ProgressNotificationState State + { + get { return state; } + set + { + state = value; + switch (state) + { + case ProgressNotificationState.Queued: + Light.Colour = colourQueued; + Light.Pulsate = false; + progressBar.Active = false; + break; + case ProgressNotificationState.Active: + Light.Colour = colourActive; + Light.Pulsate = true; + progressBar.Active = true; + break; + case ProgressNotificationState.Cancelled: + Light.Colour = colourCancelled; + Light.Pulsate = false; + progressBar.Active = false; + break; + } + } + } + + private ProgressNotificationState state; + + public Action Completed; + + public override bool DisplayOnTop => false; + + private ProgressBar progressBar; + private Color4 colourQueued; + private Color4 colourActive; + private Color4 colourCancelled; + + public ProgressNotification(string text) + { + this.text = text; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + colourQueued = colours.YellowDark; + colourActive = colours.Blue; + colourCancelled = colours.Red; + + IconContent.Add(new Box + { + RelativeSizeAxes = Axes.Both, + }); + + Content.Add(new SpriteText + { + TextSize = 16, + Colour = OsuColour.Gray(128), + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Text = text + }); + + NotificationContent.Add(progressBar = new ProgressBar + { + Origin = Anchor.BottomLeft, + Anchor = Anchor.BottomLeft, + RelativeSizeAxes = Axes.X, + }); + + State = ProgressNotificationState.Queued; + } + + public void Complete() + { + Debug.Assert(state != ProgressNotificationState.Completed); + + state = ProgressNotificationState.Completed; + + NotificationContent.MoveToY(-DrawSize.Y / 2, 200, EasingTypes.OutQuint); + FadeTo(0.01f, 200); //don't completely fade out or our scheduled task won't run. + + Delay(100); + Schedule(() => + { + CompletionTarget?.Invoke(new ProgressCompletionNotification(this)); + base.Close(); + }); + } + + public override void Close() + { + switch (State) + { + case ProgressNotificationState.Cancelled: + base.Close(); + break; + case ProgressNotificationState.Active: + case ProgressNotificationState.Queued: + State = ProgressNotificationState.Cancelled; + break; + } + } + + public Action CompletionTarget { get; set; } + + class ProgressBar : Container + { + private Box box; + + private Color4 colourActive; + private Color4 colourInactive; + + private float progress; + public float Progress + { + get { return progress; } + set + { + if (progress == value) return; + + progress = value; + box.ResizeTo(new Vector2(progress, 1), 100, EasingTypes.OutQuad); + } + } + + private bool active; + + public bool Active + { + get { return active; } + set + { + active = value; + FadeColour(active ? colourActive : colourInactive, 100); + } + } + + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + colourActive = colours.Blue; + Colour = colourInactive = OsuColour.Gray(0.5f); + + Height = 5; + + Children = new[] + { + box = new Box + { + RelativeSizeAxes = Axes.Both, + Width = 0, + } + }; + } + } + } + + public enum ProgressNotificationState + { + Queued, + Active, + Completed, + Cancelled + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Notifications/SimpleNotification.cs b/osu.Game/Overlays/Notifications/SimpleNotification.cs new file mode 100644 index 0000000000..7c6666082e --- /dev/null +++ b/osu.Game/Overlays/Notifications/SimpleNotification.cs @@ -0,0 +1,66 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Colour; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; + +namespace osu.Game.Overlays.Notifications +{ + public class SimpleNotification : Notification + { + private string text; + + public SimpleNotification(string text) + { + this.text = text; + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + IconContent.Add(new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + ColourInfo = ColourInfo.GradientVertical(OsuColour.Gray(0.2f), OsuColour.Gray(0.5f)) + }, + new TextAwesome + { + Anchor = Anchor.Centre, + Icon = FontAwesome.fa_info_circle, + } + }); + + Content.Add(new SpriteText + { + TextSize = 16, + Colour = OsuColour.Gray(128), + AutoSizeAxes = Axes.Y, + RelativeSizeAxes = Axes.X, + Text = text + }); + + Light.Colour = colours.Green; + } + + public override bool Read + { + get + { + return base.Read; + } + + set + { + if (base.Read = value) + Light.FadeOut(100); + else + Light.FadeIn(100); + } + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/OptionsOverlay.cs b/osu.Game/Overlays/OptionsOverlay.cs index 1fce450104..a93bbc10d3 100644 --- a/osu.Game/Overlays/OptionsOverlay.cs +++ b/osu.Game/Overlays/OptionsOverlay.cs @@ -90,7 +90,7 @@ namespace osu.Game.Overlays { Text = "settings", TextSize = 40, - Margin = new MarginPadding { Left = CONTENT_MARGINS, Top = 30 }, + Margin = new MarginPadding { Left = CONTENT_MARGINS, Top = Toolbar.Toolbar.TOOLTIP_HEIGHT }, }, new OsuSpriteText { diff --git a/osu.Game/Overlays/Toolbar/Toolbar.cs b/osu.Game/Overlays/Toolbar/Toolbar.cs index 503a3e0bf5..dc8b8d1e9a 100644 --- a/osu.Game/Overlays/Toolbar/Toolbar.cs +++ b/osu.Game/Overlays/Toolbar/Toolbar.cs @@ -17,6 +17,7 @@ namespace osu.Game.Overlays.Toolbar public class Toolbar : OverlayContainer { public const float HEIGHT = 40; + public const float TOOLTIP_HEIGHT = 30; public Action OnHome; public Action OnPlayModeChange; @@ -73,10 +74,7 @@ namespace osu.Game.Overlays.Toolbar Icon = FontAwesome.fa_search }, userArea = new ToolbarUserArea(), - new ToolbarButton - { - Icon = FontAwesome.fa_bars - }, + new ToolbarNotificationButton(), } } }; diff --git a/osu.Game/Overlays/Toolbar/ToolbarButton.cs b/osu.Game/Overlays/Toolbar/ToolbarButton.cs index 160e4460d9..67b0039971 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarButton.cs @@ -56,6 +56,8 @@ namespace osu.Game.Overlays.Toolbar } } + protected virtual Anchor TooltipAnchor => Anchor.TopLeft; + public Action Action; protected TextAwesome DrawableIcon; protected SpriteText DrawableText; @@ -107,19 +109,24 @@ namespace osu.Game.Overlays.Toolbar { Direction = FlowDirection.VerticalOnly, RelativeSizeAxes = Axes.Both, //stops us being considered in parent's autosize - Anchor = Anchor.BottomLeft, - Position = new Vector2(5, 5), + Anchor = (TooltipAnchor & Anchor.x0) > 0 ? Anchor.BottomLeft : Anchor.BottomRight, + Origin = TooltipAnchor, + Position = new Vector2((TooltipAnchor & Anchor.x0) > 0 ? 5 : -5, 5), Alpha = 0, Children = new[] { tooltip1 = new OsuSpriteText { + Anchor = TooltipAnchor, + Origin = TooltipAnchor, Shadow = true, TextSize = 22, Font = @"Exo2.0-Bold", }, tooltip2 = new OsuSpriteText { + Anchor = TooltipAnchor, + Origin = TooltipAnchor, Shadow = true, TextSize = 16 } diff --git a/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs new file mode 100644 index 0000000000..973f9f2d8a --- /dev/null +++ b/osu.Game/Overlays/Toolbar/ToolbarNotificationButton.cs @@ -0,0 +1,28 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Graphics; + +namespace osu.Game.Overlays.Toolbar +{ + class ToolbarNotificationButton : ToolbarOverlayToggleButton + { + protected override Anchor TooltipAnchor => Anchor.TopRight; + + public ToolbarNotificationButton() + { + Icon = FontAwesome.fa_bars; + TooltipMain = "Notifications"; + TooltipSub = "Waiting for 'ya"; + } + + [BackgroundDependencyLoader] + private void load(NotificationManager notificationManager) + { + StateContainer = notificationManager; + Action = notificationManager.ToggleVisibility; + } + } +} \ No newline at end of file diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 2ead6aad48..0477d85b43 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -100,6 +100,13 @@ + + + + + + + @@ -107,6 +114,7 @@ +