| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 import 'dart:math' as math; |
| 6 |
| 5 import '../rendering/box.dart'; | 7 import '../rendering/box.dart'; |
| 6 import '../rendering/object.dart'; | 8 import '../rendering/object.dart'; |
| 7 import '../theme/view_configuration.dart'; | 9 import '../theme/view_configuration.dart'; |
| 8 import 'widget.dart'; | 10 import 'widget.dart'; |
| 9 | 11 |
| 12 // Slots are painted in this order and hit tested in reverse of this order |
| 10 enum ScaffoldSlots { | 13 enum ScaffoldSlots { |
| 11 toolbar, | |
| 12 body, | 14 body, |
| 13 statusBar, | 15 statusBar, |
| 14 drawer, | 16 toolbar, |
| 15 floatingActionButton | 17 snackBar, |
| 18 floatingActionButton, |
| 19 drawer |
| 16 } | 20 } |
| 17 | 21 |
| 18 class RenderScaffold extends RenderBox { | 22 class RenderScaffold extends RenderBox { |
| 19 | 23 |
| 20 RenderScaffold({ | 24 RenderScaffold({ |
| 21 RenderBox toolbar, | |
| 22 RenderBox body, | 25 RenderBox body, |
| 23 RenderBox statusBar, | 26 RenderBox statusBar, |
| 24 RenderBox drawer, | 27 RenderBox toolbar, |
| 25 RenderBox floatingActionButton | 28 RenderBox snackBar, |
| 29 RenderBox floatingActionButton, |
| 30 RenderBox drawer |
| 26 }) { | 31 }) { |
| 27 this[ScaffoldSlots.toolbar] = toolbar; | |
| 28 this[ScaffoldSlots.body] = body; | 32 this[ScaffoldSlots.body] = body; |
| 29 this[ScaffoldSlots.statusBar] = statusBar; | 33 this[ScaffoldSlots.statusBar] = statusBar; |
| 34 this[ScaffoldSlots.toolbar] = toolbar; |
| 35 this[ScaffoldSlots.snackBar] = snackBar; |
| 36 this[ScaffoldSlots.floatingActionButton] = floatingActionButton; |
| 30 this[ScaffoldSlots.drawer] = drawer; | 37 this[ScaffoldSlots.drawer] = drawer; |
| 31 this[ScaffoldSlots.floatingActionButton] = floatingActionButton; | |
| 32 } | 38 } |
| 33 | 39 |
| 34 Map<ScaffoldSlots, RenderBox> _slots = new Map<ScaffoldSlots, RenderBox>(); | 40 Map<ScaffoldSlots, RenderBox> _slots = new Map<ScaffoldSlots, RenderBox>(); |
| 35 RenderBox operator[] (ScaffoldSlots slot) => _slots[slot]; | 41 RenderBox operator[] (ScaffoldSlots slot) => _slots[slot]; |
| 36 void operator[]= (ScaffoldSlots slot, RenderBox value) { | 42 void operator[]= (ScaffoldSlots slot, RenderBox value) { |
| 37 RenderBox old = _slots[slot]; | 43 RenderBox old = _slots[slot]; |
| 38 if (old == value) | 44 if (old == value) |
| 39 return; | 45 return; |
| 40 if (old != null) | 46 if (old != null) |
| 41 dropChild(old); | 47 dropChild(old); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 82 } | 88 } |
| 83 | 89 |
| 84 // TODO(eseidel): These change based on device size! | 90 // TODO(eseidel): These change based on device size! |
| 85 // http://www.google.com/design/spec/layout/metrics-keylines.html#metrics-keyl
ines-keylines-spacing | 91 // http://www.google.com/design/spec/layout/metrics-keylines.html#metrics-keyl
ines-keylines-spacing |
| 86 static const kButtonX = 16.0; // left from right edge of body | 92 static const kButtonX = 16.0; // left from right edge of body |
| 87 static const kButtonY = 16.0; // up from bottom edge of body | 93 static const kButtonY = 16.0; // up from bottom edge of body |
| 88 | 94 |
| 89 void performLayout() { | 95 void performLayout() { |
| 90 double bodyHeight = size.height; | 96 double bodyHeight = size.height; |
| 91 double bodyPosition = 0.0; | 97 double bodyPosition = 0.0; |
| 98 if (_slots[ScaffoldSlots.statusBar] != null) { |
| 99 RenderBox statusBar = _slots[ScaffoldSlots.statusBar]; |
| 100 statusBar.layout(new BoxConstraints.tight(new Size(size.width, kStatusBarH
eight))); |
| 101 assert(statusBar.parentData is BoxParentData); |
| 102 statusBar.parentData.position = new Point(0.0, size.height - kStatusBarHei
ght); |
| 103 bodyHeight -= kStatusBarHeight; |
| 104 } |
| 92 if (_slots[ScaffoldSlots.toolbar] != null) { | 105 if (_slots[ScaffoldSlots.toolbar] != null) { |
| 93 RenderBox toolbar = _slots[ScaffoldSlots.toolbar]; | 106 RenderBox toolbar = _slots[ScaffoldSlots.toolbar]; |
| 94 double toolbarHeight = kToolBarHeight + kNotificationAreaHeight; | 107 double toolbarHeight = kToolBarHeight + kNotificationAreaHeight; |
| 95 toolbar.layout(new BoxConstraints.tight(new Size(size.width, toolbarHeight
))); | 108 toolbar.layout(new BoxConstraints.tight(new Size(size.width, toolbarHeight
))); |
| 96 assert(toolbar.parentData is BoxParentData); | 109 assert(toolbar.parentData is BoxParentData); |
| 97 toolbar.parentData.position = Point.origin; | 110 toolbar.parentData.position = Point.origin; |
| 98 bodyPosition += toolbarHeight; | 111 bodyPosition += toolbarHeight; |
| 99 bodyHeight -= toolbarHeight; | 112 bodyHeight -= toolbarHeight; |
| 100 } | 113 } |
| 101 if (_slots[ScaffoldSlots.statusBar] != null) { | |
| 102 RenderBox statusBar = _slots[ScaffoldSlots.statusBar]; | |
| 103 statusBar.layout(new BoxConstraints.tight(new Size(size.width, kStatusBarH
eight))); | |
| 104 assert(statusBar.parentData is BoxParentData); | |
| 105 statusBar.parentData.position = new Point(0.0, size.height - kStatusBarHei
ght); | |
| 106 bodyHeight -= kStatusBarHeight; | |
| 107 } | |
| 108 if (_slots[ScaffoldSlots.body] != null) { | 114 if (_slots[ScaffoldSlots.body] != null) { |
| 109 RenderBox body = _slots[ScaffoldSlots.body]; | 115 RenderBox body = _slots[ScaffoldSlots.body]; |
| 110 body.layout(new BoxConstraints.tight(new Size(size.width, bodyHeight))); | 116 body.layout(new BoxConstraints.tight(new Size(size.width, bodyHeight))); |
| 111 assert(body.parentData is BoxParentData); | 117 assert(body.parentData is BoxParentData); |
| 112 body.parentData.position = new Point(0.0, bodyPosition); | 118 body.parentData.position = new Point(0.0, bodyPosition); |
| 113 } | 119 } |
| 120 double snackBarHeight = 0.0; |
| 121 if (_slots[ScaffoldSlots.snackBar] != null) { |
| 122 RenderBox snackBar = _slots[ScaffoldSlots.snackBar]; |
| 123 // TODO(jackson): On tablet/desktop, minWidth = 288, maxWidth = 568 |
| 124 snackBar.layout(new BoxConstraints(minWidth: size.width, maxWidth: size.wi
dth, minHeight: 0.0, maxHeight: size.height), |
| 125 parentUsesSize: true); |
| 126 assert(snackBar.parentData is BoxParentData); |
| 127 snackBar.parentData.position = new Point(0.0, size.height - snackBar.size.
height); |
| 128 snackBarHeight = snackBar.size.height; |
| 129 } |
| 130 if (_slots[ScaffoldSlots.floatingActionButton] != null) { |
| 131 RenderBox floatingActionButton = _slots[ScaffoldSlots.floatingActionButton
]; |
| 132 Size area = new Size(size.width - kButtonX, size.height - kButtonY - snack
BarHeight); |
| 133 floatingActionButton.layout(new BoxConstraints.loose(area), parentUsesSize
: true); |
| 134 assert(floatingActionButton.parentData is BoxParentData); |
| 135 floatingActionButton.parentData.position = (area - floatingActionButton.si
ze).toPoint(); |
| 136 } |
| 114 if (_slots[ScaffoldSlots.drawer] != null) { | 137 if (_slots[ScaffoldSlots.drawer] != null) { |
| 115 RenderBox drawer = _slots[ScaffoldSlots.drawer]; | 138 RenderBox drawer = _slots[ScaffoldSlots.drawer]; |
| 116 drawer.layout(new BoxConstraints(minWidth: 0.0, maxWidth: size.width, minH
eight: size.height, maxHeight: size.height)); | 139 drawer.layout(new BoxConstraints(minWidth: 0.0, maxWidth: size.width, minH
eight: size.height, maxHeight: size.height)); |
| 117 assert(drawer.parentData is BoxParentData); | 140 assert(drawer.parentData is BoxParentData); |
| 118 drawer.parentData.position = Point.origin; | 141 drawer.parentData.position = Point.origin; |
| 119 } | 142 } |
| 120 if (_slots[ScaffoldSlots.floatingActionButton] != null) { | |
| 121 RenderBox floatingActionButton = _slots[ScaffoldSlots.floatingActionButton
]; | |
| 122 Size area = new Size(size.width - kButtonX, size.height - kButtonY); | |
| 123 floatingActionButton.layout(new BoxConstraints.loose(area), parentUsesSize
: true); | |
| 124 assert(floatingActionButton.parentData is BoxParentData); | |
| 125 floatingActionButton.parentData.position = (area - floatingActionButton.si
ze).toPoint(); | |
| 126 } | |
| 127 } | 143 } |
| 128 | 144 |
| 129 void paint(PaintingCanvas canvas, Offset offset) { | 145 void paint(PaintingCanvas canvas, Offset offset) { |
| 130 for (ScaffoldSlots slot in [ScaffoldSlots.body, ScaffoldSlots.statusBar, Sca
ffoldSlots.toolbar, ScaffoldSlots.floatingActionButton, ScaffoldSlots.drawer]) { | 146 for (ScaffoldSlots slot in ScaffoldSlots.values) { |
| 131 RenderBox box = _slots[slot]; | 147 RenderBox box = _slots[slot]; |
| 132 if (box != null) { | 148 if (box != null) { |
| 133 assert(box.parentData is BoxParentData); | 149 assert(box.parentData is BoxParentData); |
| 134 canvas.paintChild(box, box.parentData.position + offset); | 150 canvas.paintChild(box, box.parentData.position + offset); |
| 135 } | 151 } |
| 136 } | 152 } |
| 137 } | 153 } |
| 138 | 154 |
| 139 void hitTestChildren(HitTestResult result, { Point position }) { | 155 void hitTestChildren(HitTestResult result, { Point position }) { |
| 140 for (ScaffoldSlots slot in [ScaffoldSlots.drawer, ScaffoldSlots.floatingActi
onButton, ScaffoldSlots.toolbar, ScaffoldSlots.statusBar, ScaffoldSlots.body]) { | 156 for (ScaffoldSlots slot in ScaffoldSlots.values.reversed) { |
| 141 RenderBox box = _slots[slot]; | 157 RenderBox box = _slots[slot]; |
| 142 if (box != null) { | 158 if (box != null) { |
| 143 assert(box.parentData is BoxParentData); | 159 assert(box.parentData is BoxParentData); |
| 144 if ((box.parentData.position & box.size).contains(position)) { | 160 if ((box.parentData.position & box.size).contains(position)) { |
| 145 if (box.hitTest(result, position: (position - box.parentData.position)
.toPoint())) | 161 if (box.hitTest(result, position: (position - box.parentData.position)
.toPoint())) |
| 146 return; | 162 return; |
| 147 } | 163 } |
| 148 } | 164 } |
| 149 } | 165 } |
| 150 } | 166 } |
| 151 | 167 |
| 152 String debugDescribeChildren(String prefix) { | 168 String debugDescribeChildren(String prefix) { |
| 153 return _slots.keys.map((slot) => '${prefix}${slot}: ${_slots[slot].toString(
prefix)}').join(); | 169 return _slots.keys.map((slot) => '${prefix}${slot}: ${_slots[slot].toString(
prefix)}').join(); |
| 154 } | 170 } |
| 155 } | 171 } |
| 156 | 172 |
| 157 class Scaffold extends RenderObjectWrapper { | 173 class Scaffold extends RenderObjectWrapper { |
| 158 | 174 |
| 159 // static final Style _style = new Style(''' | |
| 160 // ${typography.typeface}; | |
| 161 // ${typography.black.body1};'''); | |
| 162 | |
| 163 Scaffold({ | 175 Scaffold({ |
| 164 String key, | 176 String key, |
| 165 Widget toolbar, | |
| 166 Widget body, | 177 Widget body, |
| 167 Widget statusBar, | 178 Widget statusBar, |
| 168 Widget drawer, | 179 Widget toolbar, |
| 169 Widget floatingActionButton | 180 Widget snackBar, |
| 170 }) : _toolbar = toolbar, | 181 Widget floatingActionButton, |
| 171 _body = body, | 182 Widget drawer |
| 172 _statusBar = statusBar, | 183 }) : super(key: key) { |
| 173 _drawer = drawer, | 184 this[ScaffoldSlots.body] = body; |
| 174 _floatingActionButton = floatingActionButton, | 185 this[ScaffoldSlots.statusBar] = statusBar; |
| 175 super(key: key); | 186 this[ScaffoldSlots.toolbar] = toolbar; |
| 187 this[ScaffoldSlots.snackBar] = snackBar; |
| 188 this[ScaffoldSlots.floatingActionButton] = floatingActionButton; |
| 189 this[ScaffoldSlots.drawer] = drawer; |
| 190 } |
| 176 | 191 |
| 177 Widget _toolbar; | 192 Map<ScaffoldSlots, Widget> _slots = new Map<ScaffoldSlots, Widget>(); |
| 178 Widget _body; | 193 Widget operator[] (ScaffoldSlots slot) => _slots[slot]; |
| 179 Widget _statusBar; | 194 void operator[]= (ScaffoldSlots slot, Widget value) { |
| 180 Widget _drawer; | 195 _slots[slot] = value; |
| 181 Widget _floatingActionButton; | 196 } |
| 182 | 197 |
| 183 RenderScaffold get root => super.root; | 198 RenderScaffold get root => super.root; |
| 184 RenderScaffold createNode() => new RenderScaffold(); | 199 RenderScaffold createNode() => new RenderScaffold(); |
| 185 | 200 |
| 186 void walkChildren(WidgetTreeWalker walker) { | 201 void walkChildren(WidgetTreeWalker walker) { |
| 187 if (_toolbar != null) | 202 for (ScaffoldSlots slot in ScaffoldSlots.values) { |
| 188 walker(_toolbar); | 203 Widget widget = _slots[slot]; |
| 189 if (_body != null) | 204 if (widget != null) |
| 190 walker(_body); | 205 walker(widget); |
| 191 if (_statusBar != null) | 206 } |
| 192 walker(_statusBar); | |
| 193 if (_drawer != null) | |
| 194 walker(_drawer); | |
| 195 if (_floatingActionButton != null) | |
| 196 walker(_floatingActionButton); | |
| 197 } | 207 } |
| 198 | 208 |
| 199 void insertChildRoot(RenderObjectWrapper child, ScaffoldSlots slot) { | 209 void insertChildRoot(RenderObjectWrapper child, ScaffoldSlots slot) { |
| 200 root[slot] = child != null ? child.root : null; | 210 root[slot] = child != null ? child.root : null; |
| 201 } | 211 } |
| 202 | 212 |
| 203 void detachChildRoot(RenderObjectWrapper child) { | 213 void detachChildRoot(RenderObjectWrapper child) { |
| 204 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer | 214 final root = this.root; // TODO(ianh): Remove this once the analyzer is clev
erer |
| 205 assert(root is RenderScaffold); | 215 assert(root is RenderScaffold); |
| 206 assert(root == child.root.parent); | 216 assert(root == child.root.parent); |
| 207 root.remove(child.root); | 217 root.remove(child.root); |
| 208 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer | 218 assert(root == this.root); // TODO(ianh): Remove this once the analyzer is c
leverer |
| 209 } | 219 } |
| 210 | 220 |
| 211 void remove() { | 221 void remove() { |
| 212 walkChildren((Widget child) => removeChild(child)); | 222 walkChildren((Widget child) => removeChild(child)); |
| 213 super.remove(); | 223 super.remove(); |
| 214 } | 224 } |
| 215 | 225 |
| 216 void syncRenderObject(Widget old) { | 226 void syncRenderObject(Widget old) { |
| 217 super.syncRenderObject(old); | 227 super.syncRenderObject(old); |
| 218 _toolbar = syncChild(_toolbar, old is Scaffold ? old._toolbar : null, Scaffo
ldSlots.toolbar); | 228 for (ScaffoldSlots slot in ScaffoldSlots.values) { |
| 219 _body = syncChild(_body, old is Scaffold ? old._body : null, ScaffoldSlots.b
ody); | 229 Widget widget = this[slot]; |
| 220 _statusBar = syncChild(_statusBar, old is Scaffold ? old._statusBar : null,
ScaffoldSlots.statusBar); | 230 this[slot] = syncChild(widget, old is Scaffold ? old[slot] : null, slot); |
| 221 _drawer = syncChild(_drawer, old is Scaffold ? old._drawer : null, ScaffoldS
lots.drawer); | 231 } |
| 222 _floatingActionButton = syncChild(_floatingActionButton, old is Scaffold ? o
ld._floatingActionButton : null, ScaffoldSlots.floatingActionButton); | |
| 223 } | 232 } |
| 224 | 233 |
| 225 } | 234 } |
| OLD | NEW |