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 System;
5using osu.Framework.Graphics;
6using osu.Framework.Graphics.Containers;
7using osu.Framework.Graphics.Effects;
8using osu.Framework.Graphics.Shapes;
9using osu.Framework.Graphics.Sprites;
10using osu.Framework.Input.Events;
11using osuTK;
12using osuTK.Graphics;
13
14namespace osu.Framework.Tests.Visual.Containers
15{
16 public class TestSceneMasking : FrameworkTestScene
17 {
18 protected Container TestContainer;
19 protected int CurrentTest;
20 protected float TestCornerExponent = 2f;
21
22 public TestSceneMasking()
23 {
24 Add(TestContainer = new Container
25 {
26 RelativeSizeAxes = Axes.Both,
27 });
28
29 string[] testNames =
30 {
31 @"Round corner masking",
32 @"Round corner AABB 1",
33 @"Round corner AABB 2",
34 @"Round corner AABB 3",
35 @"Edge/border blurriness",
36 @"Nested masking",
37 @"Rounded corner input",
38 @"Offset shadow",
39 @"Negative size"
40 };
41
42 for (int i = 0; i < testNames.Length; i++)
43 {
44 int test = i;
45 AddStep(testNames[i], delegate { loadTest(test); });
46 }
47
48 AddSliderStep("Corner exponent", 0.01f, 10, 2, exponent =>
49 {
50 TestCornerExponent = exponent;
51 loadTest(CurrentTest);
52 });
53
54 loadTest(0);
55 addCrosshair();
56 }
57
58 private void addCrosshair()
59 {
60 Add(new Box
61 {
62 Colour = Color4.Black,
63 Size = new Vector2(22, 4),
64 Anchor = Anchor.Centre,
65 Origin = Anchor.Centre
66 });
67
68 Add(new Box
69 {
70 Colour = Color4.Black,
71 Size = new Vector2(4, 22),
72 Anchor = Anchor.Centre,
73 Origin = Anchor.Centre
74 });
75
76 Add(new Box
77 {
78 Colour = Color4.WhiteSmoke,
79 Size = new Vector2(20, 2),
80 Anchor = Anchor.Centre,
81 Origin = Anchor.Centre
82 });
83
84 Add(new Box
85 {
86 Colour = Color4.WhiteSmoke,
87 Size = new Vector2(2, 20),
88 Anchor = Anchor.Centre,
89 Origin = Anchor.Centre
90 });
91 }
92
93 private void loadTest(int testType)
94 {
95 TestContainer.Clear();
96 CurrentTest = testType;
97
98 switch (testType)
99 {
100 default:
101 {
102 Container box;
103 TestContainer.Add(box = new InfofulBoxAutoSize
104 {
105 Anchor = Anchor.Centre,
106 Origin = Anchor.Centre,
107 Masking = true,
108 CornerRadius = 100,
109 CornerExponent = TestCornerExponent,
110 BorderColour = Color4.Aquamarine,
111 BorderThickness = 3,
112 EdgeEffect = new EdgeEffectParameters
113 {
114 Type = EdgeEffectType.Shadow,
115 Radius = 100,
116 Colour = new Color4(0, 50, 100, 200),
117 },
118 });
119
120 box.Add(box = new InfofulBox
121 {
122 Size = new Vector2(250, 250),
123 Alpha = 0.5f,
124 Origin = Anchor.Centre,
125 Anchor = Anchor.Centre,
126 Colour = Color4.DarkSeaGreen,
127 });
128
129 box.OnUpdate += delegate { box.Rotation += 0.05f; };
130 break;
131 }
132
133 case 1:
134 {
135 Container box;
136 TestContainer.Add(new InfofulBoxAutoSize
137 {
138 Anchor = Anchor.Centre,
139 Origin = Anchor.Centre,
140 Children = new[]
141 {
142 box = new InfofulBox
143 {
144 Masking = true,
145 CornerRadius = 100,
146 CornerExponent = TestCornerExponent,
147 Size = new Vector2(400, 400),
148 Alpha = 0.5f,
149 Origin = Anchor.Centre,
150 Anchor = Anchor.Centre,
151 Colour = Color4.DarkSeaGreen,
152 }
153 }
154 });
155
156 box.OnUpdate += delegate
157 {
158 box.Rotation += 0.05f;
159 box.CornerRadius = 100 + 100 * MathF.Sin(box.Rotation * 0.01f);
160 };
161 break;
162 }
163
164 case 2:
165 {
166 Container box;
167 TestContainer.Add(new InfofulBoxAutoSize
168 {
169 Anchor = Anchor.Centre,
170 Origin = Anchor.Centre,
171 Children = new[]
172 {
173 box = new InfofulBox
174 {
175 Masking = true,
176 CornerRadius = 25,
177 CornerExponent = TestCornerExponent,
178 Shear = new Vector2(0.5f, 0),
179 Size = new Vector2(150, 150),
180 Scale = new Vector2(2.5f, 1.5f),
181 Alpha = 0.5f,
182 Origin = Anchor.Centre,
183 Anchor = Anchor.Centre,
184 Colour = Color4.DarkSeaGreen,
185 }
186 }
187 });
188
189 box.OnUpdate += delegate { box.Rotation += 0.05f; };
190 break;
191 }
192
193 case 3:
194 {
195 Color4 glowColour = Color4.Aquamarine;
196 glowColour.A = 0.5f;
197
198 Container box1;
199 Container box2;
200
201 TestContainer.Add(new InfofulBoxAutoSize
202 {
203 Anchor = Anchor.Centre,
204 Origin = Anchor.Centre,
205 EdgeEffect = new EdgeEffectParameters
206 {
207 Type = EdgeEffectType.Glow,
208 Radius = 100,
209 Roundness = 50,
210 Colour = glowColour,
211 },
212 BorderColour = Color4.Aquamarine,
213 BorderThickness = 3,
214 Children = new[]
215 {
216 box1 = new InfofulBoxAutoSize
217 {
218 Masking = true,
219 CornerRadius = 25,
220 CornerExponent = TestCornerExponent,
221 Shear = new Vector2(0.5f, 0),
222 Alpha = 0.5f,
223 Origin = Anchor.Centre,
224 Anchor = Anchor.Centre,
225 Colour = Color4.DarkSeaGreen,
226 Children = new[]
227 {
228 box2 = new InfofulBox
229 {
230 Masking = true,
231 CornerRadius = 25,
232 CornerExponent = TestCornerExponent,
233 Shear = new Vector2(0.25f, 0.25f),
234 Size = new Vector2(100, 200),
235 Alpha = 0.5f,
236 Origin = Anchor.Centre,
237 Anchor = Anchor.Centre,
238 Colour = Color4.Blue,
239 }
240 }
241 }
242 }
243 });
244
245 box1.OnUpdate += delegate { box1.Rotation += 0.07f; };
246 box2.OnUpdate += delegate { box2.Rotation -= 0.15f; };
247 break;
248 }
249
250 case 4:
251 {
252 static Drawable createMaskingBox(float scale, float testCornerExponent)
253 {
254 float size = 200 / scale;
255 return new Container
256 {
257 Masking = true,
258 CornerRadius = 25 / scale,
259 CornerExponent = testCornerExponent,
260 BorderThickness = 12.5f / scale,
261 BorderColour = Color4.Red,
262 Size = new Vector2(size),
263 Scale = new Vector2(scale),
264 Anchor = Anchor.Centre,
265 Origin = Anchor.Centre,
266 Children = new Drawable[]
267 {
268 new Box
269 {
270 RelativeSizeAxes = Axes.Both,
271 Colour = Color4.White,
272 Anchor = Anchor.Centre,
273 Origin = Anchor.Centre,
274 },
275 new SpriteText
276 {
277 Text = @"Size: " + size + ", Scale: " + scale,
278 Font = new FontUsage(size: 20 / scale),
279 Colour = Color4.Blue,
280 Anchor = Anchor.Centre,
281 Origin = Anchor.Centre,
282 },
283 }
284 };
285 }
286
287 TestContainer.Add(new FillFlowContainer
288 {
289 RelativeSizeAxes = Axes.Both,
290 Children = new[]
291 {
292 new Container
293 {
294 RelativeSizeAxes = Axes.Both,
295 Size = new Vector2(0.5f),
296 Masking = true,
297 Children = new[] { createMaskingBox(100, TestCornerExponent) }
298 },
299 new Container
300 {
301 RelativeSizeAxes = Axes.Both,
302 Size = new Vector2(0.5f),
303 Masking = true,
304 Children = new[] { createMaskingBox(10, TestCornerExponent) }
305 },
306 new Container
307 {
308 RelativeSizeAxes = Axes.Both,
309 Size = new Vector2(0.5f),
310 Masking = true,
311 Children = new[] { createMaskingBox(1, TestCornerExponent) }
312 },
313 new Container
314 {
315 RelativeSizeAxes = Axes.Both,
316 Size = new Vector2(0.5f),
317 Masking = true,
318 Children = new[] { createMaskingBox(0.1f, TestCornerExponent) }
319 },
320 }
321 });
322
323 break;
324 }
325
326 case 5:
327 {
328 TestContainer.Add(new Container
329 {
330 Masking = true,
331 Size = new Vector2(0.5f),
332 RelativeSizeAxes = Axes.Both,
333 Children = new[]
334 {
335 new Container
336 {
337 Masking = true,
338 CornerRadius = 100f,
339 CornerExponent = TestCornerExponent,
340 BorderThickness = 50f,
341 BorderColour = Color4.Red,
342 RelativeSizeAxes = Axes.Both,
343 Size = new Vector2(1.5f),
344 Anchor = Anchor.BottomRight,
345 Origin = Anchor.Centre,
346 Children = new Drawable[]
347 {
348 new Box
349 {
350 RelativeSizeAxes = Axes.Both,
351 Colour = Color4.White,
352 },
353 }
354 }
355 }
356 });
357 break;
358 }
359
360 case 6:
361 {
362 TestContainer.Add(new FillFlowContainer
363 {
364 Direction = FillDirection.Vertical,
365 AutoSizeAxes = Axes.Both,
366 Spacing = new Vector2(0, 10),
367 Children = new Drawable[]
368 {
369 new SpriteText
370 {
371 Text = $"None of the folowing {nameof(CircularContainer)}s should trigger until the white part is hovered"
372 },
373 new FillFlowContainer
374 {
375 Direction = FillDirection.Vertical,
376 AutoSizeAxes = Axes.Both,
377 Spacing = new Vector2(0, 2),
378 Children = new Drawable[]
379 {
380 new SpriteText
381 {
382 Text = "No masking"
383 },
384 new CircularContainerWithInput
385 {
386 Size = new Vector2(200),
387 Children = new Drawable[]
388 {
389 new Box
390 {
391 RelativeSizeAxes = Axes.Both,
392 Colour = Color4.Red
393 },
394 new CircularContainer
395 {
396 RelativeSizeAxes = Axes.Both,
397 Colour = Color4.White,
398 Masking = true,
399 Children = new[]
400 {
401 new Box
402 {
403 RelativeSizeAxes = Axes.Both
404 }
405 }
406 }
407 }
408 }
409 }
410 },
411 new FillFlowContainer
412 {
413 Direction = FillDirection.Vertical,
414 AutoSizeAxes = Axes.Both,
415 Spacing = new Vector2(0, 2),
416 Children = new Drawable[]
417 {
418 new SpriteText
419 {
420 Text = "With masking"
421 },
422 new CircularContainerWithInput
423 {
424 Size = new Vector2(200),
425 Masking = true,
426 Children = new Drawable[]
427 {
428 new Box
429 {
430 RelativeSizeAxes = Axes.Both,
431 Colour = Color4.Red
432 },
433 new CircularContainer
434 {
435 RelativeSizeAxes = Axes.Both,
436 Colour = Color4.White,
437 Masking = true,
438 Children = new[]
439 {
440 new Box
441 {
442 RelativeSizeAxes = Axes.Both
443 }
444 }
445 }
446 }
447 }
448 }
449 }
450 }
451 });
452 break;
453 }
454
455 case 7:
456 {
457 Container box;
458 TestContainer.Add(box = new InfofulBoxAutoSize
459 {
460 Anchor = Anchor.Centre,
461 Origin = Anchor.Centre,
462 Masking = true,
463 CornerRadius = 100,
464 CornerExponent = TestCornerExponent,
465 Alpha = 0.8f,
466 EdgeEffect = new EdgeEffectParameters
467 {
468 Type = EdgeEffectType.Shadow,
469 Offset = new Vector2(0, 50),
470 Hollow = true,
471 Radius = 50,
472 Roundness = 50,
473 Colour = new Color4(0, 255, 255, 255),
474 },
475 });
476
477 box.Add(box = new InfofulBox
478 {
479 Size = new Vector2(250, 250),
480 Origin = Anchor.Centre,
481 Anchor = Anchor.Centre,
482 Colour = Color4.DarkSeaGreen,
483 });
484
485 box.OnUpdate += delegate { box.Rotation += 0.05f; };
486 break;
487 }
488
489 case 8:
490 TestContainer.Add(new Container
491 {
492 Size = new Vector2(200, 200),
493 Anchor = Anchor.Centre,
494 Origin = Anchor.Centre,
495 Children = new Drawable[]
496 {
497 new Box
498 {
499 RelativeSizeAxes = Axes.Both,
500 Colour = Color4.Gray,
501 },
502 new InfofulBox
503 {
504 RelativeSizeAxes = Axes.Both,
505 Masking = true,
506 CornerRadius = 50,
507 CornerExponent = TestCornerExponent,
508 BorderColour = Color4.Red,
509 BorderThickness = 10,
510 EdgeEffect = new EdgeEffectParameters
511 {
512 Type = EdgeEffectType.Glow,
513 Radius = 100,
514 Roundness = 50,
515 Colour = Color4.Blue,
516 },
517 }
518 }
519 }.With(c => c.OnLoadComplete += _ =>
520 {
521 c.ResizeWidthTo(-200, 1000, Easing.InOutSine).Then()
522 .ResizeHeightTo(-200, 1000, Easing.InOutSine).Then()
523 .ResizeTo(new Vector2(200, 200), 1000).Loop();
524 }));
525 break;
526 }
527
528#if DEBUG
529 //if (toggleDebugAutosize.State)
530 // testContainer.Children.FindAll(c => c.HasAutosizeChildren).ForEach(c => c.AutoSizeDebug = true);
531#endif
532 }
533
534 private class CircularContainerWithInput : CircularContainer
535 {
536 protected override bool OnHover(HoverEvent e)
537 {
538 this.ScaleTo(1.2f, 100);
539 return true;
540 }
541
542 protected override void OnHoverLost(HoverLostEvent e)
543 {
544 this.ScaleTo(1f, 100);
545 }
546 }
547 }
548}