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 osuTK;
6
7namespace osu.Framework.Graphics.Containers
8{
9 /// <summary>
10 /// A <see cref="Container"/> filling its parent while preserving a given target
11 /// <see cref="Drawable.DrawSize"/> according to a <see cref="DrawSizePreservationStrategy"/>.
12 /// This is useful, for example, to automatically scale the user interface according to
13 /// the window resolution, or to provide automatic HiDPI display support.
14 /// </summary>
15 public class DrawSizePreservingFillContainer : Container
16 {
17 private readonly Container content;
18
19 protected override Container<Drawable> Content => content;
20
21 /// <summary>
22 /// The target <see cref="Drawable.DrawSize"/> to be enforced according to <see cref="Strategy"/>.
23 /// </summary>
24 public Vector2 TargetDrawSize = new Vector2(1024, 768);
25
26 /// <summary>
27 /// The strategy to be used for enforcing <see cref="TargetDrawSize"/>. The default strategy
28 /// is Minimum, which preserves the aspect ratio of all children while ensuring one of the
29 /// two axes matches <see cref="TargetDrawSize"/> while the other is always larger.
30 /// </summary>
31 public DrawSizePreservationStrategy Strategy;
32
33 public DrawSizePreservingFillContainer()
34 {
35 AddInternal(content = new Container
36 {
37 RelativeSizeAxes = Axes.Both,
38 });
39
40 RelativeSizeAxes = Axes.Both;
41 }
42
43 protected override void Update()
44 {
45 base.Update();
46
47 Vector2 drawSizeRatio = Vector2.Divide(Parent.ChildSize, TargetDrawSize);
48
49 switch (Strategy)
50 {
51 case DrawSizePreservationStrategy.Minimum:
52 content.Scale = new Vector2(Math.Min(drawSizeRatio.X, drawSizeRatio.Y));
53 break;
54
55 case DrawSizePreservationStrategy.Maximum:
56 content.Scale = new Vector2(Math.Max(drawSizeRatio.X, drawSizeRatio.Y));
57 break;
58
59 case DrawSizePreservationStrategy.Average:
60 content.Scale = new Vector2(0.5f * (drawSizeRatio.X + drawSizeRatio.Y));
61 break;
62
63 case DrawSizePreservationStrategy.Separate:
64 content.Scale = drawSizeRatio;
65 break;
66 }
67
68 content.Size = Vector2.Divide(Vector2.One, content.Scale);
69 }
70 }
71
72 /// <summary>
73 /// Strategies used by <see cref="DrawSizePreservingFillContainer"/> to enforce its
74 /// <see cref="DrawSizePreservingFillContainer.TargetDrawSize"/>.
75 /// </summary>
76 public enum DrawSizePreservationStrategy
77 {
78 /// <summary>
79 /// Preserves the aspect ratio of all children while ensuring one of the
80 /// two axes matches <see cref="DrawSizePreservingFillContainer.TargetDrawSize"/>
81 /// while the other is always larger.
82 /// </summary>
83 Minimum,
84
85 /// <summary>
86 /// Preserves the aspect ratio of all children while ensuring one of the
87 /// two axes matches <see cref="DrawSizePreservingFillContainer.TargetDrawSize"/>
88 /// while the other is always smaller.
89 /// </summary>
90 Maximum,
91
92 /// <summary>
93 /// Preserves the aspect ratio of all children while one axis is always larger and
94 /// the other always smaller than <see cref="DrawSizePreservingFillContainer.TargetDrawSize"/>,
95 /// achieving a good compromise.
96 /// </summary>
97 Average,
98
99 /// <summary>
100 /// Ensures <see cref="DrawSizePreservingFillContainer.TargetDrawSize"/> is perfectly
101 /// matched while aspect ratio of children is disregarded.
102 /// </summary>
103 Separate,
104 }
105}