| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 | import 'dart:math' as math;import 'package:flutter/material.dart';import 'package:flutter/rendering.dart';import './popover.dart';class PopoverLayoutDelegate extends SingleChildLayoutDelegate {  PopoverLink link;  PopoverDirection direction;  final Offset offset;  PopoverLayoutDelegate({    required this.link,    required this.direction,    required this.offset,  });  @override  bool shouldRelayout(PopoverLayoutDelegate oldDelegate) {    if (direction != oldDelegate.direction) {      return true;    }    if (link != oldDelegate.link) {      return true;    }    if (link.leaderOffset != oldDelegate.link.leaderOffset) {      return true;    }    if (link.leaderSize != oldDelegate.link.leaderSize) {      return true;    }    return false;  }  @override  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {    return constraints.loosen();    // assert(link.leaderSize != null);    // // if (link.leaderSize == null) {    // //   return constraints.loosen();    // // }    // final anchorRect = Rect.fromLTWH(    //   link.leaderOffset!.dx,    //   link.leaderOffset!.dy,    //   link.leaderSize!.width,    //   link.leaderSize!.height,    // );    // BoxConstraints childConstraints;    // switch (direction) {    //   case PopoverDirection.topLeft:    //     childConstraints = BoxConstraints.loose(Size(    //       anchorRect.left,    //       anchorRect.top,    //     ));    //     break;    //   case PopoverDirection.topRight:    //     childConstraints = BoxConstraints.loose(Size(    //       constraints.maxWidth - anchorRect.right,    //       anchorRect.top,    //     ));    //     break;    //   case PopoverDirection.bottomLeft:    //     childConstraints = BoxConstraints.loose(Size(    //       anchorRect.left,    //       constraints.maxHeight - anchorRect.bottom,    //     ));    //     break;    //   case PopoverDirection.bottomRight:    //     childConstraints = BoxConstraints.loose(Size(    //       constraints.maxWidth - anchorRect.right,    //       constraints.maxHeight - anchorRect.bottom,    //     ));    //     break;    //   case PopoverDirection.center:    //     childConstraints = BoxConstraints.loose(Size(    //       constraints.maxWidth,    //       constraints.maxHeight,    //     ));    //     break;    //   case PopoverDirection.topWithLeftAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       constraints.maxWidth - anchorRect.left,    //       anchorRect.top,    //     ));    //     break;    //   case PopoverDirection.topWithCenterAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       constraints.maxWidth,    //       anchorRect.top,    //     ));    //     break;    //   case PopoverDirection.topWithRightAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       anchorRect.right,    //       anchorRect.top,    //     ));    //     break;    //   case PopoverDirection.rightWithTopAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       constraints.maxWidth - anchorRect.right,    //       constraints.maxHeight - anchorRect.top,    //     ));    //     break;    //   case PopoverDirection.rightWithCenterAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       constraints.maxWidth - anchorRect.right,    //       constraints.maxHeight,    //     ));    //     break;    //   case PopoverDirection.rightWithBottomAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       constraints.maxWidth - anchorRect.right,    //       anchorRect.bottom,    //     ));    //     break;    //   case PopoverDirection.bottomWithLeftAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       anchorRect.left,    //       constraints.maxHeight - anchorRect.bottom,    //     ));    //     break;    //   case PopoverDirection.bottomWithCenterAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       constraints.maxWidth,    //       constraints.maxHeight - anchorRect.bottom,    //     ));    //     break;    //   case PopoverDirection.bottomWithRightAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       anchorRect.right,    //       constraints.maxHeight - anchorRect.bottom,    //     ));    //     break;    //   case PopoverDirection.leftWithTopAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       anchorRect.left,    //       constraints.maxHeight - anchorRect.top,    //     ));    //     break;    //   case PopoverDirection.leftWithCenterAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       anchorRect.left,    //       constraints.maxHeight,    //     ));    //     break;    //   case PopoverDirection.leftWithBottomAligned:    //     childConstraints = BoxConstraints.loose(Size(    //       anchorRect.left,    //       anchorRect.bottom,    //     ));    //     break;    //   case PopoverDirection.custom:    //     childConstraints = constraints.loosen();    //     break;    //   default:    //     throw UnimplementedError();    // }    // return childConstraints;  }  @override  Offset getPositionForChild(Size size, Size childSize) {    if (link.leaderSize == null) {      return Offset.zero;    }    final anchorRect = Rect.fromLTWH(      link.leaderOffset!.dx + offset.dx,      link.leaderOffset!.dy + offset.dy,      link.leaderSize!.width,      link.leaderSize!.height,    );    Offset position;    switch (direction) {      case PopoverDirection.topLeft:        position = Offset(          anchorRect.left - childSize.width,          anchorRect.top - childSize.height,        );        break;      case PopoverDirection.topRight:        position = Offset(          anchorRect.right,          anchorRect.top - childSize.height,        );        break;      case PopoverDirection.bottomLeft:        position = Offset(          anchorRect.left - childSize.width,          anchorRect.bottom,        );        break;      case PopoverDirection.bottomRight:        position = Offset(          anchorRect.right,          anchorRect.bottom,        );        break;      case PopoverDirection.center:        position = anchorRect.center;        break;      case PopoverDirection.topWithLeftAligned:        position = Offset(          anchorRect.left,          anchorRect.top - childSize.height,        );        break;      case PopoverDirection.topWithCenterAligned:        position = Offset(          anchorRect.left + anchorRect.width / 2.0 - childSize.width / 2.0,          anchorRect.top - childSize.height,        );        break;      case PopoverDirection.topWithRightAligned:        position = Offset(          anchorRect.right - childSize.width,          anchorRect.top - childSize.height,        );        break;      case PopoverDirection.rightWithTopAligned:        position = Offset(anchorRect.right, anchorRect.top);        break;      case PopoverDirection.rightWithCenterAligned:        position = Offset(          anchorRect.right,          anchorRect.top + anchorRect.height / 2.0 - childSize.height / 2.0,        );        break;      case PopoverDirection.rightWithBottomAligned:        position = Offset(          anchorRect.right,          anchorRect.bottom - childSize.height,        );        break;      case PopoverDirection.bottomWithLeftAligned:        position = Offset(          anchorRect.left,          anchorRect.bottom,        );        break;      case PopoverDirection.bottomWithCenterAligned:        position = Offset(          anchorRect.left + anchorRect.width / 2.0 - childSize.width / 2.0,          anchorRect.bottom,        );        break;      case PopoverDirection.bottomWithRightAligned:        position = Offset(          anchorRect.right - childSize.width,          anchorRect.bottom,        );        break;      case PopoverDirection.leftWithTopAligned:        position = Offset(          anchorRect.left - childSize.width,          anchorRect.top,        );        break;      case PopoverDirection.leftWithCenterAligned:        position = Offset(          anchorRect.left - childSize.width,          anchorRect.top + anchorRect.height / 2.0 - childSize.height / 2.0,        );        break;      case PopoverDirection.leftWithBottomAligned:        position = Offset(          anchorRect.left - childSize.width,          anchorRect.bottom - childSize.height,        );        break;      default:        throw UnimplementedError();    }    return Offset(      math.max(0.0, math.min(size.width - childSize.width, position.dx)),      math.max(0.0, math.min(size.height - childSize.height, position.dy)),    );  }}class PopoverTarget extends SingleChildRenderObjectWidget {  final PopoverLink link;  const PopoverTarget({    super.key,    super.child,    required this.link,  });  @override  PopoverTargetRenderBox createRenderObject(BuildContext context) {    return PopoverTargetRenderBox(      link: link,    );  }  @override  void updateRenderObject(      BuildContext context, PopoverTargetRenderBox renderObject) {    renderObject.link = link;  }}class PopoverTargetRenderBox extends RenderProxyBox {  PopoverLink link;  PopoverTargetRenderBox({required this.link, RenderBox? child}) : super(child);  @override  bool get alwaysNeedsCompositing => true;  @override  void performLayout() {    super.performLayout();    link.leaderSize = size;  }  @override  void paint(PaintingContext context, Offset offset) {    link.leaderOffset = localToGlobal(Offset.zero);    super.paint(context, offset);  }  @override  void detach() {    link.leaderOffset = null;    link.leaderSize = null;    super.detach();  }  @override  void debugFillProperties(DiagnosticPropertiesBuilder properties) {    super.debugFillProperties(properties);    properties.add(DiagnosticsProperty<PopoverLink>('link', link));  }}class PopoverLink {  Offset? leaderOffset;  Size? leaderSize;}
 |