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;
- }
|