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

Side by Side Diff: sky/examples/raw/sector_layout.dart

Issue 1173233002: Separate out the raw (directly manipulating sky.view) examples from the rendering (using RenderObje… (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 5 years, 6 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/examples/raw/render_paragraph.dart ('k') | sky/examples/raw/shadowed_box.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 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 import 'dart:math' as math;
6 import 'dart:sky' as sky;
7 import 'package:sky/framework/app.dart';
8 import 'package:sky/framework/rendering/box.dart';
9 import 'package:sky/framework/rendering/object.dart';
10
11 const double kTwoPi = 2 * math.PI;
12
13 class SectorConstraints {
14 const SectorConstraints({
15 this.minDeltaRadius: 0.0,
16 this.maxDeltaRadius: double.INFINITY,
17 this.minDeltaTheta: 0.0,
18 this.maxDeltaTheta: kTwoPi
19 });
20
21 const SectorConstraints.tight({ double deltaRadius: 0.0, double deltaTheta: 0. 0 })
22 : minDeltaRadius = deltaRadius,
23 maxDeltaRadius = deltaRadius,
24 minDeltaTheta = deltaTheta,
25 maxDeltaTheta = deltaTheta;
26
27 final double minDeltaRadius;
28 final double maxDeltaRadius;
29 final double minDeltaTheta;
30 final double maxDeltaTheta;
31
32 double constrainDeltaRadius(double deltaRadius) {
33 return clamp(min: minDeltaRadius, max: maxDeltaRadius, value: deltaRadius);
34 }
35
36 double constrainDeltaTheta(double deltaTheta) {
37 return clamp(min: minDeltaTheta, max: maxDeltaTheta, value: deltaTheta);
38 }
39 }
40
41 class SectorDimensions {
42 const SectorDimensions({ this.deltaRadius: 0.0, this.deltaTheta: 0.0 });
43
44 factory SectorDimensions.withConstraints(
45 SectorConstraints constraints,
46 { double deltaRadius: 0.0, double deltaTheta: 0.0 }
47 ) {
48 return new SectorDimensions(
49 deltaRadius: constraints.constrainDeltaRadius(deltaRadius),
50 deltaTheta: constraints.constrainDeltaTheta(deltaTheta)
51 );
52 }
53
54 final double deltaRadius;
55 final double deltaTheta;
56 }
57
58 class SectorParentData extends ParentData {
59 double radius = 0.0;
60 double theta = 0.0;
61 }
62
63 abstract class RenderSector extends RenderObject {
64
65 void setParentData(RenderObject child) {
66 if (child.parentData is! SectorParentData)
67 child.parentData = new SectorParentData();
68 }
69
70 SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
71 return new SectorDimensions.withConstraints(constraints);
72 }
73
74 SectorConstraints get constraints { SectorConstraints result = super.constrain ts; return result; }
75 void performResize() {
76 // default behaviour for subclasses that have sizedByParent = true
77 deltaRadius = constraints.constrainDeltaRadius(0.0);
78 deltaTheta = constraints.constrainDeltaTheta(0.0);
79 }
80 void performLayout() {
81 // descendants have to either override performLayout() to set both
82 // the dimensions and lay out children, or, set sizedByParent to
83 // true so that performResize()'s logic above does its thing.
84 assert(sizedByParent);
85 }
86
87 bool hitTest(HitTestResult result, { double radius, double theta }) {
88 assert(parentData is SectorParentData);
89 if (radius < parentData.radius || radius >= parentData.radius + deltaRadius ||
90 theta < parentData.theta || theta >= parentData.theta + deltaTheta)
91 return false;
92 hitTestChildren(result, radius: radius, theta: theta);
93 result.add(new HitTestEntry(this));
94 return true;
95 }
96 void hitTestChildren(HitTestResult result, { double radius, double theta }) { }
97
98 double deltaRadius;
99 double deltaTheta;
100 }
101
102 class RenderDecoratedSector extends RenderSector {
103
104 RenderDecoratedSector(BoxDecoration decoration) : _decoration = decoration;
105
106 BoxDecoration _decoration;
107 BoxDecoration get decoration => _decoration;
108 void set decoration (BoxDecoration value) {
109 if (value == _decoration)
110 return;
111 _decoration = value;
112 markNeedsPaint();
113 }
114
115 // origin must be set to the center of the circle
116 void paint(RenderObjectDisplayList canvas) {
117 assert(deltaRadius != null);
118 assert(deltaTheta != null);
119 assert(parentData is SectorParentData);
120
121 if (_decoration == null)
122 return;
123
124 if (_decoration.backgroundColor != null) {
125 Paint paint = new Paint()..color = _decoration.backgroundColor;
126 Path path = new Path();
127 double outerRadius = (parentData.radius + deltaRadius);
128 Rect outerBounds = new Rect.fromLTRB(-outerRadius, -outerRadius, outerRadi us, outerRadius);
129 path.arcTo(outerBounds, parentData.theta, deltaTheta, true);
130 double innerRadius = parentData.radius;
131 Rect innerBounds = new Rect.fromLTRB(-innerRadius, -innerRadius, innerRadi us, innerRadius);
132 path.arcTo(innerBounds, parentData.theta + deltaTheta, -deltaTheta, false) ;
133 path.close();
134 canvas.drawPath(path, paint);
135 }
136 }
137 }
138
139 class SectorChildListParentData extends SectorParentData with ContainerParentDat aMixin<RenderSector> { }
140
141 class RenderSectorWithChildren extends RenderDecoratedSector with ContainerRende rObjectMixin<RenderSector, SectorChildListParentData> {
142 RenderSectorWithChildren(BoxDecoration decoration) : super(decoration);
143
144 void hitTestChildren(HitTestResult result, { double radius, double theta }) {
145 RenderSector child = lastChild;
146 while (child != null) {
147 assert(child.parentData is SectorChildListParentData);
148 if (child.hitTest(result, radius: radius, theta: theta))
149 return;
150 child = child.parentData.previousSibling;
151 }
152 }
153 }
154
155 class RenderSectorRing extends RenderSectorWithChildren {
156 // lays out RenderSector children in a ring
157
158 RenderSectorRing({
159 BoxDecoration decoration,
160 double deltaRadius: double.INFINITY,
161 double padding: 0.0
162 }) : super(decoration), _padding = padding, _desiredDeltaRadius = deltaRadius;
163
164 double _desiredDeltaRadius;
165 double get desiredDeltaRadius => _desiredDeltaRadius;
166 void set desiredDeltaRadius(double value) {
167 assert(value != null);
168 if (_desiredDeltaRadius != value) {
169 _desiredDeltaRadius = value;
170 markNeedsLayout();
171 }
172 }
173
174 double _padding;
175 double get padding => _padding;
176 void set padding(double value) {
177 // TODO(ianh): avoid code duplication
178 assert(value != null);
179 if (_padding != value) {
180 _padding = value;
181 markNeedsLayout();
182 }
183 }
184
185 void setParentData(RenderObject child) {
186 // TODO(ianh): avoid code duplication
187 if (child.parentData is! SectorChildListParentData)
188 child.parentData = new SectorChildListParentData();
189 }
190
191 SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
192 double outerDeltaRadius = constraints.constrainDeltaRadius(desiredDeltaRadiu s);
193 double innerDeltaRadius = outerDeltaRadius - padding * 2.0;
194 double childRadius = radius + padding;
195 double paddingTheta = math.atan(padding / (radius + outerDeltaRadius));
196 double innerTheta = paddingTheta; // increments with each child
197 double remainingDeltaTheta = constraints.maxDeltaTheta - (innerTheta + paddi ngTheta);
198 RenderSector child = firstChild;
199 while (child != null) {
200 SectorConstraints innerConstraints = new SectorConstraints(
201 maxDeltaRadius: innerDeltaRadius,
202 maxDeltaTheta: remainingDeltaTheta
203 );
204 SectorDimensions childDimensions = child.getIntrinsicDimensions(innerConst raints, childRadius);
205 innerTheta += childDimensions.deltaTheta;
206 remainingDeltaTheta -= childDimensions.deltaTheta;
207 assert(child.parentData is SectorChildListParentData);
208 child = child.parentData.nextSibling;
209 if (child != null) {
210 innerTheta += paddingTheta;
211 remainingDeltaTheta -= paddingTheta;
212 }
213 }
214 return new SectorDimensions.withConstraints(constraints,
215 deltaRadius: outerDeltaRadius,
216 deltaTheta: innerTheta);
217 }
218
219 void performLayout() {
220 assert(this.parentData is SectorParentData);
221 deltaRadius = constraints.constrainDeltaRadius(desiredDeltaRadius);
222 assert(deltaRadius < double.INFINITY);
223 double innerDeltaRadius = deltaRadius - padding * 2.0;
224 double childRadius = this.parentData.radius + padding;
225 double paddingTheta = math.atan(padding / (this.parentData.radius + deltaRad ius));
226 double innerTheta = paddingTheta; // increments with each child
227 double remainingDeltaTheta = constraints.maxDeltaTheta - (innerTheta + paddi ngTheta);
228 RenderSector child = firstChild;
229 while (child != null) {
230 SectorConstraints innerConstraints = new SectorConstraints(
231 maxDeltaRadius: innerDeltaRadius,
232 maxDeltaTheta: remainingDeltaTheta
233 );
234 assert(child.parentData is SectorParentData);
235 child.parentData.theta = innerTheta;
236 child.parentData.radius = childRadius;
237 child.layout(innerConstraints, parentUsesSize: true);
238 innerTheta += child.deltaTheta;
239 remainingDeltaTheta -= child.deltaTheta;
240 assert(child.parentData is SectorChildListParentData);
241 child = child.parentData.nextSibling;
242 if (child != null) {
243 innerTheta += paddingTheta;
244 remainingDeltaTheta -= paddingTheta;
245 }
246 }
247 deltaTheta = innerTheta;
248 }
249
250 // paint origin is 0,0 of our circle
251 // each sector then knows how to paint itself at its location
252 void paint(RenderObjectDisplayList canvas) {
253 // TODO(ianh): avoid code duplication
254 super.paint(canvas);
255 RenderSector child = firstChild;
256 while (child != null) {
257 assert(child.parentData is SectorChildListParentData);
258 canvas.paintChild(child, Point.origin);
259 child = child.parentData.nextSibling;
260 }
261 }
262
263 }
264
265 class RenderSectorSlice extends RenderSectorWithChildren {
266 // lays out RenderSector children in a stack
267
268 RenderSectorSlice({
269 BoxDecoration decoration,
270 double deltaTheta: kTwoPi,
271 double padding: 0.0
272 }) : super(decoration), _padding = padding, _desiredDeltaTheta = deltaTheta;
273
274 double _desiredDeltaTheta;
275 double get desiredDeltaTheta => _desiredDeltaTheta;
276 void set desiredDeltaTheta(double value) {
277 assert(value != null);
278 if (_desiredDeltaTheta != value) {
279 _desiredDeltaTheta = value;
280 markNeedsLayout();
281 }
282 }
283
284 double _padding;
285 double get padding => _padding;
286 void set padding(double value) {
287 // TODO(ianh): avoid code duplication
288 assert(value != null);
289 if (_padding != value) {
290 _padding = value;
291 markNeedsLayout();
292 }
293 }
294
295 void setParentData(RenderObject child) {
296 // TODO(ianh): avoid code duplication
297 if (child.parentData is! SectorChildListParentData)
298 child.parentData = new SectorChildListParentData();
299 }
300
301 SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
302 assert(this.parentData is SectorParentData);
303 double paddingTheta = math.atan(padding / this.parentData.radius);
304 double outerDeltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
305 double innerDeltaTheta = outerDeltaTheta - paddingTheta * 2.0;
306 double childRadius = this.parentData.radius + padding;
307 double remainingDeltaRadius = constraints.maxDeltaRadius - (padding * 2.0);
308 RenderSector child = firstChild;
309 while (child != null) {
310 SectorConstraints innerConstraints = new SectorConstraints(
311 maxDeltaRadius: remainingDeltaRadius,
312 maxDeltaTheta: innerDeltaTheta
313 );
314 SectorDimensions childDimensions = child.getIntrinsicDimensions(innerConst raints, childRadius);
315 childRadius += childDimensions.deltaRadius;
316 remainingDeltaRadius -= childDimensions.deltaRadius;
317 assert(child.parentData is SectorChildListParentData);
318 child = child.parentData.nextSibling;
319 childRadius += padding;
320 remainingDeltaRadius -= padding;
321 }
322 return new SectorDimensions.withConstraints(constraints,
323 deltaRadius: childRadius - this. parentData.radius,
324 deltaTheta: outerDeltaTheta);
325 }
326
327 void performLayout() {
328 assert(this.parentData is SectorParentData);
329 deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
330 assert(deltaTheta <= kTwoPi);
331 double paddingTheta = math.atan(padding / this.parentData.radius);
332 double innerTheta = this.parentData.theta + paddingTheta;
333 double innerDeltaTheta = deltaTheta - paddingTheta * 2.0;
334 double childRadius = this.parentData.radius + padding;
335 double remainingDeltaRadius = constraints.maxDeltaRadius - (padding * 2.0);
336 RenderSector child = firstChild;
337 while (child != null) {
338 SectorConstraints innerConstraints = new SectorConstraints(
339 maxDeltaRadius: remainingDeltaRadius,
340 maxDeltaTheta: innerDeltaTheta
341 );
342 child.parentData.theta = innerTheta;
343 child.parentData.radius = childRadius;
344 child.layout(innerConstraints, parentUsesSize: true);
345 childRadius += child.deltaRadius;
346 remainingDeltaRadius -= child.deltaRadius;
347 assert(child.parentData is SectorChildListParentData);
348 child = child.parentData.nextSibling;
349 childRadius += padding;
350 remainingDeltaRadius -= padding;
351 }
352 deltaRadius = childRadius - this.parentData.radius;
353 }
354
355 // paint origin is 0,0 of our circle
356 // each sector then knows how to paint itself at its location
357 void paint(RenderObjectDisplayList canvas) {
358 // TODO(ianh): avoid code duplication
359 super.paint(canvas);
360 RenderSector child = firstChild;
361 while (child != null) {
362 assert(child.parentData is SectorChildListParentData);
363 canvas.paintChild(child, Point.origin);
364 child = child.parentData.nextSibling;
365 }
366 }
367
368 }
369
370 class RenderBoxToRenderSectorAdapter extends RenderBox {
371
372 RenderBoxToRenderSectorAdapter({ double innerRadius: 0.0, RenderSector child } ) :
373 _innerRadius = innerRadius {
374 _child = child;
375 adoptChild(_child);
376 }
377
378 double _innerRadius;
379 double get innerRadius => _innerRadius;
380 void set innerRadius(double value) {
381 _innerRadius = value;
382 markNeedsLayout();
383 }
384
385 RenderSector _child;
386 RenderSector get child => _child;
387 void set child(RenderSector value) {
388 if (_child != null)
389 dropChild(_child);
390 _child = value;
391 adoptChild(_child);
392 markNeedsLayout();
393 }
394
395 void setParentData(RenderObject child) {
396 if (child.parentData is! SectorParentData)
397 child.parentData = new SectorParentData();
398 }
399
400 Size getIntrinsicDimensions(BoxConstraints constraints) {
401 if (child == null)
402 return constraints.constrain(Size.zero);
403 assert(child is RenderSector);
404 assert(child.parentData is SectorParentData);
405 assert(!constraints.isInfinite);
406 double maxChildDeltaRadius = math.min(constraints.maxWidth, constraints.maxH eight) / 2.0 - innerRadius;
407 SectorDimensions childDimensions = child.getIntrinsicDimensions(new SectorCo nstraints(maxDeltaRadius: maxChildDeltaRadius), innerRadius);
408 double dimension = (innerRadius + childDimensions.deltaRadius) * 2.0;
409 return constraints.constrain(new Size(dimension, dimension));
410 }
411
412 void performLayout() {
413 if (child == null) {
414 size = constraints.constrain(Size.zero);
415 } else {
416 assert(child is RenderSector);
417 assert(!constraints.isInfinite);
418 print("constraint maxes: ${constraints.maxWidth} and ${constraints.maxHeig ht}");
419 double maxChildDeltaRadius = math.min(constraints.maxWidth, constraints.ma xHeight) / 2.0 - innerRadius;
420 print("maxChildDeltaRadius = $maxChildDeltaRadius");
421 assert(child.parentData is SectorParentData);
422 child.parentData.radius = innerRadius;
423 child.parentData.theta = 0.0;
424 child.layout(new SectorConstraints(maxDeltaRadius: maxChildDeltaRadius), p arentUsesSize: true);
425 double dimension = (innerRadius + child.deltaRadius) * 2.0;
426 size = constraints.constrain(new Size(dimension, dimension));
427 }
428 }
429
430 // paint origin is 0,0 of our circle
431 void paint(RenderObjectDisplayList canvas) {
432 super.paint(canvas);
433 if (child != null) {
434 Rect bounds = new Rect.fromSize(size);
435 canvas.paintChild(child, bounds.center);
436 }
437 }
438
439 bool hitTest(HitTestResult result, { Point position }) {
440 double x = position.x;
441 double y = position.y;
442 if (child == null)
443 return false;
444 // translate to our origin
445 x -= size.width/2.0;
446 y -= size.height/2.0;
447 // convert to radius/theta
448 double radius = math.sqrt(x*x+y*y);
449 double theta = (math.atan2(x, -y) - math.PI/2.0) % kTwoPi;
450 if (radius < innerRadius)
451 return false;
452 if (radius >= innerRadius + child.deltaRadius)
453 return false;
454 if (theta > child.deltaTheta)
455 return false;
456 child.hitTest(result, radius: radius, theta: theta);
457 result.add(new BoxHitTestEntry(this, position));
458 return true;
459 }
460
461 }
462
463 class RenderSolidColor extends RenderDecoratedSector {
464 RenderSolidColor(Color backgroundColor, {
465 this.desiredDeltaRadius: double.INFINITY,
466 this.desiredDeltaTheta: kTwoPi
467 }) : this.backgroundColor = backgroundColor,
468 super(new BoxDecoration(backgroundColor: backgroundColor));
469
470 double desiredDeltaRadius;
471 double desiredDeltaTheta;
472 final Color backgroundColor;
473
474 SectorDimensions getIntrinsicDimensions(SectorConstraints constraints, double radius) {
475 return new SectorDimensions.withConstraints(constraints, deltaTheta: 1.0); / / 1.0 radians
476 }
477
478 void performLayout() {
479 deltaRadius = constraints.constrainDeltaRadius(desiredDeltaRadius);
480 deltaTheta = constraints.constrainDeltaTheta(desiredDeltaTheta);
481 }
482
483 void handleEvent(sky.Event event, HitTestEntry entry) {
484 if (event.type == 'pointerdown')
485 decoration = new BoxDecoration(backgroundColor: const Color(0xFFFF0000));
486 else if (event.type == 'pointerup')
487 decoration = new BoxDecoration(backgroundColor: backgroundColor);
488 }
489 }
490
491 AppView app;
492
493 void main() {
494
495 var rootCircle = new RenderSectorRing(padding: 20.0);
496 rootCircle.add(new RenderSolidColor(const Color(0xFF00FFFF), desiredDeltaTheta : kTwoPi * 0.15));
497 rootCircle.add(new RenderSolidColor(const Color(0xFF0000FF), desiredDeltaTheta : kTwoPi * 0.4));
498 var stack = new RenderSectorSlice(padding: 2.0);
499 stack.add(new RenderSolidColor(const Color(0xFFFFFF00), desiredDeltaRadius: 20 .0));
500 stack.add(new RenderSolidColor(const Color(0xFFFF9000), desiredDeltaRadius: 20 .0));
501 stack.add(new RenderSolidColor(const Color(0xFF00FF00)));
502 rootCircle.add(stack);
503
504 var root = new RenderBoxToRenderSectorAdapter(innerRadius: 50.0, child: rootCi rcle);
505 app = new AppView(root);
506 }
OLDNEW
« no previous file with comments | « sky/examples/raw/render_paragraph.dart ('k') | sky/examples/raw/shadowed_box.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698