Index: sky/examples/style/hex-layout.sky |
diff --git a/sky/examples/style/hex-layout.sky b/sky/examples/style/hex-layout.sky |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ca286f0401a2c604ea34221c8a48b6502e7f7784 |
--- /dev/null |
+++ b/sky/examples/style/hex-layout.sky |
@@ -0,0 +1,146 @@ |
+#!mojo mojo:sky |
+<import src="sky:core" as="sky"/> |
+<script> |
+ class BeehiveLayoutManager extends sky.LayoutManager { |
+ function layout(width, height) { |
+ if (width == null) |
+ width = this.getIntrinsicWidth().value; |
+ let autoHeight = false; |
+ if (height == null) { |
+ height = 0; |
+ autoHeight = true; |
+ } |
+ this.assumeDimensions(width, height); |
+ let cellCount = this.node.getProperty('beehive-count'); |
+ let cellDim = width / cellCount; |
+ let children = this.walkChildren(); |
+ let loop = children.next(); |
+ let x = 0; |
+ let y = 0; |
+ while (!loop.done) { |
+ let child = loop.value; |
+ if (child.needsLayout) { |
+ child.layoutManager.layout(cellDim, cellDim); |
+ // we ignore the size the child reported from layout(), and force it to the cell dimensions |
+ this.setChildSize(child, cellDim, cellDim); |
+ } |
+ this.setChildPosition(child, x * cellDim + (y % 2) * cellDim/2, y * 3/4 * cellDim); |
+ x += 1; |
+ if (x > cellCount) { |
+ y += 1; |
+ x = 0; |
+ } |
+ loop = children.next(); |
+ } |
+ if (height == 0) |
+ height = (1 + y * 3/4) * cellDim; |
+ return { |
+ width: width, |
+ height: height, |
+ } |
+ } |
+ function getIntrinsicWidth() { |
+ // this is the logic that LayoutManager.getIntrinsicWidth() has by default |
+ // shown here because I wrote it before realising it should be the default |
+ let width = this.node.getProperty('width'); |
+ if (typeof width != 'number') |
+ width = 0; |
+ let minWidth = this.node.getProperty('min-width'); |
+ if (typeof width != 'number') |
+ minWidth = 0; |
+ let maxWidth = this.node.getProperty('max-width'); |
+ if (typeof width != 'number') |
+ maxWidth = Infinity; |
+ if (maxWidth < minWidth) |
+ maxWidth = minWidth; |
+ if (width > maxWidth) |
+ width = maxWidth; |
+ if (width < minWidth) |
+ width = minWidth; |
+ return { |
+ minimum: minWidth, |
+ value: width, |
+ maximum: maxWidth, |
+ }; |
+ } |
+ function getIntrinsicHeight() { |
+ let height = this.node.getProperty('height'); |
+ if (typeof height != 'number') { |
+ // e.g. height: auto |
+ width = this.getIntrinsicWidth().value; |
+ let cellCount = this.node.getProperty('beehive-count'); |
+ let cellDim = width / cellCount; |
+ let children = this.walkChildren(); |
+ let loop = children.next(); |
+ let childCount = 0; |
+ while (!loop.done) { |
+ childCount += 1; |
+ loop.next(); |
+ } |
+ if (childCount > 0) |
+ height = cellDim * (1/4 + Math.ceil(childCount / cellCount) * 3/4); |
+ else |
+ height = 0; |
+ } |
+ return super(height); // does the equivalent of getIntrinsicWidth() above, applying min-height etc |
+ } |
+ function paintChildren(RenderingSurface canvas) { |
+ let width = this.node.width; |
+ let cellCount = this.node.getProperty('beehive-count'); |
+ let cellDim = width / cellCount; |
+ let children = this.walkChildren(); |
+ let loop = children.next(); |
+ while (!loop.done) { |
+ let child = loop.value; |
+ if (child.needsPaint) { |
+ canvas.save(); |
+ try { |
+ canvas.beginPath(); |
+ canvas.moveTo(child.x, child.y + cellDim/4); |
+ canvas.lineTo(child.x + cellDim/2, child.y); |
+ canvas.lineTo(child.x + cellDim, child.y + cellDim/4); |
+ canvas.lineTo(child.x + cellDim, child.y + 3*cellDim/4); |
+ canvas.lineTo(child.x + cellDim/2, child.y + cellDim); |
+ canvas.moveTo(child.x, child.y + 3*cellDim/4); |
+ canvas.closePath(); |
+ canvas.clip(); |
+ child.paint(canvas); |
+ } finally { |
+ canvas.restore(); |
+ } |
+ } |
+ loop = children.next(); |
+ } |
+ } |
+ } |
+ sky.registerLayoutManager('beehive', BeehiveLayoutManager); |
+ let BeehiveCountStyleValueType = new StyleValueType(); |
+ BeehiveCountStyleValueType.addParser((tokens) => { |
+ let token = tokens.next(); |
+ if (token.done) throw new Error(); |
+ if (token.value.kind != 'number') throw new Error(); |
+ if (token.value.value <= 0) throw new Error(); |
+ if (Math.trunc(token.value.value) != token.value.value) throw new Error(); |
+ let result = token.value.value; |
+ if (!token.next().done) throw new Error(); |
+ return result; |
+ }); |
+ sky.registerProperty({ |
+ name: 'beehive-count', |
+ type: BeehiveCountStyleValueType, |
+ inherits: true, |
+ initialValue: 5, |
+ needsLayout: true, |
+ }); |
+</script> |
+<style> |
+ div { display: beehive; beehive-count: 3; } |
+</style> |
+<div> |
+ <t>Hello</t> |
+ <t>World</t> |
+ <t>How</t> |
+ <t>Are</t> |
+ <t>You</t> |
+ <t>Today?</t> |
+</div> |