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.Extensions.Color4Extensions;
5using osu.Framework.Graphics.Containers;
6using osu.Framework.Graphics.Shapes;
7using osu.Framework.Graphics.Sprites;
8using osu.Framework.Input.Events;
9using osuTK;
10using osuTK.Graphics;
11
12namespace osu.Framework.Graphics.UserInterface
13{
14 public class BasicTextBox : TextBox
15 {
16 protected virtual float CaretWidth => 2;
17
18 private const float caret_move_time = 60;
19
20 protected virtual Color4 SelectionColour => FrameworkColour.YellowGreen;
21
22 protected Color4 BackgroundCommit { get; set; } = FrameworkColour.Green;
23
24 private Color4 backgroundFocused = new Color4(100, 100, 100, 255);
25 private Color4 backgroundUnfocused = new Color4(100, 100, 100, 120);
26
27 private readonly Box background;
28
29 protected Color4 BackgroundFocused
30 {
31 get => backgroundFocused;
32 set
33 {
34 backgroundFocused = value;
35 if (HasFocus)
36 background.Colour = value;
37 }
38 }
39
40 protected Color4 BackgroundUnfocused
41 {
42 get => backgroundUnfocused;
43 set
44 {
45 backgroundUnfocused = value;
46 if (!HasFocus)
47 background.Colour = value;
48 }
49 }
50
51 protected virtual Color4 InputErrorColour => Color4.Red;
52
53 public BasicTextBox()
54 {
55 Add(background = new Box
56 {
57 RelativeSizeAxes = Axes.Both,
58 Depth = 1,
59 Colour = BackgroundUnfocused,
60 });
61
62 BackgroundFocused = FrameworkColour.BlueGreen;
63 BackgroundUnfocused = FrameworkColour.BlueGreenDark;
64 TextContainer.Height = 0.75f;
65 }
66
67 protected override void NotifyInputError() => background.FlashColour(InputErrorColour, 200);
68
69 protected override void OnTextCommitted(bool textChanged)
70 {
71 base.OnTextCommitted(textChanged);
72
73 background.Colour = ReleaseFocusOnCommit ? BackgroundUnfocused : BackgroundFocused;
74 background.ClearTransforms();
75 background.FlashColour(BackgroundCommit, 400);
76 }
77
78 protected override void OnFocusLost(FocusLostEvent e)
79 {
80 base.OnFocusLost(e);
81
82 background.ClearTransforms();
83 background.Colour = BackgroundFocused;
84 background.FadeColour(BackgroundUnfocused, 200, Easing.OutExpo);
85 }
86
87 protected override void OnFocus(FocusEvent e)
88 {
89 base.OnFocus(e);
90
91 background.ClearTransforms();
92 background.Colour = BackgroundUnfocused;
93 background.FadeColour(BackgroundFocused, 200, Easing.Out);
94 }
95
96 protected override Drawable GetDrawableCharacter(char c) => new FallingDownContainer
97 {
98 AutoSizeAxes = Axes.Both,
99 Child = new SpriteText { Text = c.ToString(), Font = FrameworkFont.Condensed.With(size: CalculatedTextSize) }
100 };
101
102 protected override SpriteText CreatePlaceholder() => new FadingPlaceholderText
103 {
104 Colour = FrameworkColour.YellowGreen,
105 Font = FrameworkFont.Condensed,
106 Anchor = Anchor.CentreLeft,
107 Origin = Anchor.CentreLeft,
108 X = CaretWidth,
109 };
110
111 public class FallingDownContainer : Container
112 {
113 public override void Show()
114 {
115 var col = (Color4)Colour;
116 this.FadeColour(col.Opacity(0)).FadeColour(col, caret_move_time * 2, Easing.Out);
117 }
118
119 public override void Hide()
120 {
121 this.FadeOut(200);
122 this.MoveToY(DrawSize.Y, 200, Easing.InExpo);
123 }
124 }
125
126 public class FadingPlaceholderText : SpriteText
127 {
128 public override void Show() => this.FadeIn(200);
129
130 public override void Hide() => this.FadeOut(200);
131 }
132
133 protected override Caret CreateCaret() => new BasicCaret
134 {
135 CaretWidth = CaretWidth,
136 SelectionColour = SelectionColour,
137 };
138
139 public class BasicCaret : Caret
140 {
141 public BasicCaret()
142 {
143 RelativeSizeAxes = Axes.Y;
144 Size = new Vector2(1, 0.9f);
145
146 Colour = Color4.Transparent;
147 Anchor = Anchor.CentreLeft;
148 Origin = Anchor.CentreLeft;
149
150 Masking = true;
151 CornerRadius = 1;
152
153 InternalChild = new Box
154 {
155 RelativeSizeAxes = Axes.Both,
156 Colour = Color4.White,
157 };
158 }
159
160 public override void Hide() => this.FadeOut(200);
161
162 public float CaretWidth { get; set; }
163
164 public Color4 SelectionColour { get; set; }
165
166 public override void DisplayAt(Vector2 position, float? selectionWidth)
167 {
168 if (selectionWidth != null)
169 {
170 this.MoveTo(new Vector2(position.X, position.Y), 60, Easing.Out);
171 this.ResizeWidthTo(selectionWidth.Value + CaretWidth / 2, caret_move_time, Easing.Out);
172 this
173 .FadeTo(0.5f, 200, Easing.Out)
174 .FadeColour(SelectionColour, 200, Easing.Out);
175 }
176 else
177 {
178 this.MoveTo(new Vector2(position.X - CaretWidth / 2, position.Y), 60, Easing.Out);
179 this.ResizeWidthTo(CaretWidth, caret_move_time, Easing.Out);
180 this
181 .FadeColour(Color4.White, 200, Easing.Out)
182 .Loop(c => c.FadeTo(0.7f).FadeTo(0.4f, 500, Easing.InOutSine));
183 }
184 }
185 }
186 }
187}