using System; using System.Collections.Generic; using UIWidgets.foundation; using UIWidgets.rendering; using UIWidgets.ui; namespace UIWidgets.widgets { public interface WidgetsBindingObserver { void didChangeMetrics(); } public class WidgetsBinding : RendererBinding { public WidgetsBinding(Window window) : base(window) { _buildOwner = new BuildOwner(window); this.buildOwner.onBuildScheduled = this._handleBuildScheduled; window.onLocaleChanged += this.handleLocaleChanged; } public BuildOwner buildOwner { get { return this._buildOwner; } } private readonly BuildOwner _buildOwner; public Element renderViewElement { get { return this._renderViewElement; } } Element _renderViewElement; public List _observers = new List(); void addObserver(WidgetsBindingObserver observer) { _observers.Add(observer); } protected override void handleMetricsChanged() { base.handleMetricsChanged(); foreach (WidgetsBindingObserver observer in _observers) { observer.didChangeMetrics(); } } bool removeObserver(WidgetsBindingObserver observer) { return _observers.Remove(observer); } void _handleBuildScheduled() { ensureVisualUpdate(); } void handleLocaleChanged() { // todo // dispatchLocaleChanged(window.locale); } protected override void drawFrame() { if (renderViewElement != null) { buildOwner.buildScope(renderViewElement); } base.drawFrame(); buildOwner.finalizeTree(); } public void attachRootWidget(Widget rootWidget) { var _adapter = new RenderObjectToWidgetAdapter( container: renderView, child: rootWidget ); _renderViewElement = _adapter.attachToRenderTree(buildOwner, _renderViewElement as RenderObjectToWidgetElement); } } public class RenderObjectToWidgetAdapter : RenderObjectWidget where T : RenderObject { public RenderObjectToWidgetAdapter(Widget child, RenderObjectWithChildMixinRenderObject container) : base( new GlobalObjectKey>(container)) { this.child = child; this.container = container; } public Widget child; public RenderObjectWithChildMixinRenderObject container; public string debugShortDescription; public override Element createElement() { return new RenderObjectToWidgetElement(this); } public override RenderObject createRenderObject(BuildContext context) { return container; } public void updateRenderObject(BuildContext context, RenderObject renderObject) { } public RenderObjectToWidgetElement attachToRenderTree(BuildOwner owner, RenderObjectToWidgetElement element) { if (element == null) { element = (RenderObjectToWidgetElement) createElement(); element.assignOwner(owner); owner.buildScope(element, () => { element.mount(null, null); }); } else { element._newWidget = this; element.markNeedsBuild(); } return element; } } public class RenderObjectToWidgetElement : RootRenderObjectElement where T : RenderObject { public RenderObjectToWidgetElement(RenderObjectWidget widget) : base(widget) { } public RenderObjectToWidgetAdapter widget { get { return (RenderObjectToWidgetAdapter) base.widget; } } Element _child; static readonly object _rootChildSlot = new object(); public Widget _newWidget; public new RenderObjectWithChildMixin renderObject { get { return base.renderObject as RenderObjectWithChildMixin; } } public override void visitChildren(ElementVisitor visitor) { if (_child != null) visitor(_child); } protected override void forgetChild(Element child) { D.assert(child == _child); _child = null; } public override void mount(Element parent, object newSlot) { D.assert(parent == null); base.mount(parent, newSlot); _rebuild(); } public override void update(Widget newWidget) { base.update(newWidget); D.assert(widget == newWidget); _rebuild(); } protected override void performRebuild() { if (_newWidget != null) { Widget newWidget = _newWidget; _newWidget = null; update(newWidget); } base.performRebuild(); D.assert(_newWidget == null); } protected override void insertChildRenderObject(RenderObject child, object slot) { D.assert(slot == _rootChildSlot); renderObject.child = child; } protected override void moveChildRenderObject(RenderObject child, object slot) { D.assert(false); } protected override void removeChildRenderObject(RenderObject child) { D.assert(renderObject.child == child); renderObject.child = null; } void _rebuild() { try { _child = updateChild(_child, widget.child, _rootChildSlot); D.assert(_child != null); } catch (Exception e) { Widget error = ErrorWidget.builder(new UIWidgetsErrorDetails(e)); _child = updateChild(null, error, _rootChildSlot); } } } public class WidgetsBindings { public WidgetsBindings(Window window) { this.window = window; this.widgetsBinding = new WidgetsBinding(window); } public readonly Window window; public readonly WidgetsBinding widgetsBinding; public void attachRootWidget(Widget root) { this.widgetsBinding.attachRootWidget(root); } } }