Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 1 library layout; | 5 library layout; |
| 2 | 6 |
| 3 // This version of layout.dart is an update to the other one, this one using new APIs. | 7 // 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. | 8 // It will not work in a stock Sky setup currently. |
| 5 | 9 |
| 6 import 'node.dart'; | 10 import 'node.dart'; |
| 7 | 11 |
| 8 import 'dart:sky' as sky; | 12 import 'dart:sky' as sky; |
| 9 | 13 |
| 10 // ABSTRACT LAYOUT | 14 // ABSTRACT LAYOUT |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 210 // pixel, on the output device. Then, the layout() method or | 214 // pixel, on the output device. Then, the layout() method or |
| 211 // equivalent will be invoked. | 215 // equivalent will be invoked. |
| 212 | 216 |
| 213 void rotate({ | 217 void rotate({ |
| 214 int oldAngle, // 0..3 | 218 int oldAngle, // 0..3 |
| 215 int newAngle, // 0..3 | 219 int newAngle, // 0..3 |
| 216 Duration time | 220 Duration time |
| 217 }) { } | 221 }) { } |
| 218 | 222 |
| 219 | 223 |
| 220 // HIT TESTING | |
| 221 | |
| 222 bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) { | |
| 223 // override this if you have children, to hand it to the appropriate child | |
| 224 // override this if you want to do anything with the pointer event | |
| 225 return false; | |
| 226 } | |
| 227 | |
| 228 | |
| 229 // PAINTING | 224 // PAINTING |
| 230 | 225 |
| 231 static bool _debugDoingPaint = false; | 226 static bool _debugDoingPaint = false; |
| 232 void markNeedsPaint() { | 227 void markNeedsPaint() { |
| 233 assert(!_debugDoingPaint); | 228 assert(!_debugDoingPaint); |
| 234 // TODO(abarth): It's very redunant to call this for every node in the | 229 // TODO(abarth): It's very redunant to call this for every node in the |
| 235 // render tree during layout. We should instead compute a summary bit and | 230 // render tree during layout. We should instead compute a summary bit and |
| 236 // call it once at the end of layout. | 231 // call it once at the end of layout. |
| 237 sky.view.scheduleFrame(); | 232 sky.view.scheduleFrame(); |
| 238 } | 233 } |
| 239 void paint(RenderNodeDisplayList canvas) { } | 234 void paint(RenderNodeDisplayList canvas) { } |
| 240 | 235 |
| 236 | |
| 237 // HIT TESTING | |
| 238 | |
| 239 void handlePointer(sky.PointerEvent event) { | |
| 240 // override this if you have a client, to hand it to the client | |
| 241 // override this if you want to do anything with the pointer event | |
| 242 } | |
| 243 | |
| 244 // RenderNode subclasses are expected to have a method like the | |
| 245 // following (with the signature being whatever passes for coordinates | |
| 246 // for this particular class): | |
| 247 // bool hitTest(HitTestResult result, { double x, double y }) { | |
| 248 // // If (x,y) is not inside this node, then return false. | |
| 249 // // Otherwise: | |
| 250 // // For each child that intersects x,y, in z-order starting from the top, | |
| 251 // // call hitTest() for that child, passing it /result/, and the coordinate s | |
| 252 // // converted to the child's coordinate origin, and stop at the first chil d | |
| 253 // // that returns true. | |
| 254 // // Then, add yourself to /result/, and return true. | |
| 255 // } | |
| 256 // You must not add yourself to /result/ if you return false. | |
| 257 | |
| 241 } | 258 } |
| 242 | 259 |
| 260 class HitTestResult { | |
| 261 final List<RenderNode> path = new List<RenderNode>(); | |
| 262 | |
| 263 RenderNode get result => path.first; | |
| 264 | |
| 265 void add(RenderNode node) { | |
| 266 path.add(node); | |
| 267 } | |
| 268 } | |
| 243 | 269 |
| 244 // GENERIC MIXIN FOR RENDER NODES THAT TAKE A LIST OF CHILDREN | 270 // GENERIC MIXIN FOR RENDER NODES THAT TAKE A LIST OF CHILDREN |
| 245 | 271 |
| 246 abstract class ContainerParentDataMixin<ChildType extends RenderNode> { | 272 abstract class ContainerParentDataMixin<ChildType extends RenderNode> { |
| 247 ChildType previousSibling; | 273 ChildType previousSibling; |
| 248 ChildType nextSibling; | 274 ChildType nextSibling; |
| 249 void detachSiblings() { | 275 void detachSiblings() { |
| 250 if (previousSibling != null) { | 276 if (previousSibling != null) { |
| 251 assert(previousSibling.parentData is ContainerParentDataMixin<ChildType>); | 277 assert(previousSibling.parentData is ContainerParentDataMixin<ChildType>); |
| 252 assert(previousSibling != this); | 278 assert(previousSibling != this); |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 458 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { | 484 BoxDimensions getIntrinsicDimensions(BoxConstraints constraints) { |
| 459 return new BoxDimensions.withConstraints(constraints); | 485 return new BoxDimensions.withConstraints(constraints); |
| 460 } | 486 } |
| 461 | 487 |
| 462 void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) { | 488 void layout(BoxConstraints constraints, { RenderNode relayoutSubtreeRoot }) { |
| 463 width = constraints.constrainWidth(0.0); | 489 width = constraints.constrainWidth(0.0); |
| 464 height = constraints.constrainHeight(0.0); | 490 height = constraints.constrainHeight(0.0); |
| 465 layoutDone(); | 491 layoutDone(); |
| 466 } | 492 } |
| 467 | 493 |
| 494 bool hitTest(HitTestResult result, { double x, double y }) { | |
| 495 if (x < 0.0 || x >= width || y < 0.0 || y >= height) | |
|
eseidel
2015/05/26 19:38:23
If we had a Rect class it could abstract this away
| |
| 496 return false; | |
| 497 hitTestChildren(result, x: x, y: y); | |
| 498 result.add(this); | |
| 499 return true; | |
| 500 } | |
| 501 void hitTestChildren(HitTestResult result, { double x, double y }) { } | |
| 502 | |
| 468 double width; | 503 double width; |
| 469 double height; | 504 double height; |
| 470 } | 505 } |
| 471 | 506 |
| 472 class BoxDecoration { | 507 class BoxDecoration { |
| 473 const BoxDecoration({ | 508 const BoxDecoration({ |
| 474 this.backgroundColor | 509 this.backgroundColor |
| 475 }); | 510 }); |
| 476 | 511 |
| 477 final int backgroundColor; | 512 final int backgroundColor; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 557 root.layout(new BoxConstraints( | 592 root.layout(new BoxConstraints( |
| 558 minWidth: width, maxWidth: width, minHeight: height, maxHeight: height)) ; | 593 minWidth: width, maxWidth: width, minHeight: height, maxHeight: height)) ; |
| 559 assert(root.width == width); | 594 assert(root.width == width); |
| 560 assert(root.height == height); | 595 assert(root.height == height); |
| 561 } | 596 } |
| 562 | 597 |
| 563 void rotate({ int oldAngle, int newAngle, Duration time }) { | 598 void rotate({ int oldAngle, int newAngle, Duration time }) { |
| 564 assert(false); // nobody tells the screen to rotate, the whole rotate() danc e is started from our layout() | 599 assert(false); // nobody tells the screen to rotate, the whole rotate() danc e is started from our layout() |
| 565 } | 600 } |
| 566 | 601 |
| 567 bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) { | 602 bool hitTest(HitTestResult result, { double x, double y }) { |
| 568 if (x < 0.0 || x >= root.width || y < 0.0 || y >= root.height) | 603 assert(root != null); |
| 604 if (x < 0.0 || x >= width || y < 0.0 || y >= height) | |
| 569 return false; | 605 return false; |
| 570 return root.handlePointer(event, x: x, y: y); | 606 if (x >= 0.0 && x < root.width && y >= 0.0 && y < root.height) |
| 607 root.hitTest(result, x: x, y: y); | |
| 608 result.add(this); | |
| 609 return true; | |
| 571 } | 610 } |
| 572 | 611 |
| 573 void paint(RenderNodeDisplayList canvas) { | 612 void paint(RenderNodeDisplayList canvas) { |
| 574 canvas.paintChild(root, 0.0, 0.0); | 613 canvas.paintChild(root, 0.0, 0.0); |
| 575 } | 614 } |
| 576 | 615 |
| 577 void paintFrame() { | 616 void paintFrame() { |
| 578 RenderNode._debugDoingPaint = true; | 617 RenderNode._debugDoingPaint = true; |
| 579 var canvas = new RenderNodeDisplayList(sky.view.width, sky.view.height); | 618 var canvas = new RenderNodeDisplayList(sky.view.width, sky.view.height); |
| 580 paint(canvas); | 619 paint(canvas); |
| 581 sky.view.picture = canvas.endRecording(); | 620 sky.view.picture = canvas.endRecording(); |
| 582 RenderNode._debugDoingPaint = false; | 621 RenderNode._debugDoingPaint = false; |
| 583 } | 622 } |
| 584 | 623 |
| 585 } | 624 } |
| 586 | 625 |
| 587 // DEFAULT BEHAVIORS FOR RENDERBOX CONTAINERS | 626 // DEFAULT BEHAVIORS FOR RENDERBOX CONTAINERS |
| 588 abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, Pare ntDataType extends ContainerParentDataMixin<ChildType>> implements ContainerRend erNodeMixin<ChildType, ParentDataType> { | 627 abstract class RenderBoxContainerDefaultsMixin<ChildType extends RenderBox, Pare ntDataType extends ContainerParentDataMixin<ChildType>> implements ContainerRend erNodeMixin<ChildType, ParentDataType> { |
| 589 bool defaultHandlePointer(sky.PointerEvent event, double x, double y) { | 628 |
| 629 void defaultHitTestChildren(HitTestResult result, { double x, double y }) { | |
| 590 // the x, y parameters have the top left of the node's box as the origin | 630 // the x, y parameters have the top left of the node's box as the origin |
| 591 ChildType child = lastChild; | 631 ChildType child = lastChild; |
| 592 while (child != null) { | 632 while (child != null) { |
| 593 assert(child.parentData is BoxParentData); | 633 assert(child.parentData is BoxParentData); |
| 594 if ((x >= child.parentData.x) && (x < child.parentData.x + child.width) && | 634 if ((x >= child.parentData.x) && (x < child.parentData.x + child.width) && |
| 595 (y >= child.parentData.y) && (y < child.parentData.y + child.height)) { | 635 (y >= child.parentData.y) && (y < child.parentData.y + child.height)) { |
| 596 if (child.handlePointer(event, x: x-child.parentData.x, y: y-child.paren tData.y)) | 636 if (child.hitTest(result, x: x-child.parentData.x, y: y-child.parentData .y)) |
| 597 return true; | 637 break; |
| 598 break; | |
| 599 } | 638 } |
| 600 child = child.parentData.previousSibling; | 639 child = child.parentData.previousSibling; |
| 601 } | 640 } |
| 602 return false; | |
| 603 } | 641 } |
| 604 | 642 |
| 605 void defaultPaint(RenderNodeDisplayList canvas) { | 643 void defaultPaint(RenderNodeDisplayList canvas) { |
| 606 RenderBox child = firstChild; | 644 RenderBox child = firstChild; |
| 607 while (child != null) { | 645 while (child != null) { |
| 608 assert(child.parentData is BoxParentData); | 646 assert(child.parentData is BoxParentData); |
| 609 canvas.paintChild(child, child.parentData.x, child.parentData.y); | 647 canvas.paintChild(child, child.parentData.x, child.parentData.y); |
| 610 child = child.parentData.nextSibling; | 648 child = child.parentData.nextSibling; |
| 611 } | 649 } |
| 612 } | 650 } |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 707 assert(child.parentData is BlockParentData); | 745 assert(child.parentData is BlockParentData); |
| 708 child.parentData.x = _padding.left; | 746 child.parentData.x = _padding.left; |
| 709 child.parentData.y = y; | 747 child.parentData.y = y; |
| 710 y += child.height; | 748 y += child.height; |
| 711 child = child.parentData.nextSibling; | 749 child = child.parentData.nextSibling; |
| 712 } | 750 } |
| 713 height = clamp(min: _minHeight, value: y + _padding.bottom, max: _maxHeight) ; | 751 height = clamp(min: _minHeight, value: y + _padding.bottom, max: _maxHeight) ; |
| 714 layoutDone(); | 752 layoutDone(); |
| 715 } | 753 } |
| 716 | 754 |
| 717 bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) { | 755 void hitTestChildren(HitTestResult result, { double x, double y }) { |
| 718 return defaultHandlePointer(event, x, y) || super.handlePointer(event, x: x, y: y); | 756 defaultHitTestChildren(result, x: x, y: y); |
| 719 } | 757 } |
| 720 | 758 |
| 721 void paint(RenderNodeDisplayList canvas) { | 759 void paint(RenderNodeDisplayList canvas) { |
| 722 super.paint(canvas); | 760 super.paint(canvas); |
| 723 defaultPaint(canvas); | 761 defaultPaint(canvas); |
| 724 } | 762 } |
| 725 | 763 |
| 726 } | 764 } |
| 727 | 765 |
| 728 // FLEXBOX LAYOUT MANAGER | 766 // FLEXBOX LAYOUT MANAGER |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 839 child.parentData.y = usedSpace; | 877 child.parentData.y = usedSpace; |
| 840 usedSpace += child.height; | 878 usedSpace += child.height; |
| 841 child.parentData.x = width / 2 - child.width / 2; | 879 child.parentData.x = width / 2 - child.width / 2; |
| 842 break; | 880 break; |
| 843 } | 881 } |
| 844 child = child.parentData.nextSibling; | 882 child = child.parentData.nextSibling; |
| 845 } | 883 } |
| 846 layoutDone(); | 884 layoutDone(); |
| 847 } | 885 } |
| 848 | 886 |
| 849 bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) { | 887 void hitTestChildren(HitTestResult result, { double x, double y }) { |
| 850 return defaultHandlePointer(event, x, y) || super.handlePointer(event, x: x, y: y); | 888 defaultHitTestChildren(result, x: x, y: y); |
| 851 } | 889 } |
| 852 | 890 |
| 853 void paint(RenderNodeDisplayList canvas) { | 891 void paint(RenderNodeDisplayList canvas) { |
| 854 super.paint(canvas); | 892 super.paint(canvas); |
| 855 defaultPaint(canvas); | 893 defaultPaint(canvas); |
| 856 } | 894 } |
| 857 } | 895 } |
| 858 | 896 |
| 859 // SCAFFOLD LAYOUT MANAGER | 897 // SCAFFOLD LAYOUT MANAGER |
| 860 | 898 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 895 statusbar.parentData.x = 0.0; | 933 statusbar.parentData.x = 0.0; |
| 896 statusbar.parentData.y = height - kStatusbarHeight; | 934 statusbar.parentData.y = height - kStatusbarHeight; |
| 897 bodyHeight -= kStatusbarHeight; | 935 bodyHeight -= kStatusbarHeight; |
| 898 } | 936 } |
| 899 body.layout(new BoxConstraints.tight(width: width, height: bodyHeight)); | 937 body.layout(new BoxConstraints.tight(width: width, height: bodyHeight)); |
| 900 if (drawer != null) | 938 if (drawer != null) |
| 901 drawer.layout(new BoxConstraints(minWidth: 0.0, maxWidth: width, minHeight : height, maxHeight: height)); | 939 drawer.layout(new BoxConstraints(minWidth: 0.0, maxWidth: width, minHeight : height, maxHeight: height)); |
| 902 layoutDone(); | 940 layoutDone(); |
| 903 } | 941 } |
| 904 | 942 |
| 905 bool handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) { | 943 void hitTestChildren(HitTestResult result, { double x, double y }) { |
| 906 if ((drawer != null) && (x < drawer.width)) { | 944 if ((drawer != null) && (x < drawer.width)) { |
| 907 if (drawer.handlePointer(event, x: x, y: y)) | 945 drawer.hitTest(result, x: x, y: y); |
| 908 return true; | |
| 909 } else if ((toolbar != null) && (y < toolbar.height)) { | 946 } else if ((toolbar != null) && (y < toolbar.height)) { |
| 910 if (toolbar.handlePointer(event, x: x, y: y)) | 947 toolbar.hitTest(result, x: x, y: y); |
| 911 return true; | |
| 912 } else if ((statusbar != null) && (y > (statusbar.parentData as BoxParentDat a).y)) { | 948 } else if ((statusbar != null) && (y > (statusbar.parentData as BoxParentDat a).y)) { |
| 913 if (statusbar.handlePointer(event, x: x, y: y-(statusbar.parentData as Box ParentData).y)) | 949 statusbar.hitTest(result, x: x, y: y-(statusbar.parentData as BoxParentDat a).y); |
| 914 return true; | |
| 915 } else { | 950 } else { |
| 916 if (body.handlePointer(event, x: x, y: y-(body.parentData as BoxParentData ).y)) | 951 body.hitTest(result, x: x, y: y-(body.parentData as BoxParentData).y); |
| 917 return true; | |
| 918 } | 952 } |
| 919 return super.handlePointer(event, x: x, y: y); | |
| 920 } | 953 } |
| 921 | 954 |
| 922 void paint(RenderNodeDisplayList canvas) { | 955 void paint(RenderNodeDisplayList canvas) { |
| 923 canvas.paintChild(body, (body.parentData as BoxParentData).x, (body.parentDa ta as BoxParentData).y); | 956 canvas.paintChild(body, (body.parentData as BoxParentData).x, (body.parentDa ta as BoxParentData).y); |
| 924 if (statusbar != null) | 957 if (statusbar != null) |
| 925 canvas.paintChild(statusbar, (statusbar.parentData as BoxParentData).x, (s tatusbar.parentData as BoxParentData).y); | 958 canvas.paintChild(statusbar, (statusbar.parentData as BoxParentData).x, (s tatusbar.parentData as BoxParentData).y); |
| 926 if (toolbar != null) | 959 if (toolbar != null) |
| 927 canvas.paintChild(toolbar, (toolbar.parentData as BoxParentData).x, (toolb ar.parentData as BoxParentData).y); | 960 canvas.paintChild(toolbar, (toolbar.parentData as BoxParentData).x, (toolb ar.parentData as BoxParentData).y); |
| 928 if (drawer != null) | 961 if (drawer != null) |
| 929 canvas.paintChild(drawer, (drawer.parentData as BoxParentData).x, (drawer. parentData as BoxParentData).y); | 962 canvas.paintChild(drawer, (drawer.parentData as BoxParentData).x, (drawer. parentData as BoxParentData).y); |
| 930 } | 963 } |
| 931 | 964 |
| 932 } | 965 } |
| OLD | NEW |