placeTooltip function

Offset placeTooltip({
  1. required Rect screen,
  2. required Rect hole,
  3. required TooltipPosition position,
  4. required Size size,
  5. required EdgeInsets safeArea,
  6. required List<Rect> avoid,
  7. double gap = _kGap,
})

Pure placement core, shared by the single and multi delegates: the offset for a tooltip of size around hole, picking the best fitting side from position's order (preferred → mirrored → orthogonal; auto — by free space) and vetoing placements that overlap avoid or leave the safe rect.

avoid must include the tooltip's own anchor hole — a tooltip never covers a spotlighted target. For multi-content slots the callers add the already-placed tooltip rects, so slots never overlap each other.

Implementation

Offset placeTooltip({
  required Rect screen,
  required Rect hole,
  required TooltipPosition position,
  required Size size,
  required EdgeInsets safeArea,
  required List<Rect> avoid,
  double gap = _kGap,
}) {
  final safe = _safeRectOf(screen, safeArea);
  for (final side in _sideOrder(position, safe, hole)) {
    final offset = _offsetFor(side, size, hole, safe, gap);
    if (_fits(offset, size, safe, avoid)) return offset;
  }
  // No side fit (tooltip/hole larger than the safe rect, or every side is
  // blocked) — try the safe-rect corners with a margin (a multi slot does
  // not land on an already-placed tooltip when a corner is free); the last
  // resort is the top-left corner (may still overflow the safe rect
  // bottom/right — nothing fits; the margin keeps it as close as the
  // degenerate case allows).
  final corners = [
    Offset(safe.left + _fallbackPadding, safe.top + _fallbackPadding),
    Offset(
      safe.right - _fallbackPadding - size.width,
      safe.top + _fallbackPadding,
    ),
    Offset(
      safe.left + _fallbackPadding,
      safe.bottom - _fallbackPadding - size.height,
    ),
    Offset(
      safe.right - _fallbackPadding - size.width,
      safe.bottom - _fallbackPadding - size.height,
    ),
  ];
  for (final corner in corners) {
    if (_fits(corner, size, safe, avoid)) return corner;
  }
  return corners.first;
}