OLD | NEW |
(Empty) | |
| 1 #!mojo mojo:sky |
| 2 <import src="sky:core" as="sky"/> |
| 3 <script> |
| 4 class BeehiveLayoutManager extends sky.LayoutManager { |
| 5 function layout(width, height) { |
| 6 if (width == null) |
| 7 width = this.getIntrinsicWidth().value; |
| 8 let autoHeight = false; |
| 9 if (height == null) { |
| 10 height = 0; |
| 11 autoHeight = true; |
| 12 } |
| 13 this.assumeDimensions(width, height); |
| 14 let cellCount = this.node.getProperty('beehive-count'); |
| 15 let cellDim = width / cellCount; |
| 16 let children = this.walkChildren(); |
| 17 let loop = children.next(); |
| 18 let x = 0; |
| 19 let y = 0; |
| 20 while (!loop.done) { |
| 21 let child = loop.value; |
| 22 if (child.needsLayout) { |
| 23 child.layoutManager.layout(cellDim, cellDim); |
| 24 // we ignore the size the child reported from layout(), and force it to
the cell dimensions |
| 25 this.setChildSize(child, cellDim, cellDim); |
| 26 } |
| 27 this.setChildPosition(child, x * cellDim + (y % 2) * cellDim/2, y * 3/4 *
cellDim); |
| 28 x += 1; |
| 29 if (x > cellCount) { |
| 30 y += 1; |
| 31 x = 0; |
| 32 } |
| 33 loop = children.next(); |
| 34 } |
| 35 if (height == 0) |
| 36 height = (1 + y * 3/4) * cellDim; |
| 37 return { |
| 38 width: width, |
| 39 height: height, |
| 40 } |
| 41 } |
| 42 function getIntrinsicWidth() { |
| 43 // this is the logic that LayoutManager.getIntrinsicWidth() has by default |
| 44 // shown here because I wrote it before realising it should be the default |
| 45 let width = this.node.getProperty('width'); |
| 46 if (typeof width != 'number') |
| 47 width = 0; |
| 48 let minWidth = this.node.getProperty('min-width'); |
| 49 if (typeof width != 'number') |
| 50 minWidth = 0; |
| 51 let maxWidth = this.node.getProperty('max-width'); |
| 52 if (typeof width != 'number') |
| 53 maxWidth = Infinity; |
| 54 if (maxWidth < minWidth) |
| 55 maxWidth = minWidth; |
| 56 if (width > maxWidth) |
| 57 width = maxWidth; |
| 58 if (width < minWidth) |
| 59 width = minWidth; |
| 60 return { |
| 61 minimum: minWidth, |
| 62 value: width, |
| 63 maximum: maxWidth, |
| 64 }; |
| 65 } |
| 66 function getIntrinsicHeight() { |
| 67 let height = this.node.getProperty('height'); |
| 68 if (typeof height != 'number') { |
| 69 // e.g. height: auto |
| 70 width = this.getIntrinsicWidth().value; |
| 71 let cellCount = this.node.getProperty('beehive-count'); |
| 72 let cellDim = width / cellCount; |
| 73 let children = this.walkChildren(); |
| 74 let loop = children.next(); |
| 75 let childCount = 0; |
| 76 while (!loop.done) { |
| 77 childCount += 1; |
| 78 loop.next(); |
| 79 } |
| 80 if (childCount > 0) |
| 81 height = cellDim * (1/4 + Math.ceil(childCount / cellCount) * 3/4); |
| 82 else |
| 83 height = 0; |
| 84 } |
| 85 return super(height); // does the equivalent of getIntrinsicWidth() above,
applying min-height etc |
| 86 } |
| 87 function paintChildren(RenderingSurface canvas) { |
| 88 let width = this.node.width; |
| 89 let cellCount = this.node.getProperty('beehive-count'); |
| 90 let cellDim = width / cellCount; |
| 91 let children = this.walkChildren(); |
| 92 let loop = children.next(); |
| 93 while (!loop.done) { |
| 94 let child = loop.value; |
| 95 if (child.needsPaint) { |
| 96 canvas.save(); |
| 97 try { |
| 98 canvas.beginPath(); |
| 99 canvas.moveTo(child.x, child.y + cellDim/4); |
| 100 canvas.lineTo(child.x + cellDim/2, child.y); |
| 101 canvas.lineTo(child.x + cellDim, child.y + cellDim/4); |
| 102 canvas.lineTo(child.x + cellDim, child.y + 3*cellDim/4); |
| 103 canvas.lineTo(child.x + cellDim/2, child.y + cellDim); |
| 104 canvas.moveTo(child.x, child.y + 3*cellDim/4); |
| 105 canvas.closePath(); |
| 106 canvas.clip(); |
| 107 child.paint(canvas); |
| 108 } finally { |
| 109 canvas.restore(); |
| 110 } |
| 111 } |
| 112 loop = children.next(); |
| 113 } |
| 114 } |
| 115 } |
| 116 sky.registerLayoutManager('beehive', BeehiveLayoutManager); |
| 117 let BeehiveCountStyleValueType = new StyleValueType(); |
| 118 BeehiveCountStyleValueType.addParser((tokens) => { |
| 119 let token = tokens.next(); |
| 120 if (token.done) throw new Error(); |
| 121 if (token.value.kind != 'number') throw new Error(); |
| 122 if (token.value.value <= 0) throw new Error(); |
| 123 if (Math.trunc(token.value.value) != token.value.value) throw new Error(); |
| 124 let result = token.value.value; |
| 125 if (!token.next().done) throw new Error(); |
| 126 return result; |
| 127 }); |
| 128 sky.registerProperty({ |
| 129 name: 'beehive-count', |
| 130 type: BeehiveCountStyleValueType, |
| 131 inherits: true, |
| 132 initialValue: 5, |
| 133 needsLayout: true, |
| 134 }); |
| 135 </script> |
| 136 <style> |
| 137 div { display: beehive; beehive-count: 3; } |
| 138 </style> |
| 139 <div> |
| 140 <t>Hello</t> |
| 141 <t>World</t> |
| 142 <t>How</t> |
| 143 <t>Are</t> |
| 144 <t>You</t> |
| 145 <t>Today?</t> |
| 146 </div> |
OLD | NEW |