Unverified Commit fb3dba74 authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Correct text selection pivot points (#71756)

parent a42aa048
...@@ -678,6 +678,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { ...@@ -678,6 +678,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
newSelection = newSelection.copyWith(extentOffset: textSelection.extentOffset); newSelection = newSelection.copyWith(extentOffset: textSelection.extentOffset);
} }
} else { } else {
// The directional arrows move the TextSelection.extentOffset, while the
// base remains fixed.
if (rightArrow && newSelection.extentOffset < _plainText.length) { if (rightArrow && newSelection.extentOffset < _plainText.length) {
int nextExtent; int nextExtent;
if (!shift && !wordModifier && !lineModifier && newSelection.start != newSelection.end) { if (!shift && !wordModifier && !lineModifier && newSelection.start != newSelection.end) {
...@@ -1849,6 +1851,9 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { ...@@ -1849,6 +1851,9 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
} }
/// Select text between the global positions [from] and [to]. /// Select text between the global positions [from] and [to].
///
/// [from] corresponds to the [TextSelection.baseOffset], and [to] corresponds
/// to the [TextSelection.extentOffset].
void selectPositionAt({ required Offset from, Offset? to, required SelectionChangedCause cause }) { void selectPositionAt({ required Offset from, Offset? to, required SelectionChangedCause cause }) {
assert(cause != null); assert(cause != null);
assert(from != null); assert(from != null);
...@@ -1861,12 +1866,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { ...@@ -1861,12 +1866,8 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin {
? null ? null
: _textPainter.getPositionForOffset(globalToLocal(to - _paintOffset)); : _textPainter.getPositionForOffset(globalToLocal(to - _paintOffset));
int baseOffset = fromPosition.offset; final int baseOffset = fromPosition.offset;
int extentOffset = fromPosition.offset; final int extentOffset = toPosition?.offset ?? fromPosition.offset;
if (toPosition != null) {
baseOffset = math.min(fromPosition.offset, toPosition.offset);
extentOffset = math.max(fromPosition.offset, toPosition.offset);
}
final TextSelection newSelection = TextSelection( final TextSelection newSelection = TextSelection(
baseOffset: baseOffset, baseOffset: baseOffset,
......
...@@ -1458,8 +1458,8 @@ void main() { ...@@ -1458,8 +1458,8 @@ void main() {
await gesture.up(); await gesture.up();
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(controller.selection.baseOffset, testValue.indexOf('e')); expect(controller.selection.baseOffset, testValue.indexOf('g'));
expect(controller.selection.extentOffset, testValue.indexOf('g')); expect(controller.selection.extentOffset, testValue.indexOf('e'));
}); });
testWidgets('Slow mouse dragging also selects text', (WidgetTester tester) async { testWidgets('Slow mouse dragging also selects text', (WidgetTester tester) async {
......
...@@ -570,8 +570,8 @@ void main() { ...@@ -570,8 +570,8 @@ void main() {
pumpFrame(); pumpFrame();
expect(currentSelection.isCollapsed, isFalse); expect(currentSelection.isCollapsed, isFalse);
expect(currentSelection.baseOffset, 1); expect(currentSelection.baseOffset, 3);
expect(currentSelection.extentOffset, 3); expect(currentSelection.extentOffset, 1);
}); });
test('selection does not flicker as user is dragging', () { test('selection does not flicker as user is dragging', () {
...@@ -1006,7 +1006,79 @@ void main() { ...@@ -1006,7 +1006,79 @@ void main() {
await simulateKeyUpEvent(LogicalKeyboardKey.arrowLeft); await simulateKeyUpEvent(LogicalKeyboardKey.arrowLeft);
expect(currentSelection.isCollapsed, true); expect(currentSelection.isCollapsed, true);
expect(currentSelection.baseOffset, 2); expect(currentSelection.baseOffset, 2);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/58068
test('arrow keys with selection text and shift', () async {
final TextSelectionDelegate delegate = FakeEditableTextState();
final ViewportOffset viewportOffset = ViewportOffset.zero();
late TextSelection currentSelection;
final RenderEditable editable = RenderEditable(
backgroundCursorColor: Colors.grey,
selectionColor: Colors.black,
textDirection: TextDirection.ltr,
cursorColor: Colors.red,
offset: viewportOffset,
textSelectionDelegate: delegate,
onSelectionChanged: (TextSelection selection, RenderEditable renderObject, SelectionChangedCause cause) {
currentSelection = selection;
},
startHandleLayerLink: LayerLink(),
endHandleLayerLink: LayerLink(),
text: const TextSpan(
text: '012345', // Thumbs up
style: TextStyle(height: 1.0, fontSize: 10.0, fontFamily: 'Ahem'),
),
selection: const TextSelection.collapsed(
offset: 0,
),
);
layout(editable);
editable.hasFocus = true;
editable.selection = const TextSelection(baseOffset: 2, extentOffset: 4);
pumpFrame();
await simulateKeyDownEvent(LogicalKeyboardKey.shift);
await simulateKeyDownEvent(LogicalKeyboardKey.arrowRight);
await simulateKeyUpEvent(LogicalKeyboardKey.arrowRight);
await simulateKeyUpEvent(LogicalKeyboardKey.shift);
expect(currentSelection.isCollapsed, false);
expect(currentSelection.baseOffset, 2);
expect(currentSelection.extentOffset, 5);
editable.selection = const TextSelection(baseOffset: 4, extentOffset: 2);
pumpFrame();
await simulateKeyDownEvent(LogicalKeyboardKey.shift);
await simulateKeyDownEvent(LogicalKeyboardKey.arrowRight);
await simulateKeyUpEvent(LogicalKeyboardKey.arrowRight);
await simulateKeyUpEvent(LogicalKeyboardKey.shift);
expect(currentSelection.isCollapsed, false);
expect(currentSelection.baseOffset, 4);
expect(currentSelection.extentOffset, 3);
editable.selection = const TextSelection(baseOffset: 2, extentOffset: 4);
pumpFrame();
await simulateKeyDownEvent(LogicalKeyboardKey.shift);
await simulateKeyDownEvent(LogicalKeyboardKey.arrowLeft);
await simulateKeyUpEvent(LogicalKeyboardKey.arrowLeft);
await simulateKeyUpEvent(LogicalKeyboardKey.shift);
expect(currentSelection.isCollapsed, false);
expect(currentSelection.baseOffset, 2);
expect(currentSelection.extentOffset, 3);
editable.selection = const TextSelection(baseOffset: 4, extentOffset: 2);
pumpFrame();
await simulateKeyDownEvent(LogicalKeyboardKey.shift);
await simulateKeyDownEvent(LogicalKeyboardKey.arrowLeft);
await simulateKeyUpEvent(LogicalKeyboardKey.arrowLeft);
await simulateKeyUpEvent(LogicalKeyboardKey.shift);
expect(currentSelection.isCollapsed, false);
expect(currentSelection.baseOffset, 4);
expect(currentSelection.extentOffset, 1);
}, skip: isBrowser); // https://github.com/flutter/flutter/issues/58068 }, skip: isBrowser); // https://github.com/flutter/flutter/issues/58068
group('delete', () { group('delete', () {
......
...@@ -765,8 +765,8 @@ void main() { ...@@ -765,8 +765,8 @@ void main() {
await gesture.up(); await gesture.up();
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(controller.selection.baseOffset, 5); expect(controller.selection.baseOffset, 8);
expect(controller.selection.extentOffset, 8); expect(controller.selection.extentOffset, 5);
}); });
testWidgets('Slow mouse dragging also selects text', (WidgetTester tester) async { testWidgets('Slow mouse dragging also selects text', (WidgetTester tester) async {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment