getSelectionGeometry method

  1. @protected
SelectionGeometry getSelectionGeometry()

Gets the combined SelectionGeometry for child Selectables.

Implementation

@protected
SelectionGeometry getSelectionGeometry() {
  if (currentSelectionEndIndex == -1 ||
      currentSelectionStartIndex == -1 ||
      selectables.isEmpty) {
    // There is no valid selection.
    return SelectionGeometry(
      status: SelectionStatus.none,
      hasContent: selectables.isNotEmpty,
    );
  }

  if (!_extendSelectionInProgress) {
    currentSelectionStartIndex = _adjustSelectionIndexBasedOnSelectionGeometry(
      currentSelectionStartIndex,
      currentSelectionEndIndex,
    );
    currentSelectionEndIndex = _adjustSelectionIndexBasedOnSelectionGeometry(
      currentSelectionEndIndex,
      currentSelectionStartIndex,
    );
  }

  // Need to find the non-null start selection point.
  SelectionGeometry startGeometry = selectables[currentSelectionStartIndex].value;
  final bool forwardSelection = currentSelectionEndIndex >= currentSelectionStartIndex;
  int startIndexWalker = currentSelectionStartIndex;
  while (startIndexWalker != currentSelectionEndIndex && startGeometry.startSelectionPoint == null) {
    startIndexWalker += forwardSelection ? 1 : -1;
    startGeometry = selectables[startIndexWalker].value;
  }

  SelectionPoint? startPoint;
  if (startGeometry.startSelectionPoint != null) {
    final Matrix4 startTransform = getTransformFrom(selectables[startIndexWalker]);
    final Offset start = MatrixUtils.transformPoint(startTransform, startGeometry.startSelectionPoint!.localPosition);
    // It can be NaN if it is detached or off-screen.
    if (start.isFinite) {
      startPoint = SelectionPoint(
        localPosition: start,
        lineHeight: startGeometry.startSelectionPoint!.lineHeight,
        handleType: startGeometry.startSelectionPoint!.handleType,
      );
    }
  }

  // Need to find the non-null end selection point.
  SelectionGeometry endGeometry = selectables[currentSelectionEndIndex].value;
  int endIndexWalker = currentSelectionEndIndex;
  while (endIndexWalker != currentSelectionStartIndex && endGeometry.endSelectionPoint == null) {
    endIndexWalker += forwardSelection ? -1 : 1;
    endGeometry = selectables[endIndexWalker].value;
  }
  SelectionPoint? endPoint;
  if (endGeometry.endSelectionPoint != null) {
    final Matrix4 endTransform = getTransformFrom(selectables[endIndexWalker]);
    final Offset end = MatrixUtils.transformPoint(endTransform, endGeometry.endSelectionPoint!.localPosition);
    // It can be NaN if it is detached or off-screen.
    if (end.isFinite) {
      endPoint = SelectionPoint(
        localPosition: end,
        lineHeight: endGeometry.endSelectionPoint!.lineHeight,
        handleType: endGeometry.endSelectionPoint!.handleType,
      );
    }
  }

  // Need to collect selection rects from selectables ranging from the
  // currentSelectionStartIndex to the currentSelectionEndIndex.
  final List<Rect> selectionRects = <Rect>[];
  final Rect? drawableArea = hasSize ? Rect
    .fromLTWH(0, 0, containerSize.width, containerSize.height) : null;
  for (int index = currentSelectionStartIndex; index <= currentSelectionEndIndex; index++) {
    final List<Rect> currSelectableSelectionRects = selectables[index].value.selectionRects;
    final List<Rect> selectionRectsWithinDrawableArea = currSelectableSelectionRects.map((Rect selectionRect) {
      final Matrix4 transform = getTransformFrom(selectables[index]);
      final Rect localRect = MatrixUtils.transformRect(transform, selectionRect);
      return drawableArea?.intersect(localRect) ?? localRect;
    }).where((Rect selectionRect) {
      return selectionRect.isFinite && !selectionRect.isEmpty;
    }).toList();
    selectionRects.addAll(selectionRectsWithinDrawableArea);
  }

  return SelectionGeometry(
    startSelectionPoint: startPoint,
    endSelectionPoint: endPoint,
    selectionRects: selectionRects,
    status: startGeometry != endGeometry
      ? SelectionStatus.uncollapsed
      : startGeometry.status,
    // Would have at least one selectable child.
    hasContent: true,
  );
}