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

iOS Text Selection Menu Overflow (#54140)

Adds the ability for the iOS text selection menu to handle items that are too wide for the screen.
parent 57dd045c
...@@ -213,7 +213,7 @@ class _TextSelectionToolbarContainerRenderBox extends RenderProxyBox { ...@@ -213,7 +213,7 @@ class _TextSelectionToolbarContainerRenderBox extends RenderProxyBox {
child.size.height, child.size.height,
)); ));
final _ToolbarParentData childParentData = child.parentData as _ToolbarParentData; final ToolbarItemsParentData childParentData = child.parentData as ToolbarItemsParentData;
childParentData.offset = Offset( childParentData.offset = Offset(
size.width - child.size.width, size.width - child.size.width,
0.0, 0.0,
...@@ -223,7 +223,7 @@ class _TextSelectionToolbarContainerRenderBox extends RenderProxyBox { ...@@ -223,7 +223,7 @@ class _TextSelectionToolbarContainerRenderBox extends RenderProxyBox {
// Paint at the offset set in the parent data. // Paint at the offset set in the parent data.
@override @override
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
final _ToolbarParentData childParentData = child.parentData as _ToolbarParentData; final ToolbarItemsParentData childParentData = child.parentData as ToolbarItemsParentData;
context.paintChild(child, childParentData.offset + offset); context.paintChild(child, childParentData.offset + offset);
} }
...@@ -231,7 +231,7 @@ class _TextSelectionToolbarContainerRenderBox extends RenderProxyBox { ...@@ -231,7 +231,7 @@ class _TextSelectionToolbarContainerRenderBox extends RenderProxyBox {
@override @override
bool hitTestChildren(BoxHitTestResult result, { Offset position }) { bool hitTestChildren(BoxHitTestResult result, { Offset position }) {
// The x, y parameters have the top left of the node's box as the origin. // The x, y parameters have the top left of the node's box as the origin.
final _ToolbarParentData childParentData = child.parentData as _ToolbarParentData; final ToolbarItemsParentData childParentData = child.parentData as ToolbarItemsParentData;
return result.addWithPaintOffset( return result.addWithPaintOffset(
offset: childParentData.offset, offset: childParentData.offset,
position: position, position: position,
...@@ -244,14 +244,14 @@ class _TextSelectionToolbarContainerRenderBox extends RenderProxyBox { ...@@ -244,14 +244,14 @@ class _TextSelectionToolbarContainerRenderBox extends RenderProxyBox {
@override @override
void setupParentData(RenderBox child) { void setupParentData(RenderBox child) {
if (child.parentData is! _ToolbarParentData) { if (child.parentData is! ToolbarItemsParentData) {
child.parentData = _ToolbarParentData(); child.parentData = ToolbarItemsParentData();
} }
} }
@override @override
void applyPaintTransform(RenderObject child, Matrix4 transform) { void applyPaintTransform(RenderObject child, Matrix4 transform) {
final _ToolbarParentData childParentData = child.parentData as _ToolbarParentData; final ToolbarItemsParentData childParentData = child.parentData as ToolbarItemsParentData;
transform.translate(childParentData.offset.dx, childParentData.offset.dy); transform.translate(childParentData.offset.dx, childParentData.offset.dy);
super.applyPaintTransform(child, transform); super.applyPaintTransform(child, transform);
} }
...@@ -292,24 +292,13 @@ class _TextSelectionToolbarItems extends MultiChildRenderObjectWidget { ...@@ -292,24 +292,13 @@ class _TextSelectionToolbarItems extends MultiChildRenderObjectWidget {
_TextSelectionToolbarItemsElement createElement() => _TextSelectionToolbarItemsElement(this); _TextSelectionToolbarItemsElement createElement() => _TextSelectionToolbarItemsElement(this);
} }
class _ToolbarParentData extends ContainerBoxParentData<RenderBox> {
/// Whether or not this child is painted.
///
/// Children in the selection toolbar may be laid out for measurement purposes
/// but not painted. This allows these children to be identified.
bool shouldPaint;
@override
String toString() => '${super.toString()}; shouldPaint=$shouldPaint';
}
class _TextSelectionToolbarItemsElement extends MultiChildRenderObjectElement { class _TextSelectionToolbarItemsElement extends MultiChildRenderObjectElement {
_TextSelectionToolbarItemsElement( _TextSelectionToolbarItemsElement(
MultiChildRenderObjectWidget widget, MultiChildRenderObjectWidget widget,
) : super(widget); ) : super(widget);
static bool _shouldPaint(Element child) { static bool _shouldPaint(Element child) {
return (child.renderObject.parentData as _ToolbarParentData).shouldPaint; return (child.renderObject.parentData as ToolbarItemsParentData).shouldPaint;
} }
@override @override
...@@ -318,7 +307,7 @@ class _TextSelectionToolbarItemsElement extends MultiChildRenderObjectElement { ...@@ -318,7 +307,7 @@ class _TextSelectionToolbarItemsElement extends MultiChildRenderObjectElement {
} }
} }
class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRenderObjectMixin<RenderBox, _ToolbarParentData> { class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRenderObjectMixin<RenderBox, ToolbarItemsParentData> {
_TextSelectionToolbarItemsRenderBox({ _TextSelectionToolbarItemsRenderBox({
@required bool isAbove, @required bool isAbove,
@required bool overflowOpen, @required bool overflowOpen,
...@@ -425,7 +414,7 @@ class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRender ...@@ -425,7 +414,7 @@ class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRender
i++; i++;
final RenderBox child = renderObjectChild as RenderBox; final RenderBox child = renderObjectChild as RenderBox;
final _ToolbarParentData childParentData = child.parentData as _ToolbarParentData; final ToolbarItemsParentData childParentData = child.parentData as ToolbarItemsParentData;
// Handle placing the navigation button after iterating all children. // Handle placing the navigation button after iterating all children.
if (renderObjectChild == navButton) { if (renderObjectChild == navButton) {
...@@ -457,7 +446,7 @@ class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRender ...@@ -457,7 +446,7 @@ class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRender
}); });
// Place the navigation button if needed. // Place the navigation button if needed.
final _ToolbarParentData navButtonParentData = navButton.parentData as _ToolbarParentData; final ToolbarItemsParentData navButtonParentData = navButton.parentData as ToolbarItemsParentData;
if (_shouldPaintChild(firstChild, 0)) { if (_shouldPaintChild(firstChild, 0)) {
navButtonParentData.shouldPaint = true; navButtonParentData.shouldPaint = true;
if (overflowOpen) { if (overflowOpen) {
...@@ -495,7 +484,7 @@ class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRender ...@@ -495,7 +484,7 @@ class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRender
void paint(PaintingContext context, Offset offset) { void paint(PaintingContext context, Offset offset) {
visitChildren((RenderObject renderObjectChild) { visitChildren((RenderObject renderObjectChild) {
final RenderBox child = renderObjectChild as RenderBox; final RenderBox child = renderObjectChild as RenderBox;
final _ToolbarParentData childParentData = child.parentData as _ToolbarParentData; final ToolbarItemsParentData childParentData = child.parentData as ToolbarItemsParentData;
if (!childParentData.shouldPaint) { if (!childParentData.shouldPaint) {
return; return;
} }
...@@ -506,8 +495,8 @@ class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRender ...@@ -506,8 +495,8 @@ class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRender
@override @override
void setupParentData(RenderBox child) { void setupParentData(RenderBox child) {
if (child.parentData is! _ToolbarParentData) { if (child.parentData is! ToolbarItemsParentData) {
child.parentData = _ToolbarParentData(); child.parentData = ToolbarItemsParentData();
} }
} }
...@@ -516,7 +505,7 @@ class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRender ...@@ -516,7 +505,7 @@ class _TextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRender
// The x, y parameters have the top left of the node's box as the origin. // The x, y parameters have the top left of the node's box as the origin.
RenderBox child = lastChild; RenderBox child = lastChild;
while (child != null) { while (child != null) {
final _ToolbarParentData childParentData = child.parentData as _ToolbarParentData; final ToolbarItemsParentData childParentData = child.parentData as ToolbarItemsParentData;
// Don't hit test children aren't shown. // Don't hit test children aren't shown.
if (!childParentData.shouldPaint) { if (!childParentData.shouldPaint) {
......
...@@ -85,6 +85,22 @@ typedef TextSelectionOverlayChanged = void Function(TextEditingValue value, Rect ...@@ -85,6 +85,22 @@ typedef TextSelectionOverlayChanged = void Function(TextEditingValue value, Rect
/// having to store the start position. /// having to store the start position.
typedef DragSelectionUpdateCallback = void Function(DragStartDetails startDetails, DragUpdateDetails updateDetails); typedef DragSelectionUpdateCallback = void Function(DragStartDetails startDetails, DragUpdateDetails updateDetails);
/// ParentData that determines whether or not to paint the corresponding child.
///
/// Used in the layout of the Cupertino and Material text selection menus, which
/// decide whether or not to paint their buttons after laying them out and
/// determining where they overflow.
class ToolbarItemsParentData extends ContainerBoxParentData<RenderBox> {
/// Whether or not this child is painted.
///
/// Children in the selection toolbar may be laid out for measurement purposes
/// but not painted. This allows these children to be identified.
bool shouldPaint = false;
@override
String toString() => '${super.toString()}; shouldPaint=$shouldPaint';
}
/// An interface for building the selection UI, to be provided by the /// An interface for building the selection UI, to be provided by the
/// implementor of the toolbar widget. /// implementor of the toolbar widget.
/// ///
......
...@@ -17,8 +17,8 @@ import 'package:flutter/gestures.dart' show DragStartBehavior, PointerDeviceKind ...@@ -17,8 +17,8 @@ import 'package:flutter/gestures.dart' show DragStartBehavior, PointerDeviceKind
import '../rendering/mock_canvas.dart'; import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
import '../widgets/text.dart' show findRenderEditable, globalize, textOffsetToPosition;
import 'feedback_tester.dart'; import 'feedback_tester.dart';
import 'text.dart' show findRenderEditable, globalize, textOffsetToPosition;
class MockClipboard { class MockClipboard {
Object _clipboardData = <String, dynamic>{ Object _clipboardData = <String, dynamic>{
......
...@@ -6,7 +6,7 @@ import 'package:flutter_test/flutter_test.dart'; ...@@ -6,7 +6,7 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'text.dart' show findRenderEditable, globalize, textOffsetToPosition; import '../widgets/text.dart' show findRenderEditable, globalize, textOffsetToPosition;
void main() { void main() {
group('canSelectAll', () { group('canSelectAll', () {
......
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