From c94da4fcf051deb7362b2db5adabf3ca28dc0951 Mon Sep 17 00:00:00 2001 From: DrabWeb Date: Fri, 24 Feb 2017 00:05:37 -0400 Subject: [PATCH 01/21] Added popup dialog --- .../Tests/TestCasePopupDialog.cs | 85 ++++ .../osu.Desktop.VisualTests.csproj | 1 + osu.Game/Overlays/Dialog/PopupDialog.cs | 383 ++++++++++++++++++ osu.Game/Overlays/Dialog/PopupDialogButton.cs | 170 ++++++++ osu.Game/osu.Game.csproj | 5 + 5 files changed, 644 insertions(+) create mode 100644 osu.Desktop.VisualTests/Tests/TestCasePopupDialog.cs create mode 100644 osu.Game/Overlays/Dialog/PopupDialog.cs create mode 100644 osu.Game/Overlays/Dialog/PopupDialogButton.cs diff --git a/osu.Desktop.VisualTests/Tests/TestCasePopupDialog.cs b/osu.Desktop.VisualTests/Tests/TestCasePopupDialog.cs new file mode 100644 index 0000000000..5cff6d452a --- /dev/null +++ b/osu.Desktop.VisualTests/Tests/TestCasePopupDialog.cs @@ -0,0 +1,85 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Framework.Screens.Testing; +using osu.Game.Graphics; +using osu.Game.Overlays.Dialog; + +namespace osu.Desktop.VisualTests.Tests +{ + public class TestCasePopupDialog : TestCase + { + public override string Name => @"Popup Dialog"; + + public override string Description => @"With various dialogs"; + + public override void Reset() + { + base.Reset(); + + var firstDialog = new PopupDialog + { + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.fa_trash_o, + ContextText = @"DELETE BEATMAP", + HeaderText = @"Confirm deletion of", + BodyText = @"Ayase Rie - Yuima-ru*World TVver.", + Buttons = new PopupDialogButton[] + { + new PopupDialogOKButton + { + Title = @"I never want to see this again.", + Action = () => System.Console.WriteLine(@"OK"), + }, + new PopupDialogCancelButton + { + Title = @"Firetruck, I still want quick ranks!", + Action = () => System.Console.WriteLine(@"Cancel"), + }, + }, + }; + var secondDialog = new PopupDialog + { + RelativeSizeAxes = Axes.Both, + Icon = FontAwesome.fa_gear, + ContextText = @"BEATMAP OPTIONS", + HeaderText = @"What do you want to do with", + BodyText = "Camellia as \"Bang Riot\" - Blastix Riotz", + Buttons = new PopupDialogButton[] + { + new PopupDialogOKButton + { + Title = @"Manage collections", + }, + new PopupDialogOKButton + { + Title = @"Delete...", + }, + new PopupDialogOKButton + { + Title = @"Remove from unplayed", + }, + new PopupDialogOKButton + { + Title = @"Clear local scores", + }, + new PopupDialogOKButton + { + Title = @"Edit", + }, + new PopupDialogCancelButton + { + Title = @"Cancel", + }, + }, + }; + + Add(firstDialog); + Add(secondDialog); + + AddButton("dialog #1", firstDialog.ToggleVisibility); + AddButton("dialog #2", secondDialog.ToggleVisibility); + } + } +} diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index cd899d4dd2..4e9bd92cbd 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -191,6 +191,7 @@ + diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs new file mode 100644 index 0000000000..fb281ac030 --- /dev/null +++ b/osu.Game/Overlays/Dialog/PopupDialog.cs @@ -0,0 +1,383 @@ +// 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 System.Linq; +using OpenTK; +using OpenTK.Graphics; +using osu.Framework; +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.Framework.MathUtils; +using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Overlays.Dialog +{ + public class PopupDialog : OverlayContainer + { + private const float header_body_offset = 4; + private readonly Vector2 ring_size = new Vector2(100f); + private readonly Vector2 ring_minified_size = new Vector2(20f); + private readonly Vector2 buttons_enter_spacing = new Vector2(0f, 100f); + + private const float enter_duration = 500; + private readonly EasingTypes enter_easing = EasingTypes.OutQuint; + + private const float exit_duration = 500; + private const float button_fade_duration = 200; + private readonly EasingTypes exit_easing = EasingTypes.InSine; + + private PopupDialogTriangles triangles; + private Container dialogContainer, iconRing, headerBodyContainer; + private TextAwesome iconText; + private OsuSpriteText contextLabel, headerLabel, bodyLabel; + private FlowContainer buttonsContainer; + + public FontAwesome Icon + { + get + { + return iconText.Icon; + } + set + { + iconText.Icon = value; + } + } + + public string ContextText + { + get + { + return contextLabel.Text; + } + set + { + contextLabel.Text = value.ToUpper(); + } + } + + public string HeaderText + { + get + { + return headerLabel.Text; + } + set + { + headerLabel.Text = value; + } + } + + public string BodyText + { + get + { + return bodyLabel.Text; + } + set + { + bodyLabel.Text = value; + } + } + + public PopupDialogButton[] Buttons + { + get + { + // buttonsContainer cannot be a FlowContainer because there is a crash on TransformSpacing if it is (probably a bug and will be fixed) + + var buttons = new List(); + foreach (Container c in buttonsContainer.Children) + { + var button = (PopupDialogButton)c; + if (button != null) buttons.Add(button); + } + return buttons.ToArray(); + } + set + { + buttonsContainer.Children = value; + + // Simple way to allow direct action setting on the button but we can still call our own logic here + foreach (PopupDialogButton b in value) + { + b.AlwaysPresent = true; + var action = b.Action; + b.Action = () => + { + fadeOutAllBut(b); + Hide(); + action?.Invoke(); + }; + } + } + } + + protected override void PopIn() + { + // Reset various animations, but only if the entire dialog animation completed + if (dialogContainer.Alpha == 0) + { + iconRing.ResizeTo(ring_minified_size); + buttonsContainer.TransformSpacingTo(buttons_enter_spacing); + headerBodyContainer.Alpha = 0; + } + + foreach (PopupDialogButton b in Buttons) + b.FadeIn(button_fade_duration, enter_easing); + + triangles.SlideIn(); + dialogContainer.FadeIn(enter_duration, enter_easing); + iconRing.ResizeTo(ring_size, enter_duration, enter_easing); + headerBodyContainer.FadeIn(enter_duration, enter_easing); + buttonsContainer.MoveToY(0, enter_duration, enter_easing); + buttonsContainer.TransformSpacingTo(new Vector2(0f), enter_duration, enter_easing); + } + + protected override void PopOut() + { + triangles.SlideOut(); + dialogContainer.FadeOut(exit_duration, exit_easing); + headerBodyContainer.FadeOut(exit_duration, exit_easing); + } + + private void fadeOutAllBut(PopupDialogButton button) + { + foreach (PopupDialogButton b in Buttons) + { + if (b != button) + { + b.FadeOut(button_fade_duration, exit_easing); + } + } + } + + public PopupDialog() + { + Children = new Drawable[] + { + triangles = new PopupDialogTriangles + { + RelativeSizeAxes = Axes.Both, + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Width = 0.5f, + }, + dialogContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Origin = Anchor.BottomCentre, + Anchor = Anchor.BottomCentre, + Width = 0.4f, + Alpha = 0, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(200), + }, + new Container + { + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Children = new Drawable[] + { + new Container + { + Origin = Anchor.BottomCentre, + Anchor = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new FlowContainer + { + Origin = Anchor.BottomCentre, + Anchor = Anchor.TopCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FlowDirections.Vertical, + Spacing = new Vector2(0f, 15f), + Children = new Drawable[] + { + new Container + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Size = ring_size, + Children = new Drawable[] + { + iconRing = new CircularContainer + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + BorderColour = Color4.White, + BorderThickness = 10f, + Size = ring_minified_size, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black.Opacity(0), + }, + iconText = new TextAwesome + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Icon = FontAwesome.fa_close, + TextSize = 50, + }, + }, + }, + } + }, + contextLabel = new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Text = @"CONTEXT", + Font = @"Exo2.0-Bold", + }, + }, + }, + headerBodyContainer = new Container + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = 100, + Alpha = 0, + Children = new Drawable[] + { + headerLabel = new OsuSpriteText + { + Origin = Anchor.BottomCentre, + Anchor = Anchor.Centre, + Position = new Vector2(0f, -header_body_offset), + Text = @"Header", + Font = @"Exo2.0-Bold", + TextSize = 18, + Alpha = 0.75f, + BlendingMode = BlendingMode.Additive, + }, + bodyLabel = new OsuSpriteText + { + Origin = Anchor.TopCentre, + Anchor = Anchor.Centre, + Position = new Vector2(0f, header_body_offset), + Text = @"Body", + Font = @"Exo2.0-BoldItalic", + TextSize = 18, + }, + }, + }, + }, + }, + }, + }, + buttonsContainer = new FlowContainer + { + RelativeSizeAxes = Axes.Both, + Height = 0.5f, + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + Direction = FlowDirections.Vertical, + Spacing = buttons_enter_spacing, + Position = new Vector2(0f, buttons_enter_spacing.Y), + }, + }, + }, + }; + } + } + + class PopupDialogTriangles : Triangles + { + private Color4[] colours; + + protected override float SpawnRatio => spawnRatio; + private float spawnRatio = 0f; + + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + colours = new Color4[] + { + colour.BlueLight, + colour.Blue, + colour.PinkLight, + colour.Pink, + colour.YellowLight, + colour.Yellow, + colour.PurpleLight, + colour.Purple, + }; + } + + protected override Color4 GetTriangleShade() => colours[RNG.Next(0, colours.Length - 1)]; + + private const float triangle_moving_speed = 300; + private const float triangle_normal_speed = 20000; + private float triangleMoveSpeed; + + protected override void Update() + { + base.Update(); + foreach (Drawable d in Children) + { + d.Position -= new Vector2(0, (float)(d.Scale.X * (Time.Elapsed / triangleMoveSpeed))); + } + } + + public void SlideIn() + { + triangleMoveSpeed = triangle_moving_speed; + TransformFloatTo(spawnRatio, 1f, 600, EasingTypes.None, new TransformFloatSpawnRatio()); + TransformFloatTo(triangleMoveSpeed, triangle_normal_speed, 600, EasingTypes.InQuint, new TransformFloatSpeed()); + } + + public void SlideOut() + { + TransformFloatTo(spawnRatio, 0f, 500, EasingTypes.None, new TransformFloatSpawnRatio()); + TransformFloatTo(triangleMoveSpeed, triangle_moving_speed, 500, EasingTypes.OutExpo, new TransformFloatSpeed()); + } + + class TransformFloatSpeed : TransformFloat + { + public override void Apply(Drawable d) + { + base.Apply(d); + PopupDialogTriangles t = d as PopupDialogTriangles; + t.triangleMoveSpeed = CurrentValue; + } + } + + class TransformFloatSpawnRatio : TransformFloat + { + public override void Apply(Drawable d) + { + base.Apply(d); + PopupDialogTriangles t = d as PopupDialogTriangles; + t.spawnRatio = CurrentValue; + } + } + + protected override void LoadComplete() + { + // override so the triangles don't do the initial fill + } + + public PopupDialogTriangles() + { + TriangleScale = 2f; + } + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Dialog/PopupDialogButton.cs b/osu.Game/Overlays/Dialog/PopupDialogButton.cs new file mode 100644 index 0000000000..ec86fd0637 --- /dev/null +++ b/osu.Game/Overlays/Dialog/PopupDialogButton.cs @@ -0,0 +1,170 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Backgrounds; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Overlays.Dialog +{ + public class PopupDialogButton : ClickableContainer + { + private float height = 50; + private float foreground_shear = 0.2f; + + private Box background, foreground; + private Triangles triangles; + private OsuSpriteText label; + + public string Title + { + get + { + return label.Text; + } + set + { + label.Text = value; + } + } + + public Color4 ForegroundColour + { + get + { + return foreground.Colour; + } + set + { + foreground.Colour = value; + } + } + + public Color4 BackgroundColour + { + get + { + return background.Colour; + } + set + { + background.Colour = value; + } + } + + public Color4 TrianglesColourLight + { + get + { + return triangles.ColourLight; + } + set + { + triangles.ColourLight = value; + } + } + + public Color4 TrianglesColourDark + { + get + { + return triangles.ColourDark; + } + set + { + triangles.ColourDark = value; + } + } + + public PopupDialogButton() + { + RelativeSizeAxes = Axes.X; + Height = height; + + Children = new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Children = new Drawable[] + { + background = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + }, + triangles = new Triangles + { + RelativeSizeAxes = Axes.Both, + } + }, + }, + new Container + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + RelativeSizeAxes = Axes.Both, + Width = 0.8f, + Shear = new Vector2(foreground_shear, 0f), + Masking = true, + EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Shadow, + Colour = Color4.Black.Opacity(50), + Radius = 5, + }, + Children = new Drawable[] + { + foreground = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.White, + EdgeSmoothness = new Vector2(2, 0), + }, + label = new OsuSpriteText + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Shear = new Vector2(-foreground_shear, 0f), + Text = @"Button", + Font = @"Exo2.0-Bold", + TextSize = 18, + }, + }, + }, + }; + } + } + + public class PopupDialogOKButton : PopupDialogButton + { + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.PinkDark; + ForegroundColour = colours.Pink; + TrianglesColourDark = colours.PinkDarker; + TrianglesColourLight = colours.Pink; + } + } + + public class PopupDialogCancelButton : PopupDialogButton + { + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + BackgroundColour = colours.BlueDark; + ForegroundColour = colours.Blue; + TrianglesColourDark = colours.BlueDarker; + TrianglesColourLight = colours.Blue; + } + } +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a336f54227..56f5597b5b 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -277,6 +277,8 @@ + + @@ -297,6 +299,9 @@ + + +