|
|
|
|
|
|
int _previousCursorLocation; |
|
|
|
|
|
|
|
bool _resetCursor = false; |
|
|
|
|
|
|
|
|
|
|
|
void _handleKeyEvent(RawKeyEvent keyEvent) { |
|
|
|
if (keyEvent is RawKeyUpEvent) { |
|
|
|
return; |
|
|
|
|
|
|
this._extentOffset = this.selection.extentOffset; |
|
|
|
this._baseOffset = this.selection.baseOffset; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool shift = (modifiers & (int)EventModifiers.Shift) > 0; |
|
|
|
bool ctrl = (modifiers & (int)EventModifiers.Control) > 0; |
|
|
|
bool alt = (modifiers & (int)EventModifiers.Alt) > 0; |
|
|
|
bool cmd = (modifiers & (int)EventModifiers.Command) > 0; |
|
|
|
|
|
|
|
bool shift = (modifiers & (int) EventModifiers.Shift) > 0; |
|
|
|
bool ctrl = (modifiers & (int) EventModifiers.Control) > 0; |
|
|
|
bool alt = (modifiers & (int) EventModifiers.Alt) > 0; |
|
|
|
bool cmd = (modifiers & (int) EventModifiers.Command) > 0; |
|
|
|
|
|
|
|
bool rightArrow = pressedKeyCode == KeyCode.RightArrow; |
|
|
|
bool leftArrow = pressedKeyCode == KeyCode.LeftArrow; |
|
|
|
bool upArrow = pressedKeyCode == KeyCode.UpArrow; |
|
|
|
|
|
|
bool del = pressedKeyCode == KeyCode.Delete; |
|
|
|
bool isMac = SystemInfo.operatingSystemFamily == OperatingSystemFamily.MacOSX; |
|
|
|
|
|
|
|
if (keyEvent is RawKeyCommandEvent) { // editor case
|
|
|
|
this._handleShortcuts(((RawKeyCommandEvent)keyEvent).command); |
|
|
|
if (keyEvent is RawKeyCommandEvent) { |
|
|
|
// editor case
|
|
|
|
this._handleShortcuts(((RawKeyCommandEvent) keyEvent).command); |
|
|
|
if ((ctrl || (isMac && cmd)) && (xKey || vKey || cKey || aKey)) { // runtime case
|
|
|
|
|
|
|
|
if ((ctrl || (isMac && cmd)) && (xKey || vKey || cKey || aKey)) { |
|
|
|
// runtime case
|
|
|
|
} else if (aKey) { |
|
|
|
} |
|
|
|
else if (aKey) { |
|
|
|
} else if (vKey) { |
|
|
|
} |
|
|
|
else if (vKey) { |
|
|
|
} else if (cKey) { |
|
|
|
} |
|
|
|
else if (cKey) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (arrow) { |
|
|
|
int newOffset = this._extentOffset; |
|
|
|
var word = (isMac && alt) || ctrl; |
|
|
|
|
|
|
|
|
|
|
if (downArrow || upArrow) |
|
|
|
if (downArrow || upArrow) { |
|
|
|
} |
|
|
|
|
|
|
|
newOffset = this._handleShift(rightArrow, leftArrow, shift, newOffset); |
|
|
|
|
|
|
|
this._extentOffset = newOffset; |
|
|
|
|
|
|
// If control is pressed, we will decide which way to look for a word
|
|
|
|
// based on which arrow is pressed.
|
|
|
|
if (leftArrow && this._extentOffset > 2) { |
|
|
|
TextSelection textSelection = this._selectWordAtOffset(new TextPosition(offset: this._extentOffset - 2)); |
|
|
|
TextSelection textSelection = |
|
|
|
this._selectWordAtOffset(new TextPosition(offset: this._extentOffset - 2)); |
|
|
|
} else if (rightArrow && this._extentOffset < this.text.text.Length - 2) { |
|
|
|
TextSelection textSelection = this._selectWordAtOffset(new TextPosition(offset: this._extentOffset + 1)); |
|
|
|
} |
|
|
|
else if (rightArrow && this._extentOffset < this.text.text.Length - 2) { |
|
|
|
TextSelection textSelection = |
|
|
|
this._selectWordAtOffset(new TextPosition(offset: this._extentOffset + 1)); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int _handleHorizontalArrows(bool rightArrow, bool leftArrow, bool shift, int newOffset) { |
|
|
|
if (rightArrow && this._extentOffset < this.text.text.Length) { |
|
|
|
newOffset += 1; |
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (leftArrow && this._extentOffset > 0) { |
|
|
|
newOffset -= 1; |
|
|
|
if (shift) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Offset caretOffset = this._textPainter.getOffsetForCaret(new TextPosition(offset: this._extentOffset), this._caretPrototype); |
|
|
|
Offset caretOffset = |
|
|
|
this._textPainter.getOffsetForCaret(new TextPosition(offset: this._extentOffset), this._caretPrototype); |
|
|
|
if (downArrow) |
|
|
|
if (downArrow) { |
|
|
|
else if (upArrow) |
|
|
|
} |
|
|
|
else if (upArrow) { |
|
|
|
} |
|
|
|
|
|
|
|
} else if (this._resetCursor && shift) { |
|
|
|
} |
|
|
|
else if (this._resetCursor && shift) { |
|
|
|
} else { |
|
|
|
} |
|
|
|
else { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (this.onSelectionChanged == null) |
|
|
|
if (this.onSelectionChanged == null) { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (shift) { |
|
|
|
if (this._baseOffset < newOffset) { |
|
|
|
this.onSelectionChanged( |
|
|
|
|
|
|
this, |
|
|
|
SelectionChangedCause.keyboard |
|
|
|
); |
|
|
|
} else { |
|
|
|
} |
|
|
|
else { |
|
|
|
this.onSelectionChanged( |
|
|
|
new TextSelection( |
|
|
|
baseOffset: newOffset, |
|
|
|
|
|
|
SelectionChangedCause.keyboard |
|
|
|
); |
|
|
|
} |
|
|
|
} else { |
|
|
|
} |
|
|
|
else { |
|
|
|
if (leftArrow) |
|
|
|
if (leftArrow) { |
|
|
|
else if (rightArrow) |
|
|
|
} |
|
|
|
else if (rightArrow) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
this.onSelectionChanged( |
|
|
|
|
|
|
SelectionChangedCause.keyboard |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
return newOffset; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
Clipboard.setData( |
|
|
|
new ClipboardData(text: this.selection.textInside(this.text.text))); |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
case KeyCommand.Cut: |
|
|
|
if (!this.selection.isCollapsed) { |
|
|
|
|
|
|
selection: TextSelection.collapsed(offset: this.selection.start) |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
case KeyCommand.Paste: |
|
|
|
TextEditingValue value = this.textSelectionDelegate.textEditingValue; |
|
|
|
|
|
|
); |
|
|
|
} |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
break; |
|
|
|
case KeyCommand.SelectAll: |
|
|
|
this._baseOffset = 0; |
|
|
|
|
|
|
+ selection.textAfter(this.text.text).Substring(1), |
|
|
|
selection: TextSelection.collapsed(offset: selection.start) |
|
|
|
); |
|
|
|
} else { |
|
|
|
} |
|
|
|
else { |
|
|
|
this.textSelectionDelegate.textEditingValue = new TextEditingValue( |
|
|
|
text: selection.textBefore(this.text.text), |
|
|
|
selection: TextSelection.collapsed(offset: selection.start) |
|
|
|
|
|
|
this._textLayoutLastWidth = null; |
|
|
|
this.markNeedsLayout(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public TextSpan text { |
|
|
|
get { return this._textPainter.text; } |
|
|
|
set { |
|
|
|
|
|
|
|
|
|
|
bool _hasFocus; |
|
|
|
bool _listenerAttached = false; |
|
|
|
|
|
|
|
public bool hasFocus { |
|
|
|
get { return this._hasFocus; } |
|
|
|
set { |
|
|
|
|
|
|
RawKeyboard.instance.removeListener(this._handleKeyEvent); |
|
|
|
this._listenerAttached = false; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this.markNeedsSemanticsUpdate(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
this.markNeedsLayout(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
set { |
|
|
|
if (this._cursorWidth == value) |
|
|
|
set { |
|
|
|
if (this._cursorWidth == value) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
set { |
|
|
|
if (this._cursorRadius == value) |
|
|
|
set { |
|
|
|
if (this._cursorRadius == value) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
set { |
|
|
|
if (this._enableInteractiveSelection == value) |
|
|
|
set { |
|
|
|
if (this._enableInteractiveSelection == value) { |
|
|
|
} |
|
|
|
|
|
|
|
this._enableInteractiveSelection = value; |
|
|
|
this.markNeedsTextLayout(); |
|
|
|
this.markNeedsSemanticsUpdate(); |
|
|
|
|
|
|
if (this._listenerAttached) { |
|
|
|
RawKeyboard.instance.removeListener(this._handleKeyEvent); |
|
|
|
} |
|
|
|
|
|
|
|
base.detach(); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
this._longPress.addPointer((PointerDownEvent) evt); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
this._lastTapDownPosition = details.globalPosition + - this._paintOffset; |
|
|
|
this._lastTapDownPosition = details.globalPosition + -this._paintOffset; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void handleTap() { |
|
|
|
this.selectPosition(cause: SelectionChangedCause.tap); |
|
|
|
} |
|
|
|
|
|
|
D.assert(!this.ignorePointer); |
|
|
|
this.handleDoubleTap(details); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void handleDoubleTap(DoubleTapDetails details) { |
|
|
|
// need set _lastTapDownPosition, otherwise it would be last single tap position
|
|
|
|
this._lastTapDownPosition = details.firstGlobalPosition - this._paintOffset; |
|
|
|
|
|
|
public void handleLongPress() { |
|
|
|
this.selectWord(cause: SelectionChangedCause.longPress); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
TextPosition position = this._textPainter.getPositionForOffset(this.globalToLocal(this._lastTapDownPosition)); |
|
|
|
TextPosition position = |
|
|
|
this._textPainter.getPositionForOffset(this.globalToLocal(this._lastTapDownPosition)); |
|
|
|
|
|
|
|
|
|
|
|
void selectWord(SelectionChangedCause? cause = null) { |
|
|
|
this._layoutText(this.constraints.maxWidth); |
|
|
|
D.assert(this._lastTapDownPosition != null); |
|
|
|
|
|
|
this._layoutText(this.constraints.maxWidth); |
|
|
|
D.assert(this._lastTapDownPosition != null); |
|
|
|
if (this.onSelectionChanged != null) { |
|
|
|
TextPosition position = this._textPainter.getPositionForOffset(this.globalToLocal(this._lastTapDownPosition)); |
|
|
|
TextPosition position = |
|
|
|
this._textPainter.getPositionForOffset(this.globalToLocal(this._lastTapDownPosition)); |
|
|
|
TextRange word = this._textPainter.getWordBoundary(position); |
|
|
|
if (position.offset - word.start <= 1) { |
|
|
|
this.onSelectionChanged( |
|
|
|
|
|
|
); |
|
|
|
} else { |
|
|
|
} |
|
|
|
else { |
|
|
|
this.onSelectionChanged( |
|
|
|
TextSelection.collapsed(offset: word.end, affinity: TextAffinity.upstream), |
|
|
|
this, |
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
TextSelection _selectWordAtOffset(TextPosition position) { |
|
|
|
D.assert(this._textLayoutLastWidth == this.constraints.maxWidth); |
|
|
|
var word = this._textPainter.getWordBoundary(position); |
|
|
|
|
|
|
|
|
|
|
return new TextSelection(baseOffset: word.start, extentOffset: word.end); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void _layoutText(float constraintWidth) { |
|
|
|
if (this._textLayoutLastWidth == constraintWidth) { |
|
|
|
return; |
|
|
|
|
|
|
this._textLayoutLastWidth = constraintWidth; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected override void performLayout() { |
|
|
|
this._layoutText(this.constraints.maxWidth); |
|
|
|
this._caretPrototype = Rect.fromLTWH(0.0f, _kCaretHeightOffset, this.cursorWidth, |
|
|
|
|
|
|
RRect caretRRect = RRect.fromRectAndRadius(caretRect, this.cursorRadius); |
|
|
|
canvas.drawRRect(caretRRect, paint); |
|
|
|
} |
|
|
|
|
|
|
|
if (!caretRect.Equals(this._lastCaretRect)) { |
|
|
|
this._lastCaretRect = caretRect; |
|
|
|
if (this.onCaretChanged != null) { |
|
|
|
|
|
|
public override Rect describeApproximatePaintClip(RenderObject child) { |
|
|
|
return this._hasVisualOverflow ? Offset.zero & this.size : null; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) { |
|
|
|
base.debugFillProperties(properties); |
|
|
|
properties.add(new DiagnosticsProperty<Color>("cursorColor", this.cursorColor)); |
|
|
|