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

Side by Side Diff: sky/sdk/lib/widgets/ui_node.dart

Issue 1190793002: Rename UINode to Widget. (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/widgets/tool_bar.dart ('k') | sky/sdk/lib/widgets/widget.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
5 import 'dart:async';
6 import 'dart:collection';
7 import 'dart:mirrors';
8 import 'dart:sky' as sky;
9
10 import '../app/view.dart';
11 import '../rendering/box.dart';
12 import '../rendering/object.dart';
13
14 export '../rendering/box.dart' show BoxConstraints, BoxDecoration, Border, Borde rSide, EdgeDims;
15 export '../rendering/flex.dart' show FlexDirection;
16 export '../rendering/object.dart' show Point, Size, Rect, Color, Paint, Path;
17
18 final bool _shouldLogRenderDuration = false;
19
20 // All Effen nodes derive from UINode. All nodes have a _parent, a _key and
21 // can be sync'd.
22 abstract class UINode {
23
24 UINode({ String key }) {
25 _key = key == null ? "$runtimeType" : "$runtimeType-$key";
26 assert(this is AbstractUINodeRoot || _inRenderDirtyComponents); // you shoul d not build the UI tree ahead of time, build it only during build()
27 }
28
29 String _key;
30 String get key => _key;
31
32 UINode _parent;
33 UINode get parent => _parent;
34
35 bool _mounted = false;
36 bool _wasMounted = false;
37 bool get mounted => _mounted;
38 static bool _notifyingMountStatus = false;
39 static Set<UINode> _mountedChanged = new HashSet<UINode>();
40
41 void setParent(UINode newParent) {
42 assert(!_notifyingMountStatus);
43 _parent = newParent;
44 if (newParent == null) {
45 if (_mounted) {
46 _mounted = false;
47 _mountedChanged.add(this);
48 }
49 } else {
50 assert(newParent._mounted);
51 if (_parent._mounted != _mounted) {
52 _mounted = _parent._mounted;
53 _mountedChanged.add(this);
54 }
55 }
56 }
57
58 static void _notifyMountStatusChanged() {
59 try {
60 _notifyingMountStatus = true;
61 for (UINode node in _mountedChanged) {
62 if (node._wasMounted != node._mounted) {
63 if (node._mounted)
64 node.didMount();
65 else
66 node.didUnmount();
67 node._wasMounted = node._mounted;
68 }
69 }
70 _mountedChanged.clear();
71 } finally {
72 _notifyingMountStatus = false;
73 }
74 }
75 void didMount() { }
76 void didUnmount() { }
77
78 RenderObject _root;
79 RenderObject get root => _root;
80
81 // Subclasses which implements Nodes that become stateful may return true
82 // if the |old| node has become stateful and should be retained.
83 // This is called immediately before _sync().
84 // Component._retainStatefulNodeIfPossible() calls syncFields().
85 bool _retainStatefulNodeIfPossible(UINode old) => false;
86
87 bool get interchangeable => false; // if true, then keys can be duplicated
88
89 void _sync(UINode old, dynamic slot);
90 // 'slot' is the identifier that the parent RenderObjectWrapper uses to know
91 // where to put this descendant
92
93 void remove() {
94 _root = null;
95 setParent(null);
96 }
97
98 UINode findAncestor(Type targetType) {
99 var ancestor = _parent;
100 while (ancestor != null && !reflectClass(ancestor.runtimeType).isSubtypeOf(r eflectClass(targetType)))
101 ancestor = ancestor._parent;
102 return ancestor;
103 }
104
105 void removeChild(UINode node) {
106 node.remove();
107 }
108
109 // Returns the child which should be retained as the child of this node.
110 UINode syncChild(UINode node, UINode oldNode, dynamic slot) {
111
112 assert(oldNode is! Component || !oldNode._disqualifiedFromEverAppearingAgain );
113
114 if (node == oldNode) {
115 assert(node == null || node.mounted);
116 return node; // Nothing to do. Subtrees must be identical.
117 }
118
119 if (node == null) {
120 // the child in this slot has gone away
121 assert(oldNode.mounted);
122 removeChild(oldNode);
123 assert(!oldNode.mounted);
124 return null;
125 }
126
127 if (oldNode != null && node._key == oldNode._key && node._retainStatefulNode IfPossible(oldNode)) {
128 assert(oldNode.mounted);
129 assert(!node.mounted);
130 oldNode._sync(node, slot);
131 assert(oldNode.root is RenderObject);
132 return oldNode;
133 }
134
135 if (oldNode != null && node._key != oldNode._key) {
136 assert(oldNode.mounted);
137 removeChild(oldNode);
138 oldNode = null;
139 }
140
141 assert(!node.mounted);
142 node.setParent(this);
143 node._sync(oldNode, slot);
144 assert(node.root is RenderObject);
145 return node;
146 }
147 }
148
149
150 // Descendants of TagNode provide a way to tag RenderObjectWrapper and
151 // Component nodes with annotations, such as event listeners,
152 // stylistic information, etc.
153 abstract class TagNode extends UINode {
154
155 TagNode(UINode content, { String key })
156 : this.content = content, super(key: key);
157
158 UINode content;
159
160 void _sync(UINode old, dynamic slot) {
161 UINode oldContent = old == null ? null : (old as TagNode).content;
162 content = syncChild(content, oldContent, slot);
163 assert(content.root != null);
164 _root = content.root;
165 assert(_root == root); // in case a subclass reintroduces it
166 }
167
168 void remove() {
169 if (content != null)
170 removeChild(content);
171 super.remove();
172 }
173
174 }
175
176 class ParentDataNode extends TagNode {
177 ParentDataNode(UINode content, this.parentData, { String key })
178 : super(content, key: key);
179 final ParentData parentData;
180 }
181
182 typedef void GestureEventListener(sky.GestureEvent e);
183 typedef void PointerEventListener(sky.PointerEvent e);
184 typedef void EventListener(sky.Event e);
185
186 class EventListenerNode extends TagNode {
187
188 EventListenerNode(UINode content, {
189 EventListener onWheel,
190 GestureEventListener onGestureFlingCancel,
191 GestureEventListener onGestureFlingStart,
192 GestureEventListener onGestureScrollStart,
193 GestureEventListener onGestureScrollUpdate,
194 GestureEventListener onGestureTap,
195 GestureEventListener onGestureTapDown,
196 PointerEventListener onPointerCancel,
197 PointerEventListener onPointerDown,
198 PointerEventListener onPointerMove,
199 PointerEventListener onPointerUp,
200 Map<String, sky.EventListener> custom
201 }) : listeners = _createListeners(
202 onWheel: onWheel,
203 onGestureFlingCancel: onGestureFlingCancel,
204 onGestureFlingStart: onGestureFlingStart,
205 onGestureScrollUpdate: onGestureScrollUpdate,
206 onGestureScrollStart: onGestureScrollStart,
207 onGestureTap: onGestureTap,
208 onGestureTapDown: onGestureTapDown,
209 onPointerCancel: onPointerCancel,
210 onPointerDown: onPointerDown,
211 onPointerMove: onPointerMove,
212 onPointerUp: onPointerUp,
213 custom: custom
214 ),
215 super(content);
216
217 final Map<String, sky.EventListener> listeners;
218
219 static Map<String, sky.EventListener> _createListeners({
220 EventListener onWheel,
221 GestureEventListener onGestureFlingCancel,
222 GestureEventListener onGestureFlingStart,
223 GestureEventListener onGestureScrollStart,
224 GestureEventListener onGestureScrollUpdate,
225 GestureEventListener onGestureTap,
226 GestureEventListener onGestureTapDown,
227 PointerEventListener onPointerCancel,
228 PointerEventListener onPointerDown,
229 PointerEventListener onPointerMove,
230 PointerEventListener onPointerUp,
231 Map<String, sky.EventListener> custom
232 }) {
233 var listeners = custom != null ?
234 new HashMap<String, sky.EventListener>.from(custom) :
235 new HashMap<String, sky.EventListener>();
236
237 if (onWheel != null)
238 listeners['wheel'] = onWheel;
239 if (onGestureFlingCancel != null)
240 listeners['gestureflingcancel'] = onGestureFlingCancel;
241 if (onGestureFlingStart != null)
242 listeners['gestureflingstart'] = onGestureFlingStart;
243 if (onGestureScrollStart != null)
244 listeners['gesturescrollstart'] = onGestureScrollStart;
245 if (onGestureScrollUpdate != null)
246 listeners['gesturescrollupdate'] = onGestureScrollUpdate;
247 if (onGestureTap != null)
248 listeners['gesturetap'] = onGestureTap;
249 if (onGestureTapDown != null)
250 listeners['gesturetapdown'] = onGestureTapDown;
251 if (onPointerCancel != null)
252 listeners['pointercancel'] = onPointerCancel;
253 if (onPointerDown != null)
254 listeners['pointerdown'] = onPointerDown;
255 if (onPointerMove != null)
256 listeners['pointermove'] = onPointerMove;
257 if (onPointerUp != null)
258 listeners['pointerup'] = onPointerUp;
259
260 return listeners;
261 }
262
263 void _handleEvent(sky.Event e) {
264 sky.EventListener listener = listeners[e.type];
265 if (listener != null) {
266 listener(e);
267 }
268 }
269
270 }
271
272
273 abstract class Component extends UINode {
274
275 Component({ String key, bool stateful })
276 : _stateful = stateful != null ? stateful : false,
277 _order = _currentOrder + 1,
278 super(key: key);
279
280 static Component _currentlyBuilding;
281 bool get _isBuilding => _currentlyBuilding == this;
282
283 bool _stateful;
284 bool _dirty = true;
285 bool _disqualifiedFromEverAppearingAgain = false;
286
287 UINode _built;
288 dynamic _slot; // cached slot from the last time we were synced
289
290 void didMount() {
291 assert(!_disqualifiedFromEverAppearingAgain);
292 super.didMount();
293 }
294
295 void remove() {
296 assert(_built != null);
297 assert(root != null);
298 removeChild(_built);
299 _built = null;
300 super.remove();
301 }
302
303 bool _retainStatefulNodeIfPossible(UINode old) {
304 assert(!_disqualifiedFromEverAppearingAgain);
305
306 Component oldComponent = old as Component;
307 if (oldComponent == null || !oldComponent._stateful)
308 return false;
309
310 assert(key == oldComponent.key);
311
312 // Make |this|, the newly-created object, into the "old" Component, and kill it
313 _stateful = false;
314 _built = oldComponent._built;
315 assert(_built != null);
316 _disqualifiedFromEverAppearingAgain = true;
317
318 // Make |oldComponent| the "new" component
319 oldComponent._built = null;
320 oldComponent._dirty = true;
321 oldComponent.syncFields(this);
322 return true;
323 }
324
325 // This is called by _retainStatefulNodeIfPossible(), during
326 // syncChild(), just before _sync() is called.
327 // This must be implemented on any subclass that can become stateful
328 // (but don't call super.syncFields() if you inherit directly from
329 // Component, since that'll fire an assert).
330 // If you don't ever become stateful, then don't override this.
331 void syncFields(Component source) {
332 assert(false);
333 }
334
335 final int _order;
336 static int _currentOrder = 0;
337
338 // There are three cases here:
339 // 1) Building for the first time:
340 // assert(_built == null && old == null)
341 // 2) Re-building (because a dirty flag got set):
342 // assert(_built != null && old == null)
343 // 3) Syncing against an old version
344 // assert(_built == null && old != null)
345 void _sync(UINode old, dynamic slot) {
346 assert(_built == null || old == null);
347 assert(!_disqualifiedFromEverAppearingAgain);
348
349 Component oldComponent = old as Component;
350
351 _slot = slot;
352
353 var oldBuilt;
354 if (oldComponent == null) {
355 oldBuilt = _built;
356 } else {
357 assert(_built == null);
358 oldBuilt = oldComponent._built;
359 }
360
361 int lastOrder = _currentOrder;
362 _currentOrder = _order;
363 _currentlyBuilding = this;
364 _built = build();
365 assert(_built != null);
366 _currentlyBuilding = null;
367 _currentOrder = lastOrder;
368
369 _built = syncChild(_built, oldBuilt, slot);
370 assert(_built != null);
371 _dirty = false;
372 _root = _built.root;
373 assert(_root == root); // in case a subclass reintroduces it
374 assert(root != null);
375 }
376
377 void _buildIfDirty() {
378 assert(!_disqualifiedFromEverAppearingAgain);
379 if (!_dirty || !_mounted)
380 return;
381
382 assert(root != null);
383 _sync(null, _slot);
384 }
385
386 void scheduleBuild() {
387 setState(() {});
388 }
389
390 void setState(Function fn()) {
391 assert(!_disqualifiedFromEverAppearingAgain);
392 _stateful = true;
393 fn();
394 if (_isBuilding || _dirty || !_mounted)
395 return;
396
397 _dirty = true;
398 _scheduleComponentForRender(this);
399 }
400
401 UINode build();
402
403 }
404
405 Set<Component> _dirtyComponents = new Set<Component>();
406 bool _buildScheduled = false;
407 bool _inRenderDirtyComponents = false;
408
409 void _buildDirtyComponents() {
410 //_tracing.begin('fn::_buildDirtyComponents');
411
412 Stopwatch sw;
413 if (_shouldLogRenderDuration)
414 sw = new Stopwatch()..start();
415
416 try {
417 _inRenderDirtyComponents = true;
418
419 List<Component> sortedDirtyComponents = _dirtyComponents.toList();
420 sortedDirtyComponents.sort((Component a, Component b) => a._order - b._order );
421 for (var comp in sortedDirtyComponents) {
422 comp._buildIfDirty();
423 }
424
425 _dirtyComponents.clear();
426 _buildScheduled = false;
427 } finally {
428 _inRenderDirtyComponents = false;
429 }
430
431 UINode._notifyMountStatusChanged();
432
433 if (_shouldLogRenderDuration) {
434 sw.stop();
435 print('Render took ${sw.elapsedMicroseconds} microseconds');
436 }
437
438 //_tracing.end('fn::_buildDirtyComponents');
439 }
440
441 void _scheduleComponentForRender(Component c) {
442 assert(!_inRenderDirtyComponents);
443 _dirtyComponents.add(c);
444
445 if (!_buildScheduled) {
446 _buildScheduled = true;
447 new Future.microtask(_buildDirtyComponents);
448 }
449 }
450
451
452 // RenderObjectWrappers correspond to a desired state of a RenderObject.
453 // They are fully immutable, with one exception: A UINode which is a
454 // Component which lives within an MultiChildRenderObjectWrapper's
455 // children list, may be replaced with the "old" instance if it has
456 // become stateful.
457 abstract class RenderObjectWrapper extends UINode {
458
459 RenderObjectWrapper({ String key }) : super(key: key);
460
461 RenderObject createNode();
462
463 void insert(RenderObjectWrapper child, dynamic slot);
464
465 static final Map<RenderObject, RenderObjectWrapper> _nodeMap =
466 new HashMap<RenderObject, RenderObjectWrapper>();
467
468 static RenderObjectWrapper _getMounted(RenderObject node) => _nodeMap[node];
469
470 void _sync(UINode old, dynamic slot) {
471 assert(parent != null);
472 if (old == null) {
473 _root = createNode();
474 var ancestor = findAncestor(RenderObjectWrapper);
475 if (ancestor is RenderObjectWrapper)
476 ancestor.insert(this, slot);
477 } else {
478 _root = old.root;
479 }
480 assert(_root == root); // in case a subclass reintroduces it
481 assert(root != null);
482 assert(mounted);
483 _nodeMap[root] = this;
484 syncRenderObject(old);
485 }
486
487 void syncRenderObject(RenderObjectWrapper old) {
488 ParentData parentData = null;
489 UINode ancestor = parent;
490 while (ancestor != null && ancestor is! RenderObjectWrapper) {
491 if (ancestor is ParentDataNode && ancestor.parentData != null) {
492 if (parentData != null)
493 parentData.merge(ancestor.parentData); // this will throw if the types aren't the same
494 else
495 parentData = ancestor.parentData;
496 }
497 ancestor = ancestor.parent;
498 }
499 if (parentData != null) {
500 assert(root.parentData != null);
501 root.parentData.merge(parentData); // this will throw if the types aren't appropriate
502 if (parent.root != null)
503 parent.root.markNeedsLayout();
504 }
505 }
506
507 void remove() {
508 assert(root != null);
509 _nodeMap.remove(root);
510 super.remove();
511 }
512 }
513
514 abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper {
515
516 OneChildRenderObjectWrapper({ UINode child, String key })
517 : _child = child, super(key: key);
518
519 UINode _child;
520 UINode get child => _child;
521
522 void syncRenderObject(RenderObjectWrapper old) {
523 super.syncRenderObject(old);
524 UINode oldChild = old == null ? null : (old as OneChildRenderObjectWrapper). child;
525 _child = syncChild(child, oldChild, null);
526 }
527
528 void insert(RenderObjectWrapper child, dynamic slot) {
529 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer
530 assert(slot == null);
531 assert(root is RenderObjectWithChildMixin);
532 root.child = child.root;
533 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c leverer
534 }
535
536 void removeChild(UINode node) {
537 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer
538 assert(root is RenderObjectWithChildMixin);
539 root.child = null;
540 super.removeChild(node);
541 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c leverer
542 }
543
544 void remove() {
545 if (child != null)
546 removeChild(child);
547 super.remove();
548 }
549
550 }
551
552 abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
553
554 // In MultiChildRenderObjectWrapper subclasses, slots are RenderObject nodes
555 // to use as the "insert before" sibling in ContainerRenderObjectMixin.add() c alls
556
557 MultiChildRenderObjectWrapper({ String key, List<UINode> children })
558 : this.children = children == null ? const [] : children,
559 super(key: key) {
560 assert(!_debugHasDuplicateIds());
561 }
562
563 final List<UINode> children;
564
565 void insert(RenderObjectWrapper child, dynamic slot) {
566 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer
567 assert(slot == null || slot is RenderObject);
568 assert(root is ContainerRenderObjectMixin);
569 root.add(child.root, before: slot);
570 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c leverer
571 }
572
573 void removeChild(UINode node) {
574 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer
575 assert(root is ContainerRenderObjectMixin);
576 assert(node.root.parent == root);
577 root.remove(node.root);
578 super.removeChild(node);
579 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c leverer
580 }
581
582 void remove() {
583 assert(children != null);
584 for (var child in children) {
585 assert(child != null);
586 removeChild(child);
587 }
588 super.remove();
589 }
590
591 bool _debugHasDuplicateIds() {
592 var idSet = new HashSet<String>();
593 for (var child in children) {
594 assert(child != null);
595 if (child.interchangeable)
596 continue; // when these nodes are reordered, we just reassign the data
597
598 if (!idSet.add(child._key)) {
599 throw '''If multiple non-interchangeable nodes of the same type exist as children
600 of another node, they must have unique keys.
601 Duplicate: "${child._key}"''';
602 }
603 }
604 return false;
605 }
606
607 void syncRenderObject(MultiChildRenderObjectWrapper old) {
608 super.syncRenderObject(old);
609
610 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev erer
611 if (root is! ContainerRenderObjectMixin)
612 return;
613
614 var startIndex = 0;
615 var endIndex = children.length;
616
617 var oldChildren = old == null ? [] : old.children;
618 var oldStartIndex = 0;
619 var oldEndIndex = oldChildren.length;
620
621 RenderObject nextSibling = null;
622 UINode currentNode = null;
623 UINode oldNode = null;
624
625 void sync(int atIndex) {
626 children[atIndex] = syncChild(currentNode, oldNode, nextSibling);
627 assert(children[atIndex] != null);
628 }
629
630 // Scan backwards from end of list while nodes can be directly synced
631 // without reordering.
632 while (endIndex > startIndex && oldEndIndex > oldStartIndex) {
633 currentNode = children[endIndex - 1];
634 oldNode = oldChildren[oldEndIndex - 1];
635
636 if (currentNode._key != oldNode._key) {
637 break;
638 }
639
640 endIndex--;
641 oldEndIndex--;
642 sync(endIndex);
643 }
644
645 HashMap<String, UINode> oldNodeIdMap = null;
646
647 bool oldNodeReordered(String key) {
648 return oldNodeIdMap != null &&
649 oldNodeIdMap.containsKey(key) &&
650 oldNodeIdMap[key] == null;
651 }
652
653 void advanceOldStartIndex() {
654 oldStartIndex++;
655 while (oldStartIndex < oldEndIndex &&
656 oldNodeReordered(oldChildren[oldStartIndex]._key)) {
657 oldStartIndex++;
658 }
659 }
660
661 void ensureOldIdMap() {
662 if (oldNodeIdMap != null)
663 return;
664
665 oldNodeIdMap = new HashMap<String, UINode>();
666 for (int i = oldStartIndex; i < oldEndIndex; i++) {
667 var node = oldChildren[i];
668 if (!node.interchangeable)
669 oldNodeIdMap.putIfAbsent(node._key, () => node);
670 }
671 }
672
673 bool searchForOldNode() {
674 if (currentNode.interchangeable)
675 return false; // never re-order these nodes
676
677 ensureOldIdMap();
678 oldNode = oldNodeIdMap[currentNode._key];
679 if (oldNode == null)
680 return false;
681
682 oldNodeIdMap[currentNode._key] = null; // mark it reordered
683 assert(root is ContainerRenderObjectMixin);
684 assert(old.root is ContainerRenderObjectMixin);
685 assert(oldNode.root != null);
686
687 (old.root as ContainerRenderObjectMixin).remove(oldNode.root); // TODO(ian h): Remove cast once the analyzer is cleverer
688 root.add(oldNode.root, before: nextSibling);
689
690 return true;
691 }
692
693 // Scan forwards, this time we may re-order;
694 nextSibling = root.firstChild;
695 while (startIndex < endIndex && oldStartIndex < oldEndIndex) {
696 currentNode = children[startIndex];
697 oldNode = oldChildren[oldStartIndex];
698
699 if (currentNode._key == oldNode._key) {
700 assert(currentNode.runtimeType == oldNode.runtimeType);
701 nextSibling = root.childAfter(nextSibling);
702 sync(startIndex);
703 startIndex++;
704 advanceOldStartIndex();
705 continue;
706 }
707
708 oldNode = null;
709 searchForOldNode();
710 sync(startIndex);
711 startIndex++;
712 }
713
714 // New insertions
715 oldNode = null;
716 while (startIndex < endIndex) {
717 currentNode = children[startIndex];
718 sync(startIndex);
719 startIndex++;
720 }
721
722 // Removals
723 currentNode = null;
724 while (oldStartIndex < oldEndIndex) {
725 oldNode = oldChildren[oldStartIndex];
726 removeChild(oldNode);
727 advanceOldStartIndex();
728 }
729
730 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c leverer
731 }
732
733 }
734
735 class UINodeAppView extends AppView {
736
737 UINodeAppView({ RenderView renderViewOverride: null })
738 : super(renderViewOverride: renderViewOverride) {
739 assert(_appView == null);
740 }
741
742 static UINodeAppView _appView;
743 static AppView get appView => _appView;
744 static void initUINodeAppView({ RenderView renderViewOverride: null }) {
745 if (_appView == null)
746 _appView = new UINodeAppView(renderViewOverride: renderViewOverride);
747 }
748
749 void dispatchEvent(sky.Event event, HitTestResult result) {
750 assert(_appView == this);
751 super.dispatchEvent(event, result);
752 for (HitTestEntry entry in result.path.reversed) {
753 UINode target = RenderObjectWrapper._getMounted(entry.target);
754 if (target == null)
755 continue;
756 RenderObject targetRoot = target.root;
757 while (target != null && target.root == targetRoot) {
758 if (target is EventListenerNode)
759 target._handleEvent(event);
760 target = target._parent;
761 }
762 }
763 }
764
765 }
766
767 abstract class AbstractUINodeRoot extends Component {
768
769 AbstractUINodeRoot({ RenderView renderViewOverride }) : super(stateful: true) {
770 UINodeAppView.initUINodeAppView(renderViewOverride: renderViewOverride);
771 _mounted = true;
772 _scheduleComponentForRender(this);
773 }
774
775 void syncFields(AbstractUINodeRoot source) {
776 assert(false);
777 // if we get here, it implies that we have a parent
778 }
779
780 void _buildIfDirty() {
781 assert(_dirty);
782 assert(_mounted);
783 assert(parent == null);
784 _sync(null, null);
785 }
786
787 }
788
789 abstract class App extends AbstractUINodeRoot {
790
791 App({ RenderView renderViewOverride }) : super(renderViewOverride: renderViewO verride);
792
793 void _buildIfDirty() {
794 super._buildIfDirty();
795
796 if (root.parent == null) {
797 // we haven't attached it yet
798 UINodeAppView._appView.root = root;
799 }
800 assert(root.parent is RenderView);
801 }
802
803 }
804
805 typedef UINode Builder();
806
807 class RenderBoxToUINodeAdapter extends AbstractUINodeRoot {
808
809 RenderBoxToUINodeAdapter(
810 RenderObjectWithChildMixin<RenderBox> container,
811 this.builder
812 ) : _container = container, super() {
813 assert(builder != null);
814 }
815
816 RenderObjectWithChildMixin<RenderBox> _container;
817 RenderObjectWithChildMixin<RenderBox> get container => _container;
818 void set container(RenderObjectWithChildMixin<RenderBox> value) {
819 if (_container != value) {
820 assert(value.child == null);
821 if (root != null) {
822 assert(_container.child == root);
823 _container.child = null;
824 }
825 _container = value;
826 if (root != null) {
827 _container.child = root;
828 assert(_container.child == root);
829 }
830 }
831 }
832
833 final Builder builder;
834
835 void _buildIfDirty() {
836 super._buildIfDirty();
837 if (root.parent == null) {
838 // we haven't attached it yet
839 assert(_container.child == null);
840 _container.child = root;
841 }
842 assert(root.parent == _container);
843 }
844
845 UINode build() => builder();
846 }
OLDNEW
« no previous file with comments | « sky/sdk/lib/widgets/tool_bar.dart ('k') | sky/sdk/lib/widgets/widget.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698