Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions android/local.properties
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion lib/src/enums.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
enum TooltipDirection { up, down, left, right }
enum TooltipDirection { up, down, left, right, auto }

enum CloseButtonType { inside, outside }

Expand Down
50 changes: 47 additions & 3 deletions lib/src/super_tooltip.dart
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,8 @@ class _SuperTooltipState extends State<SuperTooltip>
late Offset shadowOffset;
late bool showBlur;

late TooltipDirection _resolvedDirection;

@override
void initState() {
_animationController = AnimationController(
Expand Down Expand Up @@ -631,6 +633,47 @@ class _SuperTooltipState extends State<SuperTooltip>
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, double>{
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);
Expand Down Expand Up @@ -668,6 +711,7 @@ class _SuperTooltipState extends State<SuperTooltip>
left = 0.0;
}
}
_resolvedDirection = preferredDirection;

_barrierEntry = showBarrier
? OverlayEntry(
Expand Down Expand Up @@ -723,7 +767,7 @@ class _SuperTooltipState extends State<SuperTooltip>
offset: offsetToTarget,
child: CustomSingleChildLayout(
delegate: ToolTipPositionDelegate(
preferredDirection: preferredDirection,
preferredDirection: _resolvedDirection,
constraints: constraints,
top: top,
bottom: bottom,
Expand Down Expand Up @@ -757,7 +801,7 @@ class _SuperTooltipState extends State<SuperTooltip>
arrowLength: widget.arrowLength,
arrowTipDistance: widget.arrowTipDistance,
closeButtonSize: closeButtonSize,
preferredDirection: preferredDirection,
preferredDirection: _resolvedDirection,
closeButtonType: closeButtonType,
showCloseButton: showCloseButton,
),
Expand Down Expand Up @@ -915,7 +959,7 @@ class _SuperTooltipState extends State<SuperTooltip>
double right;
double top;

switch (widget.popupDirectionBuilder?.call() ?? widget.popupDirection) {
switch (_resolvedDirection) {
//
// LEFT: -------------------------------------
case TooltipDirection.left:
Expand Down
12 changes: 12 additions & 0 deletions lib/src/tooltip_position_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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".
Expand Down
34 changes: 34 additions & 0 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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, double>{
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;
}
}