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