diff --git a/examples/stocks2/lib/stock_app.dart b/examples/stocks2/lib/stock_app.dart
index fcd95d663f851264dd5c77e44a8f249f7c6d3963..4e29072c8720f8b072f3bb4c130a0baaaf4aa4c4 100644
--- a/examples/stocks2/lib/stock_app.dart
+++ b/examples/stocks2/lib/stock_app.dart
@@ -2,30 +2,26 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'package:sky/framework/components2/tool_bar.dart';
-import 'package:sky/framework/components2/drawer.dart';
-import 'package:sky/framework/components2/drawer_header.dart';
-import 'package:sky/framework/components2/floating_action_button.dart';
-import 'package:sky/framework/components2/icon.dart';
-import 'package:sky/framework/components2/icon_button.dart';
-import 'package:sky/framework/components2/menu_divider.dart';
-import 'package:sky/framework/components2/menu_item.dart';
-import 'package:sky/framework/components2/input.dart';
-import 'package:sky/framework/components2/modal_overlay.dart';
-import 'package:sky/framework/components2/popup_menu.dart';
-import 'package:sky/framework/components2/radio.dart';
-import 'package:sky/framework/components2/scaffold.dart';
-import 'package:sky/framework/fn2.dart';
-import 'package:sky/framework/theme2/typography.dart' as typography;
+import 'package:sky/framework/editing2/input.dart';
import 'package:sky/framework/theme2/colors.dart' as colors;
+import 'package:sky/framework/widgets/drawer.dart';
+import 'package:sky/framework/widgets/drawer_header.dart';
+import 'package:sky/framework/widgets/floating_action_button.dart';
+import 'package:sky/framework/widgets/icon.dart';
+import 'package:sky/framework/widgets/icon_button.dart';
+import 'package:sky/framework/widgets/menu_divider.dart';
+import 'package:sky/framework/widgets/menu_item.dart';
+import 'package:sky/framework/widgets/modal_overlay.dart';
+import 'package:sky/framework/widgets/popup_menu.dart';
+import 'package:sky/framework/widgets/radio.dart';
+import 'package:sky/framework/widgets/scaffold.dart';
+import 'package:sky/framework/widgets/tool_bar.dart';
+import 'package:sky/framework/widgets/wrappers.dart';
+
import 'stock_data.dart';
-import 'package:sky/framework/rendering/box.dart';
import 'stock_list.dart';
import 'stock_menu.dart';
-import 'dart:async';
-import 'dart:sky' as sky;
-
enum StockMode { optimistic, pessimistic }
class StocksApp extends App {
diff --git a/examples/stocks2/lib/stock_arrow.dart b/examples/stocks2/lib/stock_arrow.dart
index f78b253dc6655346aed4c9b9e6884c37cf7471fc..da585fd1b4cdb2c5cad883e442c862ad29e56d1a 100644
--- a/examples/stocks2/lib/stock_arrow.dart
+++ b/examples/stocks2/lib/stock_arrow.dart
@@ -2,14 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'package:sky/framework/fn2.dart';
-import 'package:vector_math/vector_math.dart';
+import 'dart:math' as math;
+import 'dart:sky' as sky;
+
import 'package:sky/framework/rendering/box.dart';
import 'package:sky/framework/rendering/object.dart';
import 'package:sky/framework/theme2/colors.dart' as colors;
-
-import 'dart:math' as math;
-import 'dart:sky' as sky;
+import 'package:sky/framework/widgets/wrappers.dart';
class StockArrow extends Component {
diff --git a/examples/stocks2/lib/stock_data.dart b/examples/stocks2/lib/stock_data.dart
index a77ca50a678c4c1b7196cf767e7d792d64aab008..075add267579eaf5a14c2ed254517dd96f3c3331 100644
--- a/examples/stocks2/lib/stock_data.dart
+++ b/examples/stocks2/lib/stock_data.dart
@@ -4,6 +4,7 @@
import 'dart:convert';
import 'dart:math';
+
import 'package:sky/framework/net/fetch.dart';
// Snapshot from http://www.nasdaq.com/screening/company-list.aspx
diff --git a/examples/stocks2/lib/stock_list.dart b/examples/stocks2/lib/stock_list.dart
index 7ff6fe8cb75f4d4809cee722c800992885b3fa7f..1c3ac12a026fa5293a6aaa4be0dd47c15c47ec86 100644
--- a/examples/stocks2/lib/stock_list.dart
+++ b/examples/stocks2/lib/stock_list.dart
@@ -2,8 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'package:sky/framework/components2/fixed_height_scrollable.dart';
-import 'package:sky/framework/fn2.dart';
+import 'package:sky/framework/widgets/fixed_height_scrollable.dart';
+import 'package:sky/framework/widgets/wrappers.dart';
+
import 'stock_data.dart';
import 'stock_row.dart';
diff --git a/examples/stocks2/lib/stock_menu.dart b/examples/stocks2/lib/stock_menu.dart
index 1ac20ccc201c3bd339ef00125427d62b688a485e..6312b1e32ac90f63b00614b690400b09b80d303b 100644
--- a/examples/stocks2/lib/stock_menu.dart
+++ b/examples/stocks2/lib/stock_menu.dart
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'package:sky/framework/fn2.dart';
-import 'package:sky/framework/components2/popup_menu.dart';
-import 'package:sky/framework/components2/checkbox.dart';
+import 'package:sky/framework/widgets/checkbox.dart';
+import 'package:sky/framework/widgets/popup_menu.dart';
+import 'package:sky/framework/widgets/wrappers.dart';
import 'package:sky/framework/theme/view_configuration.dart';
class StockMenu extends Component {
diff --git a/examples/stocks2/lib/stock_row.dart b/examples/stocks2/lib/stock_row.dart
index 1ecb06846962e7171176f677dd5d42a7bc3d49a1..fc0555bce72131ab34788224bd9ef536902fa699 100644
--- a/examples/stocks2/lib/stock_row.dart
+++ b/examples/stocks2/lib/stock_row.dart
@@ -3,11 +3,11 @@
// found in the LICENSE file.
import 'dart:sky' as sky;
-import 'package:sky/framework/components2/ink_well.dart';
-import 'package:sky/framework/fn2.dart';
-import 'package:sky/framework/rendering/flex.dart';
+
import 'package:sky/framework/rendering/box.dart';
-import 'package:sky/framework/theme/typography.dart' as typography;
+import 'package:sky/framework/widgets/wrappers.dart';
+import 'package:sky/framework/widgets/ink_well.dart';
+
import 'stock_arrow.dart';
import 'stock_data.dart';
diff --git a/examples/fn2/container.dart b/examples/widgets/container.dart
similarity index 91%
rename from examples/fn2/container.dart
rename to examples/widgets/container.dart
index f1eec6bbea4558b79b488c8fed36e20411c37a09..437784078ade73ed332a35772e5d65e328441091 100644
--- a/examples/fn2/container.dart
+++ b/examples/widgets/container.dart
@@ -3,8 +3,11 @@
// found in the LICENSE file.
import 'dart:sky' as sky;
-import 'package:sky/framework/fn2.dart';
+
import 'package:sky/framework/rendering/box.dart';
+import 'package:sky/framework/widgets/ui_node.dart';
+import 'package:sky/framework/widgets/wrappers.dart';
+
import '../lib/solid_color_box.dart';
class Rectangle extends RenderObjectWrapper {
@@ -29,7 +32,7 @@ class ContainerApp extends App {
child: new Block([
new Container(
decoration: new BoxDecoration(backgroundColor: const sky.Color(0xFFFFFF00)),
- height: 20.0,
+ height: 20.0
),
new Image(src: "https://www.dartlang.org/logos/dart-logo.png",
size: new sky.Size(300.0, 300.0),
diff --git a/examples/fn2/hello_fn2.dart b/examples/widgets/hello_widgets.dart
similarity index 84%
rename from examples/fn2/hello_fn2.dart
rename to examples/widgets/hello_widgets.dart
index 1aeda5d2ebc12d0dc5ab9d17586b64f0e99118af..127e26fa9e749708ea411180523440a8c3909fc5 100644
--- a/examples/fn2/hello_fn2.dart
+++ b/examples/widgets/hello_widgets.dart
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'package:sky/framework/fn2.dart';
+import 'package:sky/framework/widgets/wrappers.dart';
class HelloWorldApp extends App {
UINode build() {
@@ -12,4 +12,4 @@ class HelloWorldApp extends App {
void main() {
new HelloWorldApp();
-}
\ No newline at end of file
+}
diff --git a/examples/widgets/main.sky b/examples/widgets/main.sky
deleted file mode 100644
index 506b0ff837521d1945a72af0108950f539768c38..0000000000000000000000000000000000000000
--- a/examples/widgets/main.sky
+++ /dev/null
@@ -1,15 +0,0 @@
-#!mojo mojo:sky_viewer
-
-
-
-
-
diff --git a/examples/widgets/pubspec.yaml b/examples/widgets/pubspec.yaml
deleted file mode 100644
index 1f45fe870a60af58ed8e39ccf141acfb1ffc0a94..0000000000000000000000000000000000000000
--- a/examples/widgets/pubspec.yaml
+++ /dev/null
@@ -1,3 +0,0 @@
-name: widgets
-dependencies:
- sky: any
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index aee3614c76d9b2eeec52e2c275442410d639cd4d..e975ac75fb56c13ab6d8aa0048d4125e4b5f3433 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -43,28 +43,6 @@ dart_pkg("sdk") {
"lib/framework/components/scaffold.dart",
"lib/framework/components/scrollable.dart",
"lib/framework/components/tool_bar.dart",
- "lib/framework/components2/animated_component.dart",
- "lib/framework/components2/button.dart",
- "lib/framework/components2/button_base.dart",
- "lib/framework/components2/checkbox.dart",
- "lib/framework/components2/drawer.dart",
- "lib/framework/components2/drawer_header.dart",
- "lib/framework/components2/fixed_height_scrollable.dart",
- "lib/framework/components2/floating_action_button.dart",
- "lib/framework/components2/icon.dart",
- "lib/framework/components2/icon_button.dart",
- "lib/framework/components2/ink_well.dart",
- "lib/framework/components2/input.dart",
- "lib/framework/components2/material.dart",
- "lib/framework/components2/menu_divider.dart",
- "lib/framework/components2/menu_item.dart",
- "lib/framework/components2/modal_overlay.dart",
- "lib/framework/components2/popup_menu.dart",
- "lib/framework/components2/popup_menu_item.dart",
- "lib/framework/components2/radio.dart",
- "lib/framework/components2/scaffold.dart",
- "lib/framework/components2/scrollable.dart",
- "lib/framework/components2/tool_bar.dart",
"lib/framework/debug/shake-to-reload.sky",
"lib/framework/debug/tracing.dart",
"lib/framework/editing/editable_string.dart",
@@ -72,6 +50,7 @@ dart_pkg("sdk") {
"lib/framework/editing/keyboard.dart",
"lib/framework/editing2/editable_string.dart",
"lib/framework/editing2/editable_text.dart",
+ "lib/framework/editing2/input.dart",
"lib/framework/editing2/keyboard.dart",
"lib/framework/elements/animation/controller.dart",
"lib/framework/elements/animation/timer.dart",
@@ -93,7 +72,6 @@ dart_pkg("sdk") {
"lib/framework/elements/sky-toolbar.sky",
"lib/framework/embedder.dart",
"lib/framework/fn.dart",
- "lib/framework/fn2.dart",
"lib/framework/layout.dart",
"lib/framework/net/fetch.dart",
"lib/framework/net/image_cache.dart",
@@ -117,6 +95,29 @@ dart_pkg("sdk") {
"lib/framework/theme2/shadows.dart",
"lib/framework/theme2/typography.dart",
"lib/framework/theme2/view_configuration.dart",
+ "lib/framework/widgets/animated_component.dart",
+ "lib/framework/widgets/button.dart",
+ "lib/framework/widgets/button_base.dart",
+ "lib/framework/widgets/checkbox.dart",
+ "lib/framework/widgets/drawer.dart",
+ "lib/framework/widgets/drawer_header.dart",
+ "lib/framework/widgets/fixed_height_scrollable.dart",
+ "lib/framework/widgets/floating_action_button.dart",
+ "lib/framework/widgets/icon.dart",
+ "lib/framework/widgets/icon_button.dart",
+ "lib/framework/widgets/ink_well.dart",
+ "lib/framework/widgets/material.dart",
+ "lib/framework/widgets/menu_divider.dart",
+ "lib/framework/widgets/menu_item.dart",
+ "lib/framework/widgets/modal_overlay.dart",
+ "lib/framework/widgets/popup_menu.dart",
+ "lib/framework/widgets/popup_menu_item.dart",
+ "lib/framework/widgets/radio.dart",
+ "lib/framework/widgets/scaffold.dart",
+ "lib/framework/widgets/scrollable.dart",
+ "lib/framework/widgets/tool_bar.dart",
+ "lib/framework/widgets/ui_node.dart",
+ "lib/framework/widgets/wrappers.dart",
"lib/sky_tool",
"pubspec.yaml",
]
diff --git a/sdk/lib/framework/README.md b/sdk/lib/framework/README.md
index a15a276002266ab10f658e339af2029febf87648..b60665f4547c3a1a0fbbd988c0e7ebeb34c28121 100644
--- a/sdk/lib/framework/README.md
+++ b/sdk/lib/framework/README.md
@@ -1,219 +1,22 @@
-Sky Framework
-=============
+SKY SDK
+========
-Effen is a functional-reactive framework for Sky which takes inspiration from
-[React](http://facebook.github.io/react/). Effen is comprised of three main
-parts: a virtual-dom and diffing engine, a component mechanism and a very early
-set of widgets for use in creating applications.
+Sky and Sky's SDK are designed as layered frameworks, where each layer
+depends on the ones below it but could be replaced wholesale.
-The central idea is that you build your UI out of components. Components
-describe what their view should look like given their current configuration &
-state. The diffing engine ensures that the DOM looks how the component describes
-by applying minimal diffs to transition it from one state to the next.
+The bottom-most layer is the Sky Platform, which is exposed to Dart
+code as the ```dart:sky``` package.
-If you just want to dive into code, see the [stocks example](../../../../examples/stocks).
+Above this are the files in the [painting/](painting/) directory,
+which provide APIs related to drawing graphics.
-Hello World
------------
+Layout primitives are provided in the next layer, found in the
+[rendering/](rendering/) directory. They use ```dart:sky``` and the
+APIs exposed in painting/ to provide a retained-mode layout and
+rendering model for applications or documents.
-To build an application, create a subclass of App and instantiate it.
+Widgets are provided by the files in the [widgets/](widgets/)
+directory, using a reactive framework.
-```HTML
-
-```
-
-```dart
-// In hello_world.dart
-import 'package:sky/framework/fn.dart';
-
-class HelloWorldApp extends App {
- UINode build() {
- return new Text('Hello, world!');
- }
-}
-```
-
-An app is comprised of (and is, itself, a) components. A component's main job is
-to implement `UINode build()`. The idea here is that the `build` method describes
-the DOM of a component at any given point during its lifetime. In this case, our
-`HelloWorldApp`'s `build` method just returns a `Text` node which displays the
-obligatory line of text.
-
-Nodes
------
-
-A component's `build` method must return a single `UINode` which *may* have
-children (and so on, forming a *subtree*). Effen comes with a few built-in nodes
-which mirror the built-in nodes/elements of sky: `Text`, `Anchor` (``,
-`Image` (``) and `Container` (`
`). `build` can return a tree of
-Nodes comprised of any of these nodes and plus any other imported object which
-extends `Component`.
-
-How to structure you app
-------------------------
-
-If you're familiar with React, the basic idea is the same: Application data
-flows *down* from components which have data to components & nodes which they
-construct via construction parameters. Generally speaking, View-Model data (data
-which is derived from *model* data, but exists only because the view needs it),
-is computed during the course of `build` and is short-lived, being handed into
-nodes & components as configuration data.
-
-What does "data flowing down the tree" mean?
---------------------------------------------
-
-Consider the case of a checkbox. (i.e. `widgets/checkbox.dart`). The `Checkbox`
-constructor looks like this:
-
-```dart
- ValueChanged onChanged;
- bool checked;
-
- Checkbox({ Object key, this.onChanged, this.checked }) : super(key: key);
-```
-
-What this means is that the `Checkbox` component *never* "owns" the state of
-the checkbox. It's current state is handed into the `checked` parameter, and
-when a click occurs, the checkbox invokes its `onChanged` callback with the
-value it thinks it should be changed to -- but it never directly changes the
-value itself. This is a bit odd at first look, but if you think about it: a
-control isn't very useful unless it gets its value out to someone and if you
-think about databinding, the same thing happens: databinding basically tells a
-control to *treat some remote variable as its storage*. That's all that is
-happening here. In this case, some owning component probably has a set of values
-which describe a form.
-
-Stateful vs. Stateless components
----------------------------------
-
-All components have access to two kinds of state: (1) configuration data
-(constructor arguments) and (2) private data (data they mutate themselves).
-While react components have explicit property bags for these two kinds of state
-(`this.prop` and `this.state`), Effen maps these ideas to the public and private
-fields of the component. Constructor arguments should (by convention) be
-reflected as public fields of the component and state should only be set on
-private (with a leading underbar `_`) fields.
-
-All (non-component) Effen nodes are stateless. Some components will be stateful.
-This state will likely encapsulate transient states of the UI, such as scroll
-position, animation state, uncommitted form values, etc...
-
-A component can become stateful in two ways: (1) by passing `super(stateful:
-true)` to its call to the superclass's constructor, or by calling
-`setState(Function fn)`. The former is a way to have a component start its life
-stateful, and the latter results in the component becoming statefull *as well
-as* scheduling the component to re-build at the end of the current animation
-frame.
-
-What does it mean to be stateful? It means that the diffing mechanism retains
-the specific *instance* of the component as long as the component which builds
-it continues to require its presence. The component which constructed it may
-have provided new configuration in form of different values for the constructor
-parameters, but these values (public fields) will be copied (using reflection)
-onto the retained instance whose privates fields are left unmodified.
-
-Rendering
----------
-
-At the end of each animation frame, all components (including the root `App`)
-which have `setState` on themselves will be rebuilt and the resulting changes
-will be minimally applied to the DOM. Note that components of lower "order"
-(those near the root of the tree) will build first because their building may
-require rebuilding of higher order (those near the leaves), thus avoiding the
-possibility that a component which is dirty build more than once during a single
-cycle.
-
-Keys
-----
-
-In order to efficiently apply changes to the DOM and to ensure that stateful
-components are correctly identified, Effen requires that `no two nodes (except
-Text) or components of the same type may exist as children of another element
-without being distinguished by unique keys`. [`Text` is excused from this rule].
-In many cases, nodes don't require a key because there is only one type amongst
-its siblings -- but if there is more one, you must assign each a key. This is
-why most nodes will take `({ Object key })` as an optional constructor
-parameter. In development mode (i.e. when sky is built `Debug`) Effen will throw
-an error if you forget to do this.
-
-Event Handling
---------------
-
-Events logically fire through the Effen node tree. If want to handle an event as
-it bubbles from the target to the root, create an `EventListenerNode`. `EventListenerNode`
-has named (typed) parameters for a small set of events that we've hit so far, as
-well as a 'custom' argument which is a `Map`. If
-you'd like to add a type argument for an event, just post a patch.
-
-```dart
-class MyComp extends Component {
- MyComp({
- Object key
- }) : super(key: key);
-
- void _handleTap(sky.GestureEvent e) {
- // do stuff
- }
-
- void _customEventCallback(sky.Event e) {
- // do other stuff
- }
-
- UINode build() {
- new EventListenerNode(
- new Container(
- children: // ...
- ),
- onGestureTap: _handleTap,
- custom: {
- 'myCustomEvent': _customEventCallback
- }
- );
- }
-
- _handleScroll(sky.Event e) {
- setState(() {
- // update the scroll position
- });
- }
-}
-```
-
-Styling
--------
-
-Styling is the part of Effen which is least designed and is likely to change.
-There are three ways to specify styles:
-
- * `Style` objects which are interned and can be applied to WrapperNodes via the
- ``style` constructor parameter. Use `Style` objects for styles which are
- `*not* animated.
-
- * An `inlineStyle` string which can be applied to Elements via the
- `inlineStyle` constructor parameter. Use `inlineStyle` for styles which
- *are* animated.
-
-If you need to apply a Style to a Component or UINode which you didn't construct
-(i.e. one that was handed into your constructor), you can wrap it in a
-`StyleNode` which also takes a `Style` constructor in it's `style` constructor
-parameter.
-
-Animation
----------
-
-Animation is still an area of exploration. Have a look at
-[AnimatedComponent](components/animated_component.dart) and
-[Drawer](components/drawer.dart) for an example of this this currently works.
-
-Performance
------------
-
-It is a design goal that it should be *possible* to arrange that all "build"
-cycles which happen during animations can complete in less than one milliesecond
-on a Nexus 5.
+Text input widgets are layered on this mechanism and can be found in
+the [editing2/](editing2/) directory.
diff --git a/sdk/lib/framework/editing2/editable_text.dart b/sdk/lib/framework/editing2/editable_text.dart
index 430933bf997d0d2f117bf3c76fa46ac95797911c..59569b04eb412e924b21c5c0692c90c5e659c011 100644
--- a/sdk/lib/framework/editing2/editable_text.dart
+++ b/sdk/lib/framework/editing2/editable_text.dart
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
-import '../theme/colors.dart';
import 'dart:async';
+
+import '../widgets/wrappers.dart';
import 'editable_string.dart';
class EditableText extends Component {
diff --git a/sdk/lib/framework/components2/input.dart b/sdk/lib/framework/editing2/input.dart
similarity index 91%
rename from sdk/lib/framework/components2/input.dart
rename to sdk/lib/framework/editing2/input.dart
index 0f7d4816398cc64dd69bf11c6bd798d3d7971c53..4a97f575b1623e36fe8969245a47bfb6aa66c436 100644
--- a/sdk/lib/framework/components2/input.dart
+++ b/sdk/lib/framework/editing2/input.dart
@@ -2,15 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../editing2/editable_string.dart';
-import '../editing2/editable_text.dart';
-import '../editing2/keyboard.dart';
-import '../fn2.dart';
-import '../theme2/colors.dart';
-import '../theme2/typography.dart' as typography;
-import '../rendering/flex.dart';
import 'dart:sky' as sky;
+import '../rendering/flex.dart';
+import '../widgets/wrappers.dart';
+import 'editable_string.dart';
+import 'editable_text.dart';
+import 'keyboard.dart';
+
typedef void ValueChanged(value);
class Input extends Component {
diff --git a/sdk/lib/framework/fn.md b/sdk/lib/framework/fn.md
new file mode 100644
index 0000000000000000000000000000000000000000..40d964a8799d43bfe193e04286df49e1d9953050
--- /dev/null
+++ b/sdk/lib/framework/fn.md
@@ -0,0 +1,222 @@
+Sky Framework
+=============
+
+(This file applies to fn.dart, which we are in the process of porting
+to a new architecture.)
+
+Effen is a functional-reactive framework for Sky which takes inspiration from
+[React](http://facebook.github.io/react/). Effen is comprised of three main
+parts: a virtual-dom and diffing engine, a component mechanism and a very early
+set of widgets for use in creating applications.
+
+The central idea is that you build your UI out of components. Components
+describe what their view should look like given their current configuration &
+state. The diffing engine ensures that the DOM looks how the component describes
+by applying minimal diffs to transition it from one state to the next.
+
+If you just want to dive into code, see the [stocks example](../../../../examples/stocks).
+
+Hello World
+-----------
+
+To build an application, create a subclass of App and instantiate it.
+
+```HTML
+
+```
+
+```dart
+// In hello_world.dart
+import 'package:sky/framework/fn.dart';
+
+class HelloWorldApp extends App {
+ UINode build() {
+ return new Text('Hello, world!');
+ }
+}
+```
+
+An app is comprised of (and is, itself, a) components. A component's main job is
+to implement `UINode build()`. The idea here is that the `build` method describes
+the DOM of a component at any given point during its lifetime. In this case, our
+`HelloWorldApp`'s `build` method just returns a `Text` node which displays the
+obligatory line of text.
+
+Nodes
+-----
+
+A component's `build` method must return a single `UINode` which *may* have
+children (and so on, forming a *subtree*). Effen comes with a few built-in nodes
+which mirror the built-in nodes/elements of sky: `Text`, `Anchor` (``,
+`Image` (``) and `Container` (``). `build` can return a tree of
+Nodes comprised of any of these nodes and plus any other imported object which
+extends `Component`.
+
+How to structure you app
+------------------------
+
+If you're familiar with React, the basic idea is the same: Application data
+flows *down* from components which have data to components & nodes which they
+construct via construction parameters. Generally speaking, View-Model data (data
+which is derived from *model* data, but exists only because the view needs it),
+is computed during the course of `build` and is short-lived, being handed into
+nodes & components as configuration data.
+
+What does "data flowing down the tree" mean?
+--------------------------------------------
+
+Consider the case of a checkbox. (i.e. `widgets/checkbox.dart`). The `Checkbox`
+constructor looks like this:
+
+```dart
+ ValueChanged onChanged;
+ bool checked;
+
+ Checkbox({ Object key, this.onChanged, this.checked }) : super(key: key);
+```
+
+What this means is that the `Checkbox` component *never* "owns" the state of
+the checkbox. It's current state is handed into the `checked` parameter, and
+when a click occurs, the checkbox invokes its `onChanged` callback with the
+value it thinks it should be changed to -- but it never directly changes the
+value itself. This is a bit odd at first look, but if you think about it: a
+control isn't very useful unless it gets its value out to someone and if you
+think about databinding, the same thing happens: databinding basically tells a
+control to *treat some remote variable as its storage*. That's all that is
+happening here. In this case, some owning component probably has a set of values
+which describe a form.
+
+Stateful vs. Stateless components
+---------------------------------
+
+All components have access to two kinds of state: (1) configuration data
+(constructor arguments) and (2) private data (data they mutate themselves).
+While react components have explicit property bags for these two kinds of state
+(`this.prop` and `this.state`), Effen maps these ideas to the public and private
+fields of the component. Constructor arguments should (by convention) be
+reflected as public fields of the component and state should only be set on
+private (with a leading underbar `_`) fields.
+
+All (non-component) Effen nodes are stateless. Some components will be stateful.
+This state will likely encapsulate transient states of the UI, such as scroll
+position, animation state, uncommitted form values, etc...
+
+A component can become stateful in two ways: (1) by passing `super(stateful:
+true)` to its call to the superclass's constructor, or by calling
+`setState(Function fn)`. The former is a way to have a component start its life
+stateful, and the latter results in the component becoming statefull *as well
+as* scheduling the component to re-build at the end of the current animation
+frame.
+
+What does it mean to be stateful? It means that the diffing mechanism retains
+the specific *instance* of the component as long as the component which builds
+it continues to require its presence. The component which constructed it may
+have provided new configuration in form of different values for the constructor
+parameters, but these values (public fields) will be copied (using reflection)
+onto the retained instance whose privates fields are left unmodified.
+
+Rendering
+---------
+
+At the end of each animation frame, all components (including the root `App`)
+which have `setState` on themselves will be rebuilt and the resulting changes
+will be minimally applied to the DOM. Note that components of lower "order"
+(those near the root of the tree) will build first because their building may
+require rebuilding of higher order (those near the leaves), thus avoiding the
+possibility that a component which is dirty build more than once during a single
+cycle.
+
+Keys
+----
+
+In order to efficiently apply changes to the DOM and to ensure that stateful
+components are correctly identified, Effen requires that `no two nodes (except
+Text) or components of the same type may exist as children of another element
+without being distinguished by unique keys`. [`Text` is excused from this rule].
+In many cases, nodes don't require a key because there is only one type amongst
+its siblings -- but if there is more one, you must assign each a key. This is
+why most nodes will take `({ Object key })` as an optional constructor
+parameter. In development mode (i.e. when sky is built `Debug`) Effen will throw
+an error if you forget to do this.
+
+Event Handling
+--------------
+
+Events logically fire through the Effen node tree. If want to handle an event as
+it bubbles from the target to the root, create an `EventListenerNode`. `EventListenerNode`
+has named (typed) parameters for a small set of events that we've hit so far, as
+well as a 'custom' argument which is a `Map`. If
+you'd like to add a type argument for an event, just post a patch.
+
+```dart
+class MyComp extends Component {
+ MyComp({
+ Object key
+ }) : super(key: key);
+
+ void _handleTap(sky.GestureEvent e) {
+ // do stuff
+ }
+
+ void _customEventCallback(sky.Event e) {
+ // do other stuff
+ }
+
+ UINode build() {
+ new EventListenerNode(
+ new Container(
+ children: // ...
+ ),
+ onGestureTap: _handleTap,
+ custom: {
+ 'myCustomEvent': _customEventCallback
+ }
+ );
+ }
+
+ _handleScroll(sky.Event e) {
+ setState(() {
+ // update the scroll position
+ });
+ }
+}
+```
+
+Styling
+-------
+
+Styling is the part of Effen which is least designed and is likely to change.
+There are three ways to specify styles:
+
+ * `Style` objects which are interned and can be applied to WrapperNodes via the
+ ``style` constructor parameter. Use `Style` objects for styles which are
+ `*not* animated.
+
+ * An `inlineStyle` string which can be applied to Elements via the
+ `inlineStyle` constructor parameter. Use `inlineStyle` for styles which
+ *are* animated.
+
+If you need to apply a Style to a Component or UINode which you didn't construct
+(i.e. one that was handed into your constructor), you can wrap it in a
+`StyleNode` which also takes a `Style` constructor in it's `style` constructor
+parameter.
+
+Animation
+---------
+
+Animation is still an area of exploration. Have a look at
+[AnimatedComponent](components/animated_component.dart) and
+[Drawer](components/drawer.dart) for an example of this this currently works.
+
+Performance
+-----------
+
+It is a design goal that it should be *possible* to arrange that all "build"
+cycles which happen during animations can complete in less than one milliesecond
+on a Nexus 5.
diff --git a/sdk/lib/framework/rendering/box.dart b/sdk/lib/framework/rendering/box.dart
index 6a8968676da24626bc4a01f09d150adaac4a6bf5..f6bf0da0977043b5f84b285908bdd0ee37d90250 100644
--- a/sdk/lib/framework/rendering/box.dart
+++ b/sdk/lib/framework/rendering/box.dart
@@ -4,7 +4,6 @@
import 'dart:math' as math;
import 'dart:sky' as sky;
-import 'dart:typed_data';
import 'object.dart';
import '../painting/box_painter.dart';
import 'package:vector_math/vector_math.dart';
diff --git a/sdk/lib/framework/rendering/object.dart b/sdk/lib/framework/rendering/object.dart
index ace0aed7cdc13d0b8030f5a7c576a6fba14e3daf..c3dc2f094936ebba5789c670adfa2314868f6731 100644
--- a/sdk/lib/framework/rendering/object.dart
+++ b/sdk/lib/framework/rendering/object.dart
@@ -4,7 +4,6 @@
import '../node.dart';
import '../scheduler.dart' as scheduler;
-import 'dart:math' as math;
import 'dart:sky' as sky;
import 'dart:sky' show Point, Size, Rect, Color, Paint, Path;
export 'dart:sky' show Point, Size, Rect, Color, Paint, Path;
diff --git a/sdk/lib/framework/scheduler.dart b/sdk/lib/framework/scheduler.dart
index 9c2f181c5c754d4a24ec70d7ae9949bc60b9be5d..96dbfd09f0219461dc9eecf2eab35752b31c2f5f 100644
--- a/sdk/lib/framework/scheduler.dart
+++ b/sdk/lib/framework/scheduler.dart
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'dart:async';
import 'dart:sky' as sky;
typedef void Callback(double timeStamp);
diff --git a/sdk/lib/framework/components2/animated_component.dart b/sdk/lib/framework/widgets/animated_component.dart
similarity index 98%
rename from sdk/lib/framework/components2/animated_component.dart
rename to sdk/lib/framework/widgets/animated_component.dart
index 9a02fd531dddd9e5b4ea10c6fea0e09382df625e..b4727da031644dcfe99baa718a9313613fa89329 100644
--- a/sdk/lib/framework/components2/animated_component.dart
+++ b/sdk/lib/framework/widgets/animated_component.dart
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../animation/animated_value.dart';
-import '../fn2.dart';
import 'dart:async';
+import '../animation/animated_value.dart';
+import 'wrappers.dart';
+
typedef void SetterFunction(double value);
class _AnimationEntry {
diff --git a/sdk/lib/framework/components2/button.dart b/sdk/lib/framework/widgets/button.dart
similarity index 96%
rename from sdk/lib/framework/components2/button.dart
rename to sdk/lib/framework/widgets/button.dart
index 59add1743f0c86a658603b904e9e0148d59b2b60..b41eadbd93e26dcabdc4a0ec40c1e83e794ec12c 100644
--- a/sdk/lib/framework/components2/button.dart
+++ b/sdk/lib/framework/widgets/button.dart
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
import 'ink_well.dart';
import 'material.dart';
+import 'wrappers.dart';
class Button extends Component {
diff --git a/sdk/lib/framework/components2/button_base.dart b/sdk/lib/framework/widgets/button_base.dart
similarity index 97%
rename from sdk/lib/framework/components2/button_base.dart
rename to sdk/lib/framework/widgets/button_base.dart
index c8a9c37e62909d516bb4652330169cd13a9ff3e3..5ae273c1a11063d9783125ebeb735596912553c5 100644
--- a/sdk/lib/framework/components2/button_base.dart
+++ b/sdk/lib/framework/widgets/button_base.dart
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
+import 'wrappers.dart';
abstract class ButtonBase extends Component {
diff --git a/sdk/lib/framework/components2/checkbox.dart b/sdk/lib/framework/widgets/checkbox.dart
similarity index 97%
rename from sdk/lib/framework/components2/checkbox.dart
rename to sdk/lib/framework/widgets/checkbox.dart
index 36fd278dbdbe9bfe133dc2d80b550616bc1a35c7..1d2630c48487e9f77f3d34126202361c8a9c698e 100644
--- a/sdk/lib/framework/components2/checkbox.dart
+++ b/sdk/lib/framework/widgets/checkbox.dart
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:sky' as sky;
+
import 'package:sky/framework/theme2/colors.dart' as colors;
-import 'dart:sky' as sky;
-import '../fn2.dart';
import '../rendering/box.dart';
-import '../rendering/object.dart';
import 'button_base.dart';
+import 'wrappers.dart';
typedef void ValueChanged(value);
diff --git a/sdk/lib/framework/components2/drawer.dart b/sdk/lib/framework/widgets/drawer.dart
similarity index 99%
rename from sdk/lib/framework/components2/drawer.dart
rename to sdk/lib/framework/widgets/drawer.dart
index 8ae1cab97acb4aeba1bd73fcad54bb3bd8900e47..71596f9aeba83246ea59862b01765a1d5e646098 100644
--- a/sdk/lib/framework/components2/drawer.dart
+++ b/sdk/lib/framework/widgets/drawer.dart
@@ -2,16 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:math' as math;
+import 'dart:sky' as sky;
+
+import 'package:vector_math/vector_math.dart';
+
import '../animation/animated_value.dart';
import '../animation/curves.dart';
-import '../fn2.dart';
import '../theme2/colors.dart';
import '../theme2/shadows.dart';
import 'animated_component.dart';
-import 'dart:math' as math;
-import 'dart:sky' as sky;
-import 'material.dart';
-import 'package:vector_math/vector_math.dart';
+import 'wrappers.dart';
// TODO(eseidel): Draw width should vary based on device size:
// http://www.google.com/design/spec/layout/structure.html#structure-side-nav
diff --git a/sdk/lib/framework/components2/drawer_header.dart b/sdk/lib/framework/widgets/drawer_header.dart
similarity index 98%
rename from sdk/lib/framework/components2/drawer_header.dart
rename to sdk/lib/framework/widgets/drawer_header.dart
index 652596d559c7899e91ba8985d87370d4ced242df..88fb881705c0bbcbf725f9a8de2edb2491f68614 100644
--- a/sdk/lib/framework/components2/drawer_header.dart
+++ b/sdk/lib/framework/widgets/drawer_header.dart
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
import '../theme2/colors.dart';
import '../theme2/view_configuration.dart';
+import 'wrappers.dart';
class DrawerHeader extends Component {
diff --git a/sdk/lib/framework/components2/fixed_height_scrollable.dart b/sdk/lib/framework/widgets/fixed_height_scrollable.dart
similarity index 98%
rename from sdk/lib/framework/components2/fixed_height_scrollable.dart
rename to sdk/lib/framework/widgets/fixed_height_scrollable.dart
index 95392802c7dfdb8d0624ffa08a62e3d90c0cc1d3..70df8523d8d28039a319935c18c28f2f3ec2909c 100644
--- a/sdk/lib/framework/components2/fixed_height_scrollable.dart
+++ b/sdk/lib/framework/widgets/fixed_height_scrollable.dart
@@ -2,12 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../animation/scroll_behavior.dart';
-import '../fn2.dart';
-import 'dart:async';
import 'dart:math' as math;
+
import 'package:vector_math/vector_math.dart';
+
+import '../animation/scroll_behavior.dart';
import 'scrollable.dart';
+import 'wrappers.dart';
abstract class FixedHeightScrollable extends Scrollable {
diff --git a/sdk/lib/framework/components2/floating_action_button.dart b/sdk/lib/framework/widgets/floating_action_button.dart
similarity index 96%
rename from sdk/lib/framework/components2/floating_action_button.dart
rename to sdk/lib/framework/widgets/floating_action_button.dart
index b5555f1cf451c152528ba5307c9b5bee9ef453c0..3aa9124665683f3ff021c194f5345bc45f4a81d4 100644
--- a/sdk/lib/framework/components2/floating_action_button.dart
+++ b/sdk/lib/framework/widgets/floating_action_button.dart
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
-import '../rendering/box.dart';
+import 'dart:sky' as sky;
+
import '../painting/shadows.dart';
import '../theme2/colors.dart';
-import 'dart:sky' as sky;
import 'ink_well.dart';
import 'material.dart';
+import 'wrappers.dart';
// TODO(eseidel): This needs to change based on device size?
// http://www.google.com/design/spec/layout/metrics-keylines.html#metrics-keylines-keylines-spacing
diff --git a/sdk/lib/framework/components2/icon.dart b/sdk/lib/framework/widgets/icon.dart
similarity index 97%
rename from sdk/lib/framework/components2/icon.dart
rename to sdk/lib/framework/widgets/icon.dart
index 7ab1e6acc0c70a4b8bf7c194c7eff4c7ebf2aad8..abd7b6cefd7a4ae5b51864781b397d8006c6403c 100644
--- a/sdk/lib/framework/components2/icon.dart
+++ b/sdk/lib/framework/widgets/icon.dart
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
+import 'wrappers.dart';
// TODO(eseidel): This should use package:.
const String kAssetBase = '/packages/sky/assets/material-design-icons';
diff --git a/sdk/lib/framework/components2/icon_button.dart b/sdk/lib/framework/widgets/icon_button.dart
similarity index 92%
rename from sdk/lib/framework/components2/icon_button.dart
rename to sdk/lib/framework/widgets/icon_button.dart
index d404be632cea8b016a2344aaaebc74ddca73036b..56af188b6714df7f85024501073b7adc67935a0a 100644
--- a/sdk/lib/framework/components2/icon_button.dart
+++ b/sdk/lib/framework/widgets/icon_button.dart
@@ -2,9 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
import '../rendering/box.dart';
import 'icon.dart';
+import 'ui_node.dart';
+import 'wrappers.dart';
class IconButton extends Component {
diff --git a/sdk/lib/framework/components2/ink_well.dart b/sdk/lib/framework/widgets/ink_well.dart
similarity index 98%
rename from sdk/lib/framework/components2/ink_well.dart
rename to sdk/lib/framework/widgets/ink_well.dart
index a67a63533c3ac60a644040496eb0bd2bd37950f2..48188f52a93897b1827a7a7cb3224e805dfb5489 100644
--- a/sdk/lib/framework/components2/ink_well.dart
+++ b/sdk/lib/framework/widgets/ink_well.dart
@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:math' as math;
+import 'dart:sky' as sky;
+
import '../animation/animated_value.dart';
import '../animation/curves.dart';
-import '../fn2.dart';
import '../rendering/box.dart';
import '../rendering/flex.dart';
import '../rendering/object.dart';
-import 'dart:async';
-import 'dart:collection';
-import 'dart:math' as math;
-import 'dart:sky' as sky;
+import 'ui_node.dart';
+import 'wrappers.dart';
const int _kSplashInitialOpacity = 0x80;
const double _kSplashInitialDelay = 0.0; // we could delay initially in case the user scrolls
diff --git a/sdk/lib/framework/components2/material.dart b/sdk/lib/framework/widgets/material.dart
similarity index 93%
rename from sdk/lib/framework/components2/material.dart
rename to sdk/lib/framework/widgets/material.dart
index 1ee295a5a13b1366a37dd3cd2a9d4119c695b71a..89f3a56a198dcc2ed058a26b6bd5bd8a7bb7d021 100644
--- a/sdk/lib/framework/components2/material.dart
+++ b/sdk/lib/framework/widgets/material.dart
@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
-import '../theme/shadows.dart';
+import 'wrappers.dart';
class Material extends Component {
diff --git a/sdk/lib/framework/components2/menu_divider.dart b/sdk/lib/framework/widgets/menu_divider.dart
similarity index 95%
rename from sdk/lib/framework/components2/menu_divider.dart
rename to sdk/lib/framework/widgets/menu_divider.dart
index 253e213a23b77491c1bea8f2fc7158a34e16e5c4..89faa11dd308cbcdd03a552ee4e181059958f4bf 100644
--- a/sdk/lib/framework/components2/menu_divider.dart
+++ b/sdk/lib/framework/widgets/menu_divider.dart
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
+import 'wrappers.dart';
class MenuDivider extends Component {
MenuDivider({ Object key }) : super(key: key);
diff --git a/sdk/lib/framework/components2/menu_item.dart b/sdk/lib/framework/widgets/menu_item.dart
similarity index 97%
rename from sdk/lib/framework/components2/menu_item.dart
rename to sdk/lib/framework/widgets/menu_item.dart
index 4f4bd79a73893249352b8b3a3237040ad45ae0df..52d1c5310e0a6061001faa78a8221e5b272cf9e3 100644
--- a/sdk/lib/framework/components2/menu_item.dart
+++ b/sdk/lib/framework/widgets/menu_item.dart
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
import 'button_base.dart';
import 'icon.dart';
import 'ink_well.dart';
+import 'ui_node.dart';
+import 'wrappers.dart';
const BoxDecoration _kHighlightDecoration = const BoxDecoration(
backgroundColor: const Color.fromARGB(102, 153, 153, 153)
diff --git a/sdk/lib/framework/components2/modal_overlay.dart b/sdk/lib/framework/widgets/modal_overlay.dart
similarity index 93%
rename from sdk/lib/framework/components2/modal_overlay.dart
rename to sdk/lib/framework/widgets/modal_overlay.dart
index 84951e051f572d71a768aeed8aed716fc8ec61c2..e53891be50a458a0ec440b0014435614bdd389ac 100644
--- a/sdk/lib/framework/components2/modal_overlay.dart
+++ b/sdk/lib/framework/widgets/modal_overlay.dart
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
+import 'ui_node.dart';
+import 'wrappers.dart';
class ModalOverlay extends Component {
diff --git a/sdk/lib/framework/components2/popup_menu.dart b/sdk/lib/framework/widgets/popup_menu.dart
similarity index 99%
rename from sdk/lib/framework/components2/popup_menu.dart
rename to sdk/lib/framework/widgets/popup_menu.dart
index 62e93f8d4901d000fe146dc19fa4b096d6451895..8307996a575d3ff27bad8154bb6a123b1a9f580a 100644
--- a/sdk/lib/framework/components2/popup_menu.dart
+++ b/sdk/lib/framework/widgets/popup_menu.dart
@@ -7,13 +7,13 @@ import 'dart:math' as math;
import 'dart:sky' as sky;
import '../animation/animated_value.dart';
-import '../fn2.dart';
import '../painting/box_painter.dart';
import '../theme2/colors.dart';
import '../theme2/shadows.dart';
import 'animated_component.dart';
import 'material.dart';
import 'popup_menu_item.dart';
+import 'wrappers.dart';
const double _kMenuOpenDuration = 300.0;
const double _kMenuCloseDuration = 200.0;
diff --git a/sdk/lib/framework/components2/popup_menu_item.dart b/sdk/lib/framework/widgets/popup_menu_item.dart
similarity index 96%
rename from sdk/lib/framework/components2/popup_menu_item.dart
rename to sdk/lib/framework/widgets/popup_menu_item.dart
index 78bb37f47bdc1f064a6f89d321c8f78258dfbd60..b0e3453baa6162ccae4f507bc6f71acd1c703e21 100644
--- a/sdk/lib/framework/components2/popup_menu_item.dart
+++ b/sdk/lib/framework/widgets/popup_menu_item.dart
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
+import 'wrappers.dart';
import 'ink_well.dart';
class PopupMenuItem extends Component {
diff --git a/sdk/lib/framework/components2/radio.dart b/sdk/lib/framework/widgets/radio.dart
similarity index 97%
rename from sdk/lib/framework/components2/radio.dart
rename to sdk/lib/framework/widgets/radio.dart
index 36134ed5d645b43c0a5fffc1727f98a587c32c7f..b119d7fe41a805db48e40ff72df511d1a4978c95 100644
--- a/sdk/lib/framework/components2/radio.dart
+++ b/sdk/lib/framework/widgets/radio.dart
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:sky' as sky;
+
import 'package:sky/framework/theme2/colors.dart' as colors;
-import '../fn2.dart';
import '../rendering/object.dart';
import 'button_base.dart';
-import 'ink_well.dart';
-import 'dart:sky' as sky;
+import 'wrappers.dart';
typedef void ValueChanged(value);
diff --git a/sdk/lib/framework/components2/scaffold.dart b/sdk/lib/framework/widgets/scaffold.dart
similarity index 99%
rename from sdk/lib/framework/components2/scaffold.dart
rename to sdk/lib/framework/widgets/scaffold.dart
index 1ba9107400e92f4239ceccaa472cceb6e808dac6..5d95f6306467b6c9c5e2d00f2032b5f8324de22d 100644
--- a/sdk/lib/framework/components2/scaffold.dart
+++ b/sdk/lib/framework/widgets/scaffold.dart
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
import '../rendering/box.dart';
import '../rendering/object.dart';
import '../theme2/view_configuration.dart';
+import 'ui_node.dart';
enum ScaffoldSlots {
toolbar,
diff --git a/sdk/lib/framework/components2/scrollable.dart b/sdk/lib/framework/widgets/scrollable.dart
similarity index 99%
rename from sdk/lib/framework/components2/scrollable.dart
rename to sdk/lib/framework/widgets/scrollable.dart
index dee2c137335f2e4647d5b4a3700459085341f169..16478f4652d6164ec227d41d3568a0b5bac6180a 100644
--- a/sdk/lib/framework/components2/scrollable.dart
+++ b/sdk/lib/framework/widgets/scrollable.dart
@@ -2,13 +2,14 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:math' as math;
+import 'dart:sky' as sky;
+
import '../animation/generators.dart';
import '../animation/mechanics.dart';
import '../animation/scroll_behavior.dart';
-import '../fn2.dart';
import '../theme/view_configuration.dart' as config;
-import 'dart:math' as math;
-import 'dart:sky' as sky;
+import 'wrappers.dart';
const double _kMillisecondsPerSecond = 1000.0;
diff --git a/sdk/lib/framework/components2/tool_bar.dart b/sdk/lib/framework/widgets/tool_bar.dart
similarity index 97%
rename from sdk/lib/framework/components2/tool_bar.dart
rename to sdk/lib/framework/widgets/tool_bar.dart
index a4df2eb8a32c7bcde727e6fc44740c6343e82b57..620f85285633cbdee1d84c8f24bcbeea2bdd6852 100644
--- a/sdk/lib/framework/components2/tool_bar.dart
+++ b/sdk/lib/framework/widgets/tool_bar.dart
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import '../fn2.dart';
import '../rendering/flex.dart';
-import '../theme2/view_configuration.dart';
import '../theme2/shadows.dart';
+import '../theme2/view_configuration.dart';
+import 'wrappers.dart';
class ToolBar extends Component {
diff --git a/sdk/lib/framework/fn2.dart b/sdk/lib/framework/widgets/ui_node.dart
similarity index 70%
rename from sdk/lib/framework/fn2.dart
rename to sdk/lib/framework/widgets/ui_node.dart
index 227d04cb3db9fad33f1765917c845acee8358cb9..2d1cd2497b73444203874a6e78180409b87536df 100644
--- a/sdk/lib/framework/fn2.dart
+++ b/sdk/lib/framework/widgets/ui_node.dart
@@ -2,23 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-library fn;
-
-import 'app.dart';
import 'dart:async';
import 'dart:collection';
import 'dart:mirrors';
import 'dart:sky' as sky;
-import 'package:vector_math/vector_math.dart';
-import 'rendering/block.dart';
-import 'rendering/box.dart';
-import 'rendering/flex.dart';
-import 'rendering/object.dart';
-import 'rendering/paragraph.dart';
-import 'rendering/stack.dart';
-export 'rendering/object.dart' show Point, Size, Rect, Color, Paint, Path;
-export 'rendering/box.dart' show BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims;
-export 'rendering/flex.dart' show FlexDirection;
+
+import '../app.dart';
+import '../rendering/box.dart';
+import '../rendering/object.dart';
+
+export '../rendering/box.dart' show BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims;
+export '../rendering/flex.dart' show FlexDirection;
+export '../rendering/object.dart' show Point, Size, Rect, Color, Paint, Path;
+
// final sky.Tracing _tracing = sky.window.tracing;
@@ -155,6 +151,7 @@ abstract class UINode {
}
}
+
// Descendants of TagNode provide a way to tag RenderObjectWrapper and
// Component nodes with annotations, such as event listeners,
// stylistic information, etc.
@@ -275,6 +272,190 @@ class EventListenerNode extends TagNode {
}
+
+abstract class Component extends UINode {
+
+ Component({ Object key, bool stateful })
+ : _stateful = stateful != null ? stateful : false,
+ _order = _currentOrder + 1,
+ super(key: key);
+
+ Component.fromArgs(Object key, bool stateful)
+ : this(key: key, stateful: stateful);
+
+ static Component _currentlyBuilding;
+ bool get _isBuilding => _currentlyBuilding == this;
+
+ bool _stateful;
+ bool _dirty = true;
+ bool _disqualifiedFromEverAppearingAgain = false;
+
+ UINode _built;
+ dynamic _slot; // cached slot from the last time we were synced
+
+ void didMount() {
+ assert(!_disqualifiedFromEverAppearingAgain);
+ super.didMount();
+ }
+
+ void remove() {
+ assert(_built != null);
+ assert(root != null);
+ removeChild(_built);
+ _built = null;
+ super.remove();
+ }
+
+ bool _retainStatefulNodeIfPossible(UINode old) {
+ assert(!_disqualifiedFromEverAppearingAgain);
+
+ Component oldComponent = old as Component;
+ if (oldComponent == null || !oldComponent._stateful)
+ return false;
+
+ assert(key == oldComponent.key);
+
+ // Make |this|, the newly-created object, into the "old" Component, and kill it
+ _stateful = false;
+ _built = oldComponent._built;
+ assert(_built != null);
+ _disqualifiedFromEverAppearingAgain = true;
+
+ // Make |oldComponent| the "new" component
+ oldComponent._built = null;
+ oldComponent._dirty = true;
+ oldComponent.syncFields(this);
+ return true;
+ }
+
+ // This is called by _retainStatefulNodeIfPossible(), during
+ // syncChild(), just before _sync() is called.
+ // This must be implemented on any subclass that can become stateful
+ // (but don't call super.syncFields() if you inherit directly from
+ // Component, since that'll fire an assert).
+ // If you don't ever become stateful, then don't override this.
+ void syncFields(Component source) {
+ assert(false);
+ }
+
+ final int _order;
+ static int _currentOrder = 0;
+
+ /* There are three cases here:
+ * 1) Building for the first time:
+ * assert(_built == null && old == null)
+ * 2) Re-building (because a dirty flag got set):
+ * assert(_built != null && old == null)
+ * 3) Syncing against an old version
+ * assert(_built == null && old != null)
+ */
+ void _sync(UINode old, dynamic slot) {
+ assert(_built == null || old == null);
+ assert(!_disqualifiedFromEverAppearingAgain);
+
+ Component oldComponent = old as Component;
+
+ _slot = slot;
+
+ var oldBuilt;
+ if (oldComponent == null) {
+ oldBuilt = _built;
+ } else {
+ assert(_built == null);
+ oldBuilt = oldComponent._built;
+ }
+
+ int lastOrder = _currentOrder;
+ _currentOrder = _order;
+ _currentlyBuilding = this;
+ _built = build();
+ assert(_built != null);
+ _currentlyBuilding = null;
+ _currentOrder = lastOrder;
+
+ _built = syncChild(_built, oldBuilt, slot);
+ assert(_built != null);
+ _dirty = false;
+ _root = _built.root;
+ assert(_root == root); // in case a subclass reintroduces it
+ assert(root != null);
+ }
+
+ void _buildIfDirty() {
+ assert(!_disqualifiedFromEverAppearingAgain);
+ if (!_dirty || !_mounted)
+ return;
+
+ assert(root != null);
+ _sync(null, _slot);
+ }
+
+ void scheduleBuild() {
+ setState(() {});
+ }
+
+ void setState(Function fn()) {
+ assert(!_disqualifiedFromEverAppearingAgain);
+ _stateful = true;
+ fn();
+ if (_isBuilding || _dirty || !_mounted)
+ return;
+
+ _dirty = true;
+ _scheduleComponentForRender(this);
+ }
+
+ UINode build();
+
+}
+
+Set _dirtyComponents = new Set();
+bool _buildScheduled = false;
+bool _inRenderDirtyComponents = false;
+
+void _buildDirtyComponents() {
+ //_tracing.begin('fn::_buildDirtyComponents');
+
+ Stopwatch sw;
+ if (_shouldLogRenderDuration)
+ sw = new Stopwatch()..start();
+
+ try {
+ _inRenderDirtyComponents = true;
+
+ List sortedDirtyComponents = _dirtyComponents.toList();
+ sortedDirtyComponents.sort((Component a, Component b) => a._order - b._order);
+ for (var comp in sortedDirtyComponents) {
+ comp._buildIfDirty();
+ }
+
+ _dirtyComponents.clear();
+ _buildScheduled = false;
+ } finally {
+ _inRenderDirtyComponents = false;
+ }
+
+ UINode._notifyMountStatusChanged();
+
+ if (_shouldLogRenderDuration) {
+ sw.stop();
+ print('Render took ${sw.elapsedMicroseconds} microseconds');
+ }
+
+ //_tracing.end('fn::_buildDirtyComponents');
+}
+
+void _scheduleComponentForRender(Component c) {
+ assert(!_inRenderDirtyComponents);
+ _dirtyComponents.add(c);
+
+ if (!_buildScheduled) {
+ _buildScheduled = true;
+ new Future.microtask(_buildDirtyComponents);
+ }
+}
+
+
/*
* RenderObjectWrappers correspond to a desired state of a RenderObject.
* They are fully immutable, with one exception: A UINode which is a
@@ -378,253 +559,76 @@ abstract class OneChildRenderObjectWrapper extends RenderObjectWrapper {
}
-class Opacity extends OneChildRenderObjectWrapper {
- Opacity({ this.opacity, UINode child, Object key })
- : super(child: child, key: key);
-
- RenderOpacity get root { RenderOpacity result = super.root; return result; }
- final double opacity;
+abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
- RenderOpacity createNode() => new RenderOpacity(opacity: opacity);
+ // In MultiChildRenderObjectWrapper subclasses, slots are RenderObject nodes
+ // to use as the "insert before" sibling in ContainerRenderObjectMixin.add() calls
- void syncRenderObject(Opacity old) {
- super.syncRenderObject(old);
- root.opacity = opacity;
+ MultiChildRenderObjectWrapper({
+ Object key,
+ List children
+ }) : this.children = children == null ? const [] : children,
+ super(key: key) {
+ assert(!_debugHasDuplicateIds());
}
-}
-
-class ClipRect extends OneChildRenderObjectWrapper {
-
- ClipRect({ UINode child, Object key })
- : super(child: child, key: key);
-
- RenderClipRect get root { RenderClipRect result = super.root; return result; }
- RenderClipRect createNode() => new RenderClipRect();
-}
-
-class ClipOval extends OneChildRenderObjectWrapper {
- ClipOval({ UINode child, Object key })
- : super(child: child, key: key);
+ final List children;
- RenderClipOval get root { RenderClipOval result = super.root; return result; }
- RenderClipOval createNode() => new RenderClipOval();
-}
+ void insert(RenderObjectWrapper child, dynamic slot) {
+ final root = this.root; // TODO(ianh): Remove this once the analyzer is cleverer
+ assert(slot == null || slot is RenderObject);
+ assert(root is ContainerRenderObjectMixin);
+ root.add(child.root, before: slot);
+ assert(root == this.root); // TODO(ianh): Remove this once the analyzer is cleverer
+ }
-class Padding extends OneChildRenderObjectWrapper {
+ void removeChild(UINode node) {
+ final root = this.root; // TODO(ianh): Remove this once the analyzer is cleverer
+ assert(root is ContainerRenderObjectMixin);
+ assert(node.root.parent == root);
+ root.remove(node.root);
+ super.removeChild(node);
+ assert(root == this.root); // TODO(ianh): Remove this once the analyzer is cleverer
+ }
- Padding({ this.padding, UINode child, Object key })
- : super(child: child, key: key);
+ void remove() {
+ assert(children != null);
+ for (var child in children) {
+ assert(child != null);
+ removeChild(child);
+ }
+ super.remove();
+ }
- RenderPadding get root { RenderPadding result = super.root; return result; }
- final EdgeDims padding;
+ bool _debugHasDuplicateIds() {
+ var idSet = new HashSet();
+ for (var child in children) {
+ assert(child != null);
+ if (child.interchangeable)
+ continue; // when these nodes are reordered, we just reassign the data
- RenderPadding createNode() => new RenderPadding(padding: padding);
+ if (!idSet.add(child._key)) {
+ throw '''If multiple non-interchangeable nodes of the same type exist as children
+ of another node, they must have unique keys.
+ Duplicate: "${child._key}"''';
+ }
+ }
+ return false;
+ }
- void syncRenderObject(Padding old) {
+ void syncRenderObject(MultiChildRenderObjectWrapper old) {
super.syncRenderObject(old);
- root.padding = padding;
- }
-}
+ final root = this.root; // TODO(ianh): Remove this once the analyzer is cleverer
+ if (root is! ContainerRenderObjectMixin)
+ return;
-class DecoratedBox extends OneChildRenderObjectWrapper {
+ var startIndex = 0;
+ var endIndex = children.length;
- DecoratedBox({ this.decoration, UINode child, Object key })
- : super(child: child, key: key);
-
- RenderDecoratedBox get root { RenderDecoratedBox result = super.root; return result; }
- final BoxDecoration decoration;
-
- RenderDecoratedBox createNode() => new RenderDecoratedBox(decoration: decoration);
-
- void syncRenderObject(DecoratedBox old) {
- super.syncRenderObject(old);
- root.decoration = decoration;
- }
-
-}
-
-class SizedBox extends OneChildRenderObjectWrapper {
-
- SizedBox({
- double width: double.INFINITY,
- double height: double.INFINITY,
- UINode child,
- Object key
- }) : desiredSize = new Size(width, height), super(child: child, key: key);
-
- RenderSizedBox get root { RenderSizedBox result = super.root; return result; }
- final Size desiredSize;
-
- RenderSizedBox createNode() => new RenderSizedBox(desiredSize: desiredSize);
-
- void syncRenderObject(SizedBox old) {
- super.syncRenderObject(old);
- root.desiredSize = desiredSize;
- }
-
-}
-
-class ConstrainedBox extends OneChildRenderObjectWrapper {
-
- ConstrainedBox({ this.constraints, UINode child, Object key })
- : super(child: child, key: key);
-
- RenderConstrainedBox get root { RenderConstrainedBox result = super.root; return result; }
- final BoxConstraints constraints;
-
- RenderConstrainedBox createNode() => new RenderConstrainedBox(additionalConstraints: constraints);
-
- void syncRenderObject(ConstrainedBox old) {
- super.syncRenderObject(old);
- root.additionalConstraints = constraints;
- }
-
-}
-
-class ShrinkWrapWidth extends OneChildRenderObjectWrapper {
-
- ShrinkWrapWidth({ UINode child, Object key }) : super(child: child, key: key);
-
- RenderShrinkWrapWidth get root { RenderShrinkWrapWidth result = super.root; return result; }
-
- RenderShrinkWrapWidth createNode() => new RenderShrinkWrapWidth();
-
-}
-
-class Transform extends OneChildRenderObjectWrapper {
-
- Transform({ this.transform, UINode child, Object key })
- : super(child: child, key: key);
-
- RenderTransform get root { RenderTransform result = super.root; return result; }
- final Matrix4 transform;
-
- RenderTransform createNode() => new RenderTransform(transform: transform);
-
- void syncRenderObject(Transform old) {
- super.syncRenderObject(old);
- root.transform = transform;
- }
-
-}
-
-class SizeObserver extends OneChildRenderObjectWrapper {
-
- SizeObserver({ this.callback, UINode child, Object key })
- : super(child: child, key: key);
-
- RenderSizeObserver get root { RenderSizeObserver result = super.root; return result; }
- final SizeChangedCallback callback;
-
- RenderSizeObserver createNode() => new RenderSizeObserver(callback: callback);
-
- void syncRenderObject(SizeObserver old) {
- super.syncRenderObject(old);
- root.callback = callback;
- }
-
- void remove() {
- root.callback = null;
- super.remove();
- }
-
-}
-
-// TODO(jackson) need a mechanism for marking the RenderCustomPaint as needing paint
-class CustomPaint extends OneChildRenderObjectWrapper {
-
- CustomPaint({ this.callback, UINode child, Object key })
- : super(child: child, key: key);
-
- RenderCustomPaint get root { RenderCustomPaint result = super.root; return result; }
- final CustomPaintCallback callback;
-
- RenderCustomPaint createNode() => new RenderCustomPaint(callback: callback);
-
- void syncRenderObject(CustomPaint old) {
- super.syncRenderObject(old);
- root.callback = callback;
- }
-
- void remove() {
- root.callback = null;
- super.remove();
- }
-
-}
-
-abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
-
- // In MultiChildRenderObjectWrapper subclasses, slots are RenderObject nodes
- // to use as the "insert before" sibling in ContainerRenderObjectMixin.add() calls
-
- MultiChildRenderObjectWrapper({
- Object key,
- List children
- }) : this.children = children == null ? const [] : children,
- super(key: key) {
- assert(!_debugHasDuplicateIds());
- }
-
- final List children;
-
- void insert(RenderObjectWrapper child, dynamic slot) {
- final root = this.root; // TODO(ianh): Remove this once the analyzer is cleverer
- assert(slot == null || slot is RenderObject);
- assert(root is ContainerRenderObjectMixin);
- root.add(child.root, before: slot);
- assert(root == this.root); // TODO(ianh): Remove this once the analyzer is cleverer
- }
-
- void removeChild(UINode node) {
- final root = this.root; // TODO(ianh): Remove this once the analyzer is cleverer
- assert(root is ContainerRenderObjectMixin);
- assert(node.root.parent == root);
- root.remove(node.root);
- super.removeChild(node);
- assert(root == this.root); // TODO(ianh): Remove this once the analyzer is cleverer
- }
-
- void remove() {
- assert(children != null);
- for (var child in children) {
- assert(child != null);
- removeChild(child);
- }
- super.remove();
- }
-
- bool _debugHasDuplicateIds() {
- var idSet = new HashSet();
- for (var child in children) {
- assert(child != null);
- if (child.interchangeable)
- continue; // when these nodes are reordered, we just reassign the data
-
- if (!idSet.add(child._key)) {
- throw '''If multiple non-interchangeable nodes of the same type exist as children
- of another node, they must have unique keys.
- Duplicate: "${child._key}"''';
- }
- }
- return false;
- }
-
- void syncRenderObject(MultiChildRenderObjectWrapper old) {
- super.syncRenderObject(old);
-
- final root = this.root; // TODO(ianh): Remove this once the analyzer is cleverer
- if (root is! ContainerRenderObjectMixin)
- return;
-
- var startIndex = 0;
- var endIndex = children.length;
-
- var oldChildren = old == null ? [] : old.children;
- var oldStartIndex = 0;
- var oldEndIndex = oldChildren.length;
+ var oldChildren = old == null ? [] : old.children;
+ var oldStartIndex = 0;
+ var oldEndIndex = oldChildren.length;
RenderObject nextSibling = null;
UINode currentNode = null;
@@ -740,357 +744,6 @@ abstract class MultiChildRenderObjectWrapper extends RenderObjectWrapper {
}
-class Block extends MultiChildRenderObjectWrapper {
-
- Block(List children, { Object key })
- : super(key: key, children: children);
-
- RenderBlock get root { RenderBlock result = super.root; return result; }
- RenderBlock createNode() => new RenderBlock();
-
-}
-
-class Stack extends MultiChildRenderObjectWrapper {
-
- Stack(List children, { Object key })
- : super(key: key, children: children);
-
- RenderStack get root { RenderStack result = super.root; return result; }
- RenderStack createNode() => new RenderStack();
-
-}
-
-class StackPositionedChild extends ParentDataNode {
- StackPositionedChild(UINode content, {
- double top, double right, double bottom, double left
- }) : super(content, new StackParentData()..top = top
- ..right = right
- ..bottom = bottom
- ..left = left);
-}
-
-class Paragraph extends RenderObjectWrapper {
-
- Paragraph({ Object key, this.text }) : super(key: key);
-
- RenderParagraph get root { RenderParagraph result = super.root; return result; }
- RenderParagraph createNode() => new RenderParagraph(text: text);
-
- final String text;
-
- void syncRenderObject(UINode old) {
- super.syncRenderObject(old);
- root.text = text;
- }
-
- void insert(RenderObjectWrapper child, dynamic slot) {
- assert(false);
- // Paragraph does not support having children currently
- }
-
-}
-
-class Text extends Component {
- Text(this.data) : super(key: '*text*');
- final String data;
- bool get interchangeable => true;
- UINode build() => new Paragraph(text: data);
-}
-
-class Flex extends MultiChildRenderObjectWrapper {
-
- Flex(List children, {
- Object key,
- this.direction: FlexDirection.horizontal,
- this.justifyContent: FlexJustifyContent.flexStart,
- this.alignItems: FlexAlignItems.center
- }) : super(key: key, children: children);
-
- RenderFlex get root { RenderFlex result = super.root; return result; }
- RenderFlex createNode() => new RenderFlex(direction: this.direction);
-
- final FlexDirection direction;
- final FlexJustifyContent justifyContent;
- final FlexAlignItems alignItems;
-
- void syncRenderObject(UINode old) {
- super.syncRenderObject(old);
- root.direction = direction;
- root.justifyContent = justifyContent;
- root.alignItems = alignItems;
- }
-
-}
-
-class FlexExpandingChild extends ParentDataNode {
- FlexExpandingChild(UINode content, { int flex: 1, Object key })
- : super(content, new FlexBoxParentData()..flex = flex, key: key);
-}
-
-class Image extends RenderObjectWrapper {
-
- Image({
- Object key,
- this.src,
- this.size
- }) : super(key: key);
-
- RenderImage get root { RenderImage result = super.root; return result; }
- RenderImage createNode() => new RenderImage(this.src, this.size);
-
- final String src;
- final Size size;
-
- void syncRenderObject(UINode old) {
- super.syncRenderObject(old);
- root.src = src;
- root.requestedSize = size;
- }
-
- void insert(RenderObjectWrapper child, dynamic slot) {
- assert(false);
- // Image does not support having children currently
- }
-
-}
-
-Set _dirtyComponents = new Set();
-bool _buildScheduled = false;
-bool _inRenderDirtyComponents = false;
-
-void _buildDirtyComponents() {
- //_tracing.begin('fn::_buildDirtyComponents');
-
- Stopwatch sw;
- if (_shouldLogRenderDuration)
- sw = new Stopwatch()..start();
-
- try {
- _inRenderDirtyComponents = true;
-
- List sortedDirtyComponents = _dirtyComponents.toList();
- sortedDirtyComponents.sort((Component a, Component b) => a._order - b._order);
- for (var comp in sortedDirtyComponents) {
- comp._buildIfDirty();
- }
-
- _dirtyComponents.clear();
- _buildScheduled = false;
- } finally {
- _inRenderDirtyComponents = false;
- }
-
- UINode._notifyMountStatusChanged();
-
- if (_shouldLogRenderDuration) {
- sw.stop();
- print('Render took ${sw.elapsedMicroseconds} microseconds');
- }
-
- //_tracing.end('fn::_buildDirtyComponents');
-}
-
-void _scheduleComponentForRender(Component c) {
- assert(!_inRenderDirtyComponents);
- _dirtyComponents.add(c);
-
- if (!_buildScheduled) {
- _buildScheduled = true;
- new Future.microtask(_buildDirtyComponents);
- }
-}
-
-abstract class Component extends UINode {
-
- Component({ Object key, bool stateful })
- : _stateful = stateful != null ? stateful : false,
- _order = _currentOrder + 1,
- super(key: key);
-
- Component.fromArgs(Object key, bool stateful)
- : this(key: key, stateful: stateful);
-
- static Component _currentlyBuilding;
- bool get _isBuilding => _currentlyBuilding == this;
-
- bool _stateful;
- bool _dirty = true;
- bool _disqualifiedFromEverAppearingAgain = false;
-
- UINode _built;
- dynamic _slot; // cached slot from the last time we were synced
-
- void didMount() {
- assert(!_disqualifiedFromEverAppearingAgain);
- super.didMount();
- }
-
- void remove() {
- assert(_built != null);
- assert(root != null);
- removeChild(_built);
- _built = null;
- super.remove();
- }
-
- bool _retainStatefulNodeIfPossible(UINode old) {
- assert(!_disqualifiedFromEverAppearingAgain);
-
- Component oldComponent = old as Component;
- if (oldComponent == null || !oldComponent._stateful)
- return false;
-
- assert(key == oldComponent.key);
-
- // Make |this|, the newly-created object, into the "old" Component, and kill it
- _stateful = false;
- _built = oldComponent._built;
- assert(_built != null);
- _disqualifiedFromEverAppearingAgain = true;
-
- // Make |oldComponent| the "new" component
- oldComponent._built = null;
- oldComponent._dirty = true;
- oldComponent.syncFields(this);
- return true;
- }
-
- // This is called by _retainStatefulNodeIfPossible(), during
- // syncChild(), just before _sync() is called.
- // This must be implemented on any subclass that can become stateful
- // (but don't call super.syncFields() if you inherit directly from
- // Component, since that'll fire an assert).
- // If you don't ever become stateful, then don't override this.
- void syncFields(Component source) {
- assert(false);
- }
-
- final int _order;
- static int _currentOrder = 0;
-
- /* There are three cases here:
- * 1) Building for the first time:
- * assert(_built == null && old == null)
- * 2) Re-building (because a dirty flag got set):
- * assert(_built != null && old == null)
- * 3) Syncing against an old version
- * assert(_built == null && old != null)
- */
- void _sync(UINode old, dynamic slot) {
- assert(_built == null || old == null);
- assert(!_disqualifiedFromEverAppearingAgain);
-
- Component oldComponent = old as Component;
-
- _slot = slot;
-
- var oldBuilt;
- if (oldComponent == null) {
- oldBuilt = _built;
- } else {
- assert(_built == null);
- oldBuilt = oldComponent._built;
- }
-
- int lastOrder = _currentOrder;
- _currentOrder = _order;
- _currentlyBuilding = this;
- _built = build();
- assert(_built != null);
- _currentlyBuilding = null;
- _currentOrder = lastOrder;
-
- _built = syncChild(_built, oldBuilt, slot);
- assert(_built != null);
- _dirty = false;
- _root = _built.root;
- assert(_root == root); // in case a subclass reintroduces it
- assert(root != null);
- }
-
- void _buildIfDirty() {
- assert(!_disqualifiedFromEverAppearingAgain);
- if (!_dirty || !_mounted)
- return;
-
- assert(root != null);
- _sync(null, _slot);
- }
-
- void scheduleBuild() {
- setState(() {});
- }
-
- void setState(Function fn()) {
- assert(!_disqualifiedFromEverAppearingAgain);
- _stateful = true;
- fn();
- if (_isBuilding || _dirty || !_mounted)
- return;
-
- _dirty = true;
- _scheduleComponentForRender(this);
- }
-
- UINode build();
-
-}
-
-class Container extends Component {
-
- Container({
- Object key,
- this.child,
- this.constraints,
- this.decoration,
- this.width,
- this.height,
- this.margin,
- this.padding,
- this.transform
- }) : super(key: key);
-
- final UINode child;
- final BoxConstraints constraints;
- final BoxDecoration decoration;
- final EdgeDims margin;
- final EdgeDims padding;
- final Matrix4 transform;
- final double width;
- final double height;
-
- UINode build() {
- UINode current = child;
-
- if (child == null && width == null && height == null)
- current = new SizedBox();
-
- if (padding != null)
- current = new Padding(padding: padding, child: current);
-
- if (decoration != null)
- current = new DecoratedBox(decoration: decoration, child: current);
-
- if (width != null || height != null)
- current = new SizedBox(
- width: width == null ? double.INFINITY : width,
- height: height == null ? double.INFINITY : height,
- child: current
- );
-
- if (constraints != null)
- current = new ConstrainedBox(constraints: constraints, child: current);
-
- if (margin != null)
- current = new Padding(padding: margin, child: current);
-
- if (transform != null)
- current = new Transform(transform: transform, child: current);
-
- return current;
- }
-
-}
class UINodeAppView extends AppView {
@@ -1164,9 +817,9 @@ abstract class App extends AbstractUINodeRoot {
typedef UINode Builder();
-class RenderNodeToUINodeAdapter extends AbstractUINodeRoot {
+class RenderObjectToUINodeAdapter extends AbstractUINodeRoot {
- RenderNodeToUINodeAdapter(
+ RenderObjectToUINodeAdapter(
RenderObjectWithChildMixin container,
this.builder
) : _container = container {
diff --git a/sdk/lib/framework/widgets/wrappers.dart b/sdk/lib/framework/widgets/wrappers.dart
new file mode 100644
index 0000000000000000000000000000000000000000..75eeb03fe06d4be7632f2292bc622bd718ea7c72
--- /dev/null
+++ b/sdk/lib/framework/widgets/wrappers.dart
@@ -0,0 +1,374 @@
+
+import 'package:vector_math/vector_math.dart';
+
+import '../rendering/block.dart';
+import '../rendering/box.dart';
+import '../rendering/flex.dart';
+import '../rendering/object.dart';
+import '../rendering/paragraph.dart';
+import '../rendering/stack.dart';
+import 'ui_node.dart';
+
+export '../rendering/box.dart' show BoxConstraints, BoxDecoration, Border, BorderSide, EdgeDims;
+export '../rendering/flex.dart' show FlexDirection;
+export '../rendering/object.dart' show Point, Size, Rect, Color, Paint, Path;
+export 'ui_node.dart' show UINode, Component, App, EventListenerNode, ParentDataNode;
+
+
+// PAINTING NODES
+
+class Opacity extends OneChildRenderObjectWrapper {
+ Opacity({ this.opacity, UINode child, Object key })
+ : super(child: child, key: key);
+
+ RenderOpacity get root { RenderOpacity result = super.root; return result; }
+ final double opacity;
+
+ RenderOpacity createNode() => new RenderOpacity(opacity: opacity);
+
+ void syncRenderObject(Opacity old) {
+ super.syncRenderObject(old);
+ root.opacity = opacity;
+ }
+}
+
+class DecoratedBox extends OneChildRenderObjectWrapper {
+
+ DecoratedBox({ this.decoration, UINode child, Object key })
+ : super(child: child, key: key);
+
+ RenderDecoratedBox get root { RenderDecoratedBox result = super.root; return result; }
+ final BoxDecoration decoration;
+
+ RenderDecoratedBox createNode() => new RenderDecoratedBox(decoration: decoration);
+
+ void syncRenderObject(DecoratedBox old) {
+ super.syncRenderObject(old);
+ root.decoration = decoration;
+ }
+
+}
+
+// TODO(jackson) need a mechanism for marking the RenderCustomPaint as needing paint
+class CustomPaint extends OneChildRenderObjectWrapper {
+
+ CustomPaint({ this.callback, UINode child, Object key })
+ : super(child: child, key: key);
+
+ RenderCustomPaint get root { RenderCustomPaint result = super.root; return result; }
+ final CustomPaintCallback callback;
+
+ RenderCustomPaint createNode() => new RenderCustomPaint(callback: callback);
+
+ void syncRenderObject(CustomPaint old) {
+ super.syncRenderObject(old);
+ root.callback = callback;
+ }
+
+ void remove() {
+ root.callback = null;
+ super.remove();
+ }
+
+}
+
+class ClipRect extends OneChildRenderObjectWrapper {
+
+ ClipRect({ UINode child, Object key })
+ : super(child: child, key: key);
+
+ RenderClipRect get root { RenderClipRect result = super.root; return result; }
+ RenderClipRect createNode() => new RenderClipRect();
+}
+
+class ClipOval extends OneChildRenderObjectWrapper {
+
+ ClipOval({ UINode child, Object key })
+ : super(child: child, key: key);
+
+ RenderClipOval get root { RenderClipOval result = super.root; return result; }
+ RenderClipOval createNode() => new RenderClipOval();
+}
+
+
+// POSITIONING AND SIZING NODES
+
+class Transform extends OneChildRenderObjectWrapper {
+
+ Transform({ this.transform, UINode child, Object key })
+ : super(child: child, key: key);
+
+ RenderTransform get root { RenderTransform result = super.root; return result; }
+ final Matrix4 transform;
+
+ RenderTransform createNode() => new RenderTransform(transform: transform);
+
+ void syncRenderObject(Transform old) {
+ super.syncRenderObject(old);
+ root.transform = transform;
+ }
+
+}
+
+class Padding extends OneChildRenderObjectWrapper {
+
+ Padding({ this.padding, UINode child, Object key })
+ : super(child: child, key: key);
+
+ RenderPadding get root { RenderPadding result = super.root; return result; }
+ final EdgeDims padding;
+
+ RenderPadding createNode() => new RenderPadding(padding: padding);
+
+ void syncRenderObject(Padding old) {
+ super.syncRenderObject(old);
+ root.padding = padding;
+ }
+
+}
+
+class SizedBox extends OneChildRenderObjectWrapper {
+
+ SizedBox({
+ double width: double.INFINITY,
+ double height: double.INFINITY,
+ UINode child,
+ Object key
+ }) : desiredSize = new Size(width, height), super(child: child, key: key);
+
+ RenderSizedBox get root { RenderSizedBox result = super.root; return result; }
+ final Size desiredSize;
+
+ RenderSizedBox createNode() => new RenderSizedBox(desiredSize: desiredSize);
+
+ void syncRenderObject(SizedBox old) {
+ super.syncRenderObject(old);
+ root.desiredSize = desiredSize;
+ }
+
+}
+
+class ConstrainedBox extends OneChildRenderObjectWrapper {
+
+ ConstrainedBox({ this.constraints, UINode child, Object key })
+ : super(child: child, key: key);
+
+ RenderConstrainedBox get root { RenderConstrainedBox result = super.root; return result; }
+ final BoxConstraints constraints;
+
+ RenderConstrainedBox createNode() => new RenderConstrainedBox(additionalConstraints: constraints);
+
+ void syncRenderObject(ConstrainedBox old) {
+ super.syncRenderObject(old);
+ root.additionalConstraints = constraints;
+ }
+
+}
+
+class ShrinkWrapWidth extends OneChildRenderObjectWrapper {
+
+ ShrinkWrapWidth({ UINode child, Object key }) : super(child: child, key: key);
+
+ RenderShrinkWrapWidth get root { RenderShrinkWrapWidth result = super.root; return result; }
+
+ RenderShrinkWrapWidth createNode() => new RenderShrinkWrapWidth();
+
+}
+
+class SizeObserver extends OneChildRenderObjectWrapper {
+
+ SizeObserver({ this.callback, UINode child, Object key })
+ : super(child: child, key: key);
+
+ RenderSizeObserver get root { RenderSizeObserver result = super.root; return result; }
+ final SizeChangedCallback callback;
+
+ RenderSizeObserver createNode() => new RenderSizeObserver(callback: callback);
+
+ void syncRenderObject(SizeObserver old) {
+ super.syncRenderObject(old);
+ root.callback = callback;
+ }
+
+ void remove() {
+ root.callback = null;
+ super.remove();
+ }
+
+}
+
+
+// CONVENIENCE CLASS TO COMBINE COMMON PAINTING, POSITIONING, AND SIZING NODES
+
+class Container extends Component {
+
+ Container({
+ Object key,
+ this.child,
+ this.constraints,
+ this.decoration,
+ this.width,
+ this.height,
+ this.margin,
+ this.padding,
+ this.transform
+ }) : super(key: key);
+
+ final UINode child;
+ final BoxConstraints constraints;
+ final BoxDecoration decoration;
+ final EdgeDims margin;
+ final EdgeDims padding;
+ final Matrix4 transform;
+ final double width;
+ final double height;
+
+ UINode build() {
+ UINode current = child;
+
+ if (child == null && width == null && height == null)
+ current = new SizedBox();
+
+ if (padding != null)
+ current = new Padding(padding: padding, child: current);
+
+ if (decoration != null)
+ current = new DecoratedBox(decoration: decoration, child: current);
+
+ if (width != null || height != null)
+ current = new SizedBox(
+ width: width == null ? double.INFINITY : width,
+ height: height == null ? double.INFINITY : height,
+ child: current
+ );
+
+ if (constraints != null)
+ current = new ConstrainedBox(constraints: constraints, child: current);
+
+ if (margin != null)
+ current = new Padding(padding: margin, child: current);
+
+ if (transform != null)
+ current = new Transform(transform: transform, child: current);
+
+ return current;
+ }
+
+}
+
+
+// LAYOUT NODES
+
+class Block extends MultiChildRenderObjectWrapper {
+
+ Block(List children, { Object key })
+ : super(key: key, children: children);
+
+ RenderBlock get root { RenderBlock result = super.root; return result; }
+ RenderBlock createNode() => new RenderBlock();
+
+}
+
+class Stack extends MultiChildRenderObjectWrapper {
+
+ Stack(List children, { Object key })
+ : super(key: key, children: children);
+
+ RenderStack get root { RenderStack result = super.root; return result; }
+ RenderStack createNode() => new RenderStack();
+
+}
+
+class StackPositionedChild extends ParentDataNode {
+ StackPositionedChild(UINode content, {
+ double top, double right, double bottom, double left
+ }) : super(content, new StackParentData()..top = top
+ ..right = right
+ ..bottom = bottom
+ ..left = left);
+}
+
+class Flex extends MultiChildRenderObjectWrapper {
+
+ Flex(List children, {
+ Object key,
+ this.direction: FlexDirection.horizontal,
+ this.justifyContent: FlexJustifyContent.flexStart,
+ this.alignItems: FlexAlignItems.center
+ }) : super(key: key, children: children);
+
+ RenderFlex get root { RenderFlex result = super.root; return result; }
+ RenderFlex createNode() => new RenderFlex(direction: this.direction);
+
+ final FlexDirection direction;
+ final FlexJustifyContent justifyContent;
+ final FlexAlignItems alignItems;
+
+ void syncRenderObject(UINode old) {
+ super.syncRenderObject(old);
+ root.direction = direction;
+ root.justifyContent = justifyContent;
+ root.alignItems = alignItems;
+ }
+
+}
+
+class FlexExpandingChild extends ParentDataNode {
+ FlexExpandingChild(UINode content, { int flex: 1, Object key })
+ : super(content, new FlexBoxParentData()..flex = flex, key: key);
+}
+
+class Paragraph extends RenderObjectWrapper {
+
+ Paragraph({ Object key, this.text }) : super(key: key);
+
+ RenderParagraph get root { RenderParagraph result = super.root; return result; }
+ RenderParagraph createNode() => new RenderParagraph(text: text);
+
+ final String text;
+
+ void syncRenderObject(UINode old) {
+ super.syncRenderObject(old);
+ root.text = text;
+ }
+
+ void insert(RenderObjectWrapper child, dynamic slot) {
+ assert(false);
+ // Paragraph does not support having children currently
+ }
+
+}
+
+class Text extends Component {
+ Text(this.data) : super(key: '*text*');
+ final String data;
+ bool get interchangeable => true;
+ UINode build() => new Paragraph(text: data);
+}
+
+class Image extends RenderObjectWrapper {
+
+ Image({
+ Object key,
+ this.src,
+ this.size
+ }) : super(key: key);
+
+ RenderImage get root { RenderImage result = super.root; return result; }
+ RenderImage createNode() => new RenderImage(this.src, this.size);
+
+ final String src;
+ final Size size;
+
+ void syncRenderObject(UINode old) {
+ super.syncRenderObject(old);
+ root.src = src;
+ root.requestedSize = size;
+ }
+
+ void insert(RenderObjectWrapper child, dynamic slot) {
+ assert(false);
+ // Image does not support having children currently
+ }
+
+}