1 /// 2 module fluid.switch_slot; 3 4 import fluid.node; 5 import fluid.utils; 6 import fluid.style; 7 import fluid.backend; 8 9 10 @safe: 11 12 13 /// A switch slot will try each of its children and pick the first one that fits the available space. If the a node 14 /// is too large to fit, it will try the next one in the list until it finds one that matches, or the last node in the 15 /// list. 16 /// 17 /// `null` is an acceptable value, indicating that no node should be drawn. 18 alias switchSlot = simpleConstructor!SwitchSlot; 19 20 /// ditto 21 class SwitchSlot : Node { 22 23 public { 24 25 Node[] availableNodes; 26 Node node; 27 28 /// If present, this node will only be drawn in case its principal node is hidden. In case the principal node is 29 /// another `SwitchSlot`, this might be because it failed to match any non-null node. 30 Node principalNode; 31 32 } 33 34 protected { 35 36 /// Last available space assigned to this node. 37 Vector2 _availableSpace; 38 39 } 40 41 @property { 42 43 alias isHidden = typeof(super).isHidden; 44 45 override bool isHidden() const return { 46 47 // Tree is available and resized 48 if (tree && !tree.resizePending) { 49 50 // Principal node is visible, hide self 51 if (principalNode && !principalNode.isHidden) 52 return true; 53 54 // Hide if no node was chosen 55 return super.isHidden || node is null; 56 57 } 58 59 return super.isHidden; 60 61 } 62 63 } 64 65 this(Node[] nodes...) { 66 67 this.availableNodes ~= nodes; 68 69 } 70 71 /// Create a new slot that will only draw if this slot is hidden or ends up with a `null` node. 72 SwitchSlot retry(Args...)(Args args) { 73 74 auto slot = switchSlot(args); 75 slot.principalNode = this; 76 return slot; 77 78 } 79 80 override void resizeImpl(Vector2 availableSpace) { 81 82 minSize = Vector2(); 83 this.node = null; 84 _availableSpace = availableSpace; 85 86 // Try each option 87 foreach (i, node; availableNodes) { 88 89 this.node = node; 90 91 // Null node reached, stop with no minSize 92 if (node is null) return; 93 94 auto previousTree = node.tree; 95 auto previousTheme = node.theme; 96 auto previousSize = node.minSize; 97 98 resizeChild(node, availableSpace); 99 100 // Stop if it fits within available space 101 if (node.minSize.x <= availableSpace.x && node.minSize.y <= availableSpace.y) break; 102 103 // Restore previous info, unless this is the last node 104 if (i+1 != availableNodes.length && previousTree) { 105 106 // Resize the node again to recursively restore old parameters 107 node.tree = null; 108 node.inheritTheme(Theme.init); 109 resizeChild(node, previousSize); 110 111 } 112 113 } 114 115 // Copy minSize 116 minSize = node.minSize; 117 118 } 119 120 override void drawImpl(Rectangle outer, Rectangle inner) { 121 122 // No node to draw, stop 123 if (node is null) return; 124 125 // Draw the node 126 drawChild(node, inner); 127 128 } 129 130 override bool hoveredImpl(Rectangle, Vector2) const { 131 132 return false; 133 134 } 135 136 }