blob: a562debbecdbb20433e60ad6b3ea54ac8186f57b [file] [log] [blame]
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:ui' show hashValues, TextAffinity, TextPosition, TextRange;
import 'package:flutter/foundation.dart';
export 'dart:ui' show TextAffinity, TextPosition, TextRange;
/// A range of text that represents a selection.
@immutable
class TextSelection extends TextRange {
/// Creates a text selection.
///
/// The [baseOffset] and [extentOffset] arguments must not be null.
const TextSelection({
required this.baseOffset,
required this.extentOffset,
this.affinity = TextAffinity.downstream,
this.isDirectional = false,
}) : super(
start: baseOffset < extentOffset ? baseOffset : extentOffset,
end: baseOffset < extentOffset ? extentOffset : baseOffset,
);
/// Creates a collapsed selection at the given offset.
///
/// A collapsed selection starts and ends at the same offset, which means it
/// contains zero characters but instead serves as an insertion point in the
/// text.
///
/// The [offset] argument must not be null.
const TextSelection.collapsed({
required int offset,
this.affinity = TextAffinity.downstream,
}) : baseOffset = offset,
extentOffset = offset,
isDirectional = false,
super.collapsed(offset);
/// Creates a collapsed selection at the given text position.
///
/// A collapsed selection starts and ends at the same offset, which means it
/// contains zero characters but instead serves as an insertion point in the
/// text.
TextSelection.fromPosition(TextPosition position)
: baseOffset = position.offset,
extentOffset = position.offset,
affinity = position.affinity,
isDirectional = false,
super.collapsed(position.offset);
/// The offset at which the selection originates.
///
/// Might be larger than, smaller than, or equal to extent.
final int baseOffset;
/// The offset at which the selection terminates.
///
/// When the user uses the arrow keys to adjust the selection, this is the
/// value that changes. Similarly, if the current theme paints a caret on one
/// side of the selection, this is the location at which to paint the caret.
///
/// Might be larger than, smaller than, or equal to base.
final int extentOffset;
/// If the text range is collapsed and has more than one visual location
/// (e.g., occurs at a line break), which of the two locations to use when
/// painting the caret.
final TextAffinity affinity;
/// Whether this selection has disambiguated its base and extent.
///
/// On some platforms, the base and extent are not disambiguated until the
/// first time the user adjusts the selection. At that point, either the start
/// or the end of the selection becomes the base and the other one becomes the
/// extent and is adjusted.
final bool isDirectional;
/// The position at which the selection originates.
///
/// Might be larger than, smaller than, or equal to extent.
TextPosition get base => TextPosition(offset: baseOffset, affinity: affinity);
/// The position at which the selection terminates.
///
/// When the user uses the arrow keys to adjust the selection, this is the
/// value that changes. Similarly, if the current theme paints a caret on one
/// side of the selection, this is the location at which to paint the caret.
///
/// Might be larger than, smaller than, or equal to base.
TextPosition get extent => TextPosition(offset: extentOffset, affinity: affinity);
@override
String toString() {
return '${objectRuntimeType(this, 'TextSelection')}(baseOffset: $baseOffset, extentOffset: $extentOffset, affinity: $affinity, isDirectional: $isDirectional)';
}
@override
bool operator ==(Object other) {
if (identical(this, other))
return true;
return other is TextSelection
&& other.baseOffset == baseOffset
&& other.extentOffset == extentOffset
&& other.affinity == affinity
&& other.isDirectional == isDirectional;
}
@override
int get hashCode => hashValues(
baseOffset.hashCode,
extentOffset.hashCode,
affinity.hashCode,
isDirectional.hashCode,
);
/// Creates a new [TextSelection] based on the current selection, with the
/// provided parameters overridden.
TextSelection copyWith({
int? baseOffset,
int? extentOffset,
TextAffinity? affinity,
bool? isDirectional,
}) {
return TextSelection(
baseOffset: baseOffset ?? this.baseOffset,
extentOffset: extentOffset ?? this.extentOffset,
affinity: affinity ?? this.affinity,
isDirectional: isDirectional ?? this.isDirectional,
);
}
}