blob: ae750c57358b71cffd0965db5786f4a00bdb27bd [file] [log] [blame]
// 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 '../rendering/box.dart';
import '../rendering/object.dart';
import '../theme2/view_configuration.dart';
import 'widget.dart';
enum ScaffoldSlots {
toolbar,
body,
statusBar,
drawer,
floatingActionButton
}
class RenderScaffold extends RenderBox {
RenderScaffold({
RenderBox toolbar,
RenderBox body,
RenderBox statusBar,
RenderBox drawer,
RenderBox floatingActionButton
}) {
this[ScaffoldSlots.toolbar] = toolbar;
this[ScaffoldSlots.body] = body;
this[ScaffoldSlots.statusBar] = statusBar;
this[ScaffoldSlots.drawer] = drawer;
this[ScaffoldSlots.floatingActionButton] = floatingActionButton;
}
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);
_slots[slot] = value;
if (value != null)
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();
}
}
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.constrain(Size.infinite);
assert(size.width < double.INFINITY);
assert(size.height < double.INFINITY);
}
// 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.toolbar] != null) {
RenderBox toolbar = _slots[ScaffoldSlots.toolbar];
double toolbarHeight = kToolBarHeight + kNotificationAreaHeight;
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.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.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.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;
}
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));
assert(floatingActionButton.parentData is BoxParentData);
floatingActionButton.parentData.position = (area - floatingActionButton.size).toPoint();
}
}
void paint(RenderObjectDisplayList canvas) {
for (ScaffoldSlots slot in [ScaffoldSlots.body, ScaffoldSlots.statusBar, ScaffoldSlots.toolbar, ScaffoldSlots.floatingActionButton, ScaffoldSlots.drawer]) {
RenderBox box = _slots[slot];
if (box != null) {
assert(box.parentData is BoxParentData);
canvas.paintChild(box, box.parentData.position);
}
}
}
void hitTestChildren(HitTestResult result, { Point position }) {
for (ScaffoldSlots slot in [ScaffoldSlots.drawer, ScaffoldSlots.floatingActionButton, ScaffoldSlots.toolbar, ScaffoldSlots.statusBar, ScaffoldSlots.body]) {
RenderBox box = _slots[slot];
if (box != null) {
assert(box.parentData is BoxParentData);
if (new Rect.fromPointAndSize(box.parentData.position, box.size).contains(position)) {
if (box.hitTest(result, position: (position - box.parentData.position).toPoint()))
return;
}
}
}
}
String debugDescribeChildren(String prefix) {
return _slots.keys.map((slot) => '${prefix}${slot}: ${_slots[slot].toString(prefix)}').join();
}
}
class Scaffold extends RenderObjectWrapper {
// static final Style _style = new Style('''
// ${typography.typeface};
// ${typography.black.body1};''');
Scaffold({
String key,
Widget toolbar,
Widget body,
Widget statusBar,
Widget drawer,
Widget floatingActionButton
}) : _toolbar = toolbar,
_body = body,
_statusBar = statusBar,
_drawer = drawer,
_floatingActionButton = floatingActionButton,
super(key: key);
Widget _toolbar;
Widget _body;
Widget _statusBar;
Widget _drawer;
Widget _floatingActionButton;
RenderScaffold get root => super.root;
RenderScaffold createNode() => new RenderScaffold();
void insert(RenderObjectWrapper child, ScaffoldSlots slot) {
root[slot] = child != null ? child.root : null;
}
void removeChild(Widget node) {
assert(node != null);
root.remove(node.root);
super.removeChild(node);
}
void remove() {
if (_toolbar != null)
removeChild(_toolbar);
if (_body != null)
removeChild(_body);
if (_statusBar != null)
removeChild(_statusBar);
if (_drawer != null)
removeChild(_drawer);
if (_floatingActionButton != null)
removeChild(_floatingActionButton);
super.remove();
}
void syncRenderObject(Widget old) {
super.syncRenderObject(old);
_toolbar = syncChild(_toolbar, old is Scaffold ? old._toolbar : null, ScaffoldSlots.toolbar);
_body = syncChild(_body, old is Scaffold ? old._body : null, ScaffoldSlots.body);
_statusBar = syncChild(_statusBar, old is Scaffold ? old._statusBar : null, ScaffoldSlots.statusBar);
_drawer = syncChild(_drawer, old is Scaffold ? old._drawer : null, ScaffoldSlots.drawer);
_floatingActionButton = syncChild(_floatingActionButton, old is Scaffold ? old._floatingActionButton : null, ScaffoldSlots.floatingActionButton);
}
}