onDragSelectionUpdate method

  1. @protected
void onDragSelectionUpdate(
  1. TapDragUpdateDetails details
)

Handler for TextSelectionGestureDetector.onDragSelectionUpdate.

By default, it updates the selection location specified in the provided details objects.

See also:

Implementation

@protected
void onDragSelectionUpdate(TapDragUpdateDetails details) {
  if (!delegate.selectionEnabled) {
    return;
  }

  if (!_isShiftPressed) {
    // Adjust the drag start offset for possible viewport offset changes.
    final Offset editableOffset = renderEditable.maxLines == 1
        ? Offset(renderEditable.offset.pixels - _dragStartViewportOffset, 0.0)
        : Offset(0.0, renderEditable.offset.pixels - _dragStartViewportOffset);
    final Offset scrollableOffset = Offset(
      0.0,
      _scrollPosition - _dragStartScrollOffset,
    );
    final Offset dragStartGlobalPosition = details.globalPosition - details.offsetFromOrigin;

    // Select word by word.
    if (_TextSelectionGestureDetectorState._getEffectiveConsecutiveTapCount(details.consecutiveTapCount) == 2) {
      renderEditable.selectWordsInRange(
        from: dragStartGlobalPosition - editableOffset - scrollableOffset,
        to: details.globalPosition,
        cause: SelectionChangedCause.drag,
      );

      switch (details.kind) {
        case PointerDeviceKind.stylus:
        case PointerDeviceKind.invertedStylus:
        case PointerDeviceKind.touch:
        case PointerDeviceKind.unknown:
          return _showMagnifierIfSupportedByPlatform(details.globalPosition);
        case PointerDeviceKind.mouse:
        case PointerDeviceKind.trackpad:
        case null:
          return;
      }
    }

    // Select paragraph-by-paragraph.
    if (_TextSelectionGestureDetectorState._getEffectiveConsecutiveTapCount(details.consecutiveTapCount) == 3) {
      switch (defaultTargetPlatform) {
        case TargetPlatform.android:
        case TargetPlatform.fuchsia:
        case TargetPlatform.iOS:
          switch (details.kind) {
            case PointerDeviceKind.mouse:
            case PointerDeviceKind.trackpad:
              return _selectParagraphsInRange(
                from: dragStartGlobalPosition - editableOffset - scrollableOffset,
                to: details.globalPosition,
                cause: SelectionChangedCause.drag,
              );
            case PointerDeviceKind.stylus:
            case PointerDeviceKind.invertedStylus:
            case PointerDeviceKind.touch:
            case PointerDeviceKind.unknown:
            case null:
              // Triple tap to drag is not present on these platforms when using
              // non-precise pointer devices at the moment.
              break;
          }
          return;
        case TargetPlatform.linux:
          return _selectLinesInRange(
            from: dragStartGlobalPosition - editableOffset - scrollableOffset,
            to: details.globalPosition,
            cause: SelectionChangedCause.drag,
          );
        case TargetPlatform.windows:
        case TargetPlatform.macOS:
          return _selectParagraphsInRange(
            from: dragStartGlobalPosition - editableOffset - scrollableOffset,
            to: details.globalPosition,
            cause: SelectionChangedCause.drag,
          );
      }
    }

    switch (defaultTargetPlatform) {
      case TargetPlatform.iOS:
        // With a touch device, nothing should happen, unless there was a double tap, or
        // there was a collapsed selection, and the tap/drag position is at the collapsed selection.
        // In that case the caret should move with the drag position.
        //
        // With a mouse device, a drag should select the range from the origin of the drag
        // to the current position of the drag.
        switch (details.kind) {
          case PointerDeviceKind.mouse:
          case PointerDeviceKind.trackpad:
            return renderEditable.selectPositionAt(
              from: dragStartGlobalPosition - editableOffset - scrollableOffset,
              to: details.globalPosition,
              cause: SelectionChangedCause.drag,
            );
          case PointerDeviceKind.stylus:
          case PointerDeviceKind.invertedStylus:
          case PointerDeviceKind.touch:
          case PointerDeviceKind.unknown:
            assert(_dragBeganOnPreviousSelection != null);
            if (renderEditable.hasFocus
                && _dragStartSelection!.isCollapsed
                && _dragBeganOnPreviousSelection!
            ) {
              renderEditable.selectPositionAt(
                from: details.globalPosition,
                cause: SelectionChangedCause.drag,
              );
              return _showMagnifierIfSupportedByPlatform(details.globalPosition);
            }
          case null:
            break;
        }
        return;
      case TargetPlatform.android:
      case TargetPlatform.fuchsia:
        // With a precise pointer device, such as a mouse, trackpad, or stylus,
        // the drag will select the text spanning the origin of the drag to the end of the drag.
        // With a touch device, the cursor should move with the drag.
        switch (details.kind) {
          case PointerDeviceKind.mouse:
          case PointerDeviceKind.trackpad:
          case PointerDeviceKind.stylus:
          case PointerDeviceKind.invertedStylus:
            return renderEditable.selectPositionAt(
              from: dragStartGlobalPosition - editableOffset - scrollableOffset,
              to: details.globalPosition,
              cause: SelectionChangedCause.drag,
            );
          case PointerDeviceKind.touch:
          case PointerDeviceKind.unknown:
            if (renderEditable.hasFocus) {
              renderEditable.selectPositionAt(
                from: details.globalPosition,
                cause: SelectionChangedCause.drag,
              );
              return _showMagnifierIfSupportedByPlatform(details.globalPosition);
            }
          case null:
            break;
        }
        return;
      case TargetPlatform.macOS:
      case TargetPlatform.linux:
      case TargetPlatform.windows:
        return renderEditable.selectPositionAt(
          from: dragStartGlobalPosition - editableOffset - scrollableOffset,
          to: details.globalPosition,
          cause: SelectionChangedCause.drag,
        );
    }
  }

  if (_dragStartSelection!.isCollapsed
      || (defaultTargetPlatform != TargetPlatform.iOS
          && defaultTargetPlatform != TargetPlatform.macOS)) {
    return _extendSelection(details.globalPosition, SelectionChangedCause.drag);
  }

  // If the drag inverts the selection, Mac and iOS revert to the initial
  // selection.
  final TextSelection selection = editableText.textEditingValue.selection;
  final TextPosition nextExtent = renderEditable.getPositionForPoint(details.globalPosition);
  final bool isShiftTapDragSelectionForward =
      _dragStartSelection!.baseOffset < _dragStartSelection!.extentOffset;
  final bool isInverted = isShiftTapDragSelectionForward
      ? nextExtent.offset < _dragStartSelection!.baseOffset
      : nextExtent.offset > _dragStartSelection!.baseOffset;
  if (isInverted && selection.baseOffset == _dragStartSelection!.baseOffset) {
    editableText.userUpdateTextEditingValue(
      editableText.textEditingValue.copyWith(
        selection: TextSelection(
          baseOffset: _dragStartSelection!.extentOffset,
          extentOffset: nextExtent.offset,
        ),
      ),
      SelectionChangedCause.drag,
    );
  } else if (!isInverted
      && nextExtent.offset != _dragStartSelection!.baseOffset
      && selection.baseOffset != _dragStartSelection!.baseOffset) {
    editableText.userUpdateTextEditingValue(
      editableText.textEditingValue.copyWith(
        selection: TextSelection(
          baseOffset: _dragStartSelection!.baseOffset,
          extentOffset: nextExtent.offset,
        ),
      ),
      SelectionChangedCause.drag,
    );
  } else {
    _extendSelection(details.globalPosition, SelectionChangedCause.drag);
  }
}