geometry.dart 2.53 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4 5 6
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:math' as math;

7
import 'package:flutter/foundation.dart' show clampDouble;
8 9
import 'basic_types.dart';

10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
/// Position a child box within a container box, either above or below a target
/// point.
///
/// The container's size is described by `size`.
///
/// The target point is specified by `target`, as an offset from the top left of
/// the container.
///
/// The child box's size is given by `childSize`.
///
/// The return value is the suggested distance from the top left of the
/// container box to the top left of the child box.
///
/// The suggested position will be above the target point if `preferBelow` is
/// false, and below the target point if it is true, unless it wouldn't fit on
/// the preferred side but would fit on the other side.
///
/// The suggested position will place the nearest side of the child to the
/// target point `verticalOffset` from the target point (even if it cannot fit
/// given that constraint).
30
///
31 32 33 34 35
/// The suggested position will be at least `margin` away from the edge of the
/// container. If possible, the child will be positioned so that its center is
/// aligned with the target point. If the child cannot fit horizontally within
/// the container given the margin, then the child will be centered in the
/// container.
36 37 38 39 40
///
/// Used by [Tooltip] to position a tooltip relative to its parent.
///
/// The arguments must not be null.
Offset positionDependentBox({
41 42 43 44
  required Size size,
  required Size childSize,
  required Offset target,
  required bool preferBelow,
45 46
  double verticalOffset = 0.0,
  double margin = 10.0,
47 48
}) {
  // VERTICAL DIRECTION
49 50
  final bool fitsBelow = target.dy + verticalOffset + childSize.height <= size.height - margin;
  final bool fitsAbove = target.dy - verticalOffset - childSize.height >= margin;
51
  final bool tooltipBelow = fitsAbove == fitsBelow ? preferBelow : fitsBelow;
52
  final double y;
53
  if (tooltipBelow) {
54
    y = math.min(target.dy + verticalOffset, size.height - margin);
55
  } else {
56
    y = math.max(target.dy - verticalOffset - childSize.height, margin);
57
  }
58
  // HORIZONTAL DIRECTION
59 60 61 62 63 64
  final double flexibleSpace = size.width - childSize.width;
  final double x = flexibleSpace <= 2 * margin
    // If there's not enough horizontal space for margin + child, center the
    // child.
    ? flexibleSpace / 2.0
    : clampDouble(target.dx - childSize.width / 2, margin, flexibleSpace - margin);
65
  return Offset(x, y);
66
}