1 module nodes.node_chain; 2 3 import fluid; 4 5 @safe: 6 7 alias chainLink = nodeBuilder!ChainLink; 8 9 class ChainLink : NodeChain { 10 11 DebugSignalIO debugSignalIO; 12 13 int drawChildCalls; 14 int beforeResizeCalls; 15 int afterResizeCalls; 16 int beforeDrawCalls; 17 int afterDrawCalls; 18 19 this(Node next = null) { 20 super(next); 21 } 22 23 override void drawChild(Node child, Rectangle space) { 24 drawChildCalls++; 25 super.drawChild(child, space); 26 } 27 28 override void beforeResize(Vector2) { 29 require(debugSignalIO); 30 debugSignalIO.emitSignal("beforeResize"); 31 beforeResizeCalls++; 32 assert(beforeResizeCalls == afterResizeCalls + 1); 33 } 34 35 override void afterResize(Vector2) { 36 debugSignalIO.emitSignal("afterResize"); 37 afterResizeCalls++; 38 assert(beforeResizeCalls == afterResizeCalls); 39 } 40 41 override void beforeDraw(Rectangle, Rectangle) { 42 debugSignalIO.emitSignal("beforeDraw"); 43 beforeDrawCalls++; 44 assert(beforeDrawCalls == afterDrawCalls + 1); 45 } 46 47 override void afterDraw(Rectangle, Rectangle) { 48 debugSignalIO.emitSignal("afterDraw"); 49 afterDrawCalls++; 50 assert(beforeDrawCalls == afterDrawCalls); 51 } 52 53 } 54 55 @("NodeChain can be empty") 56 unittest { 57 58 auto link = chainLink(); 59 auto root = testSpace(link); 60 root.drawAndAssert( 61 link.emits("beforeResize"), 62 link.emits("afterResize"), 63 link.emits("beforeDraw"), 64 link.emits("afterDraw"), 65 link.doesNotDraw, 66 ); 67 assert(link.afterResizeCalls == 1); 68 assert(link.afterDrawCalls == 1); 69 70 } 71 72 @("Node chain can contain other nodes") 73 unittest { 74 75 auto content = label("Child"); 76 auto link = chainLink(content); 77 auto root = testSpace(link); 78 root.drawAndAssert( 79 link.drawsChild(content), 80 content.drawsImage(), 81 ); 82 assert(link.afterResizeCalls == 1); 83 assert(link.afterDrawCalls == 1); 84 85 } 86 87 @("Chain nodes can be linked") 88 unittest { 89 90 Label content; 91 ChainLink link1, link2, link3; 92 93 auto link = chainLink(.layout!0, 94 link1 = chainLink(.layout!1, 95 link2 = chainLink(.layout!2, 96 link3 = chainLink(.layout!3, 97 content = label("hi"), 98 ), 99 ), 100 ), 101 ); 102 auto root = testSpace(link); 103 104 // Root link draws all the links, but it is not exposed through tree actions 105 root.drawAndAssert( 106 107 // Resize 108 link1.emits("beforeResize"), 109 link2.emits("beforeResize"), 110 link3.emits("beforeResize"), 111 link3.emits("afterResize"), 112 link2.emits("afterResize"), 113 link1.emits("afterResize"), 114 115 // Draw 116 link.emits("beforeDraw"), 117 link.drawsChild(link1), 118 link1.emits("beforeDraw"), 119 link1.drawsChild(link2), 120 link2.emits("beforeDraw"), 121 link2.drawsChild(link3), 122 link3.emits("beforeDraw"), 123 link3.drawsChild(content), 124 link3.emits("afterDraw"), 125 link2.emits("afterDraw"), 126 link1.emits("afterDraw"), 127 ); 128 assert(link3.afterResizeCalls == 1); 129 assert(link.afterDrawCalls == 1); 130 assert(link1.afterDrawCalls == 1); 131 assert(link2.afterDrawCalls == 1); 132 assert(link3.afterDrawCalls == 1); 133 assert(link.drawChildCalls == 1); 134 assert(link1.drawChildCalls == 0); 135 assert(link2.drawChildCalls == 0); 136 assert(link3.drawChildCalls == 0); 137 138 } 139 140 @("chain() can be used as a prettier alternative to the constructor") 141 unittest { 142 143 Label content; 144 ChainLink link1, link2, link3; 145 146 NodeChain link = chain( 147 link1 = chainLink(), 148 link2 = chainLink(), 149 link3 = chainLink(), 150 content = label("hi"), 151 ); 152 auto root = testSpace(link); 153 154 assert(link.opEquals(link1)); 155 156 root.drawAndAssert( 157 link1.drawsChild(link2), 158 link2.drawsChild(link3), 159 link3.drawsChild(content), 160 ); 161 162 } 163 164 @("chain() returns a node if not given a chain") 165 unittest { 166 167 Node node = chain( 168 label("Foo") 169 ); 170 assert(node); 171 172 }