flutter/examples/style/hex-layout.sky
Hixie 7598f1fd3c Examples: move markAsLaidOut() to just before the return, so the asserts work
Specs: introduce layoutDescendants() to avoid work when a layout
manager is unaffected by its childrens' intrinsic dimensions
Examples: update for layoutDescendants() change
Specs: add "lifetime" to resolver settings so that a transition can
avoid having to dirty every consumer of the property every frame when
it only needs to update the objects that are changing that frame
Specs: expose the parents on AbstractStyleDeclarationList subclasses
Specs: fix documentation around autoreap
Specs: fix definition of setProperty()
Specs: clean up the dimension-related logic of layout managers

Review URL: https://codereview.chromium.org/850593003
2015-01-13 11:25:24 -08:00

153 lines
4.7 KiB
Plaintext

#!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);
} else if (child.descendantNeedsLayout) {
child.layoutManager.layoutDescendants();
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;
this.markAsLaidOut();
return {
width: width,
height: height,
}
}
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(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;
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();
canvas.paintChild(child);
} finally {
canvas.restore();
}
loop = children.next();
}
}
function inHex(topLeftX, topLeftY, width, height, hitX, hitY) {
let centerX = topLeftX - width/2;
let absCenteredHitX = Math.abs(hitX - centerX);
if (absCenteredHitX > width/2)
return false;
let centerY = topLeftY - height/2;
let absCenteredHitY = Math.abs(hitY - centerY);
if (absCenteredHitY > height/2)
return false;
if (absCenteredHitY < height * absCenteredHitX / (2 * width) + height / 2)
return true;
return false;
}
function hitTest(x, y) {
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 (this.inHex(child.x, child.y, child.width, child.height, x, y))
return child.layoutManager.hitTest(x-child.x, y-child.y);
loop = children.next();
}
return this.node;
}
}
sky.registerLayoutManager('beehive', BeehiveLayoutManager);
let BeehiveCountStyleGrammar = new StyleGrammar();
BeehiveCountStyleGrammar.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) // is integer
throw new Error();
return new NumericStyleValue(token.value.value);
});
sky.registerProperty({
name: 'beehive-count',
type: BeehiveCountStyleGrammar,
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>