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

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

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

Powered by Google App Engine
This is Rietveld 408576698