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

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

Powered by Google App Engine
This is Rietveld 408576698