Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(79)

Unified Diff: sky/examples/style/toolbar-layout.sky

Issue 716013002: Specs: Initial hack at extensible style/layout (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sky/examples/style/sky-core-styles.sky ('k') | sky/specs/apis.md » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sky/examples/style/toolbar-layout.sky
diff --git a/sky/examples/style/toolbar-layout.sky b/sky/examples/style/toolbar-layout.sky
new file mode 100644
index 0000000000000000000000000000000000000000..a43ce3fc5d773ed8e9ce859b62b7eb215e348674
--- /dev/null
+++ b/sky/examples/style/toolbar-layout.sky
@@ -0,0 +1,208 @@
+SKY MODULE
+<import src="sky:core" as="sky"/>
+<script>
+ // display: toolbar;
+ // toolbar-spacing: <length>
+ // display: spring; // remaining space is split equally amongst the springs
+ // children are vertically centered, layout out left-to-right with toolbar-spacing space between them
+ // last child is hidden by default unless there's not enough room for the others, then it's shown last, right-aligned
+ module.exports.SpringLayoutManager = class SpringLayoutManager extends sky.LayoutManager { }
+ sky.registerLayoutManager('spring', module.exports.SpringLayoutManager);
+ sky.registerProperty({
+ name: 'toolbar-spacing',
+ type: sky.LengthStyleValueType,
+ inherits: true,
+ initialValue: { value: 8, unit: 'px' },
+ needsLayout: true,
+ });
+ module.exports.ToolbarLayoutManager = class ToolbarLayoutManager extends sky.LayoutManager {
+ constructor (styleNode) {
+ super(styleNode);
+ this.showingOverflow = false;
+ this.firstSkippedChild = null;
+ this.overflowChild = null;
+ }
+ function layout(width, height) {
+ let children = null;
+ let loop = null;
+ if (height == null)
+ height = this.getIntrinsicHeight().value;
+ if (width == null)
+ this.assumeDimensions(0, height);
+ else
+ this.assumeDimensions(width, height);
+ let spacing = this.node.getProperty('toolbar-spacing');
+ if (typeof spacing != 'number')
+ spacing = 0;
+ this.overflowChild = null;
+ this.firstSkippedChild = null;
+
+ // layout children and figure out whether we need to truncate the child list and show the overflow child
+ let springCount = 0;
+ let minX = 0;
+ let overflowChildWidth = 0;
+ let pendingSpacing = 0;
+ children = this.walkChildren();
+ loop = children.next();
+ while (!loop.done) {
+ let child = loop.value;
+ let dims = null;
+ if (child.layoutManager instanceof module.exports.SpringLayoutManager) {
+ springCount += 1;
+ pendingSpacing = spacing; // not +=, because we only have one extra spacing per batch of springs
+ } else {
+ if (child.needsLayout) {
+ childHeight = child.layoutManager.getIntrinsicHeight();
+ if (childHeight.value < height)
+ childHeight = childHeight.value;
+ else
+ childHeight = height;
+ dims = child.layoutManager.layout(width, height);
+ this.setChildSize(child, dims.width, dims.height);
+ } else {
+ dims = {
+ width: child.width,
+ height: child.height,
+ };
+ }
+ loop = children.next();
+ if (!loop.done) {
+ if (minX > 0)
+ minX += spacing + pendingSpacing;
+ minX += dims.width;
+ pendingSpacing = 0;
+ } else {
+ overflowChildWidth = spacing + dims.width;
+ this.overflowChild = child;
+ }
+ }
+ }
+
+ // figure out the spacing
+ this.showingOverflow = false;
+ let springSize = 0;
+ if (width != null) {
+ if (minX <= width) {
+ if (springCount > 0)
+ springSize = (width - minX) / sprintCount;
+ } else {
+ this.showingOverflow = true;
+ }
+ } else {
+ width = minX;
+ }
+
+ // position the children
+ // TODO(ianh): support rtl toolbars
+ let x = 0;
+ let lastWasNonSpring = false;
+ children = this.walkChildren();
+ loop = children.next();
+ while (!loop.done) {
+ let child = loop.value;
+ if (child.layoutManager instanceof module.exports.SpringLayoutManager) {
+ x += springSize;
+ if (lastWasNonSpring)
+ x += spacing;
+ lastWasNonSpring = false;
+ } else {
+ if (!loop.done) {
+ if (x + child.width + overflowChildWidth > width) {
+ this.firstSkippedChild = child;
+ break; // don't display any more children
+ }
+ this.setChildPosition(child, x, (height - child.height)/2);
+ x += child.width + spacing;
+ lastWasNonSpring = true;
+ } else {
+ // assert: this.showingOverflow == false
+ }
+ }
+ }
+ if (this.showingOverflow)
+ this.setChildPosition(this.overflowChild, width-this.overflowChild.width, (height - this.overflowChild.height)/2);
+ else
+ this.firstSkippedChild = this.overflowChild;
+
+ return {
+ width: width,
+ height: height,
+ }
+ }
+ function getIntrinsicWidth() {
+ let width = this.node.getProperty('width');
+ if (typeof height != 'number') {
+ let spacing = this.node.getProperty('toolbar-spacing');
+ if (typeof spacing != 'number')
+ spacing = 0;
+ width = 0;
+ let children = this.walkChildren();
+ let loop = children.next();
+ // we exclude the last child because at our ideal width we wouldn't need it
+ let last1 = null; // last one
+ let last2 = null; // one before the last one
+ while (!loop.done) {
+ if (last1)
+ width += last1.layoutManager.getIntrinsicWidth().value;
+ if (last2)
+ width += spacing;
+ last2 = last1;
+ last1 = loop.value;
+ loop = children.next();
+ }
+ }
+ return super(width); // applies and provides our own min-width/max-width rules
+ }
+ function getIntrinsicHeight() {
+ // we grow our minimum height to be no smaller than the children's
+ let result = super();
+ let determineHeight = false;
+ let heightProperty = this.node.getProperty('height');
+ if (typeof heightProperty != 'number')
+ determineHeight = true;
+ let children = this.walkChildren();
+ let loop = children.next();
+ // here we include the last child so that if it pops in our height doesn't change
+ while (!loop.done) {
+ let child = loop.value;
+ let childHeight = child.layoutManager.getIntrinsicHeight();
+ if (determineHeight) {
+ if (result.value < childHeight.value)
+ result.value = childHeight.value;
+ }
+ if (result.minimum < childHeight.minimum)
+ result.minimum = childHeight.minimum;
+ loop = children.next();
+ }
+ if (result.minimum > result.maximum)
+ result.maximum = result.minimum;
+ if (result.value > result.maximum)
+ result.value = result.maximum;
+ if (result.value < result.minimum)
+ result.value = result.minimum;
+ return result;
+ }
+ function paintChildren(canvas) {
+ let width = this.node.width;
+ let loop = children.next();
+ while ((!loop.done) && (loop.value != this.firstSkippedChild))
+ this.paintChild(loop.value, canvas);
+ if (this.showingOverflow)
+ this.paintChild(this.overflowChild, canvas);
+ }
+ function paintChild(child, canvas) {
+ if (child.needsPaint) {
+ canvas.save();
+ try {
+ canvas.beginPath();
+ canvas.rect(child.x, child.y, child.width, child.height);
+ canvas.clip();
+ child.paint(canvas);
+ } finally {
+ canvas.restore();
+ }
+ }
+ }
+ }
+ sky.registerLayoutManager('toolbar', module.exports.ToolbarLayoutManager);
+</script>
« no previous file with comments | « sky/examples/style/sky-core-styles.sky ('k') | sky/specs/apis.md » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698