sectors.dart 5.93 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:math' as math;

7
import 'package:flutter/material.dart';
8

9
import '../rendering/src/sector_layout.dart';
10

11
RenderBoxToRenderSectorAdapter initCircle() {
12
  return RenderBoxToRenderSectorAdapter(
13
    innerRadius: 25.0,
14
    child: RenderSectorRing(padding: 0.0),
15 16 17
  );
}

18
class SectorApp extends StatefulWidget {
19 20
  const SectorApp({Key? key}) : super(key: key);

21
  @override
22
  SectorAppState createState() => SectorAppState();
Hixie's avatar
Hixie committed
23 24 25
}

class SectorAppState extends State<SectorApp> {
26

Hixie's avatar
Hixie committed
27
  final RenderBoxToRenderSectorAdapter sectors = initCircle();
28
  final math.Random rand = math.Random(1);
29

30 31
  List<double> wantedSectorSizes = <double>[];
  List<double> actualSectorSizes = <double>[];
32
  double get currentTheta => wantedSectorSizes.fold<double>(0.0, (double total, double value) => total + value);
33

34
  void addSector() {
35 36 37
    final double currentTheta = this.currentTheta;
    if (currentTheta < kTwoPi) {
      double deltaTheta;
38
      if (currentTheta >= kTwoPi - (math.pi * 0.2 + 0.05))
39 40
        deltaTheta = kTwoPi - currentTheta;
      else
41
        deltaTheta = math.pi * rand.nextDouble() / 5.0 + 0.05;
42 43 44
      wantedSectorSizes.add(deltaTheta);
      updateEnabledState();
    }
45 46 47
  }

  void removeSector() {
48 49 50 51 52 53 54 55 56 57
    if (wantedSectorSizes.isNotEmpty) {
      wantedSectorSizes.removeLast();
      updateEnabledState();
    }
  }

  void doUpdates() {
    int index = 0;
    while (index < actualSectorSizes.length && index < wantedSectorSizes.length && actualSectorSizes[index] == wantedSectorSizes[index])
      index += 1;
58
    final RenderSectorRing ring = sectors.child! as RenderSectorRing;
59
    while (index < actualSectorSizes.length) {
60
      ring.remove(ring.lastChild!);
61 62 63
      actualSectorSizes.removeLast();
    }
    while (index < wantedSectorSizes.length) {
64 65
      final Color color = Color(((0xFF << 24) + rand.nextInt(0xFFFFFF)) | 0x808080);
      ring.add(RenderSolidColor(color, desiredDeltaTheta: wantedSectorSizes[index]));
66 67 68
      actualSectorSizes.add(wantedSectorSizes[index]);
      index += 1;
    }
69 70
  }

71
  static RenderBoxToRenderSectorAdapter initSector(Color color) {
72 73 74 75 76
    final RenderSectorRing ring = RenderSectorRing(padding: 1.0);
    ring.add(RenderSolidColor(const Color(0xFF909090), desiredDeltaTheta: kTwoPi * 0.15));
    ring.add(RenderSolidColor(const Color(0xFF909090), desiredDeltaTheta: kTwoPi * 0.15));
    ring.add(RenderSolidColor(color, desiredDeltaTheta: kTwoPi * 0.2));
    return RenderBoxToRenderSectorAdapter(
77
      innerRadius: 5.0,
78
      child: ring,
79 80 81 82 83
    );
  }
  RenderBoxToRenderSectorAdapter sectorAddIcon = initSector(const Color(0xFF00DD00));
  RenderBoxToRenderSectorAdapter sectorRemoveIcon = initSector(const Color(0xFFDD0000));

Hixie's avatar
Hixie committed
84 85
  bool _enabledAdd = true;
  bool _enabledRemove = false;
86 87
  void updateEnabledState() {
    setState(() {
88 89
      _enabledAdd = currentTheta < kTwoPi;
      _enabledRemove = wantedSectorSizes.isNotEmpty;
90 91 92
    });
  }

93 94 95 96 97 98 99
  void recursivelyDisposeChildren(RenderObject parent) {
    parent.visitChildren((RenderObject child) {
      recursivelyDisposeChildren(child);
      child.dispose();
    });
  }

100
  Widget buildBody() {
101
    return Column(
102
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
103
      children: <Widget>[
104
        Container(
105
          padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 25.0),
106
          child: Row(
107
            mainAxisAlignment: MainAxisAlignment.spaceAround,
108
            children: <Widget>[
109
              ElevatedButton(
110
                onPressed: _enabledAdd ? addSector : null,
111 112
                child: IntrinsicWidth(
                  child: Row(
113
                    children: <Widget>[
114
                      Container(
115 116
                        padding: const EdgeInsets.all(4.0),
                        margin: const EdgeInsets.only(right: 10.0),
117 118 119 120 121 122
                        child: WidgetToRenderBoxAdapter(
                          renderBox: sectorAddIcon,
                          onUnmount: () {
                            recursivelyDisposeChildren(sectorAddIcon);
                          },
                        ),
123
                      ),
124
                      const Text('ADD SECTOR'),
125 126 127
                    ],
                  ),
                ),
128
              ),
129
              ElevatedButton(
130
                onPressed: _enabledRemove ? removeSector : null,
131 132
                child: IntrinsicWidth(
                  child: Row(
133
                    children: <Widget>[
134
                      Container(
135 136
                        padding: const EdgeInsets.all(4.0),
                        margin: const EdgeInsets.only(right: 10.0),
137 138 139 140 141 142
                        child: WidgetToRenderBoxAdapter(
                          renderBox: sectorRemoveIcon,
                          onUnmount: () {
                            recursivelyDisposeChildren(sectorRemoveIcon);
                          },
                        ),
143
                      ),
144
                      const Text('REMOVE SECTOR'),
145 146 147
                    ],
                  ),
                ),
148
              ),
149
            ],
150
          ),
151
        ),
152 153
        Expanded(
          child: Container(
154
            margin: const EdgeInsets.all(8.0),
155
            decoration: BoxDecoration(
156
              border: Border.all(),
157
            ),
158
            padding: const EdgeInsets.all(8.0),
159
            child: WidgetToRenderBoxAdapter(
160
              renderBox: sectors,
161
              onBuild: doUpdates,
162 163 164
              onUnmount: () {
                recursivelyDisposeChildren(sectors);
              },
165 166
            ),
          ),
167 168
        ),
      ],
169 170 171
    );
  }

172
  @override
Hixie's avatar
Hixie committed
173
  Widget build(BuildContext context) {
174 175
    return MaterialApp(
      theme: ThemeData.light(),
Hixie's avatar
Hixie committed
176
      title: 'Sector Layout',
177 178
      home: Scaffold(
        appBar: AppBar(
179
          title: const Text('Sector Layout in a Widget Tree'),
180
        ),
181 182
        body: buildBody(),
      ),
183 184 185 186 187
    );
  }
}

void main() {
188
  runApp(const SectorApp());
189
}