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

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

Issue 1143343004: Rationalise hit testing in the new RenderNode world (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 6 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
« no previous file with comments | « sky/sdk/lib/framework/app.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « sky/sdk/lib/framework/app.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698