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

Side by Side Diff: sky/sdk/lib/framework/layout2.dart

Issue 1151293002: WIP Flexbox Layout Manager for Sky framework. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Rebasing onto master Created 5 years, 7 months 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 unified diff | Download patch
OLDNEW
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 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 int newAngle, // 0..3 214 int newAngle, // 0..3
215 Duration time 215 Duration time
216 }) { } 216 }) { }
217 217
218 218
219 // HIT TESTING 219 // HIT TESTING
220 220
221 bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) { 221 bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) {
222 // override this if you have children, to hand it to the appropriate child 222 // override this if you have children, to hand it to the appropriate child
223 // override this if you want to do anything with the pointer event 223 // override this if you want to do anything with the pointer event
224 return false;
224 } 225 }
225 226
226 227
227 // PAINTING 228 // PAINTING
228 229
229 static bool _debugDoingPaint = false; 230 static bool _debugDoingPaint = false;
230 void markNeedsPaint() { 231 void markNeedsPaint() {
231 assert(!_debugDoingPaint); 232 assert(!_debugDoingPaint);
232 // TODO(abarth): It's very redunant to call this for every node in the 233 // TODO(abarth): It's very redunant to call this for every node in the
233 // render tree during layout. We should instead compute a summary bit and 234 // render tree during layout. We should instead compute a summary bit and
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 419
419 double constrainHeight(double height) { 420 double constrainHeight(double height) {
420 return clamp(min: minHeight, max: maxHeight, value: height); 421 return clamp(min: minHeight, max: maxHeight, value: height);
421 } 422 }
422 } 423 }
423 424
424 class BoxDimensions { 425 class BoxDimensions {
425 const BoxDimensions({this.width, this.height}); 426 const BoxDimensions({this.width, this.height});
426 427
427 BoxDimensions.withConstraints( 428 BoxDimensions.withConstraints(
428 BoxConstraints constraints, {double width: 0.0, double height: 0.0}) { 429 BoxConstraints constraints, {double width: 0.0, double height: 0.0})
429 this.width = constraints.constrainWidth(width); 430 : width = constraints.constrainWidth(width),
430 this.height = constraints.constrainHeight(height); 431 height = constraints.constrainHeight(height);
431 }
432 432
433 final double width; 433 final double width;
434 final double height; 434 final double height;
435 } 435 }
436 436
437 class BoxParentData extends ParentData { 437 class BoxParentData extends ParentData {
438 double x = 0.0; 438 double x = 0.0;
439 double y = 0.0; 439 double y = 0.0;
440 } 440 }
441 441
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
573 void paintFrame() { 573 void paintFrame() {
574 RenderNode._debugDoingPaint = true; 574 RenderNode._debugDoingPaint = true;
575 var canvas = new RenderNodeDisplayList(sky.view.width, sky.view.height); 575 var canvas = new RenderNodeDisplayList(sky.view.width, sky.view.height);
576 paint(canvas); 576 paint(canvas);
577 sky.view.picture = canvas.endRecording(); 577 sky.view.picture = canvas.endRecording();
578 RenderNode._debugDoingPaint = false; 578 RenderNode._debugDoingPaint = false;
579 } 579 }
580 580
581 } 581 }
582 582
583 // DEFAULT BEHAVIORS FOR RENDERBOX CONTAINERS
584 abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, Pare ntDataType extends ContainerParentDataMixin<ChildType>> implements ContainerRend erNodeMixin<ChildType, ParentDataType> {
585 bool defaultHandlePointer(sky.PointerEvent event, double x, double y) {
586 // the x, y parameters have the top left of the node's box as the origin
587 ChildType child = lastChild;
588 while (child != null) {
589 assert(child.parentData is BoxParentData);
590 if ((x >= child.parentData.x) && (x < child.parentData.x + child.width) &&
591 (y >= child.parentData.y) && (y < child.parentData.y + child.height)) {
592 if (child.handlePointer(event, x: x-child.parentData.x, y: y-child.paren tData.y))
593 return true;
594 break;
595 }
596 child = child.parentData.previousSibling;
597 }
598 return false;
599 }
600
601 void defaultPaint(RenderNodeDisplayList canvas) {
602 RenderBox child = firstChild;
603 while (child != null) {
604 assert(child.parentData is BoxParentData);
605 canvas.paintChild(child, child.parentData.x, child.parentData.y);
606 child = child.parentData.nextSibling;
607 }
608 }
609 }
583 610
584 // BLOCK LAYOUT MANAGER 611 // BLOCK LAYOUT MANAGER
585 612
586 class EdgeDims { 613 class EdgeDims {
587 // used for e.g. padding 614 // used for e.g. padding
588 const EdgeDims(this.top, this.right, this.bottom, this.left); 615 const EdgeDims(this.top, this.right, this.bottom, this.left);
589 final double top; 616 final double top;
590 final double right; 617 final double right;
591 final double bottom; 618 final double bottom;
592 final double left; 619 final double left;
593 operator ==(EdgeDims other) => (top == other.top) || 620 operator ==(EdgeDims other) => (top == other.top) ||
594 (right == other.right) || 621 (right == other.right) ||
595 (bottom == other.bottom) || 622 (bottom == other.bottom) ||
596 (left == other.left); 623 (left == other.left);
597 } 624 }
598 625
599 class BlockParentData extends BoxParentData with ContainerParentDataMixin<Render Box> { } 626 class BlockParentData extends BoxParentData with ContainerParentDataMixin<Render Box> { }
600 627
601 class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende rBox, BlockParentData> { 628 class RenderBlock extends RenderDecoratedBox with ContainerRenderNodeMixin<Rende rBox, BlockParentData>,
629 RenderBoxContainerDefaultsMixi n<RenderBox, BlockParentData> {
602 // lays out RenderBox children in a vertical stack 630 // lays out RenderBox children in a vertical stack
603 // uses the maximum width provided by the parent 631 // uses the maximum width provided by the parent
604 // sizes itself to the height of its child stack 632 // sizes itself to the height of its child stack
605 633
606 RenderBlock({ 634 RenderBlock({
607 BoxDecoration decoration, 635 BoxDecoration decoration,
608 EdgeDims padding: const EdgeDims(0.0, 0.0, 0.0, 0.0) 636 EdgeDims padding: const EdgeDims(0.0, 0.0, 0.0, 0.0)
609 }) : super(decoration), _padding = padding; 637 }) : super(decoration), _padding = padding;
610 638
611 EdgeDims _padding; 639 EdgeDims _padding;
(...skipping 15 matching lines...) Expand all
627 // were laid out with the given constraints this can walk the tree 655 // were laid out with the given constraints this can walk the tree
628 // if it must, but it should be as cheap as possible; just get the 656 // if it must, but it should be as cheap as possible; just get the
629 // dimensions and nothing else (e.g. don't calculate hypothetical 657 // dimensions and nothing else (e.g. don't calculate hypothetical
630 // child positions if they're not needed to determine dimensions) 658 // child positions if they're not needed to determine dimensions)
631 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { 659 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) {
632 double outerHeight = _padding.top + _padding.bottom; 660 double outerHeight = _padding.top + _padding.bottom;
633 double outerWidth = constraints.constrainWidth(constraints.maxWidth); 661 double outerWidth = constraints.constrainWidth(constraints.maxWidth);
634 assert(outerWidth < double.INFINITY); 662 assert(outerWidth < double.INFINITY);
635 double innerWidth = outerWidth - (_padding.left + _padding.right); 663 double innerWidth = outerWidth - (_padding.left + _padding.right);
636 RenderBox child = _firstChild; 664 RenderBox child = _firstChild;
637 BoxConstraints constraints = new BoxConstraints(minWidth: innerWidth, 665 BoxConstraints innerConstraints = new BoxConstraints(minWidth: innerWidth,
638 maxWidth: innerWidth); 666 maxWidth: innerWidth);
639 while (child != null) { 667 while (child != null) {
640 outerHeight += child.getIntrinsicDimensions(constraints).height; 668 outerHeight += child.getIntrinsicDimensions(innerConstraints).height;
641 assert(child.parentData is BlockParentData); 669 assert(child.parentData is BlockParentData);
642 child = child.parentData.nextSibling; 670 child = child.parentData.nextSibling;
643 } 671 }
644 672
645 return new BoxDimensions(width: outerWidth, 673 return new BoxDimensions(width: outerWidth,
646 height: constraints.constrainHeight(outerHeight)); 674 height: constraints.constrainHeight(outerHeight));
647 } 675 }
648 676
649 double _minHeight; // value cached from parent for relayout call 677 double _minHeight; // value cached from parent for relayout call
650 double _maxHeight; // value cached from parent for relayout call 678 double _maxHeight; // value cached from parent for relayout call
(...skipping 25 matching lines...) Expand all
676 child.parentData.x = _padding.left; 704 child.parentData.x = _padding.left;
677 child.parentData.y = y; 705 child.parentData.y = y;
678 y += child.height; 706 y += child.height;
679 child = child.parentData.nextSibling; 707 child = child.parentData.nextSibling;
680 } 708 }
681 height = clamp(min: _minHeight, value: y + _padding.bottom, max: _maxHeight) ; 709 height = clamp(min: _minHeight, value: y + _padding.bottom, max: _maxHeight) ;
682 layoutDone(); 710 layoutDone();
683 } 711 }
684 712
685 bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) { 713 bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) {
686 // the x, y parameters have the top left of the node's box as the origin 714 return defaultHandlePointer(event, x, y) || super.handlePointer(event, x: x, y: y);
687 RenderBox child = _lastChild;
688 while (child != null) {
689 assert(child.parentData is BlockParentData);
690 if ((x >= child.parentData.x) && (x < child.parentData.x + child.width) &&
691 (y >= child.parentData.y) && (y < child.parentData.y + child.height)) {
692 if (child.handlePointer(event, x: x-child.parentData.x, y: y-child.paren tData.y))
693 return true;
694 break;
695 }
696 child = child.parentData.previousSibling;
697 }
698 return super.handlePointer(event, x: x, y: y);
699 } 715 }
700 716
701 void paint(RenderNodeDisplayList canvas) { 717 void paint(RenderNodeDisplayList canvas) {
702 super.paint(canvas); 718 super.paint(canvas);
703 RenderBox child = _firstChild; 719 defaultPaint(canvas);
704 while (child != null) {
705 assert(child.parentData is BlockParentData);
706 canvas.paintChild(child, child.parentData.x, child.parentData.y);
707 child = child.parentData.nextSibling;
708 }
709 } 720 }
710 721
711 } 722 }
712 723
713 class FlexBoxParentData extends BoxParentData { 724 // FLEXBOX LAYOUT MANAGER
725
726 class FlexBoxParentData extends BoxParentData with ContainerParentDataMixin<Rend erBox> {
714 int flex; 727 int flex;
715 void merge(FlexBoxParentData other) { 728 void merge(FlexBoxParentData other) {
716 if (other.flex != null) 729 if (other.flex != null)
717 flex = other.flex; 730 flex = other.flex;
718 super.merge(other); 731 super.merge(other);
719 } 732 }
720 } 733 }
721 734
722 enum FlexDirection { Row, Column } 735 enum FlexDirection { Horizontal, Vertical }
723 736
724 // TODO(ianh): FlexBox 737 class RenderFlex extends RenderDecoratedBox with ContainerRenderNodeMixin<Render Box, FlexBoxParentData>,
738 RenderBoxContainerDefaultsMixin <RenderBox, BlockParentData> {
739 // lays out RenderBox children using flexible layout
725 740
741 RenderFlex({
742 BoxDecoration decoration,
743 FlexDirection direction: FlexDirection.Horizontal
744 }) : super(decoration), _direction = direction;
745
746 FlexDirection _direction;
747 FlexDirection get direction => _direction;
748 void set direction (FlexDirection value) {
749 if (_direction != value) {
750 _direction = value;
751 markNeedsLayout();
752 }
753 }
754
755 void setParentData(RenderBox child) {
756 if (child.parentData is! FlexBoxParentData)
757 child.parentData = new FlexBoxParentData();
758 }
759
760 BoxConstraints _constraints; // value cached from parent for relayout call
761 void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) {
762 if (relayoutSubtreeRoot != null)
763 saveRelayoutSubtreeRoot(relayoutSubtreeRoot);
764 relayoutSubtreeRoot = relayoutSubtreeRoot == null ? this : relayoutSubtreeRo ot;
765 _constraints = constraints;
766 width = _constraints.constrainWidth(_constraints.maxWidth);
767 height = _constraints.constrainHeight(_constraints.maxHeight);
768 assert(height < double.INFINITY);
769 assert(width < double.INFINITY);
770 internalLayout(relayoutSubtreeRoot);
771 }
772
773 void relayout() {
774 internalLayout(this);
775 }
776
777 int _getFlex(RenderBox child) {
778 assert(child.parentData is FlexBoxParentData);
779 return (child.parentData.flex != null ? child.parentData.flex : 0);
780 }
781
782 void internalLayout(RenderNode relayoutSubtreeRoot) {
783 // 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
785 int numFlexibleChildren = 0;
786 int totalFlex = 0;
787 assert(_constraints != null);
788 double freeSpace = (_direction == FlexDirection.Horizontal) ? _constraints.m axWidth : _constraints.maxHeight;
789 RenderBox child = _firstChild;
790 while (child != null) {
791 int flex = _getFlex(child);
792 if (flex > 0) {
793 numFlexibleChildren++;
794 totalFlex += child.parentData.flex;
795 } else {
796 BoxConstraints constraints = new BoxConstraints(maxHeight: _constraints. maxHeight,
797 maxWidth: _constraints.m axWidth);
798 child.layout(constraints,
799 relayoutSubtreeRoot: relayoutSubtreeRoot);
800 freeSpace -= (_direction == FlexDirection.Horizontal) ? child.width : ch ild.height;
801 }
802 child = child.parentData.nextSibling;
803 }
804
805 // Steps 4-5. Distribute remaining space to flexible children.
806 double spacePerFlex = totalFlex > 0 ? (freeSpace / totalFlex) : 0.0;
807 double usedSpace = 0.0;
808 child = _firstChild;
809 while (child != null) {
810 int flex = _getFlex(child);
811 if (flex > 0) {
812 double spaceForChild = spacePerFlex * flex;
813 BoxConstraints constraints;
814 switch (_direction) {
815 case FlexDirection.Horizontal:
816 constraints = new BoxConstraints(maxHeight: _constraints.maxHeight,
817 minWidth: spaceForChild,
818 maxWidth: spaceForChild);
819 break;
820 case FlexDirection.Vertical:
821 constraints = new BoxConstraints(minHeight: spaceForChild,
822 maxHeight: spaceForChild,
823 maxWidth: _constraints.maxWidth);
824 break;
825 }
826 child.layout(constraints, relayoutSubtreeRoot: relayoutSubtreeRoot);
827 }
828
829 // For now, center the flex items in the cross direction
830 switch (_direction) {
831 case FlexDirection.Horizontal:
832 child.parentData.x = usedSpace;
833 usedSpace += child.width;
834 child.parentData.y = height / 2 - child.height / 2;
835 break;
836 case FlexDirection.Vertical:
837 child.parentData.y = usedSpace;
838 usedSpace += child.height;
839 child.parentData.x = width / 2 - child.width / 2;
840 break;
841 }
842 child = child.parentData.nextSibling;
843 }
844 layoutDone();
845 }
846
847 bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) {
848 return defaultHandlePointer(event, x, y) || super.handlePointer(event, x: x, y: y);
849 }
850
851 void paint(RenderNodeDisplayList canvas) {
852 super.paint(canvas);
853 defaultPaint(canvas);
854 }
855 }
726 856
727 // SCAFFOLD LAYOUT MANAGER 857 // SCAFFOLD LAYOUT MANAGER
728 858
729 // a sample special-purpose layout manager 859 // a sample special-purpose layout manager
730 860
731 class ScaffoldBox extends RenderBox { 861 class ScaffoldBox extends RenderBox {
732 862
733 ScaffoldBox(this.toolbar, this.body, this.statusbar, this.drawer) { 863 ScaffoldBox(this.toolbar, this.body, this.statusbar, this.drawer) {
734 assert(body != null); 864 assert(body != null);
735 } 865 }
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
791 canvas.paintChild(body, (body.parentData as BoxParentData).x, (body.parentDa ta as BoxParentData).y); 921 canvas.paintChild(body, (body.parentData as BoxParentData).x, (body.parentDa ta as BoxParentData).y);
792 if (statusbar != null) 922 if (statusbar != null)
793 canvas.paintChild(statusbar, (statusbar.parentData as BoxParentData).x, (s tatusbar.parentData as BoxParentData).y); 923 canvas.paintChild(statusbar, (statusbar.parentData as BoxParentData).x, (s tatusbar.parentData as BoxParentData).y);
794 if (toolbar != null) 924 if (toolbar != null)
795 canvas.paintChild(toolbar, (toolbar.parentData as BoxParentData).x, (toolb ar.parentData as BoxParentData).y); 925 canvas.paintChild(toolbar, (toolbar.parentData as BoxParentData).x, (toolb ar.parentData as BoxParentData).y);
796 if (drawer != null) 926 if (drawer != null)
797 canvas.paintChild(drawer, (drawer.parentData as BoxParentData).x, (drawer. parentData as BoxParentData).y); 927 canvas.paintChild(drawer, (drawer.parentData as BoxParentData).x, (drawer. parentData as BoxParentData).y);
798 } 928 }
799 929
800 } 930 }
OLDNEW
« sky/examples/raw/simple_render_tree.dart ('K') | « sky/examples/raw/simple_render_tree.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698