A game framework written with osu! in mind.
at master 16 kB view raw
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 System.Linq; 6using System.Reflection; 7using osu.Framework.Graphics; 8using osu.Framework.Graphics.Containers; 9using osu.Framework.Graphics.Shapes; 10using osu.Framework.Graphics.Sprites; 11using osu.Framework.Graphics.UserInterface; 12using osu.Framework.Localisation; 13using osu.Framework.Utils; 14using osu.Framework.Threading; 15using osuTK; 16using osuTK.Graphics; 17 18namespace osu.Framework.Tests.Visual.Layout 19{ 20 public class TestSceneFillFlowContainer : FrameworkTestScene 21 { 22 private FillDirectionDropdown selectionDropdown; 23 24 private Anchor childAnchor = Anchor.TopLeft; 25 private AnchorDropdown anchorDropdown; 26 27 private Anchor childOrigin = Anchor.TopLeft; 28 private AnchorDropdown originDropdown; 29 30 private FillFlowContainer fillContainer; 31 private ScheduledDelegate scheduledAdder; 32 private bool doNotAddChildren; 33 34 public TestSceneFillFlowContainer() 35 { 36 reset(); 37 } 38 39 private void reset() 40 { 41 doNotAddChildren = false; 42 scheduledAdder?.Cancel(); 43 44 Child = new Container 45 { 46 RelativeSizeAxes = Axes.Both, 47 Width = 0.2f, 48 Anchor = Anchor.TopRight, 49 Origin = Anchor.TopRight, 50 Depth = float.MinValue, 51 Children = new[] 52 { 53 new FillFlowContainer 54 { 55 Direction = FillDirection.Vertical, 56 RelativeSizeAxes = Axes.X, 57 AutoSizeAxes = Axes.Y, 58 Children = new Drawable[] 59 { 60 new SpriteText { Text = @"Fill mode" }, 61 selectionDropdown = new FillDirectionDropdown 62 { 63 RelativeSizeAxes = Axes.X, 64 Items = (FlowTestType[])Enum.GetValues(typeof(FlowTestType)), 65 }, 66 new SpriteText { Text = @"Child anchor" }, 67 anchorDropdown = new AnchorDropdown 68 { 69 RelativeSizeAxes = Axes.X, 70 Items = new[] 71 { 72 Anchor.TopLeft, 73 Anchor.TopCentre, 74 Anchor.TopRight, 75 Anchor.CentreLeft, 76 Anchor.Centre, 77 Anchor.CentreRight, 78 Anchor.BottomLeft, 79 Anchor.BottomCentre, 80 Anchor.BottomRight, 81 }, 82 }, 83 new SpriteText { Text = @"Child origin" }, 84 originDropdown = new AnchorDropdown 85 { 86 RelativeSizeAxes = Axes.X, 87 Items = new[] 88 { 89 Anchor.TopLeft, 90 Anchor.TopCentre, 91 Anchor.TopRight, 92 Anchor.CentreLeft, 93 Anchor.Centre, 94 Anchor.CentreRight, 95 Anchor.BottomLeft, 96 Anchor.BottomCentre, 97 Anchor.BottomRight, 98 }, 99 }, 100 } 101 } 102 } 103 }; 104 105 selectionDropdown.Current.ValueChanged += e => changeTest(e.NewValue); 106 buildTest(); 107 selectionDropdown.Current.Value = FlowTestType.Full; 108 changeTest(FlowTestType.Full); 109 } 110 111 protected override void Update() 112 { 113 base.Update(); 114 115 if (childAnchor != anchorDropdown.Current.Value) 116 { 117 childAnchor = anchorDropdown.Current.Value; 118 foreach (var child in fillContainer.Children) 119 child.Anchor = childAnchor; 120 } 121 122 if (childOrigin != originDropdown.Current.Value) 123 { 124 childOrigin = originDropdown.Current.Value; 125 foreach (var child in fillContainer.Children) 126 child.Origin = childOrigin; 127 } 128 } 129 130 private void changeTest(FlowTestType testType) 131 { 132 var method = 133 GetType().GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).SingleOrDefault(m => m.GetCustomAttribute<FlowTestCaseAttribute>()?.TestType == testType); 134 if (method != null) 135 method.Invoke(this, Array.Empty<object>()); 136 } 137 138 private void buildTest() 139 { 140 Add(new Container 141 { 142 Padding = new MarginPadding(25f), 143 RelativeSizeAxes = Axes.Both, 144 Children = new Drawable[] 145 { 146 fillContainer = new FillFlowContainer 147 { 148 RelativeSizeAxes = Axes.Both, 149 AutoSizeAxes = Axes.None, 150 }, 151 new Box 152 { 153 Anchor = Anchor.CentreLeft, 154 Origin = Anchor.Centre, 155 RelativeSizeAxes = Axes.Y, 156 Size = new Vector2(3, 1), 157 Colour = Color4.HotPink, 158 }, 159 new Box 160 { 161 Anchor = Anchor.CentreRight, 162 Origin = Anchor.Centre, 163 RelativeSizeAxes = Axes.Y, 164 Size = new Vector2(3, 1), 165 Colour = Color4.HotPink, 166 }, 167 new Box 168 { 169 Anchor = Anchor.TopCentre, 170 Origin = Anchor.Centre, 171 RelativeSizeAxes = Axes.X, 172 Size = new Vector2(1, 3), 173 Colour = Color4.HotPink, 174 }, 175 new Box 176 { 177 Anchor = Anchor.BottomCentre, 178 Origin = Anchor.Centre, 179 RelativeSizeAxes = Axes.X, 180 Size = new Vector2(1, 3), 181 Colour = Color4.HotPink, 182 } 183 } 184 }); 185 186 AddToggleStep("Rotate Container", state => { fillContainer.RotateTo(state ? 45f : 0, 1000); }); 187 AddToggleStep("Scale Container", state => { fillContainer.ScaleTo(state ? 1.2f : 1f, 1000); }); 188 AddToggleStep("Shear Container", state => { fillContainer.Shear = state ? new Vector2(0.5f, 0f) : new Vector2(0f, 0f); }); 189 AddToggleStep("Center Container Anchor", state => { fillContainer.Anchor = state ? Anchor.Centre : Anchor.TopLeft; }); 190 AddToggleStep("Center Container Origin", state => { fillContainer.Origin = state ? Anchor.Centre : Anchor.TopLeft; }); 191 AddToggleStep("Autosize Container", state => 192 { 193 if (state) 194 { 195 fillContainer.RelativeSizeAxes = Axes.None; 196 fillContainer.AutoSizeAxes = Axes.Both; 197 } 198 else 199 { 200 fillContainer.AutoSizeAxes = Axes.None; 201 fillContainer.RelativeSizeAxes = Axes.Both; 202 fillContainer.Width = 1; 203 fillContainer.Height = 1; 204 } 205 }); 206 AddToggleStep("Rotate children", state => 207 { 208 if (state) 209 { 210 foreach (var child in fillContainer.Children) 211 child.RotateTo(45f, 1000); 212 } 213 else 214 { 215 foreach (var child in fillContainer.Children) 216 child.RotateTo(0f, 1000); 217 } 218 }); 219 AddToggleStep("Shear children", state => 220 { 221 if (state) 222 { 223 foreach (var child in fillContainer.Children) 224 child.Shear = new Vector2(0.2f, 0.2f); 225 } 226 else 227 { 228 foreach (var child in fillContainer.Children) 229 child.Shear = Vector2.Zero; 230 } 231 }); 232 AddToggleStep("Scale children", state => 233 { 234 if (state) 235 { 236 foreach (var child in fillContainer.Children) 237 child.ScaleTo(1.25f, 1000); 238 } 239 else 240 { 241 foreach (var child in fillContainer.Children) 242 child.ScaleTo(1f, 1000); 243 } 244 }); 245 AddToggleStep("Randomly scale children", state => 246 { 247 if (state) 248 { 249 foreach (var child in fillContainer.Children) 250 child.ScaleTo(RNG.NextSingle(1, 2), 1000); 251 } 252 else 253 { 254 foreach (var child in fillContainer.Children) 255 child.ScaleTo(1f, 1000); 256 } 257 }); 258 AddToggleStep("Randomly set child origins", state => 259 { 260 if (state) 261 { 262 foreach (var child in fillContainer.Children) 263 { 264 switch (RNG.Next(9)) 265 { 266 case 0: 267 child.Origin = Anchor.TopLeft; 268 break; 269 270 case 1: 271 child.Origin = Anchor.TopCentre; 272 break; 273 274 case 2: 275 child.Origin = Anchor.TopRight; 276 break; 277 278 case 3: 279 child.Origin = Anchor.CentreLeft; 280 break; 281 282 case 4: 283 child.Origin = Anchor.Centre; 284 break; 285 286 case 5: 287 child.Origin = Anchor.CentreRight; 288 break; 289 290 case 6: 291 child.Origin = Anchor.BottomLeft; 292 break; 293 294 case 7: 295 child.Origin = Anchor.BottomCentre; 296 break; 297 298 case 8: 299 child.Origin = Anchor.BottomRight; 300 break; 301 } 302 } 303 } 304 else 305 { 306 foreach (var child in fillContainer.Children) 307 child.Origin = originDropdown.Current.Value; 308 } 309 }); 310 311 AddToggleStep("Stop adding children", state => { doNotAddChildren = state; }); 312 313 scheduledAdder?.Cancel(); 314 scheduledAdder = Scheduler.AddDelayed( 315 () => 316 { 317 if (fillContainer.Parent == null) 318 scheduledAdder.Cancel(); 319 320 if (doNotAddChildren) 321 { 322 fillContainer.Invalidate(); 323 } 324 325 if (fillContainer.Children.Count < 1000 && !doNotAddChildren) 326 { 327 fillContainer.Add(new Container 328 { 329 Anchor = childAnchor, 330 Origin = childOrigin, 331 AutoSizeAxes = Axes.Both, 332 Children = new Drawable[] 333 { 334 new Box 335 { 336 Width = 50, 337 Height = 50, 338 Colour = Color4.White 339 }, 340 new SpriteText 341 { 342 Colour = Color4.Black, 343 RelativePositionAxes = Axes.Both, 344 Position = new Vector2(0.5f, 0.5f), 345 Origin = Anchor.Centre, 346 Text = fillContainer.Children.Count.ToString() 347 } 348 } 349 }); 350 } 351 }, 352 100, 353 true 354 ); 355 } 356 357 [FlowTestCase(FlowTestType.Full)] 358 private void test1() 359 { 360 fillContainer.Direction = FillDirection.Full; 361 fillContainer.Spacing = new Vector2(5, 5); 362 } 363 364 [FlowTestCase(FlowTestType.Horizontal)] 365 private void test2() 366 { 367 fillContainer.Direction = FillDirection.Horizontal; 368 fillContainer.Spacing = new Vector2(5, 5); 369 } 370 371 [FlowTestCase(FlowTestType.Vertical)] 372 private void test3() 373 { 374 fillContainer.Direction = FillDirection.Vertical; 375 fillContainer.Spacing = new Vector2(5, 5); 376 } 377 378 private class TestSceneDropdownHeader : DropdownHeader 379 { 380 private readonly SpriteText label; 381 382 protected internal override LocalisableString Label 383 { 384 get => label.Text; 385 set => label.Text = value; 386 } 387 388 public TestSceneDropdownHeader() 389 { 390 Foreground.Padding = new MarginPadding(4); 391 BackgroundColour = new Color4(100, 100, 100, 255); 392 BackgroundColourHover = Color4.HotPink; 393 Children = new[] 394 { 395 label = new SpriteText(), 396 }; 397 } 398 } 399 400 private class AnchorDropdown : BasicDropdown<Anchor> 401 { 402 protected override DropdownHeader CreateHeader() => new TestSceneDropdownHeader(); 403 } 404 405 private class FillDirectionDropdown : BasicDropdown<FlowTestType> 406 { 407 protected override DropdownHeader CreateHeader() => new TestSceneDropdownHeader(); 408 } 409 410 [AttributeUsage(AttributeTargets.Method)] 411 private class FlowTestCaseAttribute : Attribute 412 { 413 public FlowTestType TestType { get; } 414 415 public FlowTestCaseAttribute(FlowTestType testType) 416 { 417 TestType = testType; 418 } 419 } 420 421 private enum FlowTestType 422 { 423 Full, 424 Horizontal, 425 Vertical, 426 } 427 } 428}