mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00

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
153 lines
4.7 KiB
Plaintext
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>
|