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 5import 'dart:math' as math; 6 7import 'package:flutter/material.dart'; 8import 'package:flutter/rendering.dart'; 9 10import '../rendering/src/sector_layout.dart'; 11 12RenderBox initCircle() { 13 return RenderBoxToRenderSectorAdapter( 14 innerRadius: 25.0, 15 child: RenderSectorRing(padding: 0.0), 16 ); 17} 18 19class SectorApp extends StatefulWidget { 20 @override 21 SectorAppState createState() => SectorAppState(); 22} 23 24class SectorAppState extends State<SectorApp> { 25 26 final RenderBoxToRenderSectorAdapter sectors = initCircle(); 27 final math.Random rand = math.Random(1); 28 29 List<double> wantedSectorSizes = <double>[]; 30 List<double> actualSectorSizes = <double>[]; 31 double get currentTheta => wantedSectorSizes.fold<double>(0.0, (double total, double value) => total + value); 32 33 void addSector() { 34 final double currentTheta = this.currentTheta; 35 if (currentTheta < kTwoPi) { 36 double deltaTheta; 37 if (currentTheta >= kTwoPi - (math.pi * 0.2 + 0.05)) 38 deltaTheta = kTwoPi - currentTheta; 39 else 40 deltaTheta = math.pi * rand.nextDouble() / 5.0 + 0.05; 41 wantedSectorSizes.add(deltaTheta); 42 updateEnabledState(); 43 } 44 } 45 46 void removeSector() { 47 if (wantedSectorSizes.isNotEmpty) { 48 wantedSectorSizes.removeLast(); 49 updateEnabledState(); 50 } 51 } 52 53 void doUpdates() { 54 int index = 0; 55 while (index < actualSectorSizes.length && index < wantedSectorSizes.length && actualSectorSizes[index] == wantedSectorSizes[index]) 56 index += 1; 57 final RenderSectorRing ring = sectors.child; 58 while (index < actualSectorSizes.length) { 59 ring.remove(ring.lastChild); 60 actualSectorSizes.removeLast(); 61 } 62 while (index < wantedSectorSizes.length) { 63 final Color color = Color(((0xFF << 24) + rand.nextInt(0xFFFFFF)) | 0x808080); 64 ring.add(RenderSolidColor(color, desiredDeltaTheta: wantedSectorSizes[index])); 65 actualSectorSizes.add(wantedSectorSizes[index]); 66 index += 1; 67 } 68 } 69 70 static RenderBox initSector(Color color) { 71 final RenderSectorRing ring = RenderSectorRing(padding: 1.0); 72 ring.add(RenderSolidColor(const Color(0xFF909090), desiredDeltaTheta: kTwoPi * 0.15)); 73 ring.add(RenderSolidColor(const Color(0xFF909090), desiredDeltaTheta: kTwoPi * 0.15)); 74 ring.add(RenderSolidColor(color, desiredDeltaTheta: kTwoPi * 0.2)); 75 return RenderBoxToRenderSectorAdapter( 76 innerRadius: 5.0, 77 child: ring, 78 ); 79 } 80 RenderBoxToRenderSectorAdapter sectorAddIcon = initSector(const Color(0xFF00DD00)); 81 RenderBoxToRenderSectorAdapter sectorRemoveIcon = initSector(const Color(0xFFDD0000)); 82 83 bool _enabledAdd = true; 84 bool _enabledRemove = false; 85 void updateEnabledState() { 86 setState(() { 87 _enabledAdd = currentTheta < kTwoPi; 88 _enabledRemove = wantedSectorSizes.isNotEmpty; 89 }); 90 } 91 92 Widget buildBody() { 93 return Column( 94 children: <Widget>[ 95 Container( 96 padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 25.0), 97 child: Row( 98 children: <Widget>[ 99 RaisedButton( 100 onPressed: _enabledAdd ? addSector : null, 101 child: IntrinsicWidth( 102 child: Row( 103 children: <Widget>[ 104 Container( 105 padding: const EdgeInsets.all(4.0), 106 margin: const EdgeInsets.only(right: 10.0), 107 child: WidgetToRenderBoxAdapter(renderBox: sectorAddIcon), 108 ), 109 const Text('ADD SECTOR'), 110 ], 111 ), 112 ), 113 ), 114 RaisedButton( 115 onPressed: _enabledRemove ? removeSector : null, 116 child: IntrinsicWidth( 117 child: Row( 118 children: <Widget>[ 119 Container( 120 padding: const EdgeInsets.all(4.0), 121 margin: const EdgeInsets.only(right: 10.0), 122 child: WidgetToRenderBoxAdapter(renderBox: sectorRemoveIcon), 123 ), 124 const Text('REMOVE SECTOR'), 125 ], 126 ), 127 ), 128 ), 129 ], 130 mainAxisAlignment: MainAxisAlignment.spaceAround, 131 ), 132 ), 133 Expanded( 134 child: Container( 135 margin: const EdgeInsets.all(8.0), 136 decoration: BoxDecoration( 137 border: Border.all() 138 ), 139 padding: const EdgeInsets.all(8.0), 140 child: WidgetToRenderBoxAdapter( 141 renderBox: sectors, 142 onBuild: doUpdates, 143 ), 144 ), 145 ), 146 ], 147 mainAxisAlignment: MainAxisAlignment.spaceBetween, 148 ); 149 } 150 151 @override 152 Widget build(BuildContext context) { 153 return MaterialApp( 154 theme: ThemeData.light(), 155 title: 'Sector Layout', 156 home: Scaffold( 157 appBar: AppBar( 158 title: const Text('Sector Layout in a Widget Tree'), 159 ), 160 body: buildBody(), 161 ), 162 ); 163 } 164} 165 166void main() { 167 runApp(SectorApp()); 168} 169