Index: sky/sdk/lib/widgets/widget.dart |
diff --git a/sky/sdk/lib/widgets/widget.dart b/sky/sdk/lib/widgets/widget.dart |
index 57f5c16bb276e971a6f6f8e2c128a7fe26c2b48d..09dd8b10e8dc1cc6abc4188b7c9a76cb3d88a31f 100644 |
--- a/sky/sdk/lib/widgets/widget.dart |
+++ b/sky/sdk/lib/widgets/widget.dart |
@@ -18,14 +18,24 @@ export '../rendering/object.dart' show Point, Size, Rect, Color, Paint, Path; |
final bool _shouldLogRenderDuration = false; |
+typedef void WidgetTreeWalker(Widget); |
+ |
// All Effen nodes derive from Widget. All nodes have a _parent, a _key and |
// can be sync'd. |
abstract class Widget { |
Widget({ String key }) : _key = key { |
- assert(this is AbstractWidgetRoot || this is App || _inRenderDirtyComponents); // you should not build the UI tree ahead of time, build it only during build() |
+ assert(_isConstructedDuringBuild()); |
+ } |
+ |
+ // TODO(jackson): Remove this workaround for limitation of Dart mixins |
+ Widget._withKey(String key) : _key = key { |
+ assert(_isConstructedDuringBuild()); |
} |
+ // you should not build the UI tree ahead of time, build it only during build() |
+ bool _isConstructedDuringBuild() => this is AbstractWidgetRoot || this is App || _inRenderDirtyComponents; |
+ |
String _key; |
String get key => _key; |
@@ -55,6 +65,9 @@ abstract class Widget { |
} |
} |
+ // Override this if you have children and call walker on each child |
+ void walkChildren(WidgetTreeWalker walker) { } |
+ |
static void _notifyMountStatusChanged() { |
try { |
sky.tracing.begin("Widget._notifyMountStatusChanged"); |
@@ -171,8 +184,16 @@ abstract class TagNode extends Widget { |
TagNode(Widget child, { String key }) |
: this.child = child, super(key: key); |
+ // TODO(jackson): Remove this workaround for limitation of Dart mixins |
+ TagNode._withKey(Widget child, String key) |
+ : this.child = child, super._withKey(key); |
+ |
Widget child; |
+ void walkChildren(WidgetTreeWalker walker) { |
+ walker(child); |
+ } |
+ |
void _sync(Widget old, dynamic slot) { |
Widget oldChild = old == null ? null : (old as TagNode).child; |
child = syncChild(child, oldChild, slot); |
@@ -200,6 +221,56 @@ class ParentDataNode extends TagNode { |
final ParentData parentData; |
} |
+abstract class _Heir implements Widget { |
+ Map<Type, Inherited> _traits; |
+ Inherited inheritedOfType(Type type) => _traits[type]; |
+ |
+ static _Heir _getHeirAncestor(Widget widget) { |
+ Widget ancestor = widget; |
+ while (ancestor != null && !(ancestor is _Heir)) { |
+ ancestor = ancestor.parent; |
+ } |
+ return ancestor as _Heir; |
+ } |
+ |
+ void _updateTraitsFromParent(Widget parent) { |
+ _Heir ancestor = _getHeirAncestor(parent); |
+ if (ancestor == null || ancestor._traits == null) return; |
+ _updateTraits(ancestor._traits); |
+ } |
+ |
+ void _updateTraitsRecursively(Widget widget) { |
+ if (widget is _Heir) |
+ widget._updateTraits(_traits); |
+ else |
+ widget.walkChildren(_updateTraitsRecursively); |
+ } |
+ |
+ void _updateTraits(Map<Type, Inherited> newTraits) { |
+ if (newTraits != _traits) { |
+ _traits = newTraits; |
+ walkChildren(_updateTraitsRecursively); |
+ } |
+ } |
+} |
+ |
+abstract class Inherited extends TagNode with _Heir { |
+ Inherited({ String key, Widget child }) : super._withKey(child, key) { |
+ _traits = new Map<Type, Inherited>(); |
+ } |
+ |
+ void set _traits(Map<Type, Inherited> value) { |
+ super._traits = new Map<Type, Inherited>.from(value) |
+ ..[runtimeType] = this; |
+ } |
+ |
+ // TODO(jackson): When Dart supports super in mixins we can move to _Heir |
+ void setParent(Widget parent) { |
+ _updateTraitsFromParent(parent); |
+ super.setParent(parent); |
+ } |
+} |
+ |
typedef void GestureEventListener(sky.GestureEvent e); |
typedef void PointerEventListener(sky.PointerEvent e); |
typedef void EventListener(sky.Event e); |
@@ -291,13 +362,12 @@ class Listener extends TagNode { |
} |
- |
-abstract class Component extends Widget { |
+abstract class Component extends Widget with _Heir { |
Component({ String key, bool stateful }) |
: _stateful = stateful != null ? stateful : false, |
_order = _currentOrder + 1, |
- super(key: key); |
+ super._withKey(key); |
static Component _currentlyBuilding; |
bool get _isBuilding => _currentlyBuilding == this; |
@@ -314,6 +384,12 @@ abstract class Component extends Widget { |
super.didMount(); |
} |
+ // TODO(jackson): When Dart supports super in mixins we can move to _Heir |
+ void setParent(Widget parent) { |
+ _updateTraitsFromParent(parent); |
+ super.setParent(parent); |
+ } |
+ |
void remove() { |
assert(_built != null); |
assert(root != null); |
@@ -573,6 +649,10 @@ abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper { |
Widget _child; |
Widget get child => _child; |
+ void walkChildren(WidgetTreeWalker walker) { |
+ walker(child); |
+ } |
+ |
void syncRenderObject(RenderObjectWrapper old) { |
super.syncRenderObject(old); |
Widget oldChild = old == null ? null : (old as OneChildRenderObjectWrapper).child; |
@@ -600,7 +680,6 @@ abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper { |
removeChild(child); |
super.remove(); |
} |
- |
} |
abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { |
@@ -616,6 +695,11 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper { |
final List<Widget> children; |
+ void walkChildren(WidgetTreeWalker walker) { |
+ for(Widget child in children) |
+ walker(child); |
+ } |
+ |
void insertChildRoot(RenderObjectWrapper child, dynamic slot) { |
final root = this.root; // TODO(ianh): Remove this once the analyzer is cleverer |
assert(slot == null || slot is RenderObject); |