| OLD | NEW |
| 1 library layout; | 1 library layout; |
| 2 | 2 |
| 3 // This version of layout.dart is an update to the other one, this one using new
APIs. | 3 // This version of layout.dart is an update to the other one, this one using new
APIs. |
| 4 // It will not work in a stock Sky setup currently. | 4 // It will not work in a stock Sky setup currently. |
| 5 | 5 |
| 6 import 'node.dart'; | 6 import 'node.dart'; |
| 7 | 7 |
| 8 import 'dart:sky' as sky; | 8 import 'dart:sky' as sky; |
| 9 | 9 |
| 10 // ABSTRACT LAYOUT | 10 // ABSTRACT LAYOUT |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 72 } | 72 } |
| 73 | 73 |
| 74 static List<RenderNode> _nodesNeedingLayout = new List<RenderNode>(); | 74 static List<RenderNode> _nodesNeedingLayout = new List<RenderNode>(); |
| 75 static bool _debugDoingLayout = false; | 75 static bool _debugDoingLayout = false; |
| 76 bool _needsLayout = true; | 76 bool _needsLayout = true; |
| 77 bool get needsLayout => _needsLayout; | 77 bool get needsLayout => _needsLayout; |
| 78 RenderNode _relayoutSubtreeRoot; | 78 RenderNode _relayoutSubtreeRoot; |
| 79 void saveRelayoutSubtreeRoot(RenderNode relayoutSubtreeRoot) { | 79 void saveRelayoutSubtreeRoot(RenderNode relayoutSubtreeRoot) { |
| 80 _relayoutSubtreeRoot = relayoutSubtreeRoot; | 80 _relayoutSubtreeRoot = relayoutSubtreeRoot; |
| 81 assert(_relayoutSubtreeRoot == null || _relayoutSubtreeRoot._relayoutSubtree
Root == null); | 81 assert(_relayoutSubtreeRoot == null || _relayoutSubtreeRoot._relayoutSubtree
Root == null); |
| 82 assert(_relayoutSubtreeRoot == null || _relayoutSubtreeRoot == parent || _re
layoutSubtreeRoot == parent._relayoutSubtreeRoot); | 82 assert(_relayoutSubtreeRoot == null || _relayoutSubtreeRoot == parent || (pa
rent is RenderNode && _relayoutSubtreeRoot == parent._relayoutSubtreeRoot)); |
| 83 } | 83 } |
| 84 bool debugAncestorsAlreadyMarkedNeedsLayout() { | 84 bool debugAncestorsAlreadyMarkedNeedsLayout() { |
| 85 if (_relayoutSubtreeRoot == null) | 85 if (_relayoutSubtreeRoot == null) |
| 86 return true; | 86 return true; |
| 87 RenderNode node = this; | 87 RenderNode node = this; |
| 88 while (node != _relayoutSubtreeRoot) { | 88 while (node != _relayoutSubtreeRoot) { |
| 89 assert(node._relayoutSubtreeRoot == _relayoutSubtreeRoot); | 89 assert(node._relayoutSubtreeRoot == _relayoutSubtreeRoot); |
| 90 assert(node.parent != null); | 90 assert(node.parent != null); |
| 91 node = node.parent as RenderNode; | 91 node = node.parent as RenderNode; |
| 92 if (!node._needsLayout) | 92 if (!node._needsLayout) |
| 93 return false; | 93 return false; |
| 94 } | 94 } |
| 95 assert(node._relayoutSubtreeRoot == null); | 95 assert(node._relayoutSubtreeRoot == null); |
| 96 return true; | 96 return true; |
| 97 } | 97 } |
| 98 void markNeedsLayout() { | 98 void markNeedsLayout() { |
| 99 assert(!_debugDoingLayout); | 99 assert(!_debugDoingLayout); |
| 100 assert(!_debugDoingPaint); | 100 assert(!_debugDoingPaint); |
| 101 if (_needsLayout) { | 101 if (_needsLayout) { |
| 102 assert(debugAncestorsAlreadyMarkedNeedsLayout()); | 102 assert(debugAncestorsAlreadyMarkedNeedsLayout()); |
| 103 return; | 103 return; |
| 104 } | 104 } |
| 105 _needsLayout = true; | 105 _needsLayout = true; |
| 106 assert(parent is RenderNode); |
| 106 if (_relayoutSubtreeRoot != null) | 107 if (_relayoutSubtreeRoot != null) |
| 107 parent.markNeedsLayout(); | 108 parent.markNeedsLayout(); |
| 108 else | 109 else |
| 109 _nodesNeedingLayout.add(this); | 110 _nodesNeedingLayout.add(this); |
| 110 } | 111 } |
| 111 static void flushLayout() { | 112 static void flushLayout() { |
| 112 _debugDoingLayout = true; | 113 _debugDoingLayout = true; |
| 113 List<RenderNode> dirtyNodes = _nodesNeedingLayout; | 114 List<RenderNode> dirtyNodes = _nodesNeedingLayout; |
| 114 _nodesNeedingLayout = new List<RenderNode>(); | 115 _nodesNeedingLayout = new List<RenderNode>(); |
| 115 dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) { | 116 dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) { |
| (...skipping 279 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 // GENERIC BOX RENDERING | 396 // GENERIC BOX RENDERING |
| 396 // Anything that has a concept of x, y, width, height is going to derive from th
is | 397 // Anything that has a concept of x, y, width, height is going to derive from th
is |
| 397 | 398 |
| 398 class BoxConstraints { | 399 class BoxConstraints { |
| 399 const BoxConstraints({ | 400 const BoxConstraints({ |
| 400 this.minWidth: 0.0, | 401 this.minWidth: 0.0, |
| 401 this.maxWidth: double.INFINITY, | 402 this.maxWidth: double.INFINITY, |
| 402 this.minHeight: 0.0, | 403 this.minHeight: 0.0, |
| 403 this.maxHeight: double.INFINITY}); | 404 this.maxHeight: double.INFINITY}); |
| 404 | 405 |
| 405 const BoxConstraints.tight({ width: width, height: height }) | 406 const BoxConstraints.tight({ double width: 0.0, double height: 0.0 }) |
| 406 : minWidth = width, | 407 : minWidth = width, |
| 407 maxWidth = width, | 408 maxWidth = width, |
| 408 minHeight = height, | 409 minHeight = height, |
| 409 maxHeight = height; | 410 maxHeight = height; |
| 410 | 411 |
| 411 final double minWidth; | 412 final double minWidth; |
| 412 final double maxWidth; | 413 final double maxWidth; |
| 413 final double minHeight; | 414 final double minHeight; |
| 414 final double maxHeight; | 415 final double maxHeight; |
| 415 | 416 |
| 416 double constrainWidth(double width) { | 417 double constrainWidth(double width) { |
| 417 return clamp(min: minWidth, max: maxWidth, value: width); | 418 return clamp(min: minWidth, max: maxWidth, value: width); |
| 418 } | 419 } |
| 419 | 420 |
| 420 double constrainHeight(double height) { | 421 double constrainHeight(double height) { |
| 421 return clamp(min: minHeight, max: maxHeight, value: height); | 422 return clamp(min: minHeight, max: maxHeight, value: height); |
| 422 } | 423 } |
| 424 |
| 425 bool get isInfinite => maxWidth >= double.INFINITY || maxHeight >= double.INFI
NITY; |
| 423 } | 426 } |
| 424 | 427 |
| 425 class BoxDimensions { | 428 class BoxDimensions { |
| 426 const BoxDimensions({this.width, this.height}); | 429 const BoxDimensions({ this.width: 0.0, this.height: 0.0 }); |
| 427 | 430 |
| 428 BoxDimensions.withConstraints( | 431 BoxDimensions.withConstraints( |
| 429 BoxConstraints constraints, {double width: 0.0, double height: 0.0}) | 432 BoxConstraints constraints, |
| 430 : width = constraints.constrainWidth(width), | 433 { double width: 0.0, double height: 0.0 } |
| 434 ) : width = constraints.constrainWidth(width), |
| 431 height = constraints.constrainHeight(height); | 435 height = constraints.constrainHeight(height); |
| 432 | 436 |
| 433 final double width; | 437 final double width; |
| 434 final double height; | 438 final double height; |
| 435 } | 439 } |
| 436 | 440 |
| 437 class BoxParentData extends ParentData { | 441 class BoxParentData extends ParentData { |
| 438 double x = 0.0; | 442 double x = 0.0; |
| 439 double y = 0.0; | 443 double y = 0.0; |
| 440 } | 444 } |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 654 // override this to report what dimensions you would have if you | 658 // override this to report what dimensions you would have if you |
| 655 // were laid out with the given constraints this can walk the tree | 659 // were laid out with the given constraints this can walk the tree |
| 656 // if it must, but it should be as cheap as possible; just get the | 660 // if it must, but it should be as cheap as possible; just get the |
| 657 // dimensions and nothing else (e.g. don't calculate hypothetical | 661 // dimensions and nothing else (e.g. don't calculate hypothetical |
| 658 // child positions if they're not needed to determine dimensions) | 662 // child positions if they're not needed to determine dimensions) |
| 659 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { | 663 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { |
| 660 double outerHeight = _padding.top + _padding.bottom; | 664 double outerHeight = _padding.top + _padding.bottom; |
| 661 double outerWidth = constraints.constrainWidth(constraints.maxWidth); | 665 double outerWidth = constraints.constrainWidth(constraints.maxWidth); |
| 662 assert(outerWidth < double.INFINITY); | 666 assert(outerWidth < double.INFINITY); |
| 663 double innerWidth = outerWidth - (_padding.left + _padding.right); | 667 double innerWidth = outerWidth - (_padding.left + _padding.right); |
| 664 RenderBox child = _firstChild; | 668 RenderBox child = firstChild; |
| 665 BoxConstraints innerConstraints = new BoxConstraints(minWidth: innerWidth, | 669 BoxConstraints innerConstraints = new BoxConstraints(minWidth: innerWidth, |
| 666 maxWidth: innerWidth); | 670 maxWidth: innerWidth); |
| 667 while (child != null) { | 671 while (child != null) { |
| 668 outerHeight += child.getIntrinsicDimensions(innerConstraints).height; | 672 outerHeight += child.getIntrinsicDimensions(innerConstraints).height; |
| 669 assert(child.parentData is BlockParentData); | 673 assert(child.parentData is BlockParentData); |
| 670 child = child.parentData.nextSibling; | 674 child = child.parentData.nextSibling; |
| 671 } | 675 } |
| 672 | 676 |
| 673 return new BoxDimensions(width: outerWidth, | 677 return new BoxDimensions(width: outerWidth, |
| 674 height: constraints.constrainHeight(outerHeight)); | 678 height: constraints.constrainHeight(outerHeight)); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 689 | 693 |
| 690 void relayout() { | 694 void relayout() { |
| 691 internalLayout(this); | 695 internalLayout(this); |
| 692 } | 696 } |
| 693 | 697 |
| 694 void internalLayout(RenderNode relayoutSubtreeRoot) { | 698 void internalLayout(RenderNode relayoutSubtreeRoot) { |
| 695 assert(_minHeight != null); | 699 assert(_minHeight != null); |
| 696 assert(_maxHeight != null); | 700 assert(_maxHeight != null); |
| 697 double y = _padding.top; | 701 double y = _padding.top; |
| 698 double innerWidth = width - (_padding.left + _padding.right); | 702 double innerWidth = width - (_padding.left + _padding.right); |
| 699 RenderBox child = _firstChild; | 703 RenderBox child = firstChild; |
| 700 while (child != null) { | 704 while (child != null) { |
| 701 child.layout(new BoxConstraints(minWidth: innerWidth, maxWidth: innerWidth
), | 705 child.layout(new BoxConstraints(minWidth: innerWidth, maxWidth: innerWidth
), |
| 702 relayoutSubtreeRoot: relayoutSubtreeRoot); | 706 relayoutSubtreeRoot: relayoutSubtreeRoot); |
| 703 assert(child.parentData is BlockParentData); | 707 assert(child.parentData is BlockParentData); |
| 704 child.parentData.x = _padding.left; | 708 child.parentData.x = _padding.left; |
| 705 child.parentData.y = y; | 709 child.parentData.y = y; |
| 706 y += child.height; | 710 y += child.height; |
| 707 child = child.parentData.nextSibling; | 711 child = child.parentData.nextSibling; |
| 708 } | 712 } |
| 709 height = clamp(min: _minHeight, value: y + _padding.bottom, max: _maxHeight)
; | 713 height = clamp(min: _minHeight, value: y + _padding.bottom, max: _maxHeight)
; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 769 assert(width < double.INFINITY); | 773 assert(width < double.INFINITY); |
| 770 internalLayout(relayoutSubtreeRoot); | 774 internalLayout(relayoutSubtreeRoot); |
| 771 } | 775 } |
| 772 | 776 |
| 773 void relayout() { | 777 void relayout() { |
| 774 internalLayout(this); | 778 internalLayout(this); |
| 775 } | 779 } |
| 776 | 780 |
| 777 int _getFlex(RenderBox child) { | 781 int _getFlex(RenderBox child) { |
| 778 assert(child.parentData is FlexBoxParentData); | 782 assert(child.parentData is FlexBoxParentData); |
| 779 return (child.parentData.flex != null ? child.parentData.flex : 0); | 783 return child.parentData.flex != null ? child.parentData.flex : 0; |
| 780 } | 784 } |
| 781 | 785 |
| 782 void internalLayout(RenderNode relayoutSubtreeRoot) { | 786 void internalLayout(RenderNode relayoutSubtreeRoot) { |
| 783 // Based on http://www.w3.org/TR/css-flexbox-1/ Section 9.7 Resolving Flexib
le Lengths | 787 // Based on http://www.w3.org/TR/css-flexbox-1/ Section 9.7 Resolving Flexib
le Lengths |
| 784 // Steps 1-3. Determine used flex factor, size inflexible items, calculate f
ree space | 788 // Steps 1-3. Determine used flex factor, size inflexible items, calculate f
ree space |
| 785 int numFlexibleChildren = 0; | |
| 786 int totalFlex = 0; | 789 int totalFlex = 0; |
| 787 assert(_constraints != null); | 790 assert(_constraints != null); |
| 788 double freeSpace = (_direction == FlexDirection.Horizontal) ? _constraints.m
axWidth : _constraints.maxHeight; | 791 double freeSpace = (_direction == FlexDirection.Horizontal) ? _constraints.m
axWidth : _constraints.maxHeight; |
| 789 RenderBox child = _firstChild; | 792 RenderBox child = firstChild; |
| 790 while (child != null) { | 793 while (child != null) { |
| 791 int flex = _getFlex(child); | 794 int flex = _getFlex(child); |
| 792 if (flex > 0) { | 795 if (flex > 0) { |
| 793 numFlexibleChildren++; | |
| 794 totalFlex += child.parentData.flex; | 796 totalFlex += child.parentData.flex; |
| 795 } else { | 797 } else { |
| 796 BoxConstraints constraints = new BoxConstraints(maxHeight: _constraints.
maxHeight, | 798 BoxConstraints constraints = new BoxConstraints(maxHeight: _constraints.
maxHeight, |
| 797 maxWidth: _constraints.m
axWidth); | 799 maxWidth: _constraints.m
axWidth); |
| 798 child.layout(constraints, | 800 child.layout(constraints, |
| 799 relayoutSubtreeRoot: relayoutSubtreeRoot); | 801 relayoutSubtreeRoot: relayoutSubtreeRoot); |
| 800 freeSpace -= (_direction == FlexDirection.Horizontal) ? child.width : ch
ild.height; | 802 freeSpace -= (_direction == FlexDirection.Horizontal) ? child.width : ch
ild.height; |
| 801 } | 803 } |
| 802 child = child.parentData.nextSibling; | 804 child = child.parentData.nextSibling; |
| 803 } | 805 } |
| 804 | 806 |
| 805 // Steps 4-5. Distribute remaining space to flexible children. | 807 // Steps 4-5. Distribute remaining space to flexible children. |
| 806 double spacePerFlex = totalFlex > 0 ? (freeSpace / totalFlex) : 0.0; | 808 double spacePerFlex = totalFlex > 0 ? (freeSpace / totalFlex) : 0.0; |
| 807 double usedSpace = 0.0; | 809 double usedSpace = 0.0; |
| 808 child = _firstChild; | 810 child = firstChild; |
| 809 while (child != null) { | 811 while (child != null) { |
| 810 int flex = _getFlex(child); | 812 int flex = _getFlex(child); |
| 811 if (flex > 0) { | 813 if (flex > 0) { |
| 812 double spaceForChild = spacePerFlex * flex; | 814 double spaceForChild = spacePerFlex * flex; |
| 813 BoxConstraints constraints; | 815 BoxConstraints constraints; |
| 814 switch (_direction) { | 816 switch (_direction) { |
| 815 case FlexDirection.Horizontal: | 817 case FlexDirection.Horizontal: |
| 816 constraints = new BoxConstraints(maxHeight: _constraints.maxHeight, | 818 constraints = new BoxConstraints(maxHeight: _constraints.maxHeight, |
| 817 minWidth: spaceForChild, | 819 minWidth: spaceForChild, |
| 818 maxWidth: spaceForChild); | 820 maxWidth: spaceForChild); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 921 canvas.paintChild(body, (body.parentData as BoxParentData).x, (body.parentDa
ta as BoxParentData).y); | 923 canvas.paintChild(body, (body.parentData as BoxParentData).x, (body.parentDa
ta as BoxParentData).y); |
| 922 if (statusbar != null) | 924 if (statusbar != null) |
| 923 canvas.paintChild(statusbar, (statusbar.parentData as BoxParentData).x, (s
tatusbar.parentData as BoxParentData).y); | 925 canvas.paintChild(statusbar, (statusbar.parentData as BoxParentData).x, (s
tatusbar.parentData as BoxParentData).y); |
| 924 if (toolbar != null) | 926 if (toolbar != null) |
| 925 canvas.paintChild(toolbar, (toolbar.parentData as BoxParentData).x, (toolb
ar.parentData as BoxParentData).y); | 927 canvas.paintChild(toolbar, (toolbar.parentData as BoxParentData).x, (toolb
ar.parentData as BoxParentData).y); |
| 926 if (drawer != null) | 928 if (drawer != null) |
| 927 canvas.paintChild(drawer, (drawer.parentData as BoxParentData).x, (drawer.
parentData as BoxParentData).y); | 929 canvas.paintChild(drawer, (drawer.parentData as BoxParentData).x, (drawer.
parentData as BoxParentData).y); |
| 928 } | 930 } |
| 929 | 931 |
| 930 } | 932 } |
| OLD | NEW |