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

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

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

Powered by Google App Engine
This is Rietveld 408576698