diff --git a/android/local.properties b/android/local.properties index dbc8194..d0afff6 100644 --- a/android/local.properties +++ b/android/local.properties @@ -1,2 +1,2 @@ -sdk.dir=/Users/bensonarafat/Library/Android/sdk -flutter.sdk=/Users/bensonarafat/development/flutter +sdk.dir=/Users/akhilgeorge/Library/Android/sdk +flutter.sdk=/Users/akhilgeorge/Development/flutter \ No newline at end of file diff --git a/lib/src/enums.dart b/lib/src/enums.dart index 2bd9683..7fa7b53 100644 --- a/lib/src/enums.dart +++ b/lib/src/enums.dart @@ -1,4 +1,4 @@ -enum TooltipDirection { up, down, left, right } +enum TooltipDirection { up, down, left, right, auto } enum CloseButtonType { inside, outside } diff --git a/lib/src/super_tooltip.dart b/lib/src/super_tooltip.dart index 477d84d..f0b96db 100644 --- a/lib/src/super_tooltip.dart +++ b/lib/src/super_tooltip.dart @@ -463,6 +463,8 @@ class _SuperTooltipState extends State late Offset shadowOffset; late bool showBlur; + late TooltipDirection _resolvedDirection; + @override void initState() { _animationController = AnimationController( @@ -631,6 +633,47 @@ class _SuperTooltipState extends State var right = widget.right; var top = widget.top; var bottom = widget.bottom; + _resolvedDirection = preferredDirection; + // When [TooltipDirection.auto] is specified, the tooltip direction is + // dynamically resolved based on available space around the target widget. + if (preferredDirection == TooltipDirection.auto && overlay != null) { + final estimatedTooltipSize = Size( + constraints.maxWidth.isFinite + ? constraints.maxWidth + : overlay.size.width * 0.8, + constraints.maxHeight.isFinite + ? constraints.maxHeight + : overlay.size.height * 0.4, + ); + + final screen = overlay.size; + + final spaceAbove = target.dy - widget.minimumOutsideMargin; + final spaceBelow = + screen.height - target.dy - widget.minimumOutsideMargin; + final spaceLeft = target.dx - widget.minimumOutsideMargin; + final spaceRight = screen.width - target.dx - widget.minimumOutsideMargin; + + if (spaceBelow >= estimatedTooltipSize.height) { + preferredDirection = TooltipDirection.down; + } else if (spaceAbove >= estimatedTooltipSize.height) { + preferredDirection = TooltipDirection.up; + } else if (spaceRight >= estimatedTooltipSize.width) { + preferredDirection = TooltipDirection.right; + } else if (spaceLeft >= estimatedTooltipSize.width) { + preferredDirection = TooltipDirection.left; + } else { + final candidates = { + TooltipDirection.down: spaceBelow, + TooltipDirection.up: spaceAbove, + TooltipDirection.right: spaceRight, + TooltipDirection.left: spaceLeft, + }; + + preferredDirection = + candidates.entries.reduce((a, b) => a.value > b.value ? a : b).key; + } + } if (widget.snapsFarAwayVertically) { constraints = constraints.copyWith(maxHeight: null); @@ -668,6 +711,7 @@ class _SuperTooltipState extends State left = 0.0; } } + _resolvedDirection = preferredDirection; _barrierEntry = showBarrier ? OverlayEntry( @@ -723,7 +767,7 @@ class _SuperTooltipState extends State offset: offsetToTarget, child: CustomSingleChildLayout( delegate: ToolTipPositionDelegate( - preferredDirection: preferredDirection, + preferredDirection: _resolvedDirection, constraints: constraints, top: top, bottom: bottom, @@ -757,7 +801,7 @@ class _SuperTooltipState extends State arrowLength: widget.arrowLength, arrowTipDistance: widget.arrowTipDistance, closeButtonSize: closeButtonSize, - preferredDirection: preferredDirection, + preferredDirection: _resolvedDirection, closeButtonType: closeButtonType, showCloseButton: showCloseButton, ), @@ -915,7 +959,7 @@ class _SuperTooltipState extends State double right; double top; - switch (widget.popupDirectionBuilder?.call() ?? widget.popupDirection) { + switch (_resolvedDirection) { // // LEFT: ------------------------------------- case TooltipDirection.left: diff --git a/lib/src/tooltip_position_delegate.dart b/lib/src/tooltip_position_delegate.dart index 2770d5c..2acfb8e 100644 --- a/lib/src/tooltip_position_delegate.dart +++ b/lib/src/tooltip_position_delegate.dart @@ -65,6 +65,18 @@ class ToolTipPositionDelegate extends SingleChildLayoutDelegate { right: right, ); break; + case TooltipDirection.auto: + availableConstraints = SuperUtils.verticalConstraints( + constraints: availableConstraints, + margin: margin, + bottom: bottom, + isUp: false, + target: target, + top: top, + left: left, + right: right, + ); + break; } // Now we merge the calculated "Available Space" with the User's "Desired Constraints". diff --git a/lib/src/utils.dart b/lib/src/utils.dart index aae2dee..80a6e6d 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -232,4 +232,38 @@ class SuperUtils { maxWidth: maxWidth, ); } + + /// This method determines the most suitable direction for displaying + /// the tooltip relative to the target widget. + static TooltipDirection resolve({ + required RenderBox overlay, + required Offset target, + required Size estimatedTooltipSize, + required double margin, + }) { + final screen = overlay.size; + + final spaceAbove = target.dy - margin; + final spaceBelow = screen.height - target.dy - margin; + final spaceLeft = target.dx - margin; + final spaceRight = screen.width - target.dx - margin; + + final requiredHeight = estimatedTooltipSize.height; + final requiredWidth = estimatedTooltipSize.width; + + if (spaceBelow >= requiredHeight) return TooltipDirection.down; + if (spaceAbove >= requiredHeight) return TooltipDirection.up; + + if (spaceRight >= requiredWidth) return TooltipDirection.right; + if (spaceLeft >= requiredWidth) return TooltipDirection.left; + + final candidates = { + TooltipDirection.down: spaceBelow, + TooltipDirection.up: spaceAbove, + TooltipDirection.right: spaceRight, + TooltipDirection.left: spaceLeft, + }; + + return candidates.entries.reduce((a, b) => a.value > b.value ? a : b).key; + } }