blob: ca286f0401a2c604ea34221c8a48b6502e7f7784 [file]
#!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>