Commit 555138e6 authored by Hixie's avatar Hixie

fn3: Binding to RenderView

In the old world, we had two ways to bind a Widget tree to a
RenderObject node, one way for RenderView and one mostly untested way
for other cases (it's only tested by the spinning_mixed.dart demo). For
fn3, I made these the same code path.

This patch also introduces GlobalKey, though the GlobalKey logic isn't
hooked in yet.

This is Hello World in the new world:

```dart
import 'package:sky/src/fn3.dart';

void main() {
  runApp(new Text('Hello World!'));
}
```
parent 8b162b59
......@@ -7,21 +7,34 @@ import 'package:sky/animation.dart';
import 'package:sky/rendering.dart';
import 'package:sky/src/fn3/framework.dart';
class WidgetSkyBinding extends SkyBinding {
class WidgetFlutterBinding extends SkyBinding {
WidgetSkyBinding({ RenderView renderViewOverride: null })
: super(renderViewOverride: renderViewOverride) {
WidgetFlutterBinding() {
BuildableElement.scheduleBuildFor = scheduleBuildFor;
_renderViewElement = new RenderObjectToWidgetElement<RenderBox>(describeApp(null));
_renderViewElement.mount(null, this);
}
/// Ensures that there is a SkyBinding object instantiated.
static void initWidgetSkyBinding({ RenderView renderViewOverride: null }) {
static void initBinding() {
if (SkyBinding.instance == null)
new WidgetSkyBinding(renderViewOverride: renderViewOverride);
assert(SkyBinding.instance is WidgetSkyBinding);
new WidgetFlutterBinding();
assert(SkyBinding.instance is WidgetFlutterBinding);
}
static WidgetSkyBinding get instance => SkyBinding.instance;
static WidgetFlutterBinding get instance => SkyBinding.instance;
/// The [Element] that is at the root of the hierarchy (and which wraps the
/// [RenderView] object at the root of the rendering hierarchy).
Element get renderViewElement => _renderViewElement;
Element _renderViewElement;
RenderObjectToWidgetAdapter<RenderBox> describeApp(Widget app) {
return new RenderObjectToWidgetAdapter<RenderBox>(
container: instance.renderView,
child: app
);
}
void handleEvent(sky.Event event, BindingHitTestEntry entry) {
for (HitTestEntry entry in entry.result.path) {
......@@ -90,3 +103,74 @@ class WidgetSkyBinding extends SkyBinding {
assert(() { _debugBuildingAtDepth = null; return true; });
}
}
void runApp(Widget app) {
WidgetFlutterBinding.initBinding();
WidgetFlutterBinding.instance.renderViewElement.update(
WidgetFlutterBinding.instance.describeApp(app)
);
}
/// This class provides a bridge from a RenderObject to an Element tree. The
/// given container is the RenderObject that the Element tree should be inserted
/// into. It must be a RenderObject that implements the
/// RenderObjectWithChildMixin protocol. The type argument T is the kind of
/// RenderObject that the container expects as its child.
class RenderObjectToWidgetAdapter<T extends RenderObject> extends RenderObjectWidget {
RenderObjectToWidgetAdapter({ this.child, RenderObjectWithChildMixin<T> container })
: container = container, super(key: new GlobalObjectKey(container));
final Widget child;
final RenderObjectWithChildMixin<T> container;
RenderObjectToWidgetElement<T> createElement() => new RenderObjectToWidgetElement<T>(this);
RenderObjectWithChildMixin<T> createRenderObject() => container;
void updateRenderObject(RenderObject renderObject, RenderObjectWidget oldWidget) { }
}
/// This element class is the instantiation of a [RenderObjectToWidgetAdapter].
/// It can only be used as the root of an Element tree (it cannot be mounted
/// into another Element, it's parent must be null).
///
/// In typical usage, it will be instantiated for a RenderObjectToWidgetAdapter
/// whose container is the RenderView that connects to the Flutter engine. In
/// this usage, it is normally instantiated by the bootstrapping logic in the
/// WidgetFlutterBinding singleton created by runApp().
class RenderObjectToWidgetElement<T extends RenderObject> extends RenderObjectElement {
RenderObjectToWidgetElement(RenderObjectToWidgetAdapter<T> widget) : super(widget);
Element _child;
static const _rootChild = const Object();
void visitChildren(ElementVisitor visitor) {
if (_child != null)
visitor(_child);
}
void mount(Element parent, dynamic slot) {
assert(parent == null);
super.mount(parent, slot);
_child = updateChild(_child, widget.child, _rootChild);
}
void update(RenderObjectToWidgetAdapter<T> newWidget) {
super.update(newWidget);
assert(widget == newWidget);
_child = updateChild(_child, widget.child, _rootChild);
}
RenderObjectWithChildMixin<T> get renderObject => super.renderObject;
void insertChildRenderObject(RenderObject child, dynamic slot) {
assert(slot == _rootChild);
renderObject.child = child;
}
void removeChildRenderObject(RenderObject child) {
assert(renderObject.child == child);
renderObject.child = null;
}
}
\ No newline at end of file
This diff is collapsed.
......@@ -57,6 +57,7 @@ void main() {
WidgetTester tester = new WidgetTester();
tester.pumpFrame(
new FlipComponent(
key: new Key('rebuild test'), // this is so we don't get the state from the TestComponentConfig in the last test, but instead instantiate a new element with a new state.
left: new TestBuildCounter(),
right: new DecoratedBox(decoration: kBoxDecorationB)
)
......
......@@ -22,21 +22,12 @@ const Object _rootSlot = const Object();
class WidgetTester {
WidgetTester() {
WidgetSkyBinding.initWidgetSkyBinding();
_rootElement = new StatefulComponentElement(new RootComponent());
_rootElement.mount(null, _rootSlot);
}
StatefulComponentElement _rootElement;
void walkElements(ElementVisitor visitor) {
void walk(Element element) {
visitor(element);
element.visitChildren(walk);
}
_rootElement.visitChildren(walk);
WidgetFlutterBinding.instance.renderViewElement.visitChildren(walk);
}
Element findElement(bool predicate(Element widget)) {
......@@ -54,12 +45,12 @@ class WidgetTester {
}
void pumpFrame(Widget widget) {
(_rootElement.state as RootComponentState).child = widget;
WidgetSkyBinding.instance.beginFrame(0.0); // TODO(ianh): https://github.com/flutter/engine/issues/1084
runApp(widget);
WidgetFlutterBinding.instance.beginFrame(0.0); // TODO(ianh): https://github.com/flutter/engine/issues/1084
}
void pumpFrameWithoutChange() {
WidgetSkyBinding.instance.beginFrame(0.0); // TODO(ianh): https://github.com/flutter/engine/issues/1084
WidgetFlutterBinding.instance.beginFrame(0.0); // TODO(ianh): https://github.com/flutter/engine/issues/1084
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment