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 }