fzhangtj
6 年前
当前提交
2887412b
共有 26 个文件被更改,包括 1421 次插入 和 51 次删除
-
2Runtime/debugger/inspector_treeview.cs
-
17Runtime/gestures/multitap.cs
-
35Runtime/painting/matrix_utils.cs
-
35Runtime/rendering/editable.cs
-
198Runtime/rendering/layer.cs
-
2Runtime/rendering/object.cs
-
142Runtime/rendering/proxy_box.cs
-
98Runtime/rendering/shifted_box.cs
-
9Runtime/service/text_input.cs
-
75Runtime/widgets/basic.cs
-
4Runtime/widgets/custom_paint.cs
-
111Runtime/widgets/editable_text.cs
-
2Runtime/widgets/framework.cs
-
1Runtime/widgets/page_view.cs
-
2Samples/ReduxSample/ObjectFinder/ObjectFinderApp.cs
-
2Samples/ReduxSample/ObjectFinder/Reducer.cs
-
2Samples/UIWidgetSample/AsScreenCanvas.cs
-
13Samples/UIWidgetSample/TextInputCanvas.cs
-
2Samples/UIWidgetSample/ToDoAppCanvas.cs
-
2Tests/Editor/EditableTextWiget.cs
-
2Tests/Editor/Gestures.cs
-
14Tests/Editor/Widgets.cs
-
42Runtime/service/clipboard.cs
-
439Runtime/widgets/text_selection.cs
-
221Runtime/material/text_selection.cs
|
|||
using Unity.UIWidgets.ui; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.ui; |
|||
|
|||
} |
|||
|
|||
public static List<string> debugDescribeTransform(Matrix3 transform) { |
|||
if (transform == null) |
|||
return new List<string> {"null"}; |
|||
|
|||
List<string> result = new List<string>(3); |
|||
for (int i = 0; i < 3; i++) { |
|||
result.Add($"[{i}] {transform[i * 3]}, {transform[i * 3 + 1]}, {transform[i * 3 + 2]}"); |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
} |
|||
|
|||
public class TransformProperty : DiagnosticsProperty<Matrix3> { |
|||
|
|||
public TransformProperty(string name, Matrix3 value, |
|||
bool showName = true, |
|||
object defaultValue = null, |
|||
DiagnosticLevel level = DiagnosticLevel.info |
|||
): base(name, value, showName: showName, defaultValue: defaultValue??Diagnostics.kNoDefaultValue, level: level) { |
|||
} |
|||
|
|||
protected override string valueToString(TextTreeConfiguration parentConfiguration = null) { |
|||
if (parentConfiguration != null && !parentConfiguration.lineBreakProperties) { |
|||
return this.value == null ? "null" : this.value.ToString(); |
|||
} |
|||
|
|||
return string.Join("\n", MatrixUtils.debugDescribeTransform(this.value)); |
|||
} |
|||
} |
|||
} |
|
|||
using RSG; |
|||
using UnityEngine; |
|||
|
|||
namespace Unity.UIWidgets.service { |
|||
public class ClipboardData { |
|||
public ClipboardData(string text = null) { |
|||
this.text = text; |
|||
} |
|||
|
|||
public readonly string text; |
|||
} |
|||
|
|||
public abstract class Clipboard { |
|||
static readonly Clipboard _instance = new UnityGUIClipboard(); |
|||
|
|||
public static readonly string kTextPlain = "text/plain"; |
|||
|
|||
public static IPromise setData(ClipboardData data) { |
|||
return _instance.setClipboardData(data); |
|||
} |
|||
|
|||
public static IPromise<ClipboardData> getData(string format) { |
|||
return _instance.getClipboardData(format); |
|||
} |
|||
|
|||
protected abstract IPromise setClipboardData(ClipboardData data); |
|||
protected abstract IPromise<ClipboardData> getClipboardData(string format); |
|||
} |
|||
|
|||
public class UnityGUIClipboard : Clipboard { |
|||
|
|||
protected override IPromise setClipboardData(ClipboardData data) { |
|||
GUIUtility.systemCopyBuffer = data.text; |
|||
return Promise.Resolved(); |
|||
} |
|||
|
|||
protected override IPromise<ClipboardData> getClipboardData(string format) { |
|||
var data = new ClipboardData(text: GUIUtility.systemCopyBuffer); |
|||
return Promise<ClipboardData>.Resolved(data); |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.animation; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.scheduler; |
|||
using Unity.UIWidgets.service; |
|||
using Unity.UIWidgets.ui; |
|||
|
|||
namespace Unity.UIWidgets.widgets { |
|||
public enum TextSelectionHandleType { |
|||
left, |
|||
right, |
|||
collapsed, |
|||
} |
|||
|
|||
internal enum _TextSelectionHandlePosition { |
|||
start, |
|||
end |
|||
} |
|||
|
|||
public delegate void TextSelectionOverlayChanged(TextEditingValue value, Rect caretRect); |
|||
|
|||
public abstract class TextSelectionControls { |
|||
public abstract Widget buildHandle(BuildContext context, TextSelectionHandleType type, double textLineHeight); |
|||
|
|||
public abstract Widget buildToolbar(BuildContext context, Rect globalEditableRegion, Offset position, |
|||
TextSelectionDelegate selectionDelegate); |
|||
|
|||
public abstract Size handleSize { get; } |
|||
|
|||
public virtual bool canCut(TextSelectionDelegate selectionDelegate) { |
|||
return !selectionDelegate.textEditingValue.selection.isCollapsed; |
|||
} |
|||
|
|||
public virtual bool canCopy(TextSelectionDelegate selectionDelegate) { |
|||
return !selectionDelegate.textEditingValue.selection.isCollapsed; |
|||
} |
|||
|
|||
public virtual bool canPaste(TextSelectionDelegate selectionDelegate) { |
|||
// TODO in flutter: return false when clipboard is empty
|
|||
return true; |
|||
} |
|||
|
|||
public virtual bool canSelectAll(TextSelectionDelegate selectionDelegate) { |
|||
return selectionDelegate.textEditingValue.text.isEmpty() && |
|||
selectionDelegate.textEditingValue.selection.isCollapsed; |
|||
} |
|||
|
|||
public void handleCut(TextSelectionDelegate selectionDelegate) { |
|||
TextEditingValue value = selectionDelegate.textEditingValue; |
|||
Clipboard.setData(new ClipboardData( |
|||
text: value.selection.textInside(value.text) |
|||
)); |
|||
selectionDelegate.textEditingValue = new TextEditingValue( |
|||
text: value.selection.textBefore(value.text) |
|||
+ value.selection.textAfter(value.text), |
|||
selection: TextSelection.collapsed( |
|||
offset: value.selection.start |
|||
) |
|||
); |
|||
selectionDelegate.bringIntoView(selectionDelegate.textEditingValue.selection.extendPos); |
|||
selectionDelegate.hideToolbar(); |
|||
} |
|||
|
|||
public void handleCopy(TextSelectionDelegate selectionDelegate) { |
|||
TextEditingValue value = selectionDelegate.textEditingValue; |
|||
Clipboard.setData(new ClipboardData( |
|||
text: value.selection.textInside(value.text) |
|||
)); |
|||
selectionDelegate.textEditingValue = new TextEditingValue( |
|||
text: value.text, |
|||
selection: TextSelection.collapsed(offset: value.selection.end) |
|||
); |
|||
selectionDelegate.bringIntoView(selectionDelegate.textEditingValue.selection.extendPos); |
|||
selectionDelegate.hideToolbar(); |
|||
} |
|||
|
|||
public void handlePaste(TextSelectionDelegate selectionDelegate) { |
|||
TextEditingValue value = selectionDelegate.textEditingValue; // Snapshot the input before using `await`.
|
|||
Clipboard.getData(Clipboard.kTextPlain).Then((data) => { |
|||
if (data != null) { |
|||
selectionDelegate.textEditingValue = new TextEditingValue( |
|||
text: value.selection.textBefore(value.text) |
|||
+ data.text |
|||
+ value.selection.textAfter(value.text), |
|||
selection: TextSelection.collapsed( |
|||
offset: value.selection.start + data.text.Length |
|||
) |
|||
); |
|||
|
|||
} |
|||
selectionDelegate.bringIntoView(selectionDelegate.textEditingValue.selection.extendPos); |
|||
selectionDelegate.hideToolbar(); |
|||
}); |
|||
} |
|||
|
|||
public void handleSelectAll(TextSelectionDelegate selectionDelegate) { |
|||
selectionDelegate.textEditingValue = new TextEditingValue( |
|||
text: selectionDelegate.textEditingValue.text, |
|||
selection: new TextSelection( |
|||
baseOffset: 0, |
|||
extentOffset: selectionDelegate.textEditingValue.text.Length |
|||
) |
|||
); |
|||
selectionDelegate.bringIntoView(selectionDelegate.textEditingValue.selection.extendPos); |
|||
} |
|||
} |
|||
|
|||
public class TextSelectionOverlay { |
|||
|
|||
public TextSelectionOverlay(TextEditingValue value = null, |
|||
BuildContext context = null, Widget debugRequiredFor = null, |
|||
LayerLink layerLink = null, |
|||
RenderEditable renderObject = null, |
|||
TextSelectionControls selectionControls = null, |
|||
TextSelectionDelegate selectionDelegate = null) { |
|||
|
|||
D.assert(value != null); |
|||
D.assert(context != null); |
|||
this.context = context; |
|||
this.debugRequiredFor = debugRequiredFor; |
|||
this.layerLink = layerLink; |
|||
this.renderObject = renderObject; |
|||
this.selectionControls = selectionControls; |
|||
this.selectionDelegate = selectionDelegate; |
|||
this._value = value; |
|||
OverlayState overlay = Overlay.of(context); |
|||
D.assert(overlay != null); |
|||
this._handleController = new AnimationController(duration: _fadeDuration, vsync: overlay); |
|||
this._toolbarController = new AnimationController(duration: _fadeDuration, vsync: overlay); |
|||
} |
|||
|
|||
public readonly BuildContext context; |
|||
public readonly Widget debugRequiredFor; |
|||
public readonly LayerLink layerLink; |
|||
public readonly RenderEditable renderObject; |
|||
public readonly TextSelectionControls selectionControls; |
|||
public readonly TextSelectionDelegate selectionDelegate; |
|||
|
|||
public static TimeSpan _fadeDuration = TimeSpan.FromMilliseconds(150); |
|||
AnimationController _handleController; |
|||
AnimationController _toolbarController; |
|||
|
|||
Animation<double> _handleOpacity => this._handleController.view; |
|||
Animation<double> _toolbarOpacity => this._toolbarController.view; |
|||
|
|||
TextEditingValue _value; |
|||
|
|||
List<OverlayEntry> _handles; |
|||
|
|||
OverlayEntry _toolbar; |
|||
|
|||
TextSelection _selection => this._value.selection; |
|||
|
|||
public void showHandles() { |
|||
D.assert(this._handles == null); |
|||
this._handles = new List<OverlayEntry> { |
|||
new OverlayEntry(builder: (BuildContext context) => |
|||
this._buildHandle(context, _TextSelectionHandlePosition.start)), |
|||
new OverlayEntry(builder: (BuildContext context) => |
|||
this._buildHandle(context, _TextSelectionHandlePosition.end)), |
|||
}; |
|||
Overlay.of(this.context, debugRequiredFor: this.debugRequiredFor).insertAll(this._handles); |
|||
this._handleController.forward(from: 0.0); |
|||
} |
|||
|
|||
public void showToolbar() { |
|||
D.assert(this._toolbar == null); |
|||
this._toolbar = new OverlayEntry(builder: this._buildToolbar); |
|||
Overlay.of(this.context, debugRequiredFor: this.debugRequiredFor).insert(this._toolbar); |
|||
this._toolbarController.forward(from: 0.0); |
|||
} |
|||
|
|||
public void update(TextEditingValue newValue) { |
|||
if (this._value == newValue) |
|||
return; |
|||
this._value = newValue; |
|||
if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) { |
|||
SchedulerBinding.instance.addPostFrameCallback((duration) => this._markNeedsBuild()); |
|||
} |
|||
else { |
|||
this._markNeedsBuild(); |
|||
} |
|||
} |
|||
|
|||
public void updateForScroll() { |
|||
this._markNeedsBuild(); |
|||
} |
|||
|
|||
void _markNeedsBuild() { |
|||
if (this._handles != null) { |
|||
this._handles[0].markNeedsBuild(); |
|||
this._handles[1].markNeedsBuild(); |
|||
} |
|||
|
|||
this._toolbar?.markNeedsBuild(); |
|||
} |
|||
|
|||
public bool handlesAreVisible => this._handles != null; |
|||
|
|||
|
|||
public bool toolbarIsVisible => this._toolbar != null; |
|||
|
|||
public void hide() { |
|||
if (this._handles != null) { |
|||
this._handles[0].remove(); |
|||
this._handles[1].remove(); |
|||
this._handles = null; |
|||
} |
|||
|
|||
this._toolbar?.remove(); |
|||
this._toolbar = null; |
|||
|
|||
this._handleController.stop(); |
|||
this._toolbarController.stop(); |
|||
} |
|||
|
|||
public void dispose() { |
|||
this.hide(); |
|||
this._handleController.dispose(); |
|||
this._toolbarController.dispose(); |
|||
} |
|||
|
|||
Widget _buildHandle(BuildContext context, _TextSelectionHandlePosition position) { |
|||
if ((this._selection.isCollapsed && position == _TextSelectionHandlePosition.end) || |
|||
this.selectionControls == null) |
|||
return new Container(); // hide the second handle when collapsed
|
|||
|
|||
return new FadeTransition( |
|||
opacity: this._handleOpacity, |
|||
child: new _TextSelectionHandleOverlay( |
|||
onSelectionHandleChanged: (TextSelection newSelection) => { |
|||
this._handleSelectionHandleChanged(newSelection, position); |
|||
}, |
|||
onSelectionHandleTapped: this._handleSelectionHandleTapped, |
|||
layerLink: this.layerLink, |
|||
renderObject: this.renderObject, |
|||
selection: this._selection, |
|||
selectionControls: this.selectionControls, |
|||
position: position |
|||
) |
|||
); |
|||
} |
|||
|
|||
Widget _buildToolbar(BuildContext context) { |
|||
if (this.selectionControls == null) |
|||
return new Container(); |
|||
|
|||
// Find the horizontal midpoint, just above the selected text.
|
|||
List<TextSelectionPoint> endpoints = this.renderObject.getEndpointsForSelection(this._selection); |
|||
Offset midpoint = new Offset( |
|||
(endpoints.Count == 1) ? endpoints[0].point.dx : (endpoints[0].point.dx + endpoints[1].point.dx) / 2.0, |
|||
endpoints[0].point.dy - this.renderObject.preferredLineHeight |
|||
); |
|||
|
|||
Rect editingRegion = Rect.fromPoints(this.renderObject.localToGlobal(Offset.zero), |
|||
this.renderObject.localToGlobal(this.renderObject.size.bottomRight(Offset.zero)) |
|||
); |
|||
|
|||
return new FadeTransition( |
|||
opacity: this._toolbarOpacity, |
|||
child: new CompositedTransformFollower( |
|||
link: this.layerLink, |
|||
showWhenUnlinked: false, |
|||
offset: -editingRegion.topLeft, |
|||
child: this.selectionControls.buildToolbar(context, editingRegion, midpoint, this.selectionDelegate) |
|||
) |
|||
); |
|||
} |
|||
|
|||
void _handleSelectionHandleChanged(TextSelection newSelection, _TextSelectionHandlePosition position) { |
|||
TextPosition textPosition = null; |
|||
switch (position) { |
|||
case _TextSelectionHandlePosition.start: |
|||
textPosition = newSelection.basePos; |
|||
break; |
|||
case _TextSelectionHandlePosition.end: |
|||
textPosition = newSelection.extendPos; |
|||
break; |
|||
} |
|||
|
|||
this.selectionDelegate.textEditingValue = |
|||
this._value.copyWith(selection: newSelection, composing: TextRange.empty); |
|||
this.selectionDelegate.bringIntoView(textPosition); |
|||
} |
|||
|
|||
void _handleSelectionHandleTapped() { |
|||
if (this._value.selection.isCollapsed) { |
|||
if (this._toolbar != null) { |
|||
this._toolbar?.remove(); |
|||
this._toolbar = null; |
|||
} |
|||
else { |
|||
this.showToolbar(); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
internal class _TextSelectionHandleOverlay : StatefulWidget { |
|||
internal _TextSelectionHandleOverlay( |
|||
Key key = null, |
|||
TextSelection selection = null, |
|||
_TextSelectionHandlePosition position = _TextSelectionHandlePosition.start, |
|||
LayerLink layerLink = null, |
|||
RenderEditable renderObject = null, |
|||
ValueChanged<TextSelection> onSelectionHandleChanged = null, |
|||
VoidCallback onSelectionHandleTapped = null, |
|||
TextSelectionControls selectionControls = null |
|||
) : base(key: key) { |
|||
this.selection = selection; |
|||
this.position = position; |
|||
this.layerLink = layerLink; |
|||
this.renderObject = renderObject; |
|||
this.onSelectionHandleChanged = onSelectionHandleChanged; |
|||
this.onSelectionHandleTapped = onSelectionHandleTapped; |
|||
this.selectionControls = selectionControls; |
|||
} |
|||
|
|||
public readonly TextSelection selection; |
|||
public readonly _TextSelectionHandlePosition position; |
|||
public readonly LayerLink layerLink; |
|||
public readonly RenderEditable renderObject; |
|||
public readonly ValueChanged<TextSelection> onSelectionHandleChanged; |
|||
public readonly VoidCallback onSelectionHandleTapped; |
|||
public readonly TextSelectionControls selectionControls; |
|||
|
|||
|
|||
public override State createState() { |
|||
return new _TextSelectionHandleOverlayState(); |
|||
} |
|||
} |
|||
|
|||
internal class _TextSelectionHandleOverlayState : State<_TextSelectionHandleOverlay> { |
|||
Offset _dragPosition; |
|||
|
|||
void _handleDragStart(DragStartDetails details) { |
|||
this._dragPosition = details.globalPosition + |
|||
new Offset(0.0, -this.widget.selectionControls.handleSize.height); |
|||
} |
|||
|
|||
void _handleDragUpdate(DragUpdateDetails details) { |
|||
this._dragPosition += details.delta; |
|||
TextPosition position = this.widget.renderObject.getPositionForPoint(this._dragPosition); |
|||
|
|||
if (this.widget.selection.isCollapsed) { |
|||
this.widget.onSelectionHandleChanged(TextSelection.fromPosition(position)); |
|||
return; |
|||
} |
|||
|
|||
TextSelection newSelection = null; |
|||
switch (this.widget.position) { |
|||
case _TextSelectionHandlePosition.start: |
|||
newSelection = new TextSelection( |
|||
baseOffset: position.offset, |
|||
extentOffset: this.widget.selection.extentOffset |
|||
); |
|||
break; |
|||
case _TextSelectionHandlePosition.end: |
|||
newSelection = new TextSelection( |
|||
baseOffset: this.widget.selection.baseOffset, |
|||
extentOffset: position.offset |
|||
); |
|||
break; |
|||
} |
|||
|
|||
if (newSelection.baseOffset >= newSelection.extentOffset) |
|||
return; // don't allow order swapping.
|
|||
|
|||
this.widget.onSelectionHandleChanged(newSelection); |
|||
} |
|||
|
|||
void _handleTap() { |
|||
this.widget.onSelectionHandleTapped(); |
|||
} |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
List<TextSelectionPoint> endpoints = |
|||
this.widget.renderObject.getEndpointsForSelection(this.widget.selection); |
|||
Offset point = null; |
|||
TextSelectionHandleType type = TextSelectionHandleType.left; |
|||
|
|||
switch (this.widget.position) { |
|||
case _TextSelectionHandlePosition.start: |
|||
point = endpoints[0].point; |
|||
type = this._chooseType(endpoints[0], TextSelectionHandleType.left, TextSelectionHandleType.right); |
|||
break; |
|||
case _TextSelectionHandlePosition.end: |
|||
D.assert(endpoints.Count == 2); |
|||
point = endpoints[1].point; |
|||
type = this._chooseType(endpoints[1], TextSelectionHandleType.right, TextSelectionHandleType.left); |
|||
break; |
|||
} |
|||
|
|||
return new CompositedTransformFollower( |
|||
link: this.widget.layerLink, |
|||
showWhenUnlinked: false, |
|||
child: new GestureDetector( |
|||
onPanStart: this._handleDragStart, |
|||
onPanUpdate: this._handleDragUpdate, |
|||
onTap: this._handleTap, |
|||
child: new Stack( |
|||
overflow: Overflow.visible, |
|||
children: new List<Widget>() { |
|||
new Positioned( |
|||
left: point.dx, |
|||
top: point.dy, |
|||
child: this.widget.selectionControls.buildHandle(context, type, |
|||
this.widget.renderObject.preferredLineHeight) |
|||
) |
|||
} |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
TextSelectionHandleType _chooseType( |
|||
TextSelectionPoint endpoint, |
|||
TextSelectionHandleType ltrType, |
|||
TextSelectionHandleType rtlType |
|||
) { |
|||
if (this.widget.selection.isCollapsed) |
|||
return TextSelectionHandleType.collapsed; |
|||
|
|||
D.assert(endpoint.direction != null); |
|||
switch (endpoint.direction) { |
|||
case TextDirection.ltr: |
|||
return ltrType; |
|||
case TextDirection.rtl: |
|||
return rtlType; |
|||
} |
|||
|
|||
D.assert(() => throw new UIWidgetsError($"invalid endpoint.direction {endpoint.direction}")); |
|||
return ltrType; |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Unity.UIWidgets.foundation; |
|||
using Unity.UIWidgets.gestures; |
|||
using Unity.UIWidgets.painting; |
|||
using Unity.UIWidgets.rendering; |
|||
using Unity.UIWidgets.service; |
|||
using Unity.UIWidgets.ui; |
|||
using Unity.UIWidgets.widgets; |
|||
|
|||
|
|||
// todo using material components: FlatButton & Material ...
|
|||
namespace Unity.UIWidgets.material { |
|||
public static class MaterialUtils { |
|||
public readonly static TextSelectionControls materialTextSelectionControls = |
|||
new _MaterialTextSelectionControls(); |
|||
} |
|||
|
|||
internal static class _TextSelectionUtils { |
|||
internal const double _kHandleSize = 22.0; |
|||
internal const double _kToolbarScreenPadding = 8.0; |
|||
} |
|||
|
|||
internal class _TextSelectionToolbar : StatelessWidget { |
|||
public _TextSelectionToolbar(Key key = null, Action handleCut = null, |
|||
Action handleCopy = null, Action handlePaste = null, Action handleSelectAll = null) : base(key: key) { |
|||
this.handleCut = handleCut; |
|||
this.handleCopy = handleCopy; |
|||
this.handlePaste = handlePaste; |
|||
this.handleSelectAll = handleSelectAll; |
|||
} |
|||
|
|||
public readonly Action handleCut; |
|||
public readonly Action handleCopy; |
|||
public readonly Action handlePaste; |
|||
public readonly Action handleSelectAll; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
List<Widget> items = new List<Widget>(); |
|||
if (this.handleCut != null) { |
|||
items.Add(new _TempButton(onPressed: () => this.handleCut(), child: new Text("Cut"))); |
|||
} |
|||
|
|||
if (this.handleCopy != null) { |
|||
items.Add(new _TempButton(onPressed: () => this.handleCopy(), child: new Text("Copy"))); |
|||
} |
|||
|
|||
if (this.handlePaste != null) { |
|||
items.Add(new _TempButton(onPressed: () => this.handlePaste(), child: new Text("Past"))); |
|||
} |
|||
|
|||
if (this.handleSelectAll != null) { |
|||
items.Add(new _TempButton(onPressed: () => this.handleSelectAll(), child: new Text("Select All"))); |
|||
} |
|||
|
|||
return new Container( |
|||
color: new Color(0xFFEFEFEF), |
|||
height: 44.0, child: new Row(mainAxisSize: MainAxisSize.min, children: items)); |
|||
} |
|||
} |
|||
|
|||
internal class _TextSelectionToolbarLayout : SingleChildLayoutDelegate { |
|||
internal _TextSelectionToolbarLayout(Size screenSize = null, Rect globalEditableRegion = null, |
|||
Offset position = null) { |
|||
this.screenSize = screenSize; |
|||
this.globalEditableRegion = globalEditableRegion; |
|||
this.position = position; |
|||
} |
|||
|
|||
public readonly Size screenSize; |
|||
public readonly Rect globalEditableRegion; |
|||
public readonly Offset position; |
|||
|
|||
public override BoxConstraints getConstraintsForChild(BoxConstraints constraints) { |
|||
return constraints.loosen(); |
|||
} |
|||
|
|||
public override Offset getPositionForChild(Size size, Size childSize) { |
|||
Offset globalPosition = this.globalEditableRegion.topLeft + this.position; |
|||
|
|||
double x = globalPosition.dx - childSize.width / 2.0; |
|||
double y = globalPosition.dy - childSize.height; |
|||
|
|||
if (x < _TextSelectionUtils._kToolbarScreenPadding) |
|||
x = _TextSelectionUtils._kToolbarScreenPadding; |
|||
else if (x + childSize.width > this.screenSize.width - _TextSelectionUtils._kToolbarScreenPadding) |
|||
x = this.screenSize.width - childSize.width - _TextSelectionUtils._kToolbarScreenPadding; |
|||
|
|||
if (y < _TextSelectionUtils._kToolbarScreenPadding) |
|||
y = _TextSelectionUtils._kToolbarScreenPadding; |
|||
else if (y + childSize.height > this.screenSize.height - _TextSelectionUtils._kToolbarScreenPadding) |
|||
y = this.screenSize.height - childSize.height - _TextSelectionUtils._kToolbarScreenPadding; |
|||
|
|||
return new Offset(x, y); |
|||
} |
|||
|
|||
public override bool shouldRelayout(SingleChildLayoutDelegate oldDelegate) { |
|||
return this.position != ((_TextSelectionToolbarLayout) oldDelegate).position; |
|||
} |
|||
} |
|||
|
|||
internal class _TextSelectionHandlePainter : CustomPainter { |
|||
internal _TextSelectionHandlePainter(Color color) { |
|||
this.color = color; |
|||
} |
|||
|
|||
public readonly Color color; |
|||
|
|||
public override void paint(Canvas canvas, Size size) { |
|||
Paint paint = new Paint(); |
|||
paint.color = this.color; |
|||
double radius = size.width / 2.0; |
|||
canvas.drawCircle(new Offset(radius, radius), radius, paint); |
|||
canvas.drawRect(Rect.fromLTWH(0.0, 0.0, radius, radius), paint); |
|||
} |
|||
|
|||
|
|||
public override bool shouldRepaint(CustomPainter oldPainter) { |
|||
return this.color != ((_TextSelectionHandlePainter) oldPainter).color; |
|||
} |
|||
} |
|||
|
|||
internal class _MaterialTextSelectionControls : TextSelectionControls { |
|||
public override Size handleSize { |
|||
get => new Size(_TextSelectionUtils._kHandleSize, |
|||
_TextSelectionUtils._kHandleSize); |
|||
} |
|||
|
|||
public override Widget buildToolbar(BuildContext context, Rect globalEditableRegion, Offset position, |
|||
TextSelectionDelegate selectionDelegate) { |
|||
return new ConstrainedBox( |
|||
constraints: BoxConstraints.tight(globalEditableRegion.size), |
|||
child: new CustomSingleChildLayout( |
|||
layoutDelegate: new _TextSelectionToolbarLayout( |
|||
MediaQuery.of(context).size, |
|||
globalEditableRegion, |
|||
position |
|||
), |
|||
child: new _TextSelectionToolbar( |
|||
handleCut: this.canCut(selectionDelegate) |
|||
? () => this.handleCut(selectionDelegate) |
|||
: (Action) null, |
|||
handleCopy: this.canCopy(selectionDelegate) |
|||
? () => this.handleCopy(selectionDelegate) |
|||
: (Action) null, |
|||
handlePaste: this.canPaste(selectionDelegate) |
|||
? () => this.handlePaste(selectionDelegate) |
|||
: (Action) null, |
|||
handleSelectAll: this.canSelectAll(selectionDelegate) |
|||
? () => this.handleSelectAll(selectionDelegate) |
|||
: (Action) null |
|||
) |
|||
) |
|||
); |
|||
} |
|||
|
|||
public override Widget buildHandle(BuildContext context, TextSelectionHandleType type, double textLineHeight) { |
|||
Widget handle = new Padding( |
|||
padding: EdgeInsets.only(right: 26.0, bottom: 26.0), |
|||
child: new SizedBox( |
|||
width: 20, |
|||
height: 20, |
|||
child: new CustomPaint( |
|||
painter: new _TextSelectionHandlePainter( |
|||
color: new Color(0xFFFF0000) |
|||
) |
|||
) |
|||
) |
|||
); |
|||
|
|||
switch (type) { |
|||
case TextSelectionHandleType.left: // points up-right
|
|||
return new Transform( |
|||
transform: Matrix3.makeRotate(90), |
|||
child: handle |
|||
); |
|||
case TextSelectionHandleType.right: // points up-left
|
|||
return handle; |
|||
case TextSelectionHandleType.collapsed: // points up
|
|||
return new Transform( |
|||
transform: Matrix3.makeRotate(45), |
|||
child: handle |
|||
); |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
|
|||
|
|||
public class _TempButton : StatelessWidget { |
|||
public _TempButton( |
|||
Key key = null, |
|||
GestureTapCallback onPressed = null, |
|||
EdgeInsets padding = null, |
|||
Color backgroundColor = null, |
|||
Widget child = null |
|||
) : base(key: key) { |
|||
this.onPressed = onPressed; |
|||
this.padding = padding ?? EdgeInsets.all(8.0); |
|||
this.backgroundColor = backgroundColor ?? new Color(0); |
|||
this.child = child; |
|||
} |
|||
|
|||
public readonly GestureTapCallback onPressed; |
|||
public readonly EdgeInsets padding; |
|||
public readonly Widget child; |
|||
public readonly Color backgroundColor; |
|||
|
|||
public override Widget build(BuildContext context) { |
|||
return new GestureDetector( |
|||
onTap: this.onPressed, |
|||
child: new Container( |
|||
padding: this.padding, |
|||
color: this.backgroundColor, |
|||
child: this.child |
|||
) |
|||
); |
|||
} |
|||
} |
|||
} |
撰写
预览
正在加载...
取消
保存
Reference in new issue