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

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

Issue 1169673002: Handle UINodes being moved around the Effen tree. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: make it work 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 | « no previous file | 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. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 library fn; 5 library fn;
6 6
7 import 'app.dart'; 7 import 'app.dart';
8 import 'dart:async'; 8 import 'dart:async';
9 import 'dart:collection'; 9 import 'dart:collection';
10 import 'dart:mirrors'; 10 import 'dart:mirrors';
11 import 'dart:sky' as sky; 11 import 'dart:sky' as sky;
12 import 'package:vector_math/vector_math.dart'; 12 import 'package:vector_math/vector_math.dart';
13 import 'reflect.dart' as reflect; 13 import 'reflect.dart' as reflect;
14 import 'rendering/block.dart'; 14 import 'rendering/block.dart';
15 import 'rendering/box.dart'; 15 import 'rendering/box.dart';
16 import 'rendering/flex.dart'; 16 import 'rendering/flex.dart';
17 import 'rendering/object.dart'; 17 import 'rendering/object.dart';
18 import 'rendering/paragraph.dart'; 18 import 'rendering/paragraph.dart';
19 import 'rendering/stack.dart'; 19 import 'rendering/stack.dart';
20 export 'rendering/object.dart' show Point, Size, Rect, Color, Paint, Path; 20 export 'rendering/object.dart' show Point, Size, Rect, Color, Paint, Path;
21 export 'rendering/box.dart' show BoxDecoration, Border, BorderSide, EdgeDims; 21 export 'rendering/box.dart' show BoxDecoration, Border, BorderSide, EdgeDims;
22 export 'rendering/flex.dart' show FlexDirection; 22 export 'rendering/flex.dart' show FlexDirection;
23 23
24 // final sky.Tracing _tracing = sky.window.tracing; 24 // final sky.Tracing _tracing = sky.window.tracing;
25 25
26 final bool _shouldLogRenderDuration = false; 26 final bool _shouldLogRenderDuration = false;
27 final bool _shouldTrace = false;
28
29 enum _SyncOperation { identical, insertion, stateful, stateless, removal }
30 27
31 /* 28 /*
32 * All Effen nodes derive from UINode. All nodes have a _parent, a _key and 29 * All Effen nodes derive from UINode. All nodes have a _parent, a _key and
33 * can be sync'd. 30 * can be sync'd.
34 */ 31 */
35 abstract class UINode { 32 abstract class UINode {
36 String _key;
37 UINode _parent;
38 UINode get parent => _parent;
39 RenderObject root;
40 bool _defunct = false;
41 33
42 UINode({ Object key }) { 34 UINode({ Object key }) {
43 _key = key == null ? "$runtimeType" : "$runtimeType-$key"; 35 _key = key == null ? "$runtimeType" : "$runtimeType-$key";
44 assert(this is App || _inRenderDirtyComponents); // you should not build the UI tree ahead of time, build it only during build() 36 assert(this is App || _inRenderDirtyComponents); // you should not build the UI tree ahead of time, build it only during build()
45 } 37 }
46 38
39 String _key;
40 String get key => _key;
41
42 UINode _parent;
43 UINode get parent => _parent;
44
45 bool _mounted = false;
46 bool _wasMounted = false;
47 bool get mounted => _mounted;
48 static bool _notifyingMountStatus = false;
49 static Set<UINode> _mountedChanged = new HashSet<UINode>();
50
51 void setParent(UINode newParent) {
52 assert(!_notifyingMountStatus);
53 _parent = newParent;
54 if (newParent == null) {
55 if (_mounted) {
56 _mounted = false;
57 _mountedChanged.add(this);
58 }
59 } else {
60 assert(newParent._mounted);
61 if (_parent._mounted != _mounted) {
62 _mounted = _parent._mounted;
63 _mountedChanged.add(this);
64 }
65 }
66 }
67
68 static void _notifyMountStatusChanged() {
69 try {
70 _notifyingMountStatus = true;
71 _mountedChanged.forEach((UINode node) {
abarth-chromium 2015/06/08 16:52:51 for (UINode node in _mountedChanged) { }
72 if (node._wasMounted != node._mounted) {
73 if (node._mounted)
74 node._didMount();
75 else
76 node._didUnmount();
77 node._wasMounted = node._mounted;
78 }
79 });
80 _mountedChanged.clear();
81 } finally {
82 _notifyingMountStatus = false;
83 }
84 }
85 void _didMount() { }
86 void _didUnmount() { }
87
88 RenderObject root;
89
47 // Subclasses which implements Nodes that become stateful may return true 90 // Subclasses which implements Nodes that become stateful may return true
48 // if the |old| node has become stateful and should be retained. 91 // if the |old| node has become stateful and should be retained.
49 bool _willSync(UINode old) => false; 92 bool _willSync(UINode old) => false;
50 93
51 bool get interchangeable => false; // if true, then keys can be duplicated 94 bool get interchangeable => false; // if true, then keys can be duplicated
52 95
53 void _sync(UINode old, dynamic slot); 96 void _sync(UINode old, dynamic slot);
54 // 'slot' is the identifier that the parent RenderObjectWrapper uses to know 97 // 'slot' is the identifier that the parent RenderObjectWrapper uses to know
55 // where to put this descendant 98 // where to put this descendant
56 99
57 void remove() { 100 void remove() {
58 _defunct = true;
59 root = null; 101 root = null;
60 handleRemoved(); 102 setParent(null);
61 } 103 }
62 void handleRemoved() { }
63 104
64 UINode findAncestor(Type targetType) { 105 UINode findAncestor(Type targetType) {
65 var ancestor = _parent; 106 var ancestor = _parent;
66 while (ancestor != null && !reflectClass(ancestor.runtimeType).isSubtypeOf(r eflectClass(targetType))) 107 while (ancestor != null && !reflectClass(ancestor.runtimeType).isSubtypeOf(r eflectClass(targetType)))
67 ancestor = ancestor._parent; 108 ancestor = ancestor._parent;
68 return ancestor; 109 return ancestor;
69 } 110 }
70 111
71 int _nodeDepth;
72 void _ensureDepth() {
73 if (_nodeDepth == null) {
74 if (_parent != null) {
75 _parent._ensureDepth();
76 _nodeDepth = _parent._nodeDepth + 1;
77 } else {
78 _nodeDepth = 0;
79 }
80 }
81 }
82
83 void _trace(String message) {
84 if (!_shouldTrace)
85 return;
86
87 _ensureDepth();
88 print((' ' * _nodeDepth) + message);
89 }
90
91 void _traceSync(_SyncOperation op, String key) {
92 if (!_shouldTrace)
93 return;
94
95 String opString = op.toString().toLowerCase();
96 String outString = opString.substring(opString.indexOf('.') + 1);
97 _trace('_sync($outString) $key');
98 }
99
100 void removeChild(UINode node) { 112 void removeChild(UINode node) {
101 _traceSync(_SyncOperation.removal, node._key);
102 node.remove(); 113 node.remove();
103 } 114 }
104 115
105 // Returns the child which should be retained as the child of this node. 116 // Returns the child which should be retained as the child of this node.
106 UINode syncChild(UINode node, UINode oldNode, dynamic slot) { 117 UINode syncChild(UINode node, UINode oldNode, dynamic slot) {
118
107 if (node == oldNode) { 119 if (node == oldNode) {
108 _traceSync(_SyncOperation.identical, node == null ? '*null*' : node._key); 120 assert(node == null || node.mounted);
109 return node; // Nothing to do. Subtrees must be identical. 121 return node; // Nothing to do. Subtrees must be identical.
110 } 122 }
111 123
112 if (node == null) { 124 if (node == null) {
113 // the child in this slot has gone away 125 // the child in this slot has gone away
126 assert(oldNode.mounted);
114 removeChild(oldNode); 127 removeChild(oldNode);
128 assert(!oldNode.mounted);
115 return null; 129 return null;
116 } 130 }
117 assert(oldNode == null || node._key == oldNode._key);
118 131
119 // TODO(rafaelw): This eagerly removes the old DOM. It may be that a 132 if (oldNode != null && node._key == oldNode._key && node._willSync(oldNode)) {
120 // new component was built that could re-use some of it. Consider 133 assert(oldNode.mounted);
121 // syncing the new VDOM against the old one. 134 assert(!node.mounted);
122 if (oldNode != null && node._key != oldNode._key) {
123 removeChild(oldNode);
124 }
125
126 if (node._willSync(oldNode)) {
127 _traceSync(_SyncOperation.stateful, node._key);
128 oldNode._sync(node, slot); 135 oldNode._sync(node, slot);
129 node._defunct = true;
130 assert(oldNode.root is RenderObject); 136 assert(oldNode.root is RenderObject);
131 return oldNode; 137 return oldNode;
132 } 138 }
133 139
134 assert(!node._defunct); 140 if (oldNode != null && node._key != oldNode._key) {
135 node._parent = this; 141 assert(oldNode.mounted);
142 removeChild(oldNode);
143 oldNode = null;
144 }
136 145
137 if (oldNode == null) { 146 assert(!node.mounted);
138 _traceSync(_SyncOperation.insertion, node._key); 147 node.setParent(this);
139 } else {
140 _traceSync(_SyncOperation.stateless, node._key);
141 }
142 node._sync(oldNode, slot); 148 node._sync(oldNode, slot);
143 if (oldNode != null)
144 oldNode._defunct = true;
145
146 assert(node.root is RenderObject); 149 assert(node.root is RenderObject);
147 return node; 150 return node;
148 } 151 }
149 } 152 }
150 153
151 abstract class ContentNode extends UINode { 154 abstract class ContentNode extends UINode {
152 UINode content; 155 UINode content;
153 156
154 ContentNode(UINode content) : this.content = content, super(key: content._key) ; 157 ContentNode(UINode content) : this.content = content, super(key: content._key) ;
155 158
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 280
278 RenderObjectWrapper({ 281 RenderObjectWrapper({
279 Object key 282 Object key
280 }) : super(key: key); 283 }) : super(key: key);
281 284
282 RenderObject createNode(); 285 RenderObject createNode();
283 286
284 void insert(RenderObjectWrapper child, dynamic slot); 287 void insert(RenderObjectWrapper child, dynamic slot);
285 288
286 void _sync(UINode old, dynamic slot) { 289 void _sync(UINode old, dynamic slot) {
290 assert(parent != null);
287 if (old == null) { 291 if (old == null) {
288 root = createNode(); 292 root = createNode();
289 assert(root != null); 293 assert(root != null);
290 var ancestor = findAncestor(RenderObjectWrapper); 294 var ancestor = findAncestor(RenderObjectWrapper);
291 if (ancestor is RenderObjectWrapper) 295 if (ancestor is RenderObjectWrapper)
292 ancestor.insert(this, slot); 296 ancestor.insert(this, slot);
293 } else { 297 } else {
294 root = old.root; 298 root = old.root;
295 assert(root != null);
296 } 299 }
297 300 assert(mounted);
301 assert(root != null);
298 _nodeMap[root] = this; 302 _nodeMap[root] = this;
299 syncRenderObject(old); 303 syncRenderObject(old);
300 } 304 }
301 305
302 void syncRenderObject(RenderObjectWrapper old) { 306 void syncRenderObject(RenderObjectWrapper old) {
303 ParentData parentData = null; 307 ParentData parentData = null;
304 UINode parent = _parent; 308 UINode ancestor = parent;
305 while (parent != null && parent is! RenderObjectWrapper) { 309 while (ancestor != null && ancestor is! RenderObjectWrapper) {
306 if (parent is ParentDataNode && parent.parentData != null) { 310 if (ancestor is ParentDataNode && ancestor.parentData != null) {
307 if (parentData != null) 311 if (parentData != null)
308 parentData.merge(parent.parentData); // this will throw if the types a ren't the same 312 parentData.merge(ancestor.parentData); // this will throw if the types aren't the same
309 else 313 else
310 parentData = parent.parentData; 314 parentData = ancestor.parentData;
311 } 315 }
312 parent = parent._parent; 316 ancestor = ancestor.parent;
313 } 317 }
314 if (parentData != null) { 318 if (parentData != null) {
315 assert(root.parentData != null); 319 assert(root.parentData != null);
316 root.parentData.merge(parentData); // this will throw if the types aren't approriate 320 root.parentData.merge(parentData); // this will throw if the types aren't appropriate
317 assert(parent != null); 321 if (parent.root != null)
318 assert(parent.root != null); 322 parent.root.markNeedsLayout();
319 parent.root.markNeedsLayout();
320 } 323 }
321 } 324 }
322 325
323 void remove() { 326 void remove() {
324 assert(root != null); 327 assert(root != null);
325 _nodeMap.remove(root); 328 _nodeMap.remove(root);
326 super.remove(); 329 super.remove();
327 } 330 }
328 } 331 }
329 332
(...skipping 404 matching lines...) Expand 10 before | Expand all | Expand 10 after
734 root.src = src; 737 root.src = src;
735 root.requestedSize = size; 738 root.requestedSize = size;
736 } 739 }
737 740
738 void insert(RenderObjectWrapper child, dynamic slot) { 741 void insert(RenderObjectWrapper child, dynamic slot) {
739 assert(false); 742 assert(false);
740 // Image does not support having children currently 743 // Image does not support having children currently
741 } 744 }
742 } 745 }
743 746
744
745 Set<Component> _mountedComponents = new HashSet<Component>();
746 Set<Component> _unmountedComponents = new HashSet<Component>();
747
748 void _enqueueDidMount(Component c) {
749 assert(!_notifingMountStatus);
750 _mountedComponents.add(c);
751 }
752
753 void _enqueueDidUnmount(Component c) {
754 assert(!_notifingMountStatus);
755 _unmountedComponents.add(c);
756 }
757
758 bool _notifingMountStatus = false;
759
760 void _notifyMountStatusChanged() {
761 try {
762 _notifingMountStatus = true;
763 _unmountedComponents.forEach((c) => c._didUnmount());
764 _mountedComponents.forEach((c) => c._didMount());
765 _mountedComponents.clear();
766 _unmountedComponents.clear();
767 } finally {
768 _notifingMountStatus = false;
769 }
770 }
771
772 List<Component> _dirtyComponents = new List<Component>(); 747 List<Component> _dirtyComponents = new List<Component>();
773 bool _buildScheduled = false; 748 bool _buildScheduled = false;
774 bool _inRenderDirtyComponents = false; 749 bool _inRenderDirtyComponents = false;
775 750
776 void _buildDirtyComponents() { 751 void _buildDirtyComponents() {
777 //_tracing.begin('fn::_buildDirtyComponents'); 752 //_tracing.begin('fn::_buildDirtyComponents');
778 753
779 Stopwatch sw; 754 Stopwatch sw;
780 if (_shouldLogRenderDuration) 755 if (_shouldLogRenderDuration)
781 sw = new Stopwatch()..start(); 756 sw = new Stopwatch()..start();
782 757
783 try { 758 try {
784 _inRenderDirtyComponents = true; 759 _inRenderDirtyComponents = true;
785 760
786 _dirtyComponents.sort((a, b) => a._order - b._order); 761 _dirtyComponents.sort((a, b) => a._order - b._order);
787 for (var comp in _dirtyComponents) { 762 for (var comp in _dirtyComponents) {
788 comp._buildIfDirty(); 763 comp._buildIfDirty();
789 } 764 }
790 765
791 _dirtyComponents.clear(); 766 _dirtyComponents.clear();
792 _buildScheduled = false; 767 _buildScheduled = false;
793 } finally { 768 } finally {
794 _inRenderDirtyComponents = false; 769 _inRenderDirtyComponents = false;
795 } 770 }
796 771
797 _notifyMountStatusChanged(); 772 UINode._notifyMountStatusChanged();
798 773
799 if (_shouldLogRenderDuration) { 774 if (_shouldLogRenderDuration) {
800 sw.stop(); 775 sw.stop();
801 print('Render took ${sw.elapsedMicroseconds} microseconds'); 776 print('Render took ${sw.elapsedMicroseconds} microseconds');
802 } 777 }
803 778
804 //_tracing.end('fn::_buildDirtyComponents'); 779 //_tracing.end('fn::_buildDirtyComponents');
805 } 780 }
806 781
807 void _scheduleComponentForRender(Component c) { 782 void _scheduleComponentForRender(Component c) {
(...skipping 26 matching lines...) Expand all
834 _mountCallbacks.add(fn); 809 _mountCallbacks.add(fn);
835 } 810 }
836 811
837 void onDidUnmount(Function fn) { 812 void onDidUnmount(Function fn) {
838 if (_unmountCallbacks == null) 813 if (_unmountCallbacks == null)
839 _unmountCallbacks = new List<Function>(); 814 _unmountCallbacks = new List<Function>();
840 815
841 _unmountCallbacks.add(fn); 816 _unmountCallbacks.add(fn);
842 } 817 }
843 818
844
845 Component({ Object key, bool stateful }) 819 Component({ Object key, bool stateful })
846 : _stateful = stateful != null ? stateful : false, 820 : _stateful = stateful != null ? stateful : false,
847 _order = _currentOrder + 1, 821 _order = _currentOrder + 1,
848 super(key: key); 822 super(key: key);
849 823
850 Component.fromArgs(Object key, bool stateful) 824 Component.fromArgs(Object key, bool stateful)
851 : this(key: key, stateful: stateful); 825 : this(key: key, stateful: stateful);
852 826
853 void _didMount() { 827 void _didMount() {
828 super._didMount();
854 if (_mountCallbacks != null) 829 if (_mountCallbacks != null)
855 _mountCallbacks.forEach((fn) => fn()); 830 _mountCallbacks.forEach((fn) => fn());
856 } 831 }
857 832
858 void _didUnmount() { 833 void _didUnmount() {
834 super._didUnmount();
859 if (_unmountCallbacks != null) 835 if (_unmountCallbacks != null)
860 _unmountCallbacks.forEach((fn) => fn()); 836 _unmountCallbacks.forEach((fn) => fn());
861 } 837 }
862 838
863 // TODO(rafaelw): It seems wrong to expose DOM at all. This is presently 839 // TODO(rafaelw): It seems wrong to expose DOM at all. This is presently
864 // needed to get sizing info. 840 // needed to get sizing info.
865 RenderObject getRoot() => root; 841 RenderObject getRoot() => root;
866 842
867 void remove() { 843 void remove() {
868 assert(_built != null); 844 assert(_built != null);
869 assert(root != null); 845 assert(root != null);
870 removeChild(_built); 846 removeChild(_built);
871 _built = null; 847 _built = null;
872 _enqueueDidUnmount(this);
873 super.remove(); 848 super.remove();
874 } 849 }
875 850
876 bool _willSync(UINode old) { 851 bool _willSync(UINode old) {
877 Component oldComponent = old as Component; 852 Component oldComponent = old as Component;
878 if (oldComponent == null || !oldComponent._stateful) 853 if (oldComponent == null || !oldComponent._stateful)
879 return false; 854 return false;
880 855
881 // Make |this| the "old" Component 856 // Make |this| the "old" Component
882 _stateful = false; 857 _stateful = false;
883 _built = oldComponent._built; 858 _built = oldComponent._built;
884 assert(_built != null); 859 assert(_built != null);
885 860
886 // Make |oldComponent| the "new" component 861 // Make |oldComponent| the "new" component
887 reflect.copyPublicFields(this, oldComponent); 862 reflect.copyPublicFields(this, oldComponent);
888 oldComponent._built = null; 863 oldComponent._built = null;
889 oldComponent._dirty = true; 864 oldComponent._dirty = true;
890 return true; 865 return true;
891 } 866 }
892 867
893 /* There are three cases here: 868 /* There are three cases here:
894 * 1) Building for the first time: 869 * 1) Building for the first time:
895 * assert(_built == null && old == null) 870 * assert(_built == null && old == null)
896 * 2) Re-building (because a dirty flag got set): 871 * 2) Re-building (because a dirty flag got set):
897 * assert(_built != null && old == null) 872 * assert(_built != null && old == null)
898 * 3) Syncing against an old version 873 * 3) Syncing against an old version
899 * assert(_built == null && old != null) 874 * assert(_built == null && old != null)
900 */ 875 */
901 void _sync(UINode old, dynamic slot) { 876 void _sync(UINode old, dynamic slot) {
902 assert(!_defunct);
903 assert(_built == null || old == null); 877 assert(_built == null || old == null);
904 878
905 Component oldComponent = old as Component; 879 Component oldComponent = old as Component;
906 880
907 _slot = slot; 881 _slot = slot;
908 882
909 var oldBuilt; 883 var oldBuilt;
910 if (oldComponent == null) { 884 if (oldComponent == null) {
911 oldBuilt = _built; 885 oldBuilt = _built;
912 } else { 886 } else {
913 assert(_built == null); 887 assert(_built == null);
914 oldBuilt = oldComponent._built; 888 oldBuilt = oldComponent._built;
915 } 889 }
916 890
917 if (oldBuilt == null)
918 _enqueueDidMount(this);
919
920 int lastOrder = _currentOrder; 891 int lastOrder = _currentOrder;
921 _currentOrder = _order; 892 _currentOrder = _order;
922 _currentlyBuilding = this; 893 _currentlyBuilding = this;
923 _built = build(); 894 _built = build();
895 assert(_built != null);
924 _currentlyBuilding = null; 896 _currentlyBuilding = null;
925 _currentOrder = lastOrder; 897 _currentOrder = lastOrder;
926 898
927 _built = syncChild(_built, oldBuilt, slot); 899 _built = syncChild(_built, oldBuilt, slot);
900 assert(_built != null);
928 _dirty = false; 901 _dirty = false;
929 root = _built.root; 902 root = _built.root;
930 assert(root != null); 903 assert(root != null);
931 } 904 }
932 905
933 void _buildIfDirty() { 906 void _buildIfDirty() {
934 if (!_dirty || _defunct) 907 if (!_dirty || !_mounted)
935 return; 908 return;
936 909
937 _trace('$_key rebuilding...');
938 assert(root != null); 910 assert(root != null);
939 _sync(null, _slot); 911 _sync(null, _slot);
940 } 912 }
941 913
942 void scheduleBuild() { 914 void scheduleBuild() {
943 setState(() {}); 915 setState(() {});
944 } 916 }
945 917
946 void setState(Function fn()) { 918 void setState(Function fn()) {
947 _stateful = true; 919 _stateful = true;
948 fn(); 920 fn();
949 if (_isBuilding || _dirty || _defunct) 921 if (_isBuilding || _dirty || !_mounted)
950 return; 922 return;
951 923
952 _dirty = true; 924 _dirty = true;
953 _scheduleComponentForRender(this); 925 _scheduleComponentForRender(this);
954 } 926 }
955 927
956 UINode build(); 928 UINode build();
957 } 929 }
958 930
959 class Container extends Component { 931 class Container extends Component {
(...skipping 11 matching lines...) Expand all
971 this.margin, 943 this.margin,
972 this.decoration, 944 this.decoration,
973 this.desiredSize, 945 this.desiredSize,
974 this.padding 946 this.padding
975 }) : super(key: key); 947 }) : super(key: key);
976 948
977 UINode build() { 949 UINode build() {
978 UINode current = child; 950 UINode current = child;
979 951
980 if (padding != null) 952 if (padding != null)
981 current = new Padding(padding: padding, child: current); 953 current = new Padding(padding: padding, child: current, key: '$key-padding ');
982 954
983 if (decoration != null) 955 if (decoration != null)
984 current = new DecoratedBox(decoration: decoration, child: current); 956 current = new DecoratedBox(decoration: decoration, child: current, key: '$ key-decoration');
985 957
986 if (desiredSize != null) 958 if (desiredSize != null)
987 current = new SizedBox(desiredSize: desiredSize, child: current); 959 current = new SizedBox(desiredSize: desiredSize, child: current, key: '$ke y-size');
988 960
989 if (margin != null) 961 if (margin != null)
990 current = new Padding(padding: margin, child: current); 962 current = new Padding(padding: margin, child: current, key: '$key-margin') ;
991 963
992 if (transform != null) 964 if (transform != null)
993 current = new Transform(transform: transform, child: current); 965 current = new Transform(transform: transform, child: current, key: '$key-t ransform');
994 966
995 return current; 967 return current;
996 } 968 }
997 } 969 }
998 970
999 class _AppView extends AppView { 971 class _AppView extends AppView {
1000 _AppView() : super(null); 972 _AppView() : super(null);
1001 973
1002 void dispatchEvent(sky.Event event, HitTestResult result) { 974 void dispatchEvent(sky.Event event, HitTestResult result) {
1003 super.dispatchEvent(event, result); 975 super.dispatchEvent(event, result);
1004 976
1005 UINode target = RenderObjectWrapper._getMounted(result.path.first); 977 UINode target = RenderObjectWrapper._getMounted(result.path.first);
1006 978
1007 // TODO(rafaelw): StopPropagation? 979 // TODO(rafaelw): StopPropagation?
1008 while (target != null) { 980 while (target != null) {
1009 if (target is EventListenerNode) 981 if (target is EventListenerNode)
1010 target._handleEvent(event); 982 target._handleEvent(event);
1011 target = target._parent; 983 target = target._parent;
1012 } 984 }
1013 } 985 }
1014 } 986 }
1015 987
1016 abstract class App extends Component { 988 abstract class App extends Component {
1017 989
1018 App() : super(stateful: true) { 990 App() : super(stateful: true) {
1019 _appView = new _AppView(); 991 _appView = new _AppView();
1020 _scheduleComponentForRender(this); 992 _scheduleComponentForRender(this);
993 _mounted = true;
1021 } 994 }
1022 995
1023 AppView _appView; 996 AppView _appView;
1024 AppView get appView => _appView; 997 AppView get appView => _appView;
1025 998
1026 void _buildIfDirty() { 999 void _buildIfDirty() {
1027 assert(_dirty); 1000 assert(_dirty);
1028 assert(!_defunct); 1001 assert(_mounted);
1029 _trace('$_key rebuilding app...');
1030 _sync(null, null); 1002 _sync(null, null);
1031 if (root.parent == null) 1003 if (root.parent == null)
1032 _appView.root = root; 1004 _appView.root = root;
1033 assert(root.parent is RenderView); 1005 assert(root.parent is RenderView);
1034 } 1006 }
1035 } 1007 }
1036 1008
1037 class Text extends Component { 1009 class Text extends Component {
1038 Text(this.data) : super(key: '*text*'); 1010 Text(this.data) : super(key: '*text*');
1039 final String data; 1011 final String data;
1040 bool get interchangeable => true; 1012 bool get interchangeable => true;
1041 UINode build() => new Paragraph(text: data); 1013 UINode build() => new Paragraph(text: data);
1042 } 1014 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698