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