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 NUnit.Framework;
5using osu.Framework.Graphics;
6using osu.Framework.Graphics.Containers;
7using osu.Framework.Graphics.Shapes;
8using osu.Framework.Layout;
9using osu.Framework.Testing;
10using osu.Framework.Tests.Visual;
11using osu.Framework.Utils;
12using osuTK;
13using osuTK.Graphics;
14
15namespace osu.Framework.Tests.Layout
16{
17 [HeadlessTest]
18 public class TestSceneDrawableLayout : FrameworkTestScene
19 {
20 /// <summary>
21 /// Tests that multiple invalidations trigger for properties that don't overlap in their invalidation types (size + scale).
22 /// </summary>
23 [Test]
24 public void TestChangeNonOverlappingProperties()
25 {
26 Box[] boxes = new Box[4];
27 TestContainer1 testContainer = null;
28
29 AddStep("create test", () =>
30 {
31 Child = testContainer = new TestContainer1
32 {
33 RelativeSizeAxes = Axes.Both,
34 Child = new FillFlowContainer
35 {
36 RelativeSizeAxes = Axes.Both,
37 Height = 0.25f,
38 Children = new[]
39 {
40 boxes[0] = new Box
41 {
42 RelativeSizeAxes = Axes.Both,
43 Colour = Color4.Beige,
44 Width = 0.2f,
45 },
46 boxes[1] = new Box
47 {
48 RelativeSizeAxes = Axes.Both,
49 Colour = Color4.Bisque,
50 Width = 0.2f,
51 },
52 boxes[2] = new Box
53 {
54 RelativeSizeAxes = Axes.Both,
55 Colour = Color4.Aquamarine,
56 Width = 0.2f,
57 },
58 boxes[3] = new Box
59 {
60 RelativeSizeAxes = Axes.Both,
61 Colour = Color4.Cornsilk,
62 Width = 0.2f,
63 },
64 }
65 }
66 };
67 });
68
69 AddWaitStep("wait for flow", 2);
70 AddStep("change scale", () => testContainer.AdjustScale(0.5f));
71
72 AddAssert("boxes flowed correctly", () =>
73 {
74 float expectedX = 0;
75
76 foreach (var child in boxes)
77 {
78 if (!Precision.AlmostEquals(expectedX, child.DrawPosition.X))
79 return false;
80
81 expectedX += child.DrawWidth;
82 }
83
84 return true;
85 });
86 }
87
88 [Test]
89 public void TestChangePositionInvalidatesMiscGeometryOnSelf()
90 {
91 TestBox1 box = null;
92
93 AddStep("create test", () =>
94 {
95 Child = box = new TestBox1
96 {
97 Anchor = Anchor.Centre,
98 Origin = Anchor.Centre
99 };
100 });
101
102 AddUntilStep("wait for validation", () => box.MiscGeometryLayoutValue.IsValid);
103
104 AddAssert("change position and ensure MiscGeometry invalidated on self", () =>
105 {
106 box.Position = new Vector2(50);
107 return !box.MiscGeometryLayoutValue.IsValid;
108 });
109 }
110
111 [Test]
112 public void TestChangeSizeInvalidatesDrawSizeOnSelf()
113 {
114 TestBox1 box = null;
115
116 AddStep("create test", () =>
117 {
118 Child = box = new TestBox1
119 {
120 Anchor = Anchor.Centre,
121 Origin = Anchor.Centre,
122 Size = new Vector2(50)
123 };
124 });
125
126 AddUntilStep("wait for validation", () => box.DrawSizeLayoutValue.IsValid);
127
128 AddAssert("change size and ensure DrawSize invalidated on self", () =>
129 {
130 box.Size = new Vector2(100);
131 return !box.DrawSizeLayoutValue.IsValid;
132 });
133 }
134
135 private class TestContainer1 : Container<Drawable>
136 {
137 public void AdjustScale(float scale = 1.0f)
138 {
139 this.ScaleTo(new Vector2(scale));
140 this.ResizeTo(new Vector2(1 / scale));
141 }
142 }
143
144 private class TestBox1 : Box
145 {
146 public readonly LayoutValue MiscGeometryLayoutValue = new LayoutValue(Invalidation.MiscGeometry, InvalidationSource.Self);
147 public readonly LayoutValue DrawSizeLayoutValue = new LayoutValue(Invalidation.DrawSize, InvalidationSource.Self);
148
149 public TestBox1()
150 {
151 AddLayout(MiscGeometryLayoutValue);
152 AddLayout(DrawSizeLayoutValue);
153 }
154
155 protected override void Update()
156 {
157 base.Update();
158
159 MiscGeometryLayoutValue.Validate();
160 DrawSizeLayoutValue.Validate();
161 }
162 }
163 }
164}