Port scaffold to fn3
This commit is contained in:
parent
9f176fc86e
commit
82dd9d65df
248
packages/flutter/lib/src/fn3/scaffold.dart
Normal file
248
packages/flutter/lib/src/fn3/scaffold.dart
Normal file
@ -0,0 +1,248 @@
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// 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/material.dart';
|
||||
import 'package:sky/rendering.dart';
|
||||
import 'package:sky/src/fn3/framework.dart';
|
||||
|
||||
// Slots are painted in this order and hit tested in reverse of this order
|
||||
enum ScaffoldSlots {
|
||||
body,
|
||||
statusBar,
|
||||
toolbar,
|
||||
snackBar,
|
||||
floatingActionButton,
|
||||
drawer
|
||||
}
|
||||
|
||||
class RenderScaffold extends RenderBox {
|
||||
|
||||
RenderScaffold({
|
||||
RenderBox body,
|
||||
RenderBox statusBar,
|
||||
RenderBox toolbar,
|
||||
RenderBox snackBar,
|
||||
RenderBox floatingActionButton,
|
||||
RenderBox drawer
|
||||
}) {
|
||||
this[ScaffoldSlots.body] = body;
|
||||
this[ScaffoldSlots.statusBar] = statusBar;
|
||||
this[ScaffoldSlots.toolbar] = toolbar;
|
||||
this[ScaffoldSlots.snackBar] = snackBar;
|
||||
this[ScaffoldSlots.floatingActionButton] = floatingActionButton;
|
||||
this[ScaffoldSlots.drawer] = drawer;
|
||||
}
|
||||
|
||||
Map<ScaffoldSlots, RenderBox> _slots = new Map<ScaffoldSlots, RenderBox>();
|
||||
RenderBox operator[] (ScaffoldSlots slot) => _slots[slot];
|
||||
void operator[]= (ScaffoldSlots slot, RenderBox value) {
|
||||
RenderBox old = _slots[slot];
|
||||
if (old == value)
|
||||
return;
|
||||
if (old != null)
|
||||
dropChild(old);
|
||||
if (value == null) {
|
||||
_slots.remove(slot);
|
||||
} else {
|
||||
_slots[slot] = value;
|
||||
adoptChild(value);
|
||||
}
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
void attachChildren() {
|
||||
for (ScaffoldSlots slot in ScaffoldSlots.values) {
|
||||
RenderBox box = _slots[slot];
|
||||
if (box != null)
|
||||
box.attach();
|
||||
}
|
||||
}
|
||||
|
||||
void detachChildren() {
|
||||
for (ScaffoldSlots slot in ScaffoldSlots.values) {
|
||||
RenderBox box = _slots[slot];
|
||||
if (box != null)
|
||||
box.detach();
|
||||
}
|
||||
}
|
||||
|
||||
void visitChildren(RenderObjectVisitor visitor) {
|
||||
for (ScaffoldSlots slot in ScaffoldSlots.values) {
|
||||
RenderBox box = _slots[slot];
|
||||
if (box != null)
|
||||
visitor(box);
|
||||
}
|
||||
}
|
||||
|
||||
ScaffoldSlots remove(RenderBox child) {
|
||||
assert(child != null);
|
||||
for (ScaffoldSlots slot in ScaffoldSlots.values) {
|
||||
if (_slots[slot] == child) {
|
||||
this[slot] = null;
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
bool get sizedByParent => true;
|
||||
void performResize() {
|
||||
size = constraints.biggest;
|
||||
assert(!size.isInfinite);
|
||||
}
|
||||
|
||||
// TODO(eseidel): These change based on device size!
|
||||
// http://www.google.com/design/spec/layout/metrics-keylines.html#metrics-keylines-keylines-spacing
|
||||
static const kButtonX = 16.0; // left from right edge of body
|
||||
static const kButtonY = 16.0; // up from bottom edge of body
|
||||
|
||||
void performLayout() {
|
||||
double bodyHeight = size.height;
|
||||
double bodyPosition = 0.0;
|
||||
if (_slots[ScaffoldSlots.statusBar] != null) {
|
||||
RenderBox statusBar = _slots[ScaffoldSlots.statusBar];
|
||||
statusBar.layout(new BoxConstraints.tight(new Size(size.width, kStatusBarHeight)));
|
||||
assert(statusBar.parentData is BoxParentData);
|
||||
statusBar.parentData.position = new Point(0.0, size.height - kStatusBarHeight);
|
||||
bodyHeight -= kStatusBarHeight;
|
||||
}
|
||||
if (_slots[ScaffoldSlots.toolbar] != null) {
|
||||
RenderBox toolbar = _slots[ScaffoldSlots.toolbar];
|
||||
double toolbarHeight = kToolBarHeight + sky.view.paddingTop;
|
||||
toolbar.layout(new BoxConstraints.tight(new Size(size.width, toolbarHeight)));
|
||||
assert(toolbar.parentData is BoxParentData);
|
||||
toolbar.parentData.position = Point.origin;
|
||||
bodyPosition += toolbarHeight;
|
||||
bodyHeight -= toolbarHeight;
|
||||
}
|
||||
if (_slots[ScaffoldSlots.body] != null) {
|
||||
RenderBox body = _slots[ScaffoldSlots.body];
|
||||
body.layout(new BoxConstraints.tight(new Size(size.width, bodyHeight)));
|
||||
assert(body.parentData is BoxParentData);
|
||||
body.parentData.position = new Point(0.0, bodyPosition);
|
||||
}
|
||||
if (_slots[ScaffoldSlots.snackBar] != null) {
|
||||
RenderBox snackBar = _slots[ScaffoldSlots.snackBar];
|
||||
// TODO(jackson): On tablet/desktop, minWidth = 288, maxWidth = 568
|
||||
snackBar.layout(new BoxConstraints(minWidth: size.width, maxWidth: size.width, minHeight: 0.0, maxHeight: size.height),
|
||||
parentUsesSize: true);
|
||||
assert(snackBar.parentData is BoxParentData);
|
||||
// Position it off-screen. SnackBar slides in with an animation.
|
||||
snackBar.parentData.position = new Point(0.0, size.height);
|
||||
}
|
||||
if (_slots[ScaffoldSlots.floatingActionButton] != null) {
|
||||
RenderBox floatingActionButton = _slots[ScaffoldSlots.floatingActionButton];
|
||||
Size area = new Size(size.width - kButtonX, size.height - kButtonY);
|
||||
floatingActionButton.layout(new BoxConstraints.loose(area), parentUsesSize: true);
|
||||
assert(floatingActionButton.parentData is BoxParentData);
|
||||
floatingActionButton.parentData.position = (area - floatingActionButton.size).toPoint();
|
||||
}
|
||||
if (_slots[ScaffoldSlots.drawer] != null) {
|
||||
RenderBox drawer = _slots[ScaffoldSlots.drawer];
|
||||
drawer.layout(new BoxConstraints(minWidth: 0.0, maxWidth: size.width, minHeight: size.height, maxHeight: size.height));
|
||||
assert(drawer.parentData is BoxParentData);
|
||||
drawer.parentData.position = Point.origin;
|
||||
}
|
||||
}
|
||||
|
||||
void paint(PaintingContext context, Offset offset) {
|
||||
for (ScaffoldSlots slot in ScaffoldSlots.values) {
|
||||
RenderBox box = _slots[slot];
|
||||
if (box != null) {
|
||||
assert(box.parentData is BoxParentData);
|
||||
context.paintChild(box, box.parentData.position + offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hitTestChildren(HitTestResult result, { Point position }) {
|
||||
for (ScaffoldSlots slot in ScaffoldSlots.values.reversed) {
|
||||
RenderBox box = _slots[slot];
|
||||
if (box != null) {
|
||||
assert(box.parentData is BoxParentData);
|
||||
if (box.hitTest(result, position: (position - box.parentData.position).toPoint()))
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String debugDescribeChildren(String prefix) {
|
||||
return _slots.keys.map((slot) => '${prefix}${slot}: ${_slots[slot].toStringDeep(prefix)}').join();
|
||||
}
|
||||
}
|
||||
|
||||
class Scaffold extends RenderObjectWidget {
|
||||
Scaffold({
|
||||
Key key,
|
||||
Widget body,
|
||||
Widget statusBar,
|
||||
Widget toolbar,
|
||||
Widget snackBar,
|
||||
Widget floatingActionButton,
|
||||
Widget drawer
|
||||
}) : super(key: key) {
|
||||
_children[ScaffoldSlots.body] = body;
|
||||
_children[ScaffoldSlots.statusBar] = statusBar;
|
||||
_children[ScaffoldSlots.toolbar] = toolbar;
|
||||
_children[ScaffoldSlots.snackBar] = snackBar;
|
||||
_children[ScaffoldSlots.floatingActionButton] = floatingActionButton;
|
||||
_children[ScaffoldSlots.drawer] = drawer;
|
||||
}
|
||||
|
||||
final Map<ScaffoldSlots, Widget> _children = new Map<ScaffoldSlots, Widget>();
|
||||
|
||||
RenderScaffold createRenderObject() => new RenderScaffold();
|
||||
|
||||
ScaffoldElement createElement() => new ScaffoldElement(this);
|
||||
}
|
||||
|
||||
class ScaffoldElement extends RenderObjectElement<Scaffold> {
|
||||
ScaffoldElement(Scaffold widget) : super(widget);
|
||||
|
||||
Map<ScaffoldSlots, Element> _children;
|
||||
|
||||
RenderScaffold get renderObject => super.renderObject;
|
||||
|
||||
void visitChildren(ElementVisitor visitor) {
|
||||
for (ScaffoldSlots slot in ScaffoldSlots.values) {
|
||||
Element element = _children[slot];
|
||||
if (element != null)
|
||||
visitor(element);
|
||||
}
|
||||
}
|
||||
|
||||
void mount(Element parent, dynamic newSlot) {
|
||||
super.mount(parent, newSlot);
|
||||
_children = new Map<ScaffoldSlots, Element>();
|
||||
for (ScaffoldSlots slot in ScaffoldSlots.values) {
|
||||
_children[slot] = widget._children[slot].createElement()
|
||||
..mount(this, slot);
|
||||
}
|
||||
}
|
||||
|
||||
void update(Scaffold newWidget) {
|
||||
super.update(newWidget);
|
||||
assert(widget == newWidget);
|
||||
for (ScaffoldSlots slot in ScaffoldSlots.values) {
|
||||
_children[slot] = updateChild(_children[slot], widget._children[slot], slot);
|
||||
assert((_children[slot] == null) == (widget._children[slot] == null));
|
||||
}
|
||||
}
|
||||
|
||||
void insertChildRenderObject(RenderObject child, ScaffoldSlots slot) {
|
||||
renderObject[slot] = child;
|
||||
}
|
||||
|
||||
void moveChildRenderObject(RenderObject child, dynamic slot) {
|
||||
removeChildRenderObject(child);
|
||||
insertChildRenderObject(child, slot);
|
||||
}
|
||||
|
||||
void removeChildRenderObject(RenderObject child) {
|
||||
assert(renderObject == child.parent);
|
||||
renderObject.remove(child);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user