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

Side by Side Diff: sky/framework/layout.dart

Issue 1132063007: Rationalize Dart mojo and sky package structure (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: 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/framework/fn.dart ('k') | sky/framework/layouts/block.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 import 'node.dart';
4 import 'dart:sky' as sky;
5 import 'dart:collection';
6
7 // UTILS
8
9 // Bridge to legacy CSS-like style specification
10 // Eventually we'll replace this with something else
11 class Style {
12 final String _className;
13 static final Map<String, Style> _cache = new HashMap<String, Style>();
14
15 static int _nextStyleId = 1;
16
17 static String _getNextClassName() { return "style${_nextStyleId++}"; }
18
19 Style extend(Style other) {
20 var className = "$_className ${other._className}";
21
22 return _cache.putIfAbsent(className, () {
23 return new Style._construct(className);
24 });
25 }
26
27 factory Style(String styles) {
28 assert(!styles.contains(new RegExp('\\b(display|flex|flex-direction)\\b')));
29 return new Style._addToCache(styles);
30 }
31
32 factory Style._addToCache(String styles) {
33 return _cache.putIfAbsent(styles, () {
34 var className = _getNextClassName();
35 sky.Element styleNode = sky.document.createElement('style');
36 styleNode.setChild(new sky.Text(".$className { $styles }"));
37 sky.document.appendChild(styleNode);
38 return new Style._construct(className);
39 });
40 }
41
42 Style._construct(this._className);
43 }
44
45 class Rect {
46 const Rect(this.x, this.y, this.width, this.height);
47 final double x;
48 final double y;
49 final double width;
50 final double height;
51 }
52
53
54 // ABSTRACT LAYOUT
55
56 class ParentData {
57 void detach() {
58 detachSiblings();
59 }
60 void detachSiblings() { } // workaround for lack of inter-class mixins in Dart
61 void merge(ParentData other) {
62 // override this in subclasses to merge in data from other into this
63 assert(other.runtimeType == this.runtimeType);
64 }
65 }
66
67 abstract class RenderNode extends Node {
68
69 // LAYOUT
70
71 // parentData is only for use by the RenderNode that actually lays this
72 // node out, and any other nodes who happen to know exactly what
73 // kind of node that is.
74 ParentData parentData;
75 void setupPos(RenderNode child) {
76 // override this to setup .parentData correctly for your class
77 if (child.parentData is! ParentData)
78 child.parentData = new ParentData();
79 }
80
81 void setAsChild(RenderNode child) { // only for use by subclasses
82 // call this whenever you decide a node is a child
83 assert(child != null);
84 setupPos(child);
85 super.setAsChild(child);
86 }
87 void dropChild(RenderNode child) { // only for use by subclasses
88 assert(child != null);
89 assert(child.parentData != null);
90 child.parentData.detach();
91 super.dropChild(child);
92 }
93
94 }
95
96 abstract class RenderBox extends RenderNode { }
97
98
99 // GENERIC MIXIN FOR RENDER NODES THAT TAKE A LIST OF CHILDREN
100
101 abstract class ContainerParentDataMixin<ChildType extends RenderNode> {
102 ChildType previousSibling;
103 ChildType nextSibling;
104 void detachSiblings() {
105 if (previousSibling != null) {
106 assert(previousSibling.parentData is ContainerParentDataMixin<ChildType>);
107 assert(previousSibling != this);
108 assert(previousSibling.parentData.nextSibling == this);
109 previousSibling.parentData.nextSibling = nextSibling;
110 }
111 if (nextSibling != null) {
112 assert(nextSibling.parentData is ContainerParentDataMixin<ChildType>);
113 assert(nextSibling != this);
114 assert(nextSibling.parentData.previousSibling == this);
115 nextSibling.parentData.previousSibling = previousSibling;
116 }
117 previousSibling = null;
118 nextSibling = null;
119 }
120 }
121
122 abstract class ContainerRenderNodeMixin<ChildType extends RenderNode, ParentData Type extends ContainerParentDataMixin<ChildType>> implements RenderNode {
123 // abstract class that has only InlineNode children
124
125 bool _debugUltimatePreviousSiblingOf(ChildType child, { ChildType equals }) {
126 assert(child.parentData is ParentDataType);
127 while (child.parentData.previousSibling != null) {
128 assert(child.parentData.previousSibling != child);
129 child = child.parentData.previousSibling;
130 assert(child.parentData is ParentDataType);
131 }
132 return child == equals;
133 }
134 bool _debugUltimateNextSiblingOf(ChildType child, { ChildType equals }) {
135 assert(child.parentData is ParentDataType);
136 while (child.parentData.nextSibling != null) {
137 assert(child.parentData.nextSibling != child);
138 child = child.parentData.nextSibling;
139 assert(child.parentData is ParentDataType);
140 }
141 return child == equals;
142 }
143
144 ChildType _firstChild;
145 ChildType _lastChild;
146 void add(ChildType child, { ChildType before }) {
147 assert(child != this);
148 assert(before != this);
149 assert(child != before);
150 assert(child != _firstChild);
151 assert(child != _lastChild);
152 setAsChild(child);
153 assert(child.parentData is ParentDataType);
154 assert(child.parentData.nextSibling == null);
155 assert(child.parentData.previousSibling == null);
156 if (before == null) {
157 // append at the end (_lastChild)
158 child.parentData.previousSibling = _lastChild;
159 if (_lastChild != null) {
160 assert(_lastChild.parentData is ParentDataType);
161 _lastChild.parentData.nextSibling = child;
162 }
163 _lastChild = child;
164 if (_firstChild == null)
165 _firstChild = child;
166 } else {
167 assert(_firstChild != null);
168 assert(_lastChild != null);
169 assert(_debugUltimatePreviousSiblingOf(before, equals: _firstChild));
170 assert(_debugUltimateNextSiblingOf(before, equals: _lastChild));
171 assert(before.parentData is ParentDataType);
172 if (before.parentData.previousSibling == null) {
173 // insert at the start (_firstChild); we'll end up with two or more chil dren
174 assert(before == _firstChild);
175 child.parentData.nextSibling = before;
176 before.parentData.previousSibling = child;
177 _firstChild = child;
178 } else {
179 // insert in the middle; we'll end up with three or more children
180 // set up links from child to siblings
181 child.parentData.previousSibling = before.parentData.previousSibling;
182 child.parentData.nextSibling = before;
183 // set up links from siblings to child
184 assert(child.parentData.previousSibling.parentData is ParentDataType);
185 assert(child.parentData.nextSibling.parentData is ParentDataType);
186 child.parentData.previousSibling.parentData.nextSibling = child;
187 child.parentData.nextSibling.parentData.previousSibling = child;
188 assert(before.parentData.previousSibling == child);
189 }
190 }
191 markNeedsLayout();
192 }
193 void remove(ChildType child) {
194 assert(child.parentData is ParentDataType);
195 assert(_debugUltimatePreviousSiblingOf(child, equals: _firstChild));
196 assert(_debugUltimateNextSiblingOf(child, equals: _lastChild));
197 if (child.parentData.previousSibling == null) {
198 assert(_firstChild == child);
199 _firstChild = child.parentData.nextSibling;
200 } else {
201 assert(child.parentData.previousSibling.parentData is ParentDataType);
202 child.parentData.previousSibling.parentData.nextSibling = child.parentData .nextSibling;
203 }
204 if (child.parentData.nextSibling == null) {
205 assert(_lastChild == child);
206 _lastChild = child.parentData.previousSibling;
207 } else {
208 assert(child.parentData.nextSibling.parentData is ParentDataType);
209 child.parentData.nextSibling.parentData.previousSibling = child.parentData .previousSibling;
210 }
211 child.parentData.previousSibling = null;
212 child.parentData.nextSibling = null;
213 dropChild(child);
214 markNeedsLayout();
215 }
216 void redepthChildren() {
217 ChildType child = _firstChild;
218 while (child != null) {
219 redepthChild(child);
220 assert(child.parentData is ParentDataType);
221 child = child.parentData.nextSibling;
222 }
223 }
224 void attachChildren() {
225 ChildType child = _firstChild;
226 while (child != null) {
227 child.attach();
228 assert(child.parentData is ParentDataType);
229 child = child.parentData.nextSibling;
230 }
231 }
232 void detachChildren() {
233 ChildType child = _firstChild;
234 while (child != null) {
235 child.detach();
236 assert(child.parentData is ParentDataType);
237 child = child.parentData.nextSibling;
238 }
239 }
240
241 ChildType get firstChild => _firstChild;
242 ChildType get lastChild => _lastChild;
243 ChildType childAfter(ChildType child) {
244 assert(child.parentData is ParentDataType);
245 return child.parentData.nextSibling;
246 }
247
248 }
249
250
251 // CSS SHIMS
252
253 abstract class RenderCSS extends RenderBox {
254
255 dynamic debug;
256 sky.Element _skyElement;
257
258 RenderCSS(this.debug) {
259 _skyElement = createSkyElement();
260 registerEventTarget(_skyElement, this);
261 }
262
263 sky.Element createSkyElement();
264
265 void updateStyles(List<Style> styles) {
266 _skyElement.setAttribute('class', stylesToClasses(styles));
267 }
268
269 String stylesToClasses(List<Style> styles) {
270 return styles.map((s) => s._className).join(' ');
271 }
272
273 String _inlineStyles = '';
274 String _additionalStylesFromParent = ''; // used internally to propagate paren tData settings to the child
275
276 void updateInlineStyle(String newStyle) {
277 assert(newStyle == null || !newStyle.contains(new RegExp('\\b(display|flex|f lex-direction)\\b')));
278 _inlineStyles = newStyle != null ? newStyle : '';
279 _updateInlineStyleAttribute();
280 }
281
282 void _updateInlineStyleAttribute() {
283 if ((_inlineStyles != '') && (_additionalStylesFromParent != ''))
284 _skyElement.setAttribute('style', "$_inlineStyles;$_additionalStylesFromPa rent");
285 else
286 _skyElement.setAttribute('style', "$_inlineStyles$_additionalStylesFromPar ent");
287 }
288
289 double get width {
290 sky.ClientRect rect = _skyElement.getBoundingClientRect();
291 return rect.width;
292 }
293
294 double get height {
295 sky.ClientRect rect = _skyElement.getBoundingClientRect();
296 return rect.height;
297 }
298
299 Rect get rect {
300 sky.ClientRect rect = _skyElement.getBoundingClientRect();
301 return new Rect(rect.left, rect.top, rect.width, rect.height);
302 }
303
304 }
305
306 class CSSParentData extends ParentData with ContainerParentDataMixin<RenderCSS> { }
307
308 class RenderCSSContainer extends RenderCSS with ContainerRenderNodeMixin<RenderC SS, CSSParentData> {
309
310 RenderCSSContainer(debug) : super(debug);
311
312 void setupPos(RenderNode child) {
313 if (child.parentData is! CSSParentData)
314 child.parentData = new CSSParentData();
315 }
316
317 sky.Element createSkyElement() => sky.document.createElement('div')
318 ..setAttribute('debug', debug.toS tring());
319
320 void markNeedsLayout() { }
321
322 void add(RenderCSS child, { RenderCSS before }) {
323 if (before != null) {
324 assert(before._skyElement.parentNode != null);
325 assert(before._skyElement.parentNode == _skyElement);
326 }
327 super.add(child, before: before);
328 if (before != null) {
329 before._skyElement.insertBefore([child._skyElement]);
330 assert(child._skyElement.parentNode != null);
331 assert(child._skyElement.parentNode == _skyElement);
332 assert(child._skyElement.parentNode == before._skyElement.parentNode);
333 } else {
334 _skyElement.appendChild(child._skyElement);
335 }
336 }
337 void remove(RenderCSS child) {
338 child._skyElement.remove();
339 super.remove(child);
340 }
341
342 }
343
344 class FlexBoxParentData extends CSSParentData {
345 int flex;
346 void merge(FlexBoxParentData other) {
347 if (other.flex != null)
348 flex = other.flex;
349 super.merge(other);
350 }
351 }
352
353 enum FlexDirection { Row, Column }
354
355 class RenderCSSFlex extends RenderCSSContainer {
356
357 RenderCSSFlex(debug, FlexDirection direction) : _direction = direction, super( debug);
358
359 FlexDirection _direction;
360 FlexDirection get direction => _direction;
361 void set direction (FlexDirection value) {
362 _direction = value;
363 markNeedsLayout();
364 }
365
366 void setupPos(RenderNode child) {
367 if (child.parentData is! FlexBoxParentData)
368 child.parentData = new FlexBoxParentData();
369 }
370
371 static final Style _displayFlex = new Style._addToCache('display:flex');
372 static final Style _displayFlexRow = new Style._addToCache('flex-direction:row ');
373 static final Style _displayFlexColumn = new Style._addToCache('flex-direction: column');
374
375 String stylesToClasses(List<Style> styles) {
376 var settings = _displayFlex._className;
377 switch (_direction) {
378 case FlexDirection.Row: settings += ' ' + _displayFlexRow._className; brea k;
379 case FlexDirection.Column: settings += ' ' + _displayFlexColumn._className ; break;
380 }
381 return super.stylesToClasses(styles) + ' ' + settings;
382 }
383
384 void markNeedsLayout() {
385 super.markNeedsLayout();
386
387 // pretend we did the layout:
388 RenderCSS child = _firstChild;
389 while (child != null) {
390 assert(child.parentData is FlexBoxParentData);
391 if (child.parentData.flex != null) {
392 child._additionalStylesFromParent = 'flex:${child.parentData.flex}';
393 child._updateInlineStyleAttribute();
394 }
395 child = child.parentData.nextSibling;
396 }
397 }
398
399 }
400
401 class StackParentData extends CSSParentData {
402 double top;
403 double left;
404 double right;
405 double bottom;
406 void merge(StackParentData other) {
407 if (other.top != null)
408 top = other.top;
409 if (other.left != null)
410 left = other.left;
411 if (other.right != null)
412 right = other.right;
413 if (other.bottom != null)
414 bottom = other.bottom;
415 super.merge(other);
416 }
417 }
418
419 class RenderCSSStack extends RenderCSSContainer {
420
421 RenderCSSStack(debug) : super(debug);
422
423 void setupPos(RenderNode child) {
424 if (child.parentData is! StackParentData)
425 child.parentData = new StackParentData();
426 }
427
428 static final Style _displayPosition = new Style._addToCache('transform:transla teX(0);position:relative');
429
430 String stylesToClasses(List<Style> styles) {
431 return super.stylesToClasses(styles) + ' ' + _displayPosition._className;
432 }
433
434 void markNeedsLayout() {
435 super.markNeedsLayout();
436
437 // pretend we did the layout:
438 RenderCSS child = _firstChild;
439 while (child != null) {
440 assert(child.parentData is StackParentData);
441 var style = 'position:absolute;';
442 if (child.parentData.top != null)
443 style += 'top:${child.parentData.top};';
444 if (child.parentData.left != null)
445 style += 'left:${child.parentData.left};';
446 if (child.parentData.right != null)
447 style += 'right:${child.parentData.right};';
448 if (child.parentData.bottom != null)
449 style += 'bottom:${child.parentData.bottom};';
450 child._additionalStylesFromParent = style;
451 child._updateInlineStyleAttribute();
452 child = child.parentData.nextSibling;
453 }
454 }
455
456 }
457
458 class RenderCSSParagraph extends RenderCSSContainer {
459
460 RenderCSSParagraph(debug) : super(debug);
461
462 static final Style _displayParagraph = new Style._addToCache('display:paragrap h');
463
464 String stylesToClasses(List<Style> styles) {
465 return super.stylesToClasses(styles) + ' ' + _displayParagraph._className;
466 }
467
468 }
469
470 class RenderCSSInline extends RenderCSS {
471
472 RenderCSSInline(debug, String newData) : super(debug) {
473 data = newData;
474 }
475
476 static final Style _displayInline = new Style._addToCache('display:inline');
477
478 String stylesToClasses(List<Style> styles) {
479 return super.stylesToClasses(styles) + ' ' + _displayInline._className;
480 }
481
482 sky.Element createSkyElement() {
483 return sky.document.createElement('div')
484 ..setChild(new sky.Text())
485 ..setAttribute('debug', debug.toString());
486 }
487
488 void set data (String value) {
489 (_skyElement.firstChild as sky.Text).data = value;
490 }
491
492 }
493
494 class RenderCSSImage extends RenderCSS {
495
496 RenderCSSImage(debug, String src, num width, num height) : super(debug) {
497 configure(src, width, height);
498 }
499
500 sky.Element createSkyElement() {
501 return sky.document.createElement('img')
502 ..setAttribute('debug', debug.toString());
503 }
504
505 void configure(String src, num width, num height) {
506 if (_skyElement.getAttribute('src') != src)
507 _skyElement.setAttribute('src', src);
508 _skyElement.style['width'] = '${width}px';
509 _skyElement.style['height'] = '${height}px';
510 }
511
512 }
513
514 class RenderCSSRoot extends RenderCSSContainer {
515 RenderCSSRoot(debug) : super(debug);
516 sky.Element createSkyElement() {
517 var result = super.createSkyElement();
518 assert(result != null);
519 sky.document.appendChild(result);
520 return result;
521 }
522 }
523
524
525 // legacy tools
526 Map<sky.EventTarget, RenderNode> _eventTargetRegistry = {};
527 void registerEventTarget(sky.EventTarget e, RenderNode n) {
528 _eventTargetRegistry[e] = n;
529 }
530 RenderNode bridgeEventTargetToRenderNode(sky.EventTarget e) {
531 return _eventTargetRegistry[e];
532 }
533
534
535
536
537 String _attributes(node) {
538 if (node is! sky.Element) return '';
539 var result = '';
540 var attrs = node.getAttributes();
541 for (var attr in attrs)
542 result += ' ${attr.name}="${attr.value}"';
543 return result;
544 }
545
546 void _serialiseDOM(node, [String prefix = '']) {
547 if (node is sky.Text) {
548 print(prefix + 'text: "' + node.data.replaceAll('\n', '\\n') + '"');
549 return;
550 }
551 print(prefix + node.toString() + _attributes(node));
552 var children = node.getChildNodes();
553 prefix = prefix + ' ';
554 for (var child in children)
555 _serialiseDOM(child, prefix);
556 }
557
558 void dumpState() {
559 _serialiseDOM(sky.document);
560 }
OLDNEW
« no previous file with comments | « sky/framework/fn.dart ('k') | sky/framework/layouts/block.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698