A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4using osu.Framework.Bindables;
5using osu.Framework.Graphics.Containers;
6using osu.Framework.Graphics.Shapes;
7
8namespace osu.Framework.Graphics.UserInterface
9{
10 public abstract class HexColourPicker : CompositeDrawable, IHasCurrentValue<Colour4>
11 {
12 private readonly BindableWithCurrent<Colour4> current = new BindableWithCurrent<Colour4>();
13
14 public Bindable<Colour4> Current
15 {
16 get => current.Current;
17 set => current.Current = value;
18 }
19
20 public new MarginPadding Padding
21 {
22 get => content.Padding;
23 set => content.Padding = value;
24 }
25
26 /// <summary>
27 /// Sets the spacing between the hex input text box and the colour preview.
28 /// </summary>
29 public float Spacing
30 {
31 get => spacer.Width;
32 set => spacer.Width = value;
33 }
34
35 /// <summary>
36 /// The background of the control.
37 /// </summary>
38 protected readonly Box Background;
39
40 private readonly Container content;
41
42 private readonly TextBox hexCodeTextBox;
43 private readonly Drawable spacer;
44 private readonly ColourPreview colourPreview;
45
46 protected HexColourPicker()
47 {
48 Current.Value = Colour4.White;
49
50 Width = 300;
51 AutoSizeAxes = Axes.Y;
52
53 InternalChildren = new Drawable[]
54 {
55 Background = new Box
56 {
57 RelativeSizeAxes = Axes.Both
58 },
59 content = new Container
60 {
61 RelativeSizeAxes = Axes.X,
62 AutoSizeAxes = Axes.Y,
63 Child = new GridContainer
64 {
65 RelativeSizeAxes = Axes.X,
66 AutoSizeAxes = Axes.Y,
67 ColumnDimensions = new[]
68 {
69 new Dimension(),
70 new Dimension(GridSizeMode.AutoSize),
71 new Dimension()
72 },
73 RowDimensions = new[]
74 {
75 new Dimension(GridSizeMode.AutoSize)
76 },
77 Content = new[]
78 {
79 new[]
80 {
81 hexCodeTextBox = CreateHexCodeTextBox().With(d =>
82 {
83 d.RelativeSizeAxes = Axes.X;
84 d.CommitOnFocusLost = true;
85 }),
86 spacer = Empty(),
87 colourPreview = CreateColourPreview().With(d => d.RelativeSizeAxes = Axes.Both)
88 }
89 }
90 }
91 }
92 };
93 }
94
95 /// <summary>
96 /// Creates the text box to be used for specifying the hex code of the target colour.
97 /// </summary>
98 protected abstract TextBox CreateHexCodeTextBox();
99
100 /// <summary>
101 /// Creates the control that will be used for displaying the preview of the target colour.
102 /// </summary>
103 protected abstract ColourPreview CreateColourPreview();
104
105 protected override void LoadComplete()
106 {
107 base.LoadComplete();
108
109 Current.BindValueChanged(_ => updateState(), true);
110
111 hexCodeTextBox.Current.BindValueChanged(_ => tryPreviewColour());
112 hexCodeTextBox.OnCommit += commitColour;
113 }
114
115 private void updateState()
116 {
117 hexCodeTextBox.Text = Current.Value.ToHex();
118 colourPreview.Current.Value = Current.Value;
119 }
120
121 private void tryPreviewColour()
122 {
123 if (!Colour4.TryParseHex(hexCodeTextBox.Text, out var colour) || colour.A < 1)
124 return;
125
126 colourPreview.Current.Value = colour;
127 }
128
129 private void commitColour(TextBox sender, bool newText)
130 {
131 if (!Colour4.TryParseHex(sender.Text, out var colour) || colour.A < 1)
132 {
133 Current.TriggerChange(); // restore previous value.
134 return;
135 }
136
137 Current.Value = colour;
138 }
139
140 public abstract class ColourPreview : CompositeDrawable
141 {
142 public Bindable<Colour4> Current = new Bindable<Colour4>();
143 }
144 }
145}