Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(619)

Side by Side Diff: sky/sdk/lib/framework/layout2.dart

Issue 1093633002: Layout API prototype, for discussion (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: git cl land Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « sky/sdk/lib/framework/layout.dart ('k') | sky/sdk/lib/framework/node.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 library layout;
2
3 // This version of layout.dart is an update to the other one, this one using new APIs.
4 // It will not work in a stock Sky setup currently.
5
6 import 'node.dart';
7
8 import 'dart:sky' as sky;
9
10 // ABSTRACT LAYOUT
11
12 class ParentData {
13 void detach() {
14 detachSiblings();
15 }
16 void detachSiblings() { } // workaround for lack of inter-class mixins in Dart
17 void merge(ParentData other) {
18 // override this in subclasses to merge in data from other into this
19 assert(other.runtimeType == this.runtimeType);
20 }
21 }
22
23 const kLayoutDirections = 4;
24
25 double clamp({double min: 0.0, double value: 0.0, double max: double.INFINITY}) {
26 if (value > max)
27 value = max;
28 if (value < min)
29 value = min;
30 return value;
31 }
32
33 class RenderNodeDisplayList extends sky.PictureRecorder {
34 RenderNodeDisplayList(double width, double height) : super(width, height);
35 void paintChild(RenderNode child, double x, double y) {
36 save();
37 translate(x, y);
38 child.paint(this);
39 restore();
40 }
41 }
42
43 abstract class RenderNode extends AbstractNode {
44
45 // LAYOUT
46
47 // parentData is only for use by the RenderNode that actually lays this
48 // node out, and any other nodes who happen to know exactly what
49 // kind of node that is.
50 ParentData parentData;
51 void setupPos(RenderNode child) {
52 // override this to setup .parentData correctly for your class
53 if (child.parentData is! ParentData)
54 child.parentData = new ParentData();
55 }
56
57 void adoptChild(RenderNode child) { // only for use by subclasses
58 // call this whenever you decide a node is a child
59 assert(child != null);
60 setupPos(child);
61 super.adoptChild(child);
62 }
63 void dropChild(RenderNode child) { // only for use by subclasses
64 assert(child != null);
65 assert(child.parentData != null);
66 child.parentData.detach();
67 super.dropChild(child);
68 }
69
70 static List<RenderNode> _nodesNeedingLayout = new List<RenderNode>();
71 static bool _debugDoingLayout = false;
72 bool _needsLayout = true;
73 bool get needsLayout => _needsLayout;
74 RenderNode _relayoutSubtreeRoot;
75 void saveRelayoutSubtreeRoot(RenderNode relayoutSubtreeRoot) {
76 _relayoutSubtreeRoot = relayoutSubtreeRoot;
77 assert(_relayoutSubtreeRoot == null || _relayoutSubtreeRoot._relayoutSubtree Root == null);
78 assert(_relayoutSubtreeRoot == null || _relayoutSubtreeRoot == parent || _re layoutSubtreeRoot == parent._relayoutSubtreeRoot);
79 }
80 bool debugAncestorsAlreadyMarkedNeedsLayout() {
81 if (_relayoutSubtreeRoot == null)
82 return true;
83 RenderNode node = this;
84 while (node != _relayoutSubtreeRoot) {
85 assert(node._relayoutSubtreeRoot == _relayoutSubtreeRoot);
86 assert(node.parent != null);
87 node = node.parent as RenderNode;
88 if (!node._needsLayout)
89 return false;
90 }
91 assert(node._relayoutSubtreeRoot == null);
92 return true;
93 }
94 void markNeedsLayout() {
95 assert(!_debugDoingLayout);
96 assert(!_debugDoingPaint);
97 if (_needsLayout) {
98 assert(debugAncestorsAlreadyMarkedNeedsLayout());
99 return;
100 }
101 _needsLayout = true;
102 if (_relayoutSubtreeRoot != null)
103 parent.markNeedsLayout();
104 else
105 _nodesNeedingLayout.add(this);
106 }
107 static void flushLayout() {
108 _debugDoingLayout = true;
109 List<RenderNode> dirtyNodes = _nodesNeedingLayout;
110 _nodesNeedingLayout = new List<RenderNode>();
111 dirtyNodes..sort((a, b) => a.depth - b.depth)..forEach((node) {
112 if (node._needsLayout && node.attached)
113 node._doLayout();
114 });
115 _debugDoingLayout = false;
116 }
117 void _doLayout() {
118 try {
119 assert(_relayoutSubtreeRoot == null);
120 relayout();
121 } catch (e, stack) {
122 print('Exception raised during layout of ${this}: ${e}');
123 print(stack);
124 return;
125 }
126 assert(!_needsLayout); // check that the relayout() method marked us "not di rty"
127 }
128 /* // this method's signature is subclass-specific, but will exist in
129 // some form in all subclasses:
130 void layout({arguments..., RenderNode relayoutSubtreeRoot}) {
131 bool childArgumentsChanged = ...; // true if arguments we're going to pas s to the children are different than last time, false otherwise
132 if (this node has an opinion about its size, e.g. because it autosizes ba sed on kids, or has an intrinsic dimension) {
133 if (relayoutSubtreeRoot != null) {
134 saveRelayoutSubtreeRoot(relayoutSubtreeRoot);
135 // for each child, if we are going to size ourselves around them:
136 if (child.needsLayout || childArgumentsChanged)
137 child.layout(... relayoutSubtreeRoot: relayoutSubtreeRoot);
138 width = ...;
139 height = ...;
140 } else {
141 saveRelayoutSubtreeRoot(null); // you can skip this if there's no way you would ever have called saveRelayoutSubtreeRoot() before
142 // we're the root of the relayout subtree
143 // for each child, if we are going to size ourselves around them:
144 if (child.needsLayout || childArgumentsChanged)
145 child.layout(... relayoutSubtreeRoot: this);
146 width = ...;
147 height = ...;
148 }
149 } else {
150 // we're sizing ourselves exclusively on input from the parent (argumen ts to this function)
151 // ignore relayoutSubtreeRoot
152 saveRelayoutSubtreeRoot(null); // you can skip this if there's no way y ou would ever have called saveRelayoutSubtreeRoot() before
153 width = ...; // based on input from arguments only
154 height = ...; // based on input from arguments only
155 }
156 // for each child whose size we'll ignore when deciding ours:
157 if (child.needsLayout || childArgumentsChanged)
158 child.layout(... relayoutSubtreeRoot: null); // or just omit relayoutSu btreeRoot
159 layoutDone();
160 return;
161 }
162 */
163 void relayout() {
164 // Override this to perform relayout without your parent's
165 // involvement.
166 //
167 // This is what is called after the first layout(), if you mark
168 // yourself dirty and don't have a _relayoutSubtreeRoot set; in
169 // other words, either if your parent doesn't care what size you
170 // are (and thus didn't pass a relayoutSubtreeRoot to your
171 // layout() method) or if you sized yourself entirely based on
172 // what your parents told you, and not based on your children (and
173 // thus you never called saveRelayoutSubtreeRoot()).
174 //
175 // In the former case, you can resize yourself here at will. In
176 // the latter case, just leave your dimensions unchanged.
177 //
178 // If _relayoutSubtreeRoot is set (i.e. you called saveRelayout-
179 // SubtreeRoot() in your layout(), with a relayoutSubtreeRoot
180 // argument that was non-null), then if you mark yourself as dirty
181 // then we'll tell that subtree root instead, and the layout will
182 // occur via the layout() tree rather than starting from this
183 // relayout() method.
184 //
185 // when calling children's layout() methods, skip any children
186 // that have needsLayout == false unless the arguments you are
187 // passing in have changed since the last time
188 assert(_relayoutSubtreeRoot == null);
189 layoutDone();
190 }
191 void layoutDone({bool needsPaint: true}) {
192 // make sure to call this at the end of your layout() or relayout()
193 _needsLayout = false;
194 if (needsPaint)
195 markNeedsPaint();
196 }
197
198 // when the parent has rotated (e.g. when the screen has been turned
199 // 90 degrees), immediately prior to layout() being called for the
200 // new dimensions, rotate() is called with the old and new angles.
201 // The next time paint() is called, the coordinate space will have
202 // been rotated N quarter-turns clockwise, where:
203 // N = newAngle-oldAngle
204 // ...but the rendering is expected to remain the same, pixel for
205 // pixel, on the output device. Then, the layout() method or
206 // equivalent will be invoked.
207
208 void rotate({
209 int oldAngle, // 0..3
210 int newAngle, // 0..3
211 Duration time
212 }) { }
213
214
215 // HIT TESTING
216
217 void handlePointer(sky.PointerEvent event) {
218 // override this if you have children, to hand it to the appropriate child
219 // override this if you want to do anything with the pointer event
220 }
221
222
223 // PAINTING
224
225 static bool _debugDoingPaint = false;
226 void markNeedsPaint() {
227 assert(!_debugDoingPaint);
228 var ancestor = this;
229 while (ancestor.parent != null)
230 ancestor = ancestor.parent;
231 assert(ancestor is Screen);
232 ancestor.paintFrame();
233 }
234 void paint(RenderNodeDisplayList canvas) { }
235
236 }
237
238
239 // GENERIC MIXIN FOR RENDER NODES THAT TAKE A LIST OF CHILDREN
240
241 abstract class ContainerParentDataMixin<ChildType extends RenderNode> {
242 ChildType previousSibling;
243 ChildType nextSibling;
244 void detachSiblings() {
245 if (previousSibling != null) {
246 assert(previousSibling.parentData is ContainerParentDataMixin<ChildType>);
247 assert(previousSibling != this);
248 assert(previousSibling.parentData.nextSibling == this);
249 previousSibling.parentData.nextSibling = nextSibling;
250 }
251 if (nextSibling != null) {
252 assert(nextSibling.parentData is ContainerParentDataMixin<ChildType>);
253 assert(nextSibling != this);
254 assert(nextSibling.parentData.previousSibling == this);
255 nextSibling.parentData.previousSibling = previousSibling;
256 }
257 previousSibling = null;
258 nextSibling = null;
259 }
260 }
261
262 abstract class ContainerRenderNodeMixin<ChildType extends RenderNode, ParentData Type extends ContainerParentDataMixin<ChildType>> implements RenderNode {
263 // abstract class that has only InlineNode children
264
265 bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType equals }) {
266 assert(child.parentData is ParentDataType);
267 while (child.parentData.previousSibling != null) {
268 assert(child.parentData.previousSibling != child);
269 child = child.parentData.previousSibling;
270 assert(child.parentData is ParentDataType);
271 }
272 return child == equals;
273 }
274 bool _debugUltimateNextSiblingOf(ChildType child, { ChildType equals }) {
275 assert(child.parentData is ParentDataType);
276 while (child.parentData.nextSibling != null) {
277 assert(child.parentData.nextSibling != child);
278 child = child.parentData.nextSibling;
279 assert(child.parentData is ParentDataType);
280 }
281 return child == equals;
282 }
283
284 ChildType _firstChild;
285 ChildType _lastChild;
286 void add(ChildType child, { ChildType before }) {
287 assert(child != this);
288 assert(before != this);
289 assert(child != before);
290 assert(child != _firstChild);
291 assert(child != _lastChild);
292 adoptChild(child);
293 assert(child.parentData is ParentDataType);
294 assert(child.parentData.nextSibling == null);
295 assert(child.parentData.previousSibling == null);
296 if (before == null) {
297 // append at the end (_lastChild)
298 child.parentData.previousSibling = _lastChild;
299 if (_lastChild != null) {
300 assert(_lastChild.parentData is ParentDataType);
301 _lastChild.parentData.nextSibling = child;
302 }
303 _lastChild = child;
304 if (_firstChild == null)
305 _firstChild = child;
306 } else {
307 assert(_firstChild != null);
308 assert(_lastChild != null);
309 assert(_debugUltimatePreviousSiblingOf(before, equals: _firstChild));
310 assert(_debugUltimateNextSiblingOf(before, equals: _lastChild));
311 assert(before.parentData is ParentDataType);
312 if (before.parentData.previousSibling == null) {
313 // insert at the start (_firstChild); we'll end up with two or more chil dren
314 assert(before == _firstChild);
315 child.parentData.nextSibling = before;
316 before.parentData.previousSibling = child;
317 _firstChild = child;
318 } else {
319 // insert in the middle; we'll end up with three or more children
320 // set up links from child to siblings
321 child.parentData.previousSibling = before.parentData.previousSibling;
322 child.parentData.nextSibling = before;
323 // set up links from siblings to child
324 assert(child.parentData.previousSibling.parentData is ParentDataType);
325 assert(child.parentData.nextSibling.parentData is ParentDataType);
326 child.parentData.previousSibling.parentData.nextSibling = child;
327 child.parentData.nextSibling.parentData.previousSibling = child;
328 assert(before.parentData.previousSibling == child);
329 }
330 }
331 markNeedsLayout();
332 }
333 void remove(ChildType child) {
334 assert(child.parentData is ParentDataType);
335 assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
336 assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
337 if (child.parentData.previousSibling == null) {
338 assert(_firstChild == child);
339 _firstChild = child.parentData.nextSibling;
340 } else {
341 assert(child.parentData.previousSibling.parentData is ParentDataType);
342 child.parentData.previousSibling.parentData.nextSibling = child.parentData .nextSibling;
343 }
344 if (child.parentData.nextSibling == null) {
345 assert(_lastChild == child);
346 _lastChild = child.parentData.previousSibling;
347 } else {
348 assert(child.parentData.nextSibling.parentData is ParentDataType);
349 child.parentData.nextSibling.parentData.previousSibling = child.parentData .previousSibling;
350 }
351 child.parentData.previousSibling = null;
352 child.parentData.nextSibling = null;
353 dropChild(child);
354 markNeedsLayout();
355 }
356 void redepthChildren() {
357 ChildType child = _firstChild;
358 while (child != null) {
359 redepthChild(child);
360 assert(child.parentData is ParentDataType);
361 child = child.parentData.nextSibling;
362 }
363 }
364 void attachChildren() {
365 ChildType child = _firstChild;
366 while (child != null) {
367 child.attach();
368 assert(child.parentData is ParentDataType);
369 child = child.parentData.nextSibling;
370 }
371 }
372 void detachChildren() {
373 ChildType child = _firstChild;
374 while (child != null) {
375 child.detach();
376 assert(child.parentData is ParentDataType);
377 child = child.parentData.nextSibling;
378 }
379 }
380
381 ChildType get firstChild => _firstChild;
382 ChildType get lastChild => _lastChild;
383 ChildType childAfter(ChildType child) {
384 assert(child.parentData is ParentDataType);
385 return child.parentData.nextSibling;
386 }
387
388 }
389
390
391 // GENERIC BOX RENDERING
392 // Anything that has a concept of x, y, width, height is going to derive from th is
393
394 class BoxDimensions {
395 const BoxDimensions({this.width, this.height});
396 final double width;
397 final double height;
398 }
399
400 class BoxParentData extends ParentData {
401 double x = 0.0;
402 double y = 0.0;
403 }
404
405 abstract class RenderBox extends RenderNode {
406
407 void setupPos(RenderNode child) {
408 if (child.parentData is! BoxParentData)
409 child.parentData = new BoxParentData();
410 }
411
412 // override this to report what dimensions you would have if you
413 // were laid out with the given constraints this can walk the tree
414 // if it must, but it should be as cheap as possible; just get the
415 // dimensions and nothing else (e.g. don't calculate hypothetical
416 // child positions if they're not needed to determine dimensions)
417 BoxDimensions getIntrinsicDimensions({
418 double minWidth: 0.0,
419 double maxWidth: double.INFINITY,
420 double minHeight: 0.0,
421 double maxHeight: double.INFINITY
422 }) {
423 return new BoxDimensions(
424 width: clamp(min: minWidth, max: maxWidth),
425 height: clamp(min: minHeight, max: maxHeight)
426 );
427 }
428
429 void layout({
430 double minWidth: 0.0,
431 double maxWidth: double.INFINITY,
432 double minHeight: 0.0,
433 double maxHeight: double.INFINITY,
434 RenderNode relayoutSubtreeRoot
435 }) {
436 width = clamp(min: minWidth, max: maxWidth);
437 height = clamp(min: minHeight, max: maxHeight);
438 layoutDone();
439 }
440
441 double width;
442 double height;
443
444 void rotate({
445 int oldAngle, // 0..3
446 int newAngle, // 0..3
447 Duration time
448 }) { }
449
450 }
451
452
453 // SCREEN LAYOUT MANAGER
454
455 class Screen extends RenderNode {
456
457 Screen({
458 RenderBox root,
459 this.timeForRotation: const Duration(microseconds: 83333)
460 }) {
461 assert(root != null);
462 this.root = root;
463 }
464
465 double _width;
466 double get width => _width;
467 double _height;
468 double get height => _height;
469
470 int _orientation; // 0..3
471 int get orientation => _orientation;
472 Duration timeForRotation;
473
474 RenderBox _root;
475 RenderBox get root => _root;
476 void set root (RenderBox value) {
477 assert(root != null);
478 _root = value;
479 adoptChild(_root);
480 markNeedsLayout();
481 }
482
483 void layout({
484 double newWidth,
485 double newHeight,
486 int newOrientation
487 }) {
488 assert(root != null);
489 if (newOrientation != orientation) {
490 if (orientation != null)
491 root.rotate(oldAngle: orientation, newAngle: newOrientation, time: timeF orRotation);
492 _orientation = newOrientation;
493 }
494 if ((newWidth != width) || (newHeight != height)) {
495 _width = newWidth;
496 _height = newHeight;
497 relayout();
498 }
499 }
500
501 void relayout() {
502 assert(root != null);
503 root.layout(
504 minWidth: width,
505 maxWidth: width,
506 minHeight: height,
507 maxHeight: height
508 );
509 assert(root.width == width);
510 assert(root.height == height);
511 }
512
513 void rotate({ int oldAngle, int newAngle, Duration time }) {
514 assert(false); // nobody tells the screen to rotate, the whole rotate() danc e is started from our layout()
515 }
516
517 void paint(RenderNodeDisplayList canvas) {
518 canvas.paintChild(root, 0.0, 0.0);
519 }
520
521 void paintFrame() {
522 RenderNode._debugDoingPaint = true;
523 var canvas = new RenderNodeDisplayList(sky.view.width, sky.view.height);
524 paint(canvas);
525 sky.view.picture = canvas.endRecording();
526 sky.view.schedulePaint();
527 RenderNode._debugDoingPaint = false;
528 }
529
530 }
531
532
533 // BLOCK LAYOUT MANAGER
534
535 class EdgeDims {
536 // used for e.g. padding
537 const EdgeDims(this.top, this.right, this.bottom, this.left);
538 final double top;
539 final double right;
540 final double bottom;
541 final double left;
542 operator ==(EdgeDims other) => (top == other.top) ||
543 (right == other.right) ||
544 (bottom == other.bottom) ||
545 (left == other.left);
546 }
547
548 class BlockParentData extends BoxParentData with ContainerParentDataMixin<Render Box> { }
549
550 class BlockBox extends RenderBox with ContainerRenderNodeMixin<RenderBox, BlockP arentData> {
551 // lays out RenderBox children in a vertical stack
552 // uses the maximum width provided by the parent
553 // sizes itself to the height of its child stack
554
555 BlockBox({
556 EdgeDims padding: const EdgeDims(0.0, 0.0, 0.0, 0.0)
557 }) {
558 _padding = padding;
559 }
560
561 EdgeDims _padding;
562 EdgeDims get padding => _padding;
563 void set padding(EdgeDims value) {
564 assert(value != null);
565 if (_padding != value) {
566 _padding = value;
567 markNeedsLayout();
568 }
569 }
570
571 void setupPos(RenderBox child) {
572 if (child.parentData is! BlockParentData)
573 child.parentData = new BlockParentData();
574 }
575
576 // override this to report what dimensions you would have if you
577 // were laid out with the given constraints this can walk the tree
578 // if it must, but it should be as cheap as possible; just get the
579 // dimensions and nothing else (e.g. don't calculate hypothetical
580 // child positions if they're not needed to determine dimensions)
581 BoxDimensions getIntrinsicDimensions({
582 double minWidth: 0.0,
583 double maxWidth: double.INFINITY,
584 double minHeight: 0.0,
585 double maxHeight: double.INFINITY
586 }) {
587 double outerHeight = _padding.top + _padding.bottom;
588 double outerWidth = clamp(min: minWidth, max: maxWidth);
589 double innerWidth = outerWidth - (_padding.left + _padding.right);
590 RenderBox child = _firstChild;
591 while (child != null) {
592 outerHeight += child.getIntrinsicDimensions(minWidth: innerWidth, maxWidth : innerWidth).height;
593 assert(child.parentData is BlockParentData);
594 child = child.parentData.nextSibling;
595 }
596 return new BoxDimensions(
597 width: outerWidth,
598 height: clamp(min: minHeight, max: maxHeight, value: outerHeight)
599 );
600 }
601
602 double _minHeight; // value cached from parent for relayout call
603 double _maxHeight; // value cached from parent for relayout call
604 void layout({
605 double minWidth: 0.0,
606 double maxWidth: double.INFINITY,
607 double minHeight: 0.0,
608 double maxHeight: double.INFINITY,
609 RenderNode relayoutSubtreeRoot
610 }) {
611 if (relayoutSubtreeRoot != null)
612 saveRelayoutSubtreeRoot(relayoutSubtreeRoot);
613 relayoutSubtreeRoot = relayoutSubtreeRoot == null ? this : relayoutSubtreeRo ot;
614 width = clamp(min: minWidth, max: maxWidth);
615 _minHeight = minHeight;
616 _maxHeight = maxHeight;
617 internalLayout(relayoutSubtreeRoot);
618 }
619
620 void relayout() {
621 internalLayout(this);
622 }
623
624 void internalLayout(RenderNode relayoutSubtreeRoot) {
625 assert(_minHeight != null);
626 assert(_maxHeight != null);
627 double y = _padding.top;
628 double innerWidth = width - (_padding.left + _padding.right);
629 RenderBox child = _firstChild;
630 while (child != null) {
631 child.layout(minWidth: innerWidth, maxWidth: innerWidth, relayoutSubtreeRo ot: relayoutSubtreeRoot);
632 assert(child.parentData is BlockParentData);
633 child.parentData.x = 0.0;
634 child.parentData.y = y;
635 y += child.height;
636 child = child.parentData.nextSibling;
637 }
638 height = clamp(min: _minHeight, value: y + _padding.bottom, max: _maxHeight) ;
639 layoutDone();
640 }
641
642 void handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) {
643 // the x, y parameters have the top left of the node's box as the origin
644 RenderBox child = _lastChild;
645 while (child != null) {
646 assert(child.parentData is BlockParentData);
647 if ((x >= child.parentData.x) && (x < child.parentData.x + child.width) &&
648 (y >= child.parentData.y) && (y < child.parentData.y + child.height)) {
649 child.handlePointer(event, x: x-child.parentData.x, y: y-child.parentDat a.y);
650 break;
651 }
652 child = child.parentData.previousSibling;
653 }
654 super.handlePointer(event);
655 }
656
657 void paint(RenderNodeDisplayList canvas) {
658 RenderBox child = _firstChild;
659 while (child != null) {
660 assert(child.parentData is BlockParentData);
661 canvas.paintChild(child, child.parentData.x, child.parentData.y);
662 child = child.parentData.nextSibling;
663 }
664 }
665
666 }
667
668 class FlexBoxParentData extends BoxParentData {
669 int flex;
670 void merge(FlexBoxParentData other) {
671 if (other.flex != null)
672 flex = other.flex;
673 super.merge(other);
674 }
675 }
676
677 enum FlexDirection { Row, Column }
678
679 // TODO(ianh): FlexBox
680
681
682 // SCAFFOLD LAYOUT MANAGER
683
684 // a sample special-purpose layout manager
685
686 class ScaffoldBox extends RenderBox {
687
688 ScaffoldBox(this.toolbar, this.body, this.statusbar, this.drawer) {
689 assert(body != null);
690 }
691
692 final RenderBox toolbar;
693 final RenderBox body;
694 final RenderBox statusbar;
695 final RenderBox drawer;
696
697 void layout({
698 double minWidth: 0.0,
699 double maxWidth: double.INFINITY,
700 double minHeight: 0.0,
701 double maxHeight: double.INFINITY,
702 RenderNode relayoutSubtreeRoot
703 }) {
704 width = clamp(min: minWidth, max: maxWidth);
705 height = clamp(min: minHeight, max: maxHeight);
706 relayout();
707 }
708
709 static const kToolbarHeight = 100.0;
710 static const kStatusbarHeight = 50.0;
711
712 void relayout() {
713 double bodyHeight = height;
714 if (toolbar != null) {
715 toolbar.layout(minWidth: width, maxWidth: width, minHeight: kToolbarHeight , maxHeight: kToolbarHeight);
716 assert(toolbar.parentData is BoxParentData);
717 toolbar.parentData.x = 0.0;
718 toolbar.parentData.y = 0.0;
719 bodyHeight -= kToolbarHeight;
720 }
721 if (statusbar != null) {
722 statusbar.layout(minWidth: width, maxWidth: width, minHeight: kStatusbarHe ight, maxHeight: kStatusbarHeight);
723 assert(statusbar.parentData is BoxParentData);
724 statusbar.parentData.x = 0.0;
725 statusbar.parentData.y = height - kStatusbarHeight;
726 bodyHeight -= kStatusbarHeight;
727 }
728 body.layout(minWidth: width, maxWidth: width, minHeight: bodyHeight, maxHeig ht: bodyHeight);
729 if (drawer != null)
730 drawer.layout(minWidth: 0.0, maxWidth: width, minHeight: height, maxHeight : height);
731 layoutDone();
732 }
733
734 void handlePointer(sky.PointerEvent event, { double x: 0.0, double y: 0.0 }) {
735 if ((drawer != null) && (x < drawer.width)) {
736 drawer.handlePointer(event, x: x, y: y);
737 } else if ((toolbar != null) && (y < toolbar.height)) {
738 toolbar.handlePointer(event, x: x, y: y);
739 } else if ((statusbar != null) && (y > (statusbar.parentData as BoxParentDat a).y)) {
740 statusbar.handlePointer(event, x: x, y: y-(statusbar.parentData as BoxPare ntData).y);
741 } else {
742 body.handlePointer(event, x: x, y: y-(body.parentData as BoxParentData).y) ;
743 }
744 super.handlePointer(event, x: x, y: y);
745 }
746
747 void paint(RenderNodeDisplayList canvas) {
748 canvas.paintChild(body, (body.parentData as BoxParentData).x, (body.parentDa ta as BoxParentData).y);
749 if (statusbar != null)
750 canvas.paintChild(statusbar, (statusbar.parentData as BoxParentData).x, (s tatusbar.parentData as BoxParentData).y);
751 if (toolbar != null)
752 canvas.paintChild(toolbar, (toolbar.parentData as BoxParentData).x, (toolb ar.parentData as BoxParentData).y);
753 if (drawer != null)
754 canvas.paintChild(drawer, (drawer.parentData as BoxParentData).x, (drawer. parentData as BoxParentData).y);
755 }
756
757 }
OLDNEW
« no previous file with comments | « sky/sdk/lib/framework/layout.dart ('k') | sky/sdk/lib/framework/node.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698