| 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 } else if (child.descendantNeedsLayout) { | |
| 27 child.layoutManager.layoutDescendants(); | |
| 28 this.setChildSize(child, cellDim, cellDim); | |
| 29 } | |
| 30 this.setChildPosition(child, x * cellDim + (y % 2) * cellDim/2, y * 3/4 *
cellDim); | |
| 31 x += 1; | |
| 32 if (x > cellCount) { | |
| 33 y += 1; | |
| 34 x = 0; | |
| 35 } | |
| 36 loop = children.next(); | |
| 37 } | |
| 38 if (height == 0) | |
| 39 height = (1 + y * 3/4) * cellDim; | |
| 40 this.markAsLaidOut(); | |
| 41 return { | |
| 42 width: width, | |
| 43 height: height, | |
| 44 } | |
| 45 } | |
| 46 function getIntrinsicHeight() { | |
| 47 let height = this.node.getProperty('height'); | |
| 48 if (typeof height != 'number') { | |
| 49 // e.g. height: auto | |
| 50 width = this.getIntrinsicWidth().value; | |
| 51 let cellCount = this.node.getProperty('beehive-count'); | |
| 52 let cellDim = width / cellCount; | |
| 53 let children = this.walkChildren(); | |
| 54 let loop = children.next(); | |
| 55 let childCount = 0; | |
| 56 while (!loop.done) { | |
| 57 childCount += 1; | |
| 58 loop.next(); | |
| 59 } | |
| 60 if (childCount > 0) | |
| 61 height = cellDim * (1/4 + Math.ceil(childCount / cellCount) * 3/4); | |
| 62 else | |
| 63 height = 0; | |
| 64 } | |
| 65 return super(height); // does the equivalent of getIntrinsicWidth() above,
applying min-height etc | |
| 66 } | |
| 67 function paintChildren(canvas) { | |
| 68 let width = this.node.width; | |
| 69 let cellCount = this.node.getProperty('beehive-count'); | |
| 70 let cellDim = width / cellCount; | |
| 71 let children = this.walkChildren(); | |
| 72 let loop = children.next(); | |
| 73 while (!loop.done) { | |
| 74 let child = loop.value; | |
| 75 canvas.save(); | |
| 76 try { | |
| 77 canvas.beginPath(); | |
| 78 canvas.moveTo(child.x, child.y + cellDim/4); | |
| 79 canvas.lineTo(child.x + cellDim/2, child.y); | |
| 80 canvas.lineTo(child.x + cellDim, child.y + cellDim/4); | |
| 81 canvas.lineTo(child.x + cellDim, child.y + 3*cellDim/4); | |
| 82 canvas.lineTo(child.x + cellDim/2, child.y + cellDim); | |
| 83 canvas.moveTo(child.x, child.y + 3*cellDim/4); | |
| 84 canvas.closePath(); | |
| 85 canvas.clip(); | |
| 86 canvas.paintChild(child); | |
| 87 } finally { | |
| 88 canvas.restore(); | |
| 89 } | |
| 90 loop = children.next(); | |
| 91 } | |
| 92 } | |
| 93 function inHex(topLeftX, topLeftY, width, height, hitX, hitY) { | |
| 94 let centerX = topLeftX - width/2; | |
| 95 let absCenteredHitX = Math.abs(hitX - centerX); | |
| 96 if (absCenteredHitX > width/2) | |
| 97 return false; | |
| 98 let centerY = topLeftY - height/2; | |
| 99 let absCenteredHitY = Math.abs(hitY - centerY); | |
| 100 if (absCenteredHitY > height/2) | |
| 101 return false; | |
| 102 if (absCenteredHitY < height * absCenteredHitX / (2 * width) + height / 2) | |
| 103 return true; | |
| 104 return false; | |
| 105 } | |
| 106 function hitTest(x, y) { | |
| 107 let cellCount = this.node.getProperty('beehive-count'); | |
| 108 let cellDim = width / cellCount; | |
| 109 let children = this.walkChildren(); | |
| 110 let loop = children.next(); | |
| 111 while (!loop.done) { | |
| 112 let child = loop.value; | |
| 113 if (this.inHex(child.x, child.y, child.width, child.height, x, y)) | |
| 114 return child.layoutManager.hitTest(x-child.x, y-child.y); | |
| 115 loop = children.next(); | |
| 116 } | |
| 117 return this.node; | |
| 118 } | |
| 119 } | |
| 120 sky.registerLayoutManager('beehive', BeehiveLayoutManager); | |
| 121 let BeehiveCountStyleGrammar = new StyleGrammar(); | |
| 122 BeehiveCountStyleGrammar.addParser((tokens) => { | |
| 123 let token = tokens.next(); | |
| 124 if (token.done) | |
| 125 throw new Error(); | |
| 126 if (token.value.kind != 'number') | |
| 127 throw new Error(); | |
| 128 if (token.value.value <= 0) | |
| 129 throw new Error(); | |
| 130 if (Math.trunc(token.value.value) != token.value.value) // is integer | |
| 131 throw new Error(); | |
| 132 return new NumericStyleValue(token.value.value); | |
| 133 }); | |
| 134 sky.registerProperty({ | |
| 135 name: 'beehive-count', | |
| 136 type: BeehiveCountStyleGrammar, | |
| 137 inherits: true, | |
| 138 initialValue: 5, | |
| 139 needsLayout: true, | |
| 140 }); | |
| 141 </script> | |
| 142 <style> | |
| 143 div { display: beehive; beehive-count: 3; } | |
| 144 </style> | |
| 145 <div> | |
| 146 <t>Hello</t> | |
| 147 <t>World</t> | |
| 148 <t>How</t> | |
| 149 <t>Are</t> | |
| 150 <t>You</t> | |
| 151 <t>Today?</t> | |
| 152 </div> | |
| OLD | NEW |