| // Copyright 2014 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'dart:ui' show lerpDouble; |
| |
| import 'package:flutter/material.dart'; |
| |
| class CutCornersBorder extends OutlineInputBorder { |
| const CutCornersBorder({ |
| BorderSide borderSide = BorderSide.none, |
| BorderRadius borderRadius = const BorderRadius.all(Radius.circular(2.0)), |
| this.cut = 7.0, |
| double gapPadding = 2.0, |
| }) : super( |
| borderSide: borderSide, |
| borderRadius: borderRadius, |
| gapPadding: gapPadding, |
| ); |
| |
| @override |
| CutCornersBorder copyWith({ |
| BorderSide? borderSide, |
| BorderRadius? borderRadius, |
| double? gapPadding, |
| double? cut, |
| }) { |
| return CutCornersBorder( |
| borderSide: borderSide ?? this.borderSide, |
| borderRadius: borderRadius ?? this.borderRadius, |
| gapPadding: gapPadding ?? this.gapPadding, |
| cut: cut ?? this.cut, |
| ); |
| } |
| |
| final double cut; |
| |
| @override |
| ShapeBorder? lerpFrom(ShapeBorder? a, double t) { |
| if (a is CutCornersBorder) { |
| final CutCornersBorder outline = a; |
| return CutCornersBorder( |
| borderRadius: BorderRadius.lerp(outline.borderRadius, borderRadius, t)!, |
| borderSide: BorderSide.lerp(outline.borderSide, borderSide, t), |
| cut: cut, |
| gapPadding: outline.gapPadding, |
| ); |
| } |
| return super.lerpFrom(a, t); |
| } |
| |
| @override |
| ShapeBorder? lerpTo(ShapeBorder? b, double t) { |
| if (b is CutCornersBorder) { |
| final CutCornersBorder outline = b; |
| return CutCornersBorder( |
| borderRadius: BorderRadius.lerp(borderRadius, outline.borderRadius, t)!, |
| borderSide: BorderSide.lerp(borderSide, outline.borderSide, t), |
| cut: cut, |
| gapPadding: outline.gapPadding, |
| ); |
| } |
| return super.lerpTo(b, t); |
| } |
| |
| Path _notchedCornerPath(Rect center, [double start = 0.0, double? extent = 0.0]) { |
| final Path path = Path(); |
| if (start > 0.0 || extent! > 0.0) { |
| path.relativeMoveTo(extent! + start, center.top); |
| _notchedSidesAndBottom(center, path); |
| path..lineTo(center.left + cut, center.top)..lineTo(start, center.top); |
| } else { |
| path.moveTo(center.left + cut, center.top); |
| _notchedSidesAndBottom(center, path); |
| path.lineTo(center.left + cut, center.top); |
| } |
| return path; |
| } |
| |
| Path _notchedSidesAndBottom(Rect center, Path path) { |
| return path |
| ..lineTo(center.right - cut, center.top) |
| ..lineTo(center.right, center.top + cut) |
| ..lineTo(center.right, center.top + center.height - cut) |
| ..lineTo(center.right - cut, center.top + center.height) |
| ..lineTo(center.left + cut, center.top + center.height) |
| ..lineTo(center.left, center.top + center.height - cut) |
| ..lineTo(center.left, center.top + cut); |
| } |
| |
| @override |
| void paint( |
| Canvas canvas, |
| Rect rect, { |
| double? gapStart, |
| double gapExtent = 0.0, |
| double gapPercentage = 0.0, |
| TextDirection? textDirection, |
| }) { |
| assert(gapPercentage >= 0.0 && gapPercentage <= 1.0); |
| |
| final Paint paint = borderSide.toPaint(); |
| final RRect outer = borderRadius.toRRect(rect); |
| if (gapStart == null || gapExtent <= 0.0 || gapPercentage == 0.0) { |
| canvas.drawPath(_notchedCornerPath(outer.middleRect), paint); |
| } else { |
| final double? extent = lerpDouble(0.0, gapExtent + gapPadding * 2.0, gapPercentage); |
| switch (textDirection) { |
| case TextDirection.rtl: { |
| final Path path = _notchedCornerPath(outer.middleRect, gapStart + gapPadding - extent!, extent); |
| canvas.drawPath(path, paint); |
| break; |
| } |
| case TextDirection.ltr: { |
| final Path path = _notchedCornerPath(outer.middleRect, gapStart - gapPadding, extent); |
| canvas.drawPath(path, paint); |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| } |
| } |