浏览代码

text selection done

/main
xingwei.zhu 6 年前
当前提交
36d4ed57
共有 8 个文件被更改,包括 364 次插入41 次删除
  1. 6
      Runtime/gestures/long_press.cs
  2. 42
      Runtime/gestures/monodrag.cs
  3. 16
      Runtime/gestures/multidrag.cs
  4. 6
      Runtime/gestures/multitap.cs
  5. 38
      Runtime/gestures/recognizer.cs
  6. 43
      Runtime/material/text_field.cs
  7. 34
      Runtime/rendering/editable.cs
  8. 220
      Runtime/widgets/text_selection.cs

6
Runtime/gestures/long_press.cs


using Unity.UIWidgets.ui;
public LongPressGestureRecognizer(object debugOwner = null) :
base(deadline: Constants.kLongPressTimeout, debugOwner: debugOwner) {
public LongPressGestureRecognizer(object debugOwner = null, PointerDeviceKind? kind = null) :
base(deadline: Constants.kLongPressTimeout, debugOwner: debugOwner, kind: kind) {
}
public GestureLongPressCallback onLongPress;

42
Runtime/gestures/monodrag.cs


public delegate void GestureDragCancelCallback();
public abstract class DragGestureRecognizer : OneSequenceGestureRecognizer {
public DragGestureRecognizer(object debugOwner = null)
: base(debugOwner: debugOwner) {
public DragGestureRecognizer(
object debugOwner = null,
PointerDeviceKind? kind = null,
DragStartBehavior dragStartBehavior = DragStartBehavior.start)
: base(debugOwner: debugOwner, kind: kind) {
this.dragStartBehavior = dragStartBehavior;
public DragStartBehavior dragStartBehavior;
public GestureDragDownCallback onDown;

}
}
public override void addPointer(PointerDownEvent evt) {
public override void addAllowedPointer(PointerDownEvent evt) {
this.startTrackingPointer(evt.pointer);
this._velocityTrackers[evt.pointer] = new VelocityTracker();
if (this._state == _DragState.ready) {

this._state = _DragState.accepted;
Offset delta = this._pendingDragOffset;
var timestamp = this._lastPendingEventTimestamp;
Offset updateDelta = null;
switch (this.dragStartBehavior) {
case DragStartBehavior.start:
this._initialPosition = this._initialPosition + delta;
updateDelta = Offset.zero;
break;
case DragStartBehavior.down:
updateDelta = this._getDeltaForDetails(delta);
break;
}
D.assert(updateDelta != null);
this._pendingDragOffset = Offset.zero;
this._lastPendingEventTimestamp = default(TimeSpan);
if (this.onStart != null) {

});
}
if (delta != Offset.zero && this.onUpdate != null) {
if (updateDelta != Offset.zero && this.onUpdate != null) {
delta: this._getDeltaForDetails(delta),
primaryDelta: this._getPrimaryValueFromOffset(delta),
globalPosition: this._initialPosition
delta: updateDelta,
primaryDelta: this._getPrimaryValueFromOffset(updateDelta),
globalPosition: this._initialPosition + updateDelta
));
return null;
});

}
public class VerticalDragGestureRecognizer : DragGestureRecognizer {
public VerticalDragGestureRecognizer(object debugOwner = null)
: base(debugOwner: debugOwner) {
public VerticalDragGestureRecognizer(object debugOwner = null, PointerDeviceKind? kind = null)
: base(debugOwner: debugOwner, kind: kind) {
}
protected override bool _isFlingGesture(VelocityEstimate estimate) {

}
public class HorizontalDragGestureRecognizer : DragGestureRecognizer {
public HorizontalDragGestureRecognizer(object debugOwner = null)
: base(debugOwner: debugOwner) {
public HorizontalDragGestureRecognizer(object debugOwner = null, PointerDeviceKind? kind = null)
: base(debugOwner: debugOwner, kind: kind) {
}
protected override bool _isFlingGesture(VelocityEstimate estimate) {

16
Runtime/gestures/multidrag.cs


public abstract class MultiDragGestureRecognizer<T> : GestureRecognizer where T : MultiDragPointerState {
protected MultiDragGestureRecognizer(
object debugOwner) : base(debugOwner: debugOwner) {
object debugOwner, PointerDeviceKind? kind = null) : base(debugOwner: debugOwner, kind: kind) {
}
public GestureMultiDragStartCallback onStart;

public override void addPointer(PointerDownEvent pEvent) {
public override void addAllowedPointer(PointerDownEvent pEvent) {
D.assert(this._pointers != null);
D.assert(pEvent.position != null);
D.assert(!this._pointers.ContainsKey(pEvent.pointer));

public class ImmediateMultiDragGestureRecognizer : MultiDragGestureRecognizer<_ImmediatePointerState> {
public ImmediateMultiDragGestureRecognizer(object debugOwner) : base(debugOwner: debugOwner) {
public ImmediateMultiDragGestureRecognizer(object debugOwner, PointerDeviceKind? kind = null) : base(
debugOwner: debugOwner, kind: kind) {
}
public override _ImmediatePointerState createNewPointerState(PointerDownEvent pEvent) {

}
public class HorizontalMultiDragGestureRecognizer : MultiDragGestureRecognizer<_HorizontalPointerState> {
public HorizontalMultiDragGestureRecognizer(object debugOwner) : base(debugOwner: debugOwner) {
public HorizontalMultiDragGestureRecognizer(object debugOwner, PointerDeviceKind? kind = null) : base(
debugOwner: debugOwner, kind: kind) {
}
public override _HorizontalPointerState createNewPointerState(PointerDownEvent pEvent) {

public class VerticalMultiDragGestureRecognizer : MultiDragGestureRecognizer<_VerticalPointerState> {
public VerticalMultiDragGestureRecognizer(object debugOwner) : base(debugOwner: debugOwner) {
public VerticalMultiDragGestureRecognizer(object debugOwner, PointerDeviceKind? kind = null) : base(
debugOwner: debugOwner, kind: kind) {
}
public override _VerticalPointerState createNewPointerState(PointerDownEvent pEvent) {

public class DelayedMultiDragGestureRecognizer : MultiDragGestureRecognizer<_DelayedPointerState> {
public DelayedMultiDragGestureRecognizer(
TimeSpan? delay = null,
object debugOwner = null) : base(debugOwner: debugOwner) {
object debugOwner = null,
PointerDeviceKind? kind = null) : base(debugOwner: debugOwner, kind: kind) {
if (delay == null) {
delay = Constants.kLongPressTimeout;
}

6
Runtime/gestures/multitap.cs


public class DoubleTapGestureRecognizer : GestureRecognizer {
public DoubleTapGestureRecognizer(object debugOwner = null)
: base(debugOwner: debugOwner) {
public DoubleTapGestureRecognizer(object debugOwner = null, PointerDeviceKind? kind = null)
: base(debugOwner: debugOwner, kind: kind) {
}
public GestureDoubleTapCallback onDoubleTap;

readonly Dictionary<int, _TapTracker> _trackers = new Dictionary<int, _TapTracker>();
public override void addPointer(PointerDownEvent evt) {
public override void addAllowedPointer(PointerDownEvent evt) {
if (this._firstTap != null &&
!this._firstTap.isWithinTolerance(evt, Constants.kDoubleTapSlop)) {
return;

38
Runtime/gestures/recognizer.cs


namespace Unity.UIWidgets.gestures {
public delegate T RecognizerCallback<T>();
public enum DragStartBehavior {
down,
start
}
protected GestureRecognizer(object debugOwner = null) {
protected GestureRecognizer(object debugOwner = null, PointerDeviceKind? kind = null) {
this._kind = kind;
public abstract void addPointer(PointerDownEvent evt);
readonly PointerDeviceKind? _kind;
public void addPointer(PointerDownEvent evt) {
if (this.isPointerAllowed(evt)) {
this.addAllowedPointer(evt);
}
else {
this.handleNonAllowedPointer(evt);
}
}
public abstract void addAllowedPointer(PointerDownEvent evt);
protected virtual void handleNonAllowedPointer(PointerDownEvent evt) {
}
protected bool isPointerAllowed(PointerDownEvent evt) {
return this._kind == null || this._kind == evt.kind;
}
public virtual void addScrollPointer(PointerScrollEvent evt) {
}

}
public abstract class OneSequenceGestureRecognizer : GestureRecognizer {
protected OneSequenceGestureRecognizer(object debugOwner = null) : base(debugOwner) {
protected OneSequenceGestureRecognizer(object debugOwner = null, PointerDeviceKind? kind = null) : base(
debugOwner, kind) {
}
readonly Dictionary<int, GestureArenaEntry> _entries = new Dictionary<int, GestureArenaEntry>();

public abstract class PrimaryPointerGestureRecognizer : OneSequenceGestureRecognizer {
protected PrimaryPointerGestureRecognizer(
TimeSpan? deadline = null,
object debugOwner = null
) : base(debugOwner: debugOwner) {
object debugOwner = null,
PointerDeviceKind? kind = null
) : base(debugOwner: debugOwner, kind: kind) {
this.deadline = deadline;
}

Timer _timer;
public override void addPointer(PointerDownEvent evt) {
public override void addAllowedPointer(PointerDownEvent evt) {
this.startTrackingPointer(evt.pointer);
if (this.state == GestureRecognizerState.ready) {
this.state = GestureRecognizerState.possible;

43
Runtime/material/text_field.cs


}
}
InteractiveInkFeature _createInkFeature(TapDownDetails details) {
InteractiveInkFeature _createInkFeature(Offset globalPosition) {
Offset position = referenceBox.globalToLocal(details.globalPosition);
Offset position = referenceBox.globalToLocal(globalPosition);
Color color = Theme.of(this.context).splashColor;
InteractiveInkFeature splash = null;

void _handleTapDown(TapDownDetails details) {
this._renderEditable.handleTapDown(details);
this._startSplash(details);
this._startSplash(details.globalPosition);
void _handleTap() {
void _handleSingleTapUp(TapUpDetails details) {
if (this.widget.enableInteractiveSelection) {
this._renderEditable.handleTap();
}

}
}
void _handleTapCancel() {
void _handleSingleTapCancel() {
this._cancelCurrentSplash();
}

this._confirmCurrentSplash();
}
void _startSplash(TapDownDetails details) {
void _handleDragSelectionStart(DragStartDetails details) {
this._renderEditable.selectPositionAt(
from: details.globalPosition,
cause: SelectionChangedCause.drag);
this._startSplash(details.globalPosition);
}
void _handleDragSelectionUpdate(DragStartDetails startDetails,
DragUpdateDetails updateDetails) {
this._renderEditable.selectPositionAt(
from: startDetails.globalPosition,
to: updateDetails.globalPosition,
cause: SelectionChangedCause.drag);
}
void _startSplash(Offset globalPosition) {
InteractiveInkFeature splash = this._createInkFeature(details);
InteractiveInkFeature splash = this._createInkFeature(globalPosition);
this._splashes = this._splashes ?? new HashSet<InteractiveInkFeature>();
this._splashes.Add(splash);
this._currentSplash = splash;

return new IgnorePointer(
ignoring: !(this.widget.enabled ?? this.widget.decoration?.enabled ?? true),
child: new GestureDetector(
behavior: HitTestBehavior.translucent,
child: new TextSelectionGestureDetector(
onTap: this._handleTap,
onTapCancel: this._handleTapCancel,
onLongPress: this._handleLongPress,
onSingleTapUp: this._handleSingleTapUp,
onSingleTapCancel: this._handleSingleTapCancel,
onSingleLongTapStart: this._handleLongPress,
onDragSelectionStart: this._handleDragSelectionStart,
onDragSelectionUpdate: this._handleDragSelectionUpdate,
behavior: HitTestBehavior.translucent,
child: child
)
);

34
Runtime/rendering/editable.cs


using System.Collections.Generic;
using System;
using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;

doubleTap,
longPress,
keyboard,
drag
}
public class TextSelectionPoint {

public void handleLongPress() {
this.selectWord(cause: SelectionChangedCause.longPress);
}
public void selectPositionAt(Offset from = null, Offset to = null, SelectionChangedCause? cause = null) {
D.assert(cause != null);
D.assert(from != null);
this._layoutText(this.constraints.maxWidth);
if (this.onSelectionChanged != null) {
TextPosition fromPosition =
this._textPainter.getPositionForOffset(this.globalToLocal(from - this._paintOffset));
TextPosition toPosition = to == null
? null
: this._textPainter.getPositionForOffset(this.globalToLocal(to - this._paintOffset));
int baseOffset = fromPosition.offset;
int extentOffset = fromPosition.offset;
if (toPosition != null) {
baseOffset = Math.Min(fromPosition.offset, toPosition.offset);
extentOffset = Math.Max(fromPosition.offset, toPosition.offset);
}
TextSelection newSelection = new TextSelection(
baseOffset: baseOffset,
extentOffset: extentOffset,
affinity: fromPosition.affinity);
if (newSelection != this._selection) {
this.onSelectionChanged(newSelection, this, cause.Value);
}
}
}
void selectPosition(SelectionChangedCause? cause = null) {

220
Runtime/widgets/text_selection.cs


using System;
using System.Collections.Generic;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.rendering;

namespace Unity.UIWidgets.widgets {
static class TextSelectionUtils {
public static TimeSpan _kDragSelectionUpdateThrottle = new TimeSpan(0, 0, 0, 0, 50);
}
public enum TextSelectionHandleType {
left,
right,

}
public delegate void TextSelectionOverlayChanged(TextEditingValue value, Rect caretRect);
public delegate void DragSelectionUpdateCallback(DragStartDetails startDetails, DragUpdateDetails updateDetails);
public abstract class TextSelectionControls {
public abstract Widget buildHandle(BuildContext context, TextSelectionHandleType type, float textLineHeight);

D.assert(() => throw new UIWidgetsError($"invalid endpoint.direction {endpoint.direction}"));
return ltrType;
}
}
public class TextSelectionGestureDetector : StatefulWidget {
public TextSelectionGestureDetector(
Key key = null,
GestureTapDownCallback onTapDown = null,
GestureTapUpCallback onSingleTapUp = null,
GestureTapCancelCallback onSingleTapCancel = null,
GestureLongPressCallback onSingleLongTapStart = null,
GestureTapDownCallback onDoubleTapDown = null,
GestureDragStartCallback onDragSelectionStart = null,
DragSelectionUpdateCallback onDragSelectionUpdate = null,
GestureDragEndCallback onDragSelectionEnd = null,
HitTestBehavior? behavior = null,
Widget child = null
) : base(key: key) {
D.assert(child != null);
this.onTapDown = onTapDown;
this.onSingleTapUp = onSingleTapUp;
this.onSingleTapCancel = onSingleTapCancel;
this.onSingleLongTapStart = onSingleLongTapStart;
this.onDoubleTapDown = onDoubleTapDown;
this.onDragSelectionStart = onDragSelectionStart;
this.onDragSelectionUpdate = onDragSelectionUpdate;
this.onDragSelectionEnd = onDragSelectionEnd;
this.behavior = behavior;
this.child = child;
}
public readonly GestureTapDownCallback onTapDown;
public readonly GestureTapUpCallback onSingleTapUp;
public readonly GestureTapCancelCallback onSingleTapCancel;
public readonly GestureLongPressCallback onSingleLongTapStart;
public readonly GestureTapDownCallback onDoubleTapDown;
public readonly GestureDragStartCallback onDragSelectionStart;
public readonly DragSelectionUpdateCallback onDragSelectionUpdate;
public readonly GestureDragEndCallback onDragSelectionEnd;
public HitTestBehavior? behavior;
public readonly Widget child;
public override State createState() {
return new _TextSelectionGestureDetectorState();
}
}
class _TextSelectionGestureDetectorState : State<TextSelectionGestureDetector> {
Timer _doubleTapTimer;
Offset _lastTapOffset;
bool _isDoubleTap = false;
public override void dispose() {
this._doubleTapTimer?.cancel();
this._dragUpdateThrottleTimer?.cancel();
base.dispose();
}
void _handleTapDown(TapDownDetails details) {
if (this.widget.onTapDown != null) {
this.widget.onTapDown(details);
}
if (this._doubleTapTimer != null &&
this._isWithinDoubleTapTolerance(details.globalPosition)) {
if (this.widget.onDoubleTapDown != null) {
this.widget.onDoubleTapDown(details);
}
this._doubleTapTimer.cancel();
this._doubleTapTimeout();
this._isDoubleTap = true;
}
}
void _handleTapUp(TapUpDetails details) {
if (!this._isDoubleTap) {
if (this.widget.onSingleTapUp != null) {
this.widget.onSingleTapUp(details);
}
this._lastTapOffset = details.globalPosition;
this._doubleTapTimer = Window.instance.run(Constants.kDoubleTapTimeout, this._doubleTapTimeout);
}
this._isDoubleTap = false;
}
void _handleTapCancel() {
if (this.widget.onSingleTapCancel != null) {
this.widget.onSingleTapCancel();
}
}
DragStartDetails _lastDragStartDetails;
DragUpdateDetails _lastDragUpdateDetails;
Timer _dragUpdateThrottleTimer;
void _handleDragStart(DragStartDetails details) {
D.assert(this._lastDragStartDetails == null);
this._lastDragStartDetails = details;
if (this.widget.onDragSelectionStart != null) {
this.widget.onDragSelectionStart(details);
}
}
void _handleDragUpdate(DragUpdateDetails details) {
this._lastDragUpdateDetails = details;
this._dragUpdateThrottleTimer = this._dragUpdateThrottleTimer ??
Window.instance.run(TextSelectionUtils._kDragSelectionUpdateThrottle,
this._handleDragUpdateThrottled);
}
void _handleDragUpdateThrottled() {
D.assert(this._lastDragStartDetails != null);
D.assert(this._lastDragUpdateDetails != null);
if (this.widget.onDragSelectionUpdate != null) {
this.widget.onDragSelectionUpdate(this._lastDragStartDetails, this._lastDragUpdateDetails);
}
this._dragUpdateThrottleTimer = null;
this._lastDragUpdateDetails = null;
}
void _handleDragEnd(DragEndDetails details) {
D.assert(this._lastDragStartDetails != null);
if (this._lastDragUpdateDetails != null) {
this._dragUpdateThrottleTimer.cancel();
this._handleDragUpdateThrottled();
}
if (this.widget.onDragSelectionEnd != null) {
this.widget.onDragSelectionEnd(details);
}
this._dragUpdateThrottleTimer = null;
this._lastDragStartDetails = null;
this._lastDragUpdateDetails = null;
}
void _handleLongPressStart() {
if (!this._isDoubleTap && this.widget.onSingleLongTapStart != null) {
this.widget.onSingleLongTapStart();
}
}
void _doubleTapTimeout() {
this._doubleTapTimer = null;
this._lastTapOffset = null;
}
bool _isWithinDoubleTapTolerance(Offset secondTapOffset) {
D.assert(secondTapOffset != null);
if (this._lastTapOffset == null) {
return false;
}
Offset difference = secondTapOffset - this._lastTapOffset;
return difference.distance <= Constants.kDoubleTapSlop;
}
public override Widget build(BuildContext context) {
Dictionary<Type, GestureRecognizerFactory> gestures = new Dictionary<Type, GestureRecognizerFactory>();
gestures.Add(typeof(TapGestureRecognizer), new GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
() => new TapGestureRecognizer(debugOwner: this),
instance => {
instance.onTapDown = this._handleTapDown;
instance.onTapUp = this._handleTapUp;
instance.onTapCancel = this._handleTapCancel;
}
)
);
if (this.widget.onSingleLongTapStart != null) {
gestures[typeof(LongPressGestureRecognizer)] = new GestureRecognizerFactoryWithHandlers<LongPressGestureRecognizer>(
() => new LongPressGestureRecognizer(debugOwner: this, kind: PointerDeviceKind.touch),
instance => {
instance.onLongPress = this._handleLongPressStart;
});
}
if (this.widget.onDragSelectionStart != null ||
this.widget.onDragSelectionUpdate != null ||
this.widget.onDragSelectionEnd != null) {
gestures.Add(typeof(HorizontalDragGestureRecognizer),
new GestureRecognizerFactoryWithHandlers<HorizontalDragGestureRecognizer>(
() => new HorizontalDragGestureRecognizer(debugOwner: this, kind: PointerDeviceKind.mouse),
instance => {
instance.dragStartBehavior = DragStartBehavior.down;
instance.onStart = this._handleDragStart;
instance.onUpdate = this._handleDragUpdate;
instance.onEnd = this._handleDragEnd;
}
)
);
}
return new RawGestureDetector(
gestures: gestures,
behavior: this.widget.behavior,
child: this.widget.child
);
}
}
}
正在加载...
取消
保存