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 |