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

Merge pull request #12478 from bdach/combo-colours-display

Add read-only combo colour display to setup screen
This commit is contained in:
Dan Balasescu 2021-04-20 11:55:35 +09:00 committed by GitHub
commit e227c076e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 374 additions and 4 deletions

View File

@ -0,0 +1,70 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Utils;
using osu.Game.Graphics.UserInterfaceV2;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneLabelledColourPalette : OsuTestScene
{
private LabelledColourPalette component;
[Test]
public void TestPalette([Values] bool hasDescription)
{
createColourPalette(hasDescription);
AddRepeatStep("add random colour", () => component.Colours.Add(randomColour()), 4);
AddStep("set custom prefix", () => component.ColourNamePrefix = "Combo");
AddRepeatStep("remove random colour", () =>
{
if (component.Colours.Count > 0)
component.Colours.RemoveAt(RNG.Next(component.Colours.Count));
}, 8);
}
private void createColourPalette(bool hasDescription = false)
{
AddStep("create component", () =>
{
Child = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Width = 500,
AutoSizeAxes = Axes.Y,
Child = component = new LabelledColourPalette
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
ColourNamePrefix = "My colour #"
}
};
component.Label = "a sample component";
component.Description = hasDescription ? "this text describes the component" : string.Empty;
component.Colours.AddRange(new[]
{
Color4.DarkRed,
Color4.Aquamarine,
Color4.Goldenrod,
Color4.Gainsboro
});
});
}
private Color4 randomColour() => new Color4(
RNG.NextSingle(),
RNG.NextSingle(),
RNG.NextSingle(),
1);
}
}

View File

@ -94,6 +94,18 @@ namespace osu.Game.Graphics
}
}
/// <summary>
/// Returns a foreground text colour that is supposed to contrast well with
/// the supplied <paramref name="backgroundColour"/>.
/// </summary>
public static Color4 ForegroundTextColourFor(Color4 backgroundColour)
{
// formula taken from the RGB->YIQ conversions: https://en.wikipedia.org/wiki/YIQ
// brightness here is equivalent to the Y component in the above colour model, which is a rough estimate of lightness.
float brightness = 0.299f * backgroundColour.R + 0.587f * backgroundColour.G + 0.114f * backgroundColour.B;
return Gray(brightness > 0.5f ? 0.2f : 0.9f);
}
// See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less
public readonly Color4 PurpleLighter = Color4Extensions.FromHex(@"eeeeff");
public readonly Color4 PurpleLight = Color4Extensions.FromHex(@"aa88ff");

View File

@ -0,0 +1,107 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Localisation;
using osu.Game.Graphics.Sprites;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Graphics.UserInterfaceV2
{
/// <summary>
/// A component which displays a colour along with related description text.
/// </summary>
public class ColourDisplay : CompositeDrawable, IHasCurrentValue<Color4>
{
private readonly BindableWithCurrent<Color4> current = new BindableWithCurrent<Color4>();
private Box fill;
private OsuSpriteText colourHexCode;
private OsuSpriteText colourName;
public Bindable<Color4> Current
{
get => current.Current;
set => current.Current = value;
}
private LocalisableString name;
public LocalisableString ColourName
{
get => name;
set
{
if (name == value)
return;
name = value;
colourName.Text = name;
}
}
[BackgroundDependencyLoader]
private void load()
{
AutoSizeAxes = Axes.Y;
Width = 100;
InternalChild = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Spacing = new Vector2(0, 10),
Children = new Drawable[]
{
new CircularContainer
{
RelativeSizeAxes = Axes.X,
Height = 100,
Masking = true,
Children = new Drawable[]
{
fill = new Box
{
RelativeSizeAxes = Axes.Both
},
colourHexCode = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Font = OsuFont.Default.With(size: 12)
}
}
},
colourName = new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre
}
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
current.BindValueChanged(_ => updateColour(), true);
}
private void updateColour()
{
fill.Colour = current.Value;
colourHexCode.Text = current.Value.ToHex();
colourHexCode.Colour = OsuColour.ForegroundTextColourFor(current.Value);
}
}
}

View File

@ -0,0 +1,119 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Graphics.UserInterfaceV2
{
/// <summary>
/// A component which displays a collection of colours in individual <see cref="ColourDisplay"/>s.
/// </summary>
public class ColourPalette : CompositeDrawable
{
public BindableList<Color4> Colours { get; } = new BindableList<Color4>();
private string colourNamePrefix = "Colour";
public string ColourNamePrefix
{
get => colourNamePrefix;
set
{
if (colourNamePrefix == value)
return;
colourNamePrefix = value;
if (IsLoaded)
reindexItems();
}
}
private FillFlowContainer<ColourDisplay> palette;
private Container placeholder;
[BackgroundDependencyLoader]
private void load()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
InternalChildren = new Drawable[]
{
palette = new FillFlowContainer<ColourDisplay>
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Spacing = new Vector2(10),
Direction = FillDirection.Full
},
placeholder = new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = new OsuSpriteText
{
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
Text = "(none)",
Font = OsuFont.Default.With(weight: FontWeight.Bold)
}
}
};
}
protected override void LoadComplete()
{
base.LoadComplete();
Colours.BindCollectionChanged((_, __) => updatePalette(), true);
FinishTransforms(true);
}
private const int fade_duration = 200;
private void updatePalette()
{
palette.Clear();
if (Colours.Any())
{
palette.FadeIn(fade_duration, Easing.OutQuint);
placeholder.FadeOut(fade_duration, Easing.OutQuint);
}
else
{
palette.FadeOut(fade_duration, Easing.OutQuint);
placeholder.FadeIn(fade_duration, Easing.OutQuint);
}
foreach (var item in Colours)
{
palette.Add(new ColourDisplay
{
Current = { Value = item }
});
}
reindexItems();
}
private void reindexItems()
{
int index = 1;
foreach (var colour in palette)
{
colour.ColourName = $"{colourNamePrefix} {index}";
index += 1;
}
}
}
}

View File

@ -0,0 +1,26 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Bindables;
using osuTK.Graphics;
namespace osu.Game.Graphics.UserInterfaceV2
{
public class LabelledColourPalette : LabelledDrawable<ColourPalette>
{
public LabelledColourPalette()
: base(true)
{
}
public BindableList<Color4> Colours => Component.Colours;
public string ColourNamePrefix
{
get => Component.ColourNamePrefix;
set => Component.ColourNamePrefix = value;
}
protected override ColourPalette CreateComponent() => new ColourPalette();
}
}

View File

@ -158,10 +158,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
circle.Colour = comboColour;
var col = circle.Colour.TopLeft.Linear;
float brightness = col.R + col.G + col.B;
// decide the combo index colour based on brightness?
colouredComponents.Colour = OsuColour.Gray(brightness > 0.5f ? 0.2f : 0.9f);
colouredComponents.Colour = OsuColour.ForegroundTextColourFor(col);
}
protected override void Update()

View File

@ -46,6 +46,7 @@ namespace osu.Game.Screens.Edit
public readonly IBeatmap PlayableBeatmap;
[CanBeNull]
public readonly ISkin BeatmapSkin;
[Resolved]

View File

@ -0,0 +1,37 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Localisation;
using osu.Game.Graphics.UserInterfaceV2;
using osu.Game.Skinning;
using osuTK.Graphics;
namespace osu.Game.Screens.Edit.Setup
{
internal class ColoursSection : SetupSection
{
public override LocalisableString Title => "Colours";
private LabelledColourPalette comboColours;
[BackgroundDependencyLoader]
private void load()
{
Children = new Drawable[]
{
comboColours = new LabelledColourPalette
{
Label = "Hitcircle / Slider Combos",
ColourNamePrefix = "Combo"
}
};
var colours = Beatmap.BeatmapSkin?.GetConfig<GlobalSkinColours, IReadOnlyList<Color4>>(GlobalSkinColours.ComboColours)?.Value;
if (colours != null)
comboColours.Colours.AddRange(colours);
}
}
}

View File

@ -34,6 +34,7 @@ namespace osu.Game.Screens.Edit.Setup
new ResourcesSection(),
new MetadataSection(),
new DifficultySection(),
new ColoursSection()
}
},
});