1 module fluid.size_lock;
2 
3 import std.algorithm;
4 
5 import fluid.node;
6 import fluid.utils;
7 import fluid.style;
8 import fluid.backend;
9 
10 
11 @safe:
12 
13 
14 SizeLimit sizeLimit(size_t x, size_t y) {
15 
16     return SizeLimit(x, y);
17 
18 }
19 
20 SizeLimit sizeLimitX(size_t x) {
21 
22     return SizeLimit(x, 0);
23 
24 }
25 
26 SizeLimit sizeLimitY(size_t y) {
27 
28     return SizeLimit(0, y);
29 
30 }
31 
32 struct SizeLimit {
33 
34     size_t x;
35     size_t y;
36 
37     void apply(T)(SizeLock!T node) {
38 
39         node.limit = this;
40 
41     }
42 
43 }
44 
45 /// `sizeLock` "locks" a node, restricting space avilable to it, and making it fill the space, if possible.
46 ///
47 /// Size-locks are extremely useful for responsible applications, making sure the content doesn't span too much space on
48 /// large screens, for example on wide-screen, where the content can be applied a sizeLimitX, so it never spreads to
49 /// more than the set value.
50 alias sizeLock(alias T) = simpleConstructor!(SizeLock, T);
51 
52 /// ditto
53 class SizeLock(T : Node) : T {
54 
55     /// The maximum size of this node.
56     /// If a value on either axis is `0`, limit will not be applied on the axis.
57     SizeLimit limit;
58 
59     this(T...)(T args) {
60 
61         super(args);
62         this.limit = limit;
63 
64     }
65 
66     override void resizeImpl(Vector2 space) {
67 
68         // Virtually limit the available space
69         if (limit.x != 0) space.x = min(space.x, limit.x);
70         if (limit.y != 0) space.y = min(space.y, limit.y);
71 
72         // Resize the child
73         super.resizeImpl(space);
74 
75         // Apply the limit to the resulting value; fill in remaining space if available
76         if (limit.x != 0) minSize.x = max(space.x, min(limit.x, minSize.x));
77         if (limit.y != 0) minSize.y = max(space.y, min(limit.y, minSize.y));
78 
79     }
80 
81 }
82 
83 ///
84 unittest {
85 
86     import fluid;
87 
88     // The frame will appear horizontally-centered in the parent node, while filling it vertically
89     sizeLock!vframe(
90         layout!(1, "center", "fill"),
91         sizeLimitX(400),
92 
93         label("Hello, World!")
94     );
95 
96 }
97 
98 unittest {
99 
100     import fluid.space;
101     import fluid.label;
102     import fluid.frame;
103     import fluid.structs;
104 
105     auto io = new HeadlessBackend;
106     auto root = sizeLock!vframe(
107         layout!("center", "fill"),
108         sizeLimitX(400),
109         label("Hello, World!"),
110     );
111 
112     root.io = io;
113 
114     with (Rule)
115     root.theme = nullTheme.derive(
116         rule!Frame(backgroundColor = color!"1c1c1c"),
117         rule!Label(textColor = color!"eee"),
118     );
119 
120     {
121         root.draw();
122 
123         // The rectangle should display neatly in the middle of the display, limited to 400px
124         io.assertRectangle(Rectangle(200, 0, 400, 600), color!"1c1c1c");
125     }
126 
127     {
128         io.nextFrame;
129         root.layout = layout!("start", "fill");
130         root.updateSize();
131         root.draw();
132 
133         io.assertRectangle(Rectangle(0, 0, 400, 600), color!"1c1c1c");
134     }
135 
136     {
137         io.nextFrame;
138         root.layout = layout!"center";
139         root.limit = sizeLimit(200, 200);
140         root.updateSize();
141         root.draw();
142 
143         io.assertRectangle(Rectangle(300, 200, 200, 200), color!"1c1c1c");
144     }
145 
146 }