Merge pull request #1291 from abarth/fn2_tag_widgets
Add TagWidget to fn3
This commit is contained in:
commit
de70bd950b
@ -467,11 +467,59 @@ class Stack extends MultiChildRenderObjectWidget {
|
|||||||
void updateRenderObject(RenderStack renderObject, Stack oldWidget) {
|
void updateRenderObject(RenderStack renderObject, Stack oldWidget) {
|
||||||
// Nothing to update
|
// Nothing to update
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(abarth): Update parent data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(abarth): Positioned
|
class Positioned extends ParentDataWidget {
|
||||||
|
Positioned({
|
||||||
|
Key key,
|
||||||
|
Widget child,
|
||||||
|
this.top,
|
||||||
|
this.right,
|
||||||
|
this.bottom,
|
||||||
|
this.left
|
||||||
|
}) : super(key: key, child: child);
|
||||||
|
|
||||||
|
final double top;
|
||||||
|
final double right;
|
||||||
|
final double bottom;
|
||||||
|
final double left;
|
||||||
|
|
||||||
|
void debugValidateAncestor(Widget ancestor) {
|
||||||
|
assert(() {
|
||||||
|
'Positioned must placed inside a Stack';
|
||||||
|
return ancestor is Stack;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyParentData(RenderObject renderObject) {
|
||||||
|
assert(renderObject.parentData is StackParentData);
|
||||||
|
final StackParentData parentData = renderObject.parentData;
|
||||||
|
bool needsLayout = false;
|
||||||
|
|
||||||
|
if (parentData.top != top) {
|
||||||
|
parentData.top = top;
|
||||||
|
needsLayout = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentData.right != right) {
|
||||||
|
parentData.right = right;
|
||||||
|
needsLayout = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentData.bottom != bottom) {
|
||||||
|
parentData.bottom = bottom;
|
||||||
|
needsLayout = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentData.left != left) {
|
||||||
|
parentData.left = left;
|
||||||
|
needsLayout = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsLayout)
|
||||||
|
renderObject.markNeedsLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Grid extends MultiChildRenderObjectWidget {
|
class Grid extends MultiChildRenderObjectWidget {
|
||||||
Grid(List<Widget> children, { Key key, this.maxChildExtent })
|
Grid(List<Widget> children, { Key key, this.maxChildExtent })
|
||||||
@ -514,8 +562,6 @@ class Flex extends MultiChildRenderObjectWidget {
|
|||||||
renderObject.alignItems = alignItems;
|
renderObject.alignItems = alignItems;
|
||||||
renderObject.textBaseline = textBaseline;
|
renderObject.textBaseline = textBaseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(abarth): Update parent data
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Row extends Flex {
|
class Row extends Flex {
|
||||||
@ -536,7 +582,28 @@ class Column extends Flex {
|
|||||||
}) : super(children, key: key, direction: FlexDirection.vertical, justifyContent: justifyContent, alignItems: alignItems, textBaseline: textBaseline);
|
}) : super(children, key: key, direction: FlexDirection.vertical, justifyContent: justifyContent, alignItems: alignItems, textBaseline: textBaseline);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(abarth): Flexible
|
class Flexible extends ParentDataWidget {
|
||||||
|
Flexible({ Key key, this.flex: 1, Widget child })
|
||||||
|
: super(key: key, child: child);
|
||||||
|
|
||||||
|
final int flex;
|
||||||
|
|
||||||
|
void debugValidateAncestor(Widget ancestor) {
|
||||||
|
assert(() {
|
||||||
|
'Flexible must placed inside a Flex';
|
||||||
|
return ancestor is Flex;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void applyParentData(RenderObject renderObject) {
|
||||||
|
assert(renderObject.parentData is FlexParentData);
|
||||||
|
final FlexParentData parentData = renderObject.parentData;
|
||||||
|
if (parentData.flex != flex) {
|
||||||
|
parentData.flex = flex;
|
||||||
|
renderObject.markNeedsLayout();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Paragraph extends LeafRenderObjectWidget {
|
class Paragraph extends LeafRenderObjectWidget {
|
||||||
Paragraph({ Key key, this.text }) : super(key: key) {
|
Paragraph({ Key key, this.text }) : super(key: key) {
|
||||||
@ -579,7 +646,51 @@ class StyledText extends StatelessComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(abarth): Text
|
class DefaultTextStyle extends InheritedWidget {
|
||||||
|
DefaultTextStyle({
|
||||||
|
Key key,
|
||||||
|
this.style,
|
||||||
|
Widget child
|
||||||
|
}) : super(key: key, child: child) {
|
||||||
|
assert(style != null);
|
||||||
|
assert(child != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
final TextStyle style;
|
||||||
|
|
||||||
|
static TextStyle of(BuildContext context) {
|
||||||
|
DefaultTextStyle result = context.inheritedWidgetOfType(DefaultTextStyle);
|
||||||
|
return result?.style;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool updateShouldNotify(DefaultTextStyle old) => style != old.style;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Text extends StatelessComponent {
|
||||||
|
Text(this.data, { Key key, TextStyle this.style }) : super(key: key) {
|
||||||
|
assert(data != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
final String data;
|
||||||
|
final TextStyle style;
|
||||||
|
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
TextSpan text = new PlainTextSpan(data);
|
||||||
|
TextStyle defaultStyle = DefaultTextStyle.of(context);
|
||||||
|
TextStyle combinedStyle;
|
||||||
|
if (defaultStyle != null) {
|
||||||
|
if (style != null)
|
||||||
|
combinedStyle = defaultStyle.merge(style);
|
||||||
|
else
|
||||||
|
combinedStyle = defaultStyle;
|
||||||
|
} else {
|
||||||
|
combinedStyle = style;
|
||||||
|
}
|
||||||
|
if (combinedStyle != null)
|
||||||
|
text = new StyledTextSpan(combinedStyle, [text]);
|
||||||
|
return new Paragraph(text: text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class Image extends LeafRenderObjectWidget {
|
class Image extends LeafRenderObjectWidget {
|
||||||
Image({
|
Image({
|
||||||
|
@ -105,7 +105,11 @@ abstract class StatelessComponent extends Widget {
|
|||||||
/// Returns another Widget out of which this StatelessComponent is built.
|
/// Returns another Widget out of which this StatelessComponent is built.
|
||||||
/// Typically that Widget will have been configured with further children,
|
/// Typically that Widget will have been configured with further children,
|
||||||
/// such that really this function returns a tree of configuration.
|
/// such that really this function returns a tree of configuration.
|
||||||
Widget build();
|
///
|
||||||
|
/// The given build context object contains information about the location in
|
||||||
|
/// the tree at which this component is being built. For example, the context
|
||||||
|
/// provides the set of inherited widgets for this location in the tree.
|
||||||
|
Widget build(BuildContext context);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// StatefulComponents provide the configuration for
|
/// StatefulComponents provide the configuration for
|
||||||
@ -162,7 +166,41 @@ abstract class ComponentState<T extends StatefulComponent> {
|
|||||||
/// Returns another Widget out of which this StatefulComponent is built.
|
/// Returns another Widget out of which this StatefulComponent is built.
|
||||||
/// Typically that Widget will have been configured with further children,
|
/// Typically that Widget will have been configured with further children,
|
||||||
/// such that really this function returns a tree of configuration.
|
/// such that really this function returns a tree of configuration.
|
||||||
Widget build();
|
///
|
||||||
|
/// The given build context object contains information about the location in
|
||||||
|
/// the tree at which this component is being built. For example, the context
|
||||||
|
/// provides the set of inherited widgets for this location in the tree.
|
||||||
|
Widget build(BuildContext context);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ProxyWidget extends StatelessComponent {
|
||||||
|
const ProxyWidget({ Key key, Widget this.child }) : super(key: key);
|
||||||
|
|
||||||
|
final Widget child;
|
||||||
|
|
||||||
|
Widget build(BuildContext context) => child;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ParentDataWidget extends ProxyWidget {
|
||||||
|
ParentDataWidget({ Key key, Widget child })
|
||||||
|
: super(key: key, child: child);
|
||||||
|
|
||||||
|
/// Subclasses should override this function to ensure that they are placed
|
||||||
|
/// inside widgets that expect them.
|
||||||
|
///
|
||||||
|
/// The given ancestor is the first RenderObjectWidget ancestor of this widget.
|
||||||
|
void debugValidateAncestor(RenderObjectWidget ancestor);
|
||||||
|
|
||||||
|
void applyParentData(RenderObject renderObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class InheritedWidget extends ProxyWidget {
|
||||||
|
const InheritedWidget({ Key key, Widget child })
|
||||||
|
: super(key: key, child: child);
|
||||||
|
|
||||||
|
InheritedElement createElement() => new InheritedElement(this);
|
||||||
|
|
||||||
|
bool updateShouldNotify(InheritedWidget oldWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _canUpdate(Widget oldWidget, Widget newWidget) {
|
bool _canUpdate(Widget oldWidget, Widget newWidget) {
|
||||||
@ -180,11 +218,15 @@ typedef void ElementVisitor(Element element);
|
|||||||
|
|
||||||
const Object _uniqueChild = const Object();
|
const Object _uniqueChild = const Object();
|
||||||
|
|
||||||
|
abstract class BuildContext {
|
||||||
|
InheritedWidget inheritedWidgetOfType(Type targetType);
|
||||||
|
}
|
||||||
|
|
||||||
/// Elements are the instantiations of Widget configurations.
|
/// Elements are the instantiations of Widget configurations.
|
||||||
///
|
///
|
||||||
/// Elements can, in principle, have children. Only subclasses of
|
/// Elements can, in principle, have children. Only subclasses of
|
||||||
/// RenderObjectElement are allowed to have more than one child.
|
/// RenderObjectElement are allowed to have more than one child.
|
||||||
abstract class Element<T extends Widget> {
|
abstract class Element<T extends Widget> implements BuildContext {
|
||||||
Element(T widget) : _widget = widget {
|
Element(T widget) : _widget = widget {
|
||||||
assert(_widget != null);
|
assert(_widget != null);
|
||||||
}
|
}
|
||||||
@ -355,9 +397,24 @@ abstract class Element<T extends Widget> {
|
|||||||
assert(_depth != null);
|
assert(_depth != null);
|
||||||
assert(() { _debugLifecycleState = _ElementLifecycle.defunct; return true; });
|
assert(() { _debugLifecycleState = _ElementLifecycle.defunct; return true; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<Type> _dependencies;
|
||||||
|
InheritedWidget inheritedWidgetOfType(Type targetType) {
|
||||||
|
if (_dependencies == null)
|
||||||
|
_dependencies = new Set<Type>();
|
||||||
|
_dependencies.add(targetType);
|
||||||
|
Element ancestor = _parent;
|
||||||
|
while (ancestor != null && ancestor._widget.runtimeType != targetType)
|
||||||
|
ancestor = ancestor._parent;
|
||||||
|
return ancestor._widget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dependenciesChanged() {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef Widget WidgetBuilder();
|
typedef Widget WidgetBuilder(BuildContext context);
|
||||||
typedef void BuildScheduler(BuildableElement element);
|
typedef void BuildScheduler(BuildableElement element);
|
||||||
|
|
||||||
/// Base class for the instantiation of StatelessComponent and StatefulComponent
|
/// Base class for the instantiation of StatelessComponent and StatefulComponent
|
||||||
@ -393,7 +450,7 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
|
|||||||
_dirty = false;
|
_dirty = false;
|
||||||
Widget built;
|
Widget built;
|
||||||
try {
|
try {
|
||||||
built = _builder();
|
built = _builder(this);
|
||||||
assert(built != null);
|
assert(built != null);
|
||||||
} catch (e, stack) {
|
} catch (e, stack) {
|
||||||
_debugReportException('building $this', e, stack);
|
_debugReportException('building $this', e, stack);
|
||||||
@ -428,10 +485,14 @@ abstract class BuildableElement<T extends Widget> extends Element<T> {
|
|||||||
super.unmount();
|
super.unmount();
|
||||||
_dirty = false; // so that we don't get rebuilt even if we're already marked dirty
|
_dirty = false; // so that we don't get rebuilt even if we're already marked dirty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dependenciesChanged() {
|
||||||
|
markNeedsBuild();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiation of StatelessComponent widgets.
|
/// Instantiation of StatelessComponent widgets.
|
||||||
class StatelessComponentElement extends BuildableElement<StatelessComponent> {
|
class StatelessComponentElement<T extends StatelessComponent> extends BuildableElement<T> {
|
||||||
StatelessComponentElement(StatelessComponent widget) : super(widget) {
|
StatelessComponentElement(StatelessComponent widget) : super(widget) {
|
||||||
_builder = _widget.build;
|
_builder = _widget.build;
|
||||||
}
|
}
|
||||||
@ -474,6 +535,52 @@ class StatefulComponentElement extends BuildableElement<StatefulComponent> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ParentDataElement extends StatelessComponentElement<ParentDataWidget> {
|
||||||
|
ParentDataElement(ParentDataWidget widget) : super(widget);
|
||||||
|
|
||||||
|
void update(ParentDataWidget newWidget) {
|
||||||
|
ParentDataWidget oldWidget = _widget;
|
||||||
|
super.update(newWidget);
|
||||||
|
assert(_widget == newWidget);
|
||||||
|
if (_widget != oldWidget)
|
||||||
|
_notifyDescendants();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _notifyDescendants() {
|
||||||
|
void notifyChildren(Element child) {
|
||||||
|
if (child is RenderObjectElement)
|
||||||
|
child.updateParentData(_widget);
|
||||||
|
else if (child is! ParentDataElement)
|
||||||
|
child.visitChildren(notifyChildren);
|
||||||
|
}
|
||||||
|
visitChildren(notifyChildren);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InheritedElement extends StatelessComponentElement<InheritedWidget> {
|
||||||
|
InheritedElement(InheritedWidget widget) : super(widget);
|
||||||
|
|
||||||
|
void update(StatelessComponent newWidget) {
|
||||||
|
InheritedWidget oldWidget = _widget;
|
||||||
|
super.update(newWidget);
|
||||||
|
assert(_widget == newWidget);
|
||||||
|
if (_widget.updateShouldNotify(oldWidget))
|
||||||
|
_notifyDescendants();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _notifyDescendants() {
|
||||||
|
final Type ourRuntimeType = runtimeType;
|
||||||
|
void notifyChildren(Element child) {
|
||||||
|
if (child._dependencies != null &&
|
||||||
|
child._dependencies.contains(ourRuntimeType))
|
||||||
|
child.dependenciesChanged();
|
||||||
|
if (child.runtimeType != ourRuntimeType)
|
||||||
|
child.visitChildren(notifyChildren);
|
||||||
|
}
|
||||||
|
visitChildren(notifyChildren);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Base class for instantiations of RenderObjectWidget subclasses
|
/// Base class for instantiations of RenderObjectWidget subclasses
|
||||||
abstract class RenderObjectElement<T extends RenderObjectWidget> extends Element<T> {
|
abstract class RenderObjectElement<T extends RenderObjectWidget> extends Element<T> {
|
||||||
RenderObjectElement(T widget)
|
RenderObjectElement(T widget)
|
||||||
@ -490,6 +597,16 @@ abstract class RenderObjectElement<T extends RenderObjectWidget> extends Element
|
|||||||
return ancestor;
|
return ancestor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ParentDataElement _findAncestorParentDataElement() {
|
||||||
|
Element ancestor = _parent;
|
||||||
|
while (ancestor != null && ancestor is! RenderObjectElement) {
|
||||||
|
if (ancestor is ParentDataElement)
|
||||||
|
return ancestor;
|
||||||
|
ancestor = ancestor._parent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
static Map<RenderObject, RenderObjectElement> _registry = new Map<RenderObject, RenderObjectElement>();
|
static Map<RenderObject, RenderObjectElement> _registry = new Map<RenderObject, RenderObjectElement>();
|
||||||
static Iterable<RenderObjectElement> getElementsForRenderObject(RenderObject renderObject) sync* {
|
static Iterable<RenderObjectElement> getElementsForRenderObject(RenderObject renderObject) sync* {
|
||||||
Element target = _registry[renderObject];
|
Element target = _registry[renderObject];
|
||||||
@ -507,10 +624,13 @@ abstract class RenderObjectElement<T extends RenderObjectWidget> extends Element
|
|||||||
assert(_ancestorRenderObjectElement == null);
|
assert(_ancestorRenderObjectElement == null);
|
||||||
_ancestorRenderObjectElement = _findAncestorRenderObjectElement();
|
_ancestorRenderObjectElement = _findAncestorRenderObjectElement();
|
||||||
_ancestorRenderObjectElement?.insertChildRenderObject(renderObject, slot);
|
_ancestorRenderObjectElement?.insertChildRenderObject(renderObject, slot);
|
||||||
|
ParentDataElement parentDataElement = _findAncestorParentDataElement();
|
||||||
|
if (parentDataElement != null)
|
||||||
|
updateParentData(parentDataElement._widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
void update(T newWidget) {
|
void update(T newWidget) {
|
||||||
Widget oldWidget = _widget;
|
RenderObjectWidget oldWidget = _widget;
|
||||||
super.update(newWidget);
|
super.update(newWidget);
|
||||||
assert(_widget == newWidget);
|
assert(_widget == newWidget);
|
||||||
_widget.updateRenderObject(renderObject, oldWidget);
|
_widget.updateRenderObject(renderObject, oldWidget);
|
||||||
@ -522,6 +642,14 @@ abstract class RenderObjectElement<T extends RenderObjectWidget> extends Element
|
|||||||
_registry.remove(renderObject);
|
_registry.remove(renderObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void updateParentData(ParentDataWidget parentData) {
|
||||||
|
assert(() {
|
||||||
|
parentData.debugValidateAncestor(_ancestorRenderObjectElement._widget);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
parentData.applyParentData(renderObject);
|
||||||
|
}
|
||||||
|
|
||||||
void detachRenderObject() {
|
void detachRenderObject() {
|
||||||
if (_ancestorRenderObjectElement != null) {
|
if (_ancestorRenderObjectElement != null) {
|
||||||
_ancestorRenderObjectElement.removeChildRenderObject(renderObject);
|
_ancestorRenderObjectElement.removeChildRenderObject(renderObject);
|
||||||
@ -590,7 +718,15 @@ class OneChildRenderObjectElement<T extends OneChildRenderObjectWidget> extends
|
|||||||
class MultiChildRenderObjectElement<T extends MultiChildRenderObjectWidget> extends RenderObjectElement<T> {
|
class MultiChildRenderObjectElement<T extends MultiChildRenderObjectWidget> extends RenderObjectElement<T> {
|
||||||
MultiChildRenderObjectElement(T widget) : super(widget);
|
MultiChildRenderObjectElement(T widget) : super(widget);
|
||||||
|
|
||||||
// TODO(ianh): implement
|
void insertChildRenderObject(RenderObject child, dynamic slot) {
|
||||||
|
// TODO(ianh): implement
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeChildRenderObject(RenderObject child) {
|
||||||
|
// TODO(ianh): implement
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void WidgetsExceptionHandler(String context, dynamic exception, StackTrace stack);
|
typedef void WidgetsExceptionHandler(String context, dynamic exception, StackTrace stack);
|
||||||
|
@ -11,7 +11,7 @@ final BoxDecoration kBoxDecorationC = new BoxDecoration();
|
|||||||
class TestComponent extends StatelessComponent {
|
class TestComponent extends StatelessComponent {
|
||||||
const TestComponent({ this.child });
|
const TestComponent({ this.child });
|
||||||
final Widget child;
|
final Widget child;
|
||||||
Widget build() => child;
|
Widget build(BuildContext context) => child;
|
||||||
}
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
@ -23,7 +23,7 @@ class TestComponentState extends ComponentState<TestComponentConfig> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget build() {
|
Widget build(BuildContext context) {
|
||||||
return _showLeft ? config.left : config.right;
|
return _showLeft ? config.left : config.right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ final BoxDecoration kBoxDecorationB = new BoxDecoration();
|
|||||||
class TestBuildCounter extends StatelessComponent {
|
class TestBuildCounter extends StatelessComponent {
|
||||||
static int buildCount = 0;
|
static int buildCount = 0;
|
||||||
|
|
||||||
Widget build() {
|
Widget build(BuildContext context) {
|
||||||
++buildCount;
|
++buildCount;
|
||||||
return new DecoratedBox(decoration: kBoxDecorationA);
|
return new DecoratedBox(decoration: kBoxDecorationA);
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ class RootComponentState extends ComponentState<RootComponent> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Widget build() => child;
|
Widget build(BuildContext context) => child;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Object _rootSlot = const Object();
|
const Object _rootSlot = const Object();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user