OLD | NEW |
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 import 'dart:async'; | 5 import 'dart:async'; |
6 import 'dart:collection'; | 6 import 'dart:collection'; |
7 import 'dart:mirrors'; | 7 import 'dart:mirrors'; |
8 import 'dart:sky' as sky; | 8 import 'dart:sky' as sky; |
9 | 9 |
10 import '../base/hit_test.dart'; | 10 import '../base/hit_test.dart'; |
11 import '../rendering/box.dart'; | 11 import '../rendering/box.dart'; |
12 import '../rendering/object.dart'; | 12 import '../rendering/object.dart'; |
13 import '../rendering/sky_binding.dart'; | 13 import '../rendering/sky_binding.dart'; |
14 | 14 |
15 export '../rendering/box.dart' show BoxConstraints, BoxDecoration, Border, Borde
rSide, EdgeDims; | 15 export '../rendering/box.dart' show BoxConstraints, BoxDecoration, Border, Borde
rSide, EdgeDims; |
16 export '../rendering/flex.dart' show FlexDirection; | 16 export '../rendering/flex.dart' show FlexDirection; |
17 export '../rendering/object.dart' show Point, Size, Rect, Color, Paint, Path; | 17 export '../rendering/object.dart' show Point, Size, Rect, Color, Paint, Path; |
18 | 18 |
19 final bool _shouldLogRenderDuration = false; | 19 final bool _shouldLogRenderDuration = false; |
20 | 20 |
| 21 typedef void WidgetTreeWalker(Widget); |
| 22 |
21 // All Effen nodes derive from Widget. All nodes have a _parent, a _key and | 23 // All Effen nodes derive from Widget. All nodes have a _parent, a _key and |
22 // can be sync'd. | 24 // can be sync'd. |
23 abstract class Widget { | 25 abstract class Widget { |
24 | 26 |
25 Widget({ String key }) : _key = key { | 27 Widget({ String key }) : _key = key { |
26 assert(this is AbstractWidgetRoot || this is App || _inRenderDirtyComponents
); // you should not build the UI tree ahead of time, build it only during build
() | 28 assert(_isConstructedDuringBuild()); |
27 } | 29 } |
28 | 30 |
| 31 // TODO(jackson): Remove this workaround for limitation of Dart mixins |
| 32 Widget._withKey(String key) : _key = key { |
| 33 assert(_isConstructedDuringBuild()); |
| 34 } |
| 35 |
| 36 // you should not build the UI tree ahead of time, build it only during build(
) |
| 37 bool _isConstructedDuringBuild() => this is AbstractWidgetRoot || this is App
|| _inRenderDirtyComponents; |
| 38 |
29 String _key; | 39 String _key; |
30 String get key => _key; | 40 String get key => _key; |
31 | 41 |
32 Widget _parent; | 42 Widget _parent; |
33 Widget get parent => _parent; | 43 Widget get parent => _parent; |
34 | 44 |
35 bool _mounted = false; | 45 bool _mounted = false; |
36 bool _wasMounted = false; | 46 bool _wasMounted = false; |
37 bool get mounted => _mounted; | 47 bool get mounted => _mounted; |
38 static bool _notifyingMountStatus = false; | 48 static bool _notifyingMountStatus = false; |
39 static Set<Widget> _mountedChanged = new HashSet<Widget>(); | 49 static Set<Widget> _mountedChanged = new HashSet<Widget>(); |
40 | 50 |
41 void setParent(Widget newParent) { | 51 void setParent(Widget newParent) { |
42 assert(!_notifyingMountStatus); | 52 assert(!_notifyingMountStatus); |
43 _parent = newParent; | 53 _parent = newParent; |
44 if (newParent == null) { | 54 if (newParent == null) { |
45 if (_mounted) { | 55 if (_mounted) { |
46 _mounted = false; | 56 _mounted = false; |
47 _mountedChanged.add(this); | 57 _mountedChanged.add(this); |
48 } | 58 } |
49 } else { | 59 } else { |
50 assert(newParent._mounted); | 60 assert(newParent._mounted); |
51 if (_parent._mounted != _mounted) { | 61 if (_parent._mounted != _mounted) { |
52 _mounted = _parent._mounted; | 62 _mounted = _parent._mounted; |
53 _mountedChanged.add(this); | 63 _mountedChanged.add(this); |
54 } | 64 } |
55 } | 65 } |
56 } | 66 } |
57 | 67 |
| 68 // Override this if you have children and call walker on each child |
| 69 void walkChildren(WidgetTreeWalker walker) { } |
| 70 |
58 static void _notifyMountStatusChanged() { | 71 static void _notifyMountStatusChanged() { |
59 try { | 72 try { |
60 sky.tracing.begin("Widget._notifyMountStatusChanged"); | 73 sky.tracing.begin("Widget._notifyMountStatusChanged"); |
61 _notifyingMountStatus = true; | 74 _notifyingMountStatus = true; |
62 for (Widget node in _mountedChanged) { | 75 for (Widget node in _mountedChanged) { |
63 if (node._wasMounted != node._mounted) { | 76 if (node._wasMounted != node._mounted) { |
64 if (node._mounted) | 77 if (node._mounted) |
65 node.didMount(); | 78 node.didMount(); |
66 else | 79 else |
67 node.didUnmount(); | 80 node.didUnmount(); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 | 177 |
165 | 178 |
166 // Descendants of TagNode provide a way to tag RenderObjectWrapper and | 179 // Descendants of TagNode provide a way to tag RenderObjectWrapper and |
167 // Component nodes with annotations, such as event listeners, | 180 // Component nodes with annotations, such as event listeners, |
168 // stylistic information, etc. | 181 // stylistic information, etc. |
169 abstract class TagNode extends Widget { | 182 abstract class TagNode extends Widget { |
170 | 183 |
171 TagNode(Widget child, { String key }) | 184 TagNode(Widget child, { String key }) |
172 : this.child = child, super(key: key); | 185 : this.child = child, super(key: key); |
173 | 186 |
| 187 // TODO(jackson): Remove this workaround for limitation of Dart mixins |
| 188 TagNode._withKey(Widget child, String key) |
| 189 : this.child = child, super._withKey(key); |
| 190 |
174 Widget child; | 191 Widget child; |
175 | 192 |
| 193 void walkChildren(WidgetTreeWalker walker) { |
| 194 walker(child); |
| 195 } |
| 196 |
176 void _sync(Widget old, dynamic slot) { | 197 void _sync(Widget old, dynamic slot) { |
177 Widget oldChild = old == null ? null : (old as TagNode).child; | 198 Widget oldChild = old == null ? null : (old as TagNode).child; |
178 child = syncChild(child, oldChild, slot); | 199 child = syncChild(child, oldChild, slot); |
179 assert(child.root != null); | 200 assert(child.root != null); |
180 _root = child.root; | 201 _root = child.root; |
181 assert(_root == root); // in case a subclass reintroduces it | 202 assert(_root == root); // in case a subclass reintroduces it |
182 } | 203 } |
183 | 204 |
184 void remove() { | 205 void remove() { |
185 if (child != null) | 206 if (child != null) |
186 removeChild(child); | 207 removeChild(child); |
187 super.remove(); | 208 super.remove(); |
188 } | 209 } |
189 | 210 |
190 void detachRoot() { | 211 void detachRoot() { |
191 if (child != null) | 212 if (child != null) |
192 child.detachRoot(); | 213 child.detachRoot(); |
193 } | 214 } |
194 | 215 |
195 } | 216 } |
196 | 217 |
197 class ParentDataNode extends TagNode { | 218 class ParentDataNode extends TagNode { |
198 ParentDataNode(Widget child, this.parentData, { String key }) | 219 ParentDataNode(Widget child, this.parentData, { String key }) |
199 : super(child, key: key); | 220 : super(child, key: key); |
200 final ParentData parentData; | 221 final ParentData parentData; |
201 } | 222 } |
202 | 223 |
| 224 abstract class _Heir implements Widget { |
| 225 Map<Type, Inherited> _traits; |
| 226 Inherited inheritedOfType(Type type) => _traits[type]; |
| 227 |
| 228 static _Heir _getHeirAncestor(Widget widget) { |
| 229 Widget ancestor = widget; |
| 230 while (ancestor != null && !(ancestor is _Heir)) { |
| 231 ancestor = ancestor.parent; |
| 232 } |
| 233 return ancestor as _Heir; |
| 234 } |
| 235 |
| 236 void _updateTraitsFromParent(Widget parent) { |
| 237 _Heir ancestor = _getHeirAncestor(parent); |
| 238 if (ancestor == null || ancestor._traits == null) return; |
| 239 _updateTraits(ancestor._traits); |
| 240 } |
| 241 |
| 242 void _updateTraitsRecursively(Widget widget) { |
| 243 if (widget is _Heir) |
| 244 widget._updateTraits(_traits); |
| 245 else |
| 246 widget.walkChildren(_updateTraitsRecursively); |
| 247 } |
| 248 |
| 249 void _updateTraits(Map<Type, Inherited> newTraits) { |
| 250 if (newTraits != _traits) { |
| 251 _traits = newTraits; |
| 252 walkChildren(_updateTraitsRecursively); |
| 253 } |
| 254 } |
| 255 } |
| 256 |
| 257 abstract class Inherited extends TagNode with _Heir { |
| 258 Inherited({ String key, Widget child }) : super._withKey(child, key) { |
| 259 _traits = new Map<Type, Inherited>(); |
| 260 } |
| 261 |
| 262 void set _traits(Map<Type, Inherited> value) { |
| 263 super._traits = new Map<Type, Inherited>.from(value) |
| 264 ..[runtimeType] = this; |
| 265 } |
| 266 |
| 267 // TODO(jackson): When Dart supports super in mixins we can move to _Heir |
| 268 void setParent(Widget parent) { |
| 269 _updateTraitsFromParent(parent); |
| 270 super.setParent(parent); |
| 271 } |
| 272 } |
| 273 |
203 typedef void GestureEventListener(sky.GestureEvent e); | 274 typedef void GestureEventListener(sky.GestureEvent e); |
204 typedef void PointerEventListener(sky.PointerEvent e); | 275 typedef void PointerEventListener(sky.PointerEvent e); |
205 typedef void EventListener(sky.Event e); | 276 typedef void EventListener(sky.Event e); |
206 | 277 |
207 class Listener extends TagNode { | 278 class Listener extends TagNode { |
208 | 279 |
209 Listener({ | 280 Listener({ |
210 Widget child, | 281 Widget child, |
211 EventListener onWheel, | 282 EventListener onWheel, |
212 GestureEventListener onGestureFlingCancel, | 283 GestureEventListener onGestureFlingCancel, |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
284 | 355 |
285 void _handleEvent(sky.Event e) { | 356 void _handleEvent(sky.Event e) { |
286 sky.EventListener listener = listeners[e.type]; | 357 sky.EventListener listener = listeners[e.type]; |
287 if (listener != null) { | 358 if (listener != null) { |
288 listener(e); | 359 listener(e); |
289 } | 360 } |
290 } | 361 } |
291 | 362 |
292 } | 363 } |
293 | 364 |
294 | 365 abstract class Component extends Widget with _Heir { |
295 abstract class Component extends Widget { | |
296 | 366 |
297 Component({ String key, bool stateful }) | 367 Component({ String key, bool stateful }) |
298 : _stateful = stateful != null ? stateful : false, | 368 : _stateful = stateful != null ? stateful : false, |
299 _order = _currentOrder + 1, | 369 _order = _currentOrder + 1, |
300 super(key: key); | 370 super._withKey(key); |
301 | 371 |
302 static Component _currentlyBuilding; | 372 static Component _currentlyBuilding; |
303 bool get _isBuilding => _currentlyBuilding == this; | 373 bool get _isBuilding => _currentlyBuilding == this; |
304 | 374 |
305 bool _stateful; | 375 bool _stateful; |
306 bool _dirty = true; | 376 bool _dirty = true; |
307 bool _disqualifiedFromEverAppearingAgain = false; | 377 bool _disqualifiedFromEverAppearingAgain = false; |
308 | 378 |
309 Widget _built; | 379 Widget _built; |
310 dynamic _slot; // cached slot from the last time we were synced | 380 dynamic _slot; // cached slot from the last time we were synced |
311 | 381 |
312 void didMount() { | 382 void didMount() { |
313 assert(!_disqualifiedFromEverAppearingAgain); | 383 assert(!_disqualifiedFromEverAppearingAgain); |
314 super.didMount(); | 384 super.didMount(); |
315 } | 385 } |
316 | 386 |
| 387 // TODO(jackson): When Dart supports super in mixins we can move to _Heir |
| 388 void setParent(Widget parent) { |
| 389 _updateTraitsFromParent(parent); |
| 390 super.setParent(parent); |
| 391 } |
| 392 |
317 void remove() { | 393 void remove() { |
318 assert(_built != null); | 394 assert(_built != null); |
319 assert(root != null); | 395 assert(root != null); |
320 removeChild(_built); | 396 removeChild(_built); |
321 _built = null; | 397 _built = null; |
322 super.remove(); | 398 super.remove(); |
323 } | 399 } |
324 | 400 |
325 void detachRoot() { | 401 void detachRoot() { |
326 assert(_built != null); | 402 assert(_built != null); |
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
566 } | 642 } |
567 | 643 |
568 abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper { | 644 abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper { |
569 | 645 |
570 OneChildRenderObjectWrapper({ String key, Widget child }) | 646 OneChildRenderObjectWrapper({ String key, Widget child }) |
571 : _child = child, super(key: key); | 647 : _child = child, super(key: key); |
572 | 648 |
573 Widget _child; | 649 Widget _child; |
574 Widget get child => _child; | 650 Widget get child => _child; |
575 | 651 |
| 652 void walkChildren(WidgetTreeWalker walker) { |
| 653 walker(child); |
| 654 } |
| 655 |
576 void syncRenderObject(RenderObjectWrapper old) { | 656 void syncRenderObject(RenderObjectWrapper old) { |
577 super.syncRenderObject(old); | 657 super.syncRenderObject(old); |
578 Widget oldChild = old == null ? null : (old as OneChildRenderObjectWrapper).
child; | 658 Widget oldChild = old == null ? null : (old as OneChildRenderObjectWrapper).
child; |
579 _child = syncChild(child, oldChild, null); | 659 _child = syncChild(child, oldChild, null); |
580 } | 660 } |
581 | 661 |
582 void insertChildRoot(RenderObjectWrapper child, dynamic slot) { | 662 void insertChildRoot(RenderObjectWrapper child, dynamic slot) { |
583 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer | 663 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer |
584 assert(root is RenderObjectWithChildMixin); | 664 assert(root is RenderObjectWithChildMixin); |
585 assert(slot == null); | 665 assert(slot == null); |
586 root.child = child.root; | 666 root.child = child.root; |
587 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer | 667 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer |
588 } | 668 } |
589 | 669 |
590 void detachChildRoot(RenderObjectWrapper child) { | 670 void detachChildRoot(RenderObjectWrapper child) { |
591 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer | 671 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer |
592 assert(root is RenderObjectWithChildMixin); | 672 assert(root is RenderObjectWithChildMixin); |
593 assert(root.child == child.root); | 673 assert(root.child == child.root); |
594 root.child = null; | 674 root.child = null; |
595 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer | 675 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer |
596 } | 676 } |
597 | 677 |
598 void remove() { | 678 void remove() { |
599 if (child != null) | 679 if (child != null) |
600 removeChild(child); | 680 removeChild(child); |
601 super.remove(); | 681 super.remove(); |
602 } | 682 } |
603 | |
604 } | 683 } |
605 | 684 |
606 abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { | 685 abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { |
607 | 686 |
608 // In MultiChildRenderObjectWrapper subclasses, slots are RenderObject nodes | 687 // In MultiChildRenderObjectWrapper subclasses, slots are RenderObject nodes |
609 // to use as the "insert before" sibling in ContainerRenderObjectMixin.add() c
alls | 688 // to use as the "insert before" sibling in ContainerRenderObjectMixin.add() c
alls |
610 | 689 |
611 MultiChildRenderObjectWrapper({ String key, List<Widget> children }) | 690 MultiChildRenderObjectWrapper({ String key, List<Widget> children }) |
612 : this.children = children == null ? const [] : children, | 691 : this.children = children == null ? const [] : children, |
613 super(key: key) { | 692 super(key: key) { |
614 assert(!_debugHasDuplicateIds()); | 693 assert(!_debugHasDuplicateIds()); |
615 } | 694 } |
616 | 695 |
617 final List<Widget> children; | 696 final List<Widget> children; |
618 | 697 |
| 698 void walkChildren(WidgetTreeWalker walker) { |
| 699 for(Widget child in children) |
| 700 walker(child); |
| 701 } |
| 702 |
619 void insertChildRoot(RenderObjectWrapper child, dynamic slot) { | 703 void insertChildRoot(RenderObjectWrapper child, dynamic slot) { |
620 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer | 704 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer |
621 assert(slot == null || slot is RenderObject); | 705 assert(slot == null || slot is RenderObject); |
622 assert(root is ContainerRenderObjectMixin); | 706 assert(root is ContainerRenderObjectMixin); |
623 root.add(child.root, before: slot); | 707 root.add(child.root, before: slot); |
624 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer | 708 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer |
625 } | 709 } |
626 | 710 |
627 void detachChildRoot(RenderObjectWrapper child) { | 711 void detachChildRoot(RenderObjectWrapper child) { |
628 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer | 712 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
915 if (root.parent == null) { | 999 if (root.parent == null) { |
916 // we haven't attached it yet | 1000 // we haven't attached it yet |
917 assert(_container.child == null); | 1001 assert(_container.child == null); |
918 _container.child = root; | 1002 _container.child = root; |
919 } | 1003 } |
920 assert(root.parent == _container); | 1004 assert(root.parent == _container); |
921 } | 1005 } |
922 | 1006 |
923 Widget build() => builder(); | 1007 Widget build() => builder(); |
924 } | 1008 } |
OLD | NEW |