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 |