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

5

Ian Hickson's avatar
Ian Hickson committed
6 7
import 'dart:math' as math;

8 9
import 'package:flutter/foundation.dart';

Ian Hickson's avatar
Ian Hickson committed
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
import 'basic_types.dart';
import 'borders.dart';
import 'edge_insets.dart';

/// A border that fits a circle within the available space.
///
/// Typically used with [ShapeDecoration] to draw a circle.
///
/// The [dimensions] assume that the border is being used in a square space.
/// When applied to a rectangular space, the border paints in the center of the
/// rectangle.
///
/// See also:
///
///  * [BorderSide], which is used to describe each side of the box.
///  * [Border], which, when used with [BoxDecoration], can also
///    describe a circle.
27
class CircleBorder extends OutlinedBorder {
Ian Hickson's avatar
Ian Hickson committed
28 29 30
  /// Create a circle border.
  ///
  /// The [side] argument must not be null.
31
  const CircleBorder({ BorderSide side = BorderSide.none }) : assert(side != null), super(side: side);
Ian Hickson's avatar
Ian Hickson committed
32 33 34

  @override
  EdgeInsetsGeometry get dimensions {
35
    return EdgeInsets.all(side.width);
Ian Hickson's avatar
Ian Hickson committed
36 37 38
  }

  @override
39
  ShapeBorder scale(double t) => CircleBorder(side: side.scale(t));
Ian Hickson's avatar
Ian Hickson committed
40 41

  @override
42
  ShapeBorder? lerpFrom(ShapeBorder? a, double t) {
Ian Hickson's avatar
Ian Hickson committed
43
    if (a is CircleBorder)
44
      return CircleBorder(side: BorderSide.lerp(a.side, side, t));
Ian Hickson's avatar
Ian Hickson committed
45 46 47 48
    return super.lerpFrom(a, t);
  }

  @override
49
  ShapeBorder? lerpTo(ShapeBorder? b, double t) {
Ian Hickson's avatar
Ian Hickson committed
50
    if (b is CircleBorder)
51
      return CircleBorder(side: BorderSide.lerp(side, b.side, t));
Ian Hickson's avatar
Ian Hickson committed
52 53 54 55
    return super.lerpTo(b, t);
  }

  @override
56
  Path getInnerPath(Rect rect, { TextDirection? textDirection }) {
57 58
    return Path()
      ..addOval(Rect.fromCircle(
Ian Hickson's avatar
Ian Hickson committed
59 60 61 62 63 64
        center: rect.center,
        radius: math.max(0.0, rect.shortestSide / 2.0 - side.width),
      ));
  }

  @override
65
  Path getOuterPath(Rect rect, { TextDirection? textDirection }) {
66 67
    return Path()
      ..addOval(Rect.fromCircle(
Ian Hickson's avatar
Ian Hickson committed
68 69 70 71 72
        center: rect.center,
        radius: rect.shortestSide / 2.0,
      ));
  }

73
  @override
74
  CircleBorder copyWith({ BorderSide? side }) {
75 76 77
    return CircleBorder(side: side ?? this.side);
  }

Ian Hickson's avatar
Ian Hickson committed
78
  @override
79
  void paint(Canvas canvas, Rect rect, { TextDirection? textDirection }) {
Ian Hickson's avatar
Ian Hickson committed
80 81 82 83 84 85 86 87 88
    switch (side.style) {
      case BorderStyle.none:
        break;
      case BorderStyle.solid:
        canvas.drawCircle(rect.center, (rect.shortestSide - side.width) / 2.0, side.toPaint());
    }
  }

  @override
89 90
  bool operator ==(Object other) {
    if (other.runtimeType != runtimeType)
Ian Hickson's avatar
Ian Hickson committed
91
      return false;
92 93
    return other is CircleBorder
        && other.side == side;
Ian Hickson's avatar
Ian Hickson committed
94 95 96 97 98 99 100
  }

  @override
  int get hashCode => side.hashCode;

  @override
  String toString() {
101
    return '${objectRuntimeType(this, 'CircleBorder')}($side)';
Ian Hickson's avatar
Ian Hickson committed
102 103
  }
}