From 583242d96d343bb342f524e3bc0275d111d945af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sun, 6 Jun 2021 13:05:26 +0200 Subject: [PATCH 1/4] Add osu!-styled colour picker control --- .../UserInterface/TestSceneColourPicker.cs | 82 +++++++++++++ .../UserInterfaceV2/OsuColourPicker.cs | 19 +++ .../UserInterfaceV2/OsuHSVColourPicker.cs | 109 ++++++++++++++++++ .../UserInterfaceV2/OsuHexColourPicker.cs | 57 +++++++++ 4 files changed, 267 insertions(+) create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs create mode 100644 osu.Game/Graphics/UserInterfaceV2/OsuColourPicker.cs create mode 100644 osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs create mode 100644 osu.Game/Graphics/UserInterfaceV2/OsuHexColourPicker.cs diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs new file mode 100644 index 0000000000..634e45e7a9 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs @@ -0,0 +1,82 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterfaceV2; +using osu.Game.Overlays; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneColourPicker : OsuTestScene + { + [SetUpSteps] + public void SetUpSteps() + { + AddStep("create pickers", () => Child = new GridContainer + { + RelativeSizeAxes = Axes.Both, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension() + }, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = @"No OverlayColourProvider", + Font = OsuFont.Default.With(size: 40) + }, + new OsuColourPicker + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + } + } + }, + new ColourProvidingContainer(OverlayColourScheme.Blue) + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = @"With blue OverlayColourProvider", + Font = OsuFont.Default.With(size: 40) + }, + new OsuColourPicker + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre + } + } + } + } + } + }); + } + + private class ColourProvidingContainer : Container + { + [Cached] + private OverlayColourProvider provider { get; } + + public ColourProvidingContainer(OverlayColourScheme colourScheme) + { + provider = new OverlayColourProvider(colourScheme); + } + } + } +} diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuColourPicker.cs b/osu.Game/Graphics/UserInterfaceV2/OsuColourPicker.cs new file mode 100644 index 0000000000..5394e5d0aa --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/OsuColourPicker.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics.UserInterface; + +namespace osu.Game.Graphics.UserInterfaceV2 +{ + public class OsuColourPicker : ColourPicker + { + public OsuColourPicker() + { + CornerRadius = 10; + Masking = true; + } + + protected override HSVColourPicker CreateHSVColourPicker() => new OsuHSVColourPicker(); + protected override HexColourPicker CreateHexColourPicker() => new OsuHexColourPicker(); + } +} diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs b/osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs new file mode 100644 index 0000000000..2a399cfaf8 --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs @@ -0,0 +1,109 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Overlays; +using osuTK; + +namespace osu.Game.Graphics.UserInterfaceV2 +{ + public class OsuHSVColourPicker : HSVColourPicker + { + protected override HueSelector CreateHueSelector() => new OsuHueSelector(); + protected override SaturationValueSelector CreateSaturationValueSelector() => new OsuSaturationValueSelector(); + + [BackgroundDependencyLoader(true)] + private void load([CanBeNull] OverlayColourProvider colourProvider, OsuColour osuColour) + { + Background.Colour = colourProvider?.Dark5 ?? osuColour.GreySeafoamDark; + + Content.Padding = new MarginPadding(10); + Content.Spacing = new Vector2(0, 10); + } + + private class OsuHueSelector : HueSelector + { + public OsuHueSelector() + { + Margin = new MarginPadding + { + Bottom = 15 + }; + + SliderBar.CornerRadius = SliderBar.Height / 2; + SliderBar.Masking = true; + } + + protected override Drawable CreateSliderNub() => new SliderNub(); + + private class SliderNub : CompositeDrawable + { + public SliderNub() + { + InternalChild = new Triangle + { + Width = 20, + Height = 15, + Anchor = Anchor.BottomCentre, + Origin = Anchor.TopCentre + }; + } + } + } + + private class OsuSaturationValueSelector : SaturationValueSelector + { + public OsuSaturationValueSelector() + { + SelectionArea.CornerRadius = 10; + SelectionArea.Masking = true; + // purposefully use hard non-AA'd masking to avoid edge artifacts. + SelectionArea.MaskingSmoothness = 0; + } + + protected override Marker CreateMarker() => new OsuMarker(); + + private class OsuMarker : Marker + { + private readonly Box previewBox; + + public OsuMarker() + { + AutoSizeAxes = Axes.Both; + + InternalChild = new CircularContainer + { + Size = new Vector2(20), + Masking = true, + BorderColour = Colour4.White, + BorderThickness = 3, + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0, 1), + Radius = 3, + Colour = Colour4.Black.Opacity(0.3f) + }, + Child = previewBox = new Box + { + RelativeSizeAxes = Axes.Both + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Current.BindValueChanged(colour => previewBox.Colour = colour.NewValue, true); + } + } + } + } +} diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuHexColourPicker.cs b/osu.Game/Graphics/UserInterfaceV2/OsuHexColourPicker.cs new file mode 100644 index 0000000000..331a1b67c9 --- /dev/null +++ b/osu.Game/Graphics/UserInterfaceV2/OsuHexColourPicker.cs @@ -0,0 +1,57 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using JetBrains.Annotations; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.UserInterface; +using osu.Game.Overlays; + +namespace osu.Game.Graphics.UserInterfaceV2 +{ + public class OsuHexColourPicker : HexColourPicker + { + public OsuHexColourPicker() + { + Padding = new MarginPadding(20); + Spacing = 20; + } + + [BackgroundDependencyLoader(true)] + private void load([CanBeNull] OverlayColourProvider overlayColourProvider, OsuColour osuColour) + { + Background.Colour = overlayColourProvider?.Dark6 ?? osuColour.GreySeafoamDarker; + } + + protected override TextBox CreateHexCodeTextBox() => new OsuTextBox(); + protected override ColourPreview CreateColourPreview() => new OsuColourPreview(); + + private class OsuColourPreview : ColourPreview + { + private readonly Box preview; + + public OsuColourPreview() + { + InternalChild = new CircularContainer + { + RelativeSizeAxes = Axes.Both, + Masking = true, + Child = preview = new Box + { + RelativeSizeAxes = Axes.Both + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + Current.BindValueChanged(colour => preview.Colour = colour.NewValue, true); + } + } + } +} From 30a7b034be65e7c7c83ad85518004cd3372d0583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 1 Jul 2021 00:30:43 +0200 Subject: [PATCH 2/4] Add HSV abbreviation to team-shared collection --- osu.sln.DotSettings | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index 62751cebb1..d2c5b1223c 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -308,6 +308,7 @@ GL GLSL HID + HSV HTML HUD ID From 083e463afd8065f19d082e9e158ab6ad31afdae1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 2 Jul 2021 01:02:36 +0200 Subject: [PATCH 3/4] Use alternative hue slider nub design --- .../UserInterfaceV2/OsuHSVColourPicker.cs | 68 ++++++++++++------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs b/osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs index 2a399cfaf8..06056f239b 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuHSVColourPicker.cs @@ -3,6 +3,7 @@ using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; @@ -15,6 +16,10 @@ namespace osu.Game.Graphics.UserInterfaceV2 { public class OsuHSVColourPicker : HSVColourPicker { + private const float spacing = 10; + private const float corner_radius = 10; + private const float control_border_thickness = 3; + protected override HueSelector CreateHueSelector() => new OsuHueSelector(); protected override SaturationValueSelector CreateSaturationValueSelector() => new OsuSaturationValueSelector(); @@ -23,37 +28,58 @@ namespace osu.Game.Graphics.UserInterfaceV2 { Background.Colour = colourProvider?.Dark5 ?? osuColour.GreySeafoamDark; - Content.Padding = new MarginPadding(10); - Content.Spacing = new Vector2(0, 10); + Content.Padding = new MarginPadding(spacing); + Content.Spacing = new Vector2(0, spacing); } + private static EdgeEffectParameters createShadowParameters() => new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Offset = new Vector2(0, 1), + Radius = 3, + Colour = Colour4.Black.Opacity(0.3f) + }; + private class OsuHueSelector : HueSelector { public OsuHueSelector() { - Margin = new MarginPadding - { - Bottom = 15 - }; - - SliderBar.CornerRadius = SliderBar.Height / 2; + SliderBar.CornerRadius = corner_radius; SliderBar.Masking = true; } - protected override Drawable CreateSliderNub() => new SliderNub(); + protected override Drawable CreateSliderNub() => new SliderNub(this); private class SliderNub : CompositeDrawable { - public SliderNub() + private readonly Bindable hue; + private readonly Box fill; + + public SliderNub(OsuHueSelector osuHueSelector) { - InternalChild = new Triangle + hue = osuHueSelector.Hue.GetBoundCopy(); + + InternalChild = new CircularContainer { - Width = 20, - Height = 15, - Anchor = Anchor.BottomCentre, - Origin = Anchor.TopCentre + Height = 35, + Width = 10, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Masking = true, + BorderColour = Colour4.White, + BorderThickness = control_border_thickness, + EdgeEffect = createShadowParameters(), + Child = fill = new Box + { + RelativeSizeAxes = Axes.Both + } }; } + + protected override void LoadComplete() + { + hue.BindValueChanged(h => fill.Colour = Colour4.FromHSV(h.NewValue, 1, 1), true); + } } } @@ -61,7 +87,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 { public OsuSaturationValueSelector() { - SelectionArea.CornerRadius = 10; + SelectionArea.CornerRadius = corner_radius; SelectionArea.Masking = true; // purposefully use hard non-AA'd masking to avoid edge artifacts. SelectionArea.MaskingSmoothness = 0; @@ -82,14 +108,8 @@ namespace osu.Game.Graphics.UserInterfaceV2 Size = new Vector2(20), Masking = true, BorderColour = Colour4.White, - BorderThickness = 3, - EdgeEffect = new EdgeEffectParameters - { - Type = EdgeEffectType.Shadow, - Offset = new Vector2(0, 1), - Radius = 3, - Colour = Colour4.Black.Opacity(0.3f) - }, + BorderThickness = control_border_thickness, + EdgeEffect = createShadowParameters(), Child = previewBox = new Box { RelativeSizeAxes = Axes.Both From d67fc87dcbc27fd0be7a3fd61faf174099fd9e68 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 2 Jul 2021 17:24:15 +0900 Subject: [PATCH 4/4] Add some basic testability of external colour setting --- .../Visual/UserInterface/TestSceneColourPicker.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs index 634e45e7a9..fa9179443d 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneColourPicker.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; @@ -14,6 +15,8 @@ namespace osu.Game.Tests.Visual.UserInterface { public class TestSceneColourPicker : OsuTestScene { + private readonly Bindable colour = new Bindable(Colour4.Aquamarine); + [SetUpSteps] public void SetUpSteps() { @@ -42,7 +45,8 @@ namespace osu.Game.Tests.Visual.UserInterface new OsuColourPicker { Anchor = Anchor.Centre, - Origin = Anchor.Centre + Origin = Anchor.Centre, + Current = { BindTarget = colour }, } } }, @@ -59,13 +63,18 @@ namespace osu.Game.Tests.Visual.UserInterface new OsuColourPicker { Anchor = Anchor.Centre, - Origin = Anchor.Centre + Origin = Anchor.Centre, + Current = { BindTarget = colour }, } } } } } }); + + AddStep("set green", () => colour.Value = Colour4.LimeGreen); + AddStep("set white", () => colour.Value = Colour4.White); + AddStep("set red", () => colour.Value = Colour4.Red); } private class ColourProvidingContainer : Container