| /* |
| * Copyright 2018 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package androidx.ui.rendering.editable |
| |
| import androidx.ui.engine.geometry.Offset |
| import androidx.ui.engine.geometry.Rect |
| import androidx.ui.engine.geometry.Size |
| import androidx.ui.engine.text.TextBaseline |
| import androidx.ui.engine.text.TextPosition |
| import androidx.ui.foundation.diagnostics.DiagnosticPropertiesBuilder |
| import androidx.ui.foundation.diagnostics.DiagnosticsNode |
| import androidx.ui.gestures.events.PointerEvent |
| import androidx.ui.gestures.hit_test.HitTestEntry |
| import androidx.ui.gestures.tap.TapDownDetails |
| import androidx.ui.painting.Canvas |
| import androidx.ui.rendering.box.RenderBox |
| import androidx.ui.rendering.obj.PaintingContext |
| import androidx.ui.rendering.obj.RenderObject |
| import androidx.ui.semantics.SemanticsConfiguration |
| import androidx.ui.services.raw_keyboard.RawKeyEvent |
| import androidx.ui.services.text_editing.TextRange |
| import androidx.ui.services.text_editing.TextSelection |
| |
| // const double _kCaretGap = 1.0; // pixels |
| // const double _kCaretHeightOffset = 2.0; // pixels |
| |
| /** |
| * Displays some text in a scrollable container with a potentially blinking |
| * cursor and with gesture recognizers. |
| * |
| * This is the renderer for an editable text field. It does not directly |
| * provide affordances for editing the text, but it does handle text selection |
| * and manipulation of the text cursor. |
| * |
| * The [text] is displayed, scrolled by the given [offset], aligned according |
| * to [textAlign]. The [maxLines] property controls whether the text displays |
| * on one line or many. The [selection], if it is not collapsed, is painted in |
| * the [selectionColor]. If it _is_ collapsed, then it represents the cursor |
| * position. The cursor is shown while [showCursor] is true. It is painted in |
| * the [cursorColor]. |
| * |
| * If, when the render object paints, the caret is found to have changed |
| * location, [onCaretChanged] is called. |
| * |
| * The user may interact with the render object by tapping or long-pressing. |
| * When the user does so, the selection is updated, and [onSelectionChanged] is |
| * called. |
| * |
| * Keyboard handling, IME handling, scrolling, toggling the [showCursor] value |
| * to actually blink the cursor, and other features not mentioned above are the |
| * responsibility of higher layers and not handled by this object. |
| */ |
| class RenderEditable : RenderBox() { |
| /** |
| * Creates a render object that implements the visual aspects of a text field. |
| * |
| * The [textAlign] argument must not be null. It defaults to [TextAlign.start]. |
| * |
| * The [textDirection] argument must not be null. |
| * |
| * If [showCursor] is not specified, then it defaults to hiding the cursor. |
| * |
| * The [maxLines] property can be set to null to remove the restriction on |
| * the number of lines. By default, it is 1, meaning this is a single-line |
| * text field. If it is not null, it must be greater than zero. |
| * |
| * The [offset] is required and must not be null. You can use [new |
| * ViewportOffset.zero] if you have no need for scrolling. |
| * |
| * The [enableInteractiveSelection] argument must not be null. |
| */ |
| // RenderEditable({ |
| // TextSpan text, |
| // @required TextDirection textDirection, |
| // TextAlign textAlign = TextAlign.start, |
| // Color cursorColor, |
| // ValueNotifier<bool> showCursor, |
| // bool hasFocus, |
| // int maxLines = 1, |
| // Color selectionColor, |
| // double textScaleFactor = 1.0, |
| // TextSelection selection, |
| // @required ViewportOffset offset, |
| // this.onSelectionChanged, |
| // this.onCaretChanged, |
| // this.ignorePointer = false, |
| // bool obscureText = false, |
| // Locale locale, |
| // double cursorWidth = 1.0, |
| // Radius cursorRadius, |
| // bool enableInteractiveSelection = true, |
| // @required this.textSelectionDelegate, |
| // }) : assert(textAlign != null), |
| // assert(textDirection != null, 'RenderEditable created without a textDirection.'), |
| // assert(maxLines == null || maxLines > 0), |
| // assert(textScaleFactor != null), |
| // assert(offset != null), |
| // assert(ignorePointer != null), |
| // assert(obscureText != null), |
| // assert(enableInteractiveSelection != null), |
| // assert(textSelectionDelegate != null), |
| // _textPainter = TextPainter( |
| // text: text, |
| // textAlign: textAlign, |
| // textDirection: textDirection, |
| // textScaleFactor: textScaleFactor, |
| // locale: locale, |
| // ), |
| // _cursorColor = cursorColor, |
| // _showCursor = showCursor ?? ValueNotifier<bool>(false), |
| // _hasFocus = hasFocus ?? false, |
| // _maxLines = maxLines, |
| // _selectionColor = selectionColor, |
| // _selection = selection, |
| // _offset = offset, |
| // _cursorWidth = cursorWidth, |
| // _cursorRadius = cursorRadius, |
| // _enableInteractiveSelection = enableInteractiveSelection, |
| // _obscureText = obscureText { |
| // assert(_showCursor != null); |
| // assert(!_showCursor.value || cursorColor != null); |
| // _tap = TapGestureRecognizer(debugOwner: this) |
| // ..> |
| // ..> |
| // _longPress = LongPressGestureRecognizer(debugOwner: this) |
| // ..> |
| // } |
| |
| /** Character used to obscure text if [obscureText] is true. */ |
| // static const String obscuringCharacter = '•'; |
| |
| /** Called when the selection changes. */ |
| // SelectionChangedHandler onSelectionChanged; |
| |
| // double _textLayoutLastWidth; |
| |
| /** Called during the paint phase when the caret location changes. */ |
| // CaretChangedHandler onCaretChanged; |
| |
| /** |
| * If true [handleEvent] does nothing and it's assumed that this renderer will be notified of |
| * input gestures via [handleTapDown], [handleTap], [handleDoubleTap], and [handleLongPress]. |
| * |
| * The default value of this property is false. |
| */ |
| // bool ignorePointer; |
| |
| /** Whether to hide the text being edited (e.g., for passwords). */ |
| // bool get obscureText => _obscureText; |
| // bool _obscureText; |
| // set obscureText(bool value) { |
| // if (_obscureText == value) |
| // return; |
| // _obscureText = value; |
| // markNeedsSemanticsUpdate(); |
| // } |
| |
| /** |
| * The object that controls the text selection, used by this render object |
| * for implementing cut, copy, and paste keyboard shortcuts. |
| * |
| * It must not be null. It will make cut, copy and paste functionality work |
| * with the most recently set [TextSelectionDelegate]. |
| */ |
| // TextSelectionDelegate textSelectionDelegate; |
| // |
| // Rect _lastCaretRect; |
| // |
| // static const int _kLeftArrowCode = 21; |
| // static const int _kRightArrowCode = 22; |
| // static const int _kUpArrowCode = 19; |
| // static const int _kDownArrowCode = 20; |
| // static const int _kXKeyCode = 52; |
| // static const int _kCKeyCode = 31; |
| // static const int _kVKeyCode = 50; |
| // static const int _kAKeyCode = 29; |
| // static const int _kDelKeyCode = 112; |
| |
| /** The extent offset of the current selection */ |
| // int _extentOffset = -1; |
| |
| /** The base offset of the current selection */ |
| // int _baseOffset = -1; |
| |
| /** |
| * Holds the last location the user selected in the case that he selects all the way to the end |
| * or beginning of the field. |
| */ |
| // int _previousCursorLocation = -1; |
| |
| /** |
| * Whether we should reset the location of the cursor in the case the user selects all the way |
| * to the end or the beginning of a field. |
| */ |
| // bool _resetCursor = false; |
| |
| // static const int _kShiftMask = 1; // https://developer.android.com/reference/android/view/KeyEvent.html#META_SHIFT_ON |
| // static const int _kControlMask = 1 << 12; // https://developer.android.com/reference/android/view/KeyEvent.html#META_CTRL_ON |
| |
| // TODO(goderbauer): doesn't handle extended grapheme clusters with more than one Unicode scalar value (https://github.com/flutter/flutter/issues/13404). |
| fun _handleKeyEvent(keyEvent: RawKeyEvent) { |
| TODO("Not yet implemented") |
| // if (defaultTargetPlatform != TargetPlatform.android) |
| // return; |
| // |
| // if (keyEvent is RawKeyUpEvent) |
| // return; |
| // |
| // final RawKeyEventDataAndroid rawAndroidEvent = keyEvent.data; |
| // final int pressedKeyCode = rawAndroidEvent.keyCode; |
| // final int pressedKeyMetaState = rawAndroidEvent.metaState; |
| // |
| // if (selection.isCollapsed) { |
| // _extentOffset = selection.extentOffset; |
| // _baseOffset = selection.baseOffset; |
| // } |
| // |
| // // Update current key states |
| // final bool shift = pressedKeyMetaState & _kShiftMask > 0; |
| // final bool ctrl = pressedKeyMetaState & _kControlMask > 0; |
| // |
| // final bool rightArrow = pressedKeyCode == _kRightArrowCode; |
| // final bool leftArrow = pressedKeyCode == _kLeftArrowCode; |
| // final bool upArrow = pressedKeyCode == _kUpArrowCode; |
| // final bool downArrow = pressedKeyCode == _kDownArrowCode; |
| // final bool arrow = leftArrow || rightArrow || upArrow || downArrow; |
| // final bool aKey = pressedKeyCode == _kAKeyCode; |
| // final bool xKey = pressedKeyCode == _kXKeyCode; |
| // final bool vKey = pressedKeyCode == _kVKeyCode; |
| // final bool cKey = pressedKeyCode == _kCKeyCode; |
| // final bool del = pressedKeyCode == _kDelKeyCode; |
| // |
| // // We will only move select or more the caret if an arrow is pressed |
| // if (arrow) { |
| // int newOffset = _extentOffset; |
| // |
| // // Because the user can use multiple keys to change how he selects |
| // // the new offset variable is threaded through these four functions |
| // // and potentially changes after each one. |
| // if (ctrl) |
| // newOffset = _handleControl(rightArrow, leftArrow, ctrl, newOffset); |
| // newOffset = _handleHorizontalArrows(rightArrow, leftArrow, shift, newOffset); |
| // if (downArrow || upArrow) |
| // newOffset = _handleVerticalArrows(upArrow, downArrow, shift, newOffset); |
| // newOffset = _handleShift(rightArrow, leftArrow, shift, newOffset); |
| // |
| // _extentOffset = newOffset; |
| // } else if (ctrl && (xKey || vKey || cKey || aKey)) { |
| // // _handleShortcuts depends on being started in the same stack invocation as the _handleKeyEvent method |
| // _handleShortcuts(pressedKeyCode); |
| // } |
| // if (del) |
| // _handleDelete(); |
| } |
| |
| /** Handles full word traversal using control. */ |
| fun _handleControl(rightArrow: Boolean, leftArrow: Boolean, ctrl: Boolean, newOffset: Boolean) { |
| TODO("Not yet implemented") |
| // // If control is pressed, we will decide which way to look for a word |
| // // based on which arrow is pressed. |
| // if (leftArrow && _extentOffset > 2) { |
| // final TextSelection textSelection = _selectWordAtOffset(TextPosition(offset: _extentOffset - 2)); |
| // newOffset = textSelection.baseOffset + 1; |
| // } else if (rightArrow && _extentOffset < text.text.length - 2) { |
| // final TextSelection textSelection = _selectWordAtOffset(TextPosition(offset: _extentOffset + 1)); |
| // newOffset = textSelection.extentOffset - 1; |
| // } |
| // return newOffset; |
| } |
| |
| fun _handleHorizontalArrows( |
| rightArrow: Boolean, |
| leftArrow: Boolean, |
| shift: Boolean, |
| newOffset: Int |
| ) { |
| TODO("Not yet implemented") |
| // // Set the new offset to be +/- 1 depending on which arrow is pressed |
| // // If shift is down, we also want to update the previous cursor location |
| // if (rightArrow && _extentOffset < text.text.length) { |
| // newOffset += 1; |
| // if (shift) |
| // _previousCursorLocation += 1; |
| // } |
| // if (leftArrow && _extentOffset > 0) { |
| // newOffset -= 1; |
| // if (shift) |
| // _previousCursorLocation -= 1; |
| // } |
| // return newOffset; |
| } |
| |
| /** |
| * Handles moving the cursor vertically as well as taking care of the case where the user moves |
| * the cursor to the end or beginning of the text and then back up or down. |
| */ |
| fun _handleVerticalArrows( |
| upArrow: Boolean, |
| downArrow: Boolean, |
| shift: Boolean, |
| newOffset: Boolean |
| ): Int { |
| TODO("Not yet implemented") |
| // // The caret offset gives a location in the upper left hand corner of |
| // // the caret so the middle of the line above is a half line above that |
| // // point and the line below is 1.5 lines below that point. |
| // final double plh = _textPainter.preferredLineHeight; |
| // final double verticalOffset = upArrow ? -0.5 * plh : 1.5 * plh; |
| // |
| // final Offset caretOffset = _textPainter.getOffsetForCaret(TextPosition(offset: _extentOffset), _caretPrototype); |
| // final Offset caretOffsetTranslated = caretOffset.translate(0.0, verticalOffset); |
| // final TextPosition position = _textPainter.getPositionForOffset(caretOffsetTranslated); |
| // |
| // // To account for the possibility where the user vertically highlights |
| // // all the way to the top or bottom of the text, we hold the previous |
| // // cursor location. This allows us to restore to this position in the |
| // // case that the user wants to unhighlight some text. |
| // if (position.offset == _extentOffset) { |
| // if (downArrow) |
| // newOffset = text.text.length; |
| // else if (upArrow) |
| // newOffset = 0; |
| // _resetCursor = shift; |
| // } else if (_resetCursor && shift) { |
| // newOffset = _previousCursorLocation; |
| // _resetCursor = false; |
| // } else { |
| // newOffset = position.offset; |
| // _previousCursorLocation = newOffset; |
| // } |
| // return newOffset; |
| } |
| |
| /** |
| * Handles the selection of text or removal of the selection and placing of the caret. |
| */ |
| fun _handleShift(rightArrow: Boolean, leftArrow: Boolean, shift: Boolean, newOffset: Int): Int { |
| TODO("Not yet implemented") |
| // if ( null) |
| // return newOffset; |
| // // In the text_selection class, a TextSelection is defined such that the |
| // // base offset is always less than the extent offset. |
| // if (shift) { |
| // if (_baseOffset < newOffset) { |
| // onSelectionChanged( |
| // TextSelection( |
| // baseOffset: _baseOffset, |
| // extentOffset: newOffset |
| // ), |
| // this, |
| // SelectionChangedCause.keyboard, |
| // ); |
| // } else { |
| // onSelectionChanged( |
| // TextSelection( |
| // baseOffset: newOffset, |
| // extentOffset: _baseOffset |
| // ), |
| // this, |
| // SelectionChangedCause.keyboard, |
| // ); |
| // } |
| // } else { |
| // // We want to put the cursor at the correct location depending on which |
| // // arrow is used while there is a selection. |
| // if (!selection.isCollapsed) { |
| // if (leftArrow) |
| // newOffset = _baseOffset < _extentOffset ? _baseOffset : _extentOffset; |
| // else if (rightArrow) |
| // newOffset = _baseOffset > _extentOffset ? _baseOffset : _extentOffset; |
| // } |
| // onSelectionChanged( |
| // TextSelection.fromPosition( |
| // TextPosition( |
| // offset: newOffset |
| // ) |
| // ), |
| // this, |
| // SelectionChangedCause.keyboard, |
| // ); |
| // } |
| // return newOffset; |
| } |
| |
| /** |
| * Handles shortcut functionality including cut, copy, paste and select all using control + |
| * (X, C, V, A). |
| */ |
| // fun Future<void> _handleShortcuts(int pressedKeyCode) async { |
| // switch (pressedKeyCode) { |
| // case _kCKeyCode: |
| // if (!selection.isCollapsed) { |
| // Clipboard.setData( |
| // ClipboardData(text: selection.textInside(text.text))); |
| // } |
| // break; |
| // case _kXKeyCode: |
| // if (!selection.isCollapsed) { |
| // Clipboard.setData( |
| // ClipboardData(text: selection.textInside(text.text))); |
| // textSelectionDelegate.textEditingValue = TextEditingValue( |
| // text: selection.textBefore(text.text) |
| // + selection.textAfter(text.text), |
| // selection: TextSelection.collapsed(offset: selection.start), |
| // ); |
| // } |
| // break; |
| // case _kVKeyCode: |
| // // Snapshot the input before using `await`. |
| // // See https://github.com/flutter/flutter/issues/11427 |
| // final TextEditingValue value = textSelectionDelegate.textEditingValue; |
| // final ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); |
| // if (data != null) { |
| // textSelectionDelegate.textEditingValue = TextEditingValue( |
| // text: value.selection.textBefore(value.text) |
| // + data.text |
| // + value.selection.textAfter(value.text), |
| // selection: TextSelection.collapsed( |
| // offset: value.selection.start + data.text.length |
| // ), |
| // ); |
| // } |
| // break; |
| // case _kAKeyCode: |
| // _baseOffset = 0; |
| // _extentOffset = textSelectionDelegate.textEditingValue.text.length; |
| // onSelectionChanged( |
| // TextSelection( |
| // baseOffset: 0, |
| // extentOffset: textSelectionDelegate.textEditingValue.text.length, |
| // ), |
| // this, |
| // SelectionChangedCause.keyboard, |
| // ); |
| // break; |
| // default: |
| // assert(false); |
| // } |
| // } |
| |
| fun _handleDelete() { |
| TODO("Not yet implemented") |
| // if (selection.textAfter(text.text).isNotEmpty) { |
| // textSelectionDelegate.textEditingValue = TextEditingValue( |
| // text: selection.textBefore(text.text) |
| // + selection.textAfter(text.text).substring(1), |
| // selection: TextSelection.collapsed(offset: selection.start) |
| // ); |
| // } else { |
| // textSelectionDelegate.textEditingValue = TextEditingValue( |
| // text: selection.textBefore(text.text), |
| // selection: TextSelection.collapsed(offset: selection.start) |
| // ); |
| // } |
| } |
| |
| /** |
| * Marks the render object as needing to be laid out again and have its text metrics recomputed. |
| * |
| * Implies [markNeedsLayout]. |
| */ |
| protected fun markNeedsTextLayout() { |
| TODO("Not yet implemented") |
| // _textLayoutLastWidth = null; |
| // markNeedsLayout(); |
| } |
| |
| /** The text to display. */ |
| // TextSpan get text => _textPainter.text; |
| // final TextPainter _textPainter; |
| // set text(TextSpan value) { |
| // if (_textPainter.text == value) |
| // return; |
| // _textPainter.text = value; |
| // markNeedsTextLayout(); |
| // markNeedsSemanticsUpdate(); |
| // } |
| |
| /** |
| * How the text should be aligned horizontally. |
| * |
| * This must not be null. |
| */ |
| // TextAlign get textAlign => _textPainter.textAlign; |
| // set textAlign(TextAlign value) { |
| // assert(value != null); |
| // if (_textPainter.textAlign == value) |
| // return; |
| // _textPainter.textAlign = value; |
| // markNeedsPaint(); |
| // } |
| |
| /** |
| * The directionality of the text. |
| * |
| * This decides how the [TextAlign.start], [TextAlign.end], and [TextAlign.justify] values of |
| * [textAlign] are interpreted. |
| * |
| * This is also used to disambiguate how to render bidirectional text. For example, if the |
| * [text] is an English phrase followed by a Hebrew phrase, in a [TextDirection.ltr] context the |
| * English phrase will be on the left and the Hebrew phrase to its right, while in a |
| * [TextDirection.rtl] context, the English phrase will be on the right and the Hebrew phrase on |
| * its left. |
| * |
| * This must not be null. |
| */ |
| // TextDirection get textDirection => _textPainter.textDirection; |
| // set textDirection(TextDirection value) { |
| // assert(value != null); |
| // if (_textPainter.textDirection == value) |
| // return; |
| // _textPainter.textDirection = value; |
| // markNeedsTextLayout(); |
| // markNeedsSemanticsUpdate(); |
| // } |
| |
| /** |
| * Used by this renderer's internal [TextPainter] to select a locale-specific font. |
| * |
| * In some cases the same Unicode character may be rendered differently depending on the locale. |
| * For example the '骨' character is rendered differently in the Chinese and Japanese locales. |
| * In these cases the [locale] may be used to select a locale-specific font. |
| * |
| * If this value is null, a system-dependent algorithm is used to select the font. |
| */ |
| // Locale get locale => _textPainter.locale; |
| // set locale(Locale value) { |
| // if (_textPainter.locale == value) |
| // return; |
| // _textPainter.locale = value; |
| // markNeedsTextLayout(); |
| // } |
| |
| /** The color to use when painting the cursor. */ |
| // Color get cursorColor => _cursorColor; |
| // Color _cursorColor; |
| // set cursorColor(Color value) { |
| // if (_cursorColor == value) |
| // return; |
| // _cursorColor = value; |
| // markNeedsPaint(); |
| // } |
| |
| /** Whether to paint the cursor. */ |
| // ValueNotifier<bool> get showCursor => _showCursor; |
| // ValueNotifier<bool> _showCursor; |
| // set showCursor(ValueNotifier<bool> value) { |
| // assert(value != null); |
| // if (_showCursor == value) |
| // return; |
| // if (attached) |
| // _showCursor.removeListener(markNeedsPaint); |
| // _showCursor = value; |
| // if (attached) |
| // _showCursor.addListener(markNeedsPaint); |
| // markNeedsPaint(); |
| // } |
| |
| /** Whether the editable is currently focused. */ |
| // bool get hasFocus => _hasFocus; |
| // bool _hasFocus; |
| // bool _listenerAttached = false; |
| // set hasFocus(bool value) { |
| // assert(value != null); |
| // if (_hasFocus == value) |
| // return; |
| // _hasFocus = value; |
| // if (_hasFocus) { |
| // assert(!_listenerAttached); |
| // RawKeyboard.instance.addListener(_handleKeyEvent); |
| // _listenerAttached = true; |
| // } |
| // else { |
| // assert(_listenerAttached); |
| // RawKeyboard.instance.removeListener(_handleKeyEvent); |
| // _listenerAttached = false; |
| // } |
| // |
| // markNeedsSemanticsUpdate(); |
| // } |
| |
| /** |
| * The maximum number of lines for the text to span, wrapping if necessary. |
| * |
| * If this is 1 (the default), the text will not wrap, but will extend indefinitely instead. |
| * |
| * If this is null, there is no limit to the number of lines. |
| * |
| * When this is not null, the intrinsic height of the render object is the height of one line of |
| * text multiplied by this value. In other words, this also controls the height of the actual |
| * editing widget. |
| */ |
| // int get maxLines => _maxLines; |
| // int _maxLines; |
| // /** The value may be null. If it is not null, then it must be greater than zero. */ |
| // set maxLines(int value) { |
| // assert(value == null || value > 0); |
| // if (maxLines == value) |
| // return; |
| // _maxLines = value; |
| // markNeedsTextLayout(); |
| // } |
| // |
| // /** The color to use when painting the selection. */ |
| // Color get selectionColor => _selectionColor; |
| // Color _selectionColor; |
| // set selectionColor(Color value) { |
| // if (_selectionColor == value) |
| // return; |
| // _selectionColor = value; |
| // markNeedsPaint(); |
| // } |
| |
| /** |
| * The number of font pixels for each logical pixel. |
| * |
| * For example, if the text scale factor is 1.5, text will be 50% larger than the specified font |
| * size. |
| */ |
| // double get textScaleFactor => _textPainter.textScaleFactor; |
| // set textScaleFactor(double value) { |
| // assert(value != null); |
| // if (_textPainter.textScaleFactor == value) |
| // return; |
| // _textPainter.textScaleFactor = value; |
| // markNeedsTextLayout(); |
| // } |
| // |
| // List<ui.TextBox> _selectionRects; |
| // |
| // /** The region of text that is selected, if any. */ |
| // TextSelection get selection => _selection; |
| // TextSelection _selection; |
| // set selection(TextSelection value) { |
| // if (_selection == value) |
| // return; |
| // _selection = value; |
| // _selectionRects = null; |
| // markNeedsPaint(); |
| // markNeedsSemanticsUpdate(); |
| // } |
| |
| /** |
| * The offset at which the text should be painted. |
| * |
| * If the text content is larger than the editable line itself, the editable line clips the |
| * text. This property controls which part of the text is visible by shifting the text by the |
| * given offset before clipping. |
| */ |
| // ViewportOffset get offset => _offset; |
| // ViewportOffset _offset; |
| // set offset(ViewportOffset value) { |
| // assert(value != null); |
| // if (_offset == value) |
| // return; |
| // if (attached) |
| // _offset.removeListener(markNeedsPaint); |
| // _offset = value; |
| // if (attached) |
| // _offset.addListener(markNeedsPaint); |
| // markNeedsLayout(); |
| // } |
| |
| /** How thick the cursor will be. */ |
| // double get cursorWidth => _cursorWidth; |
| // double _cursorWidth = 1.0; |
| // set cursorWidth(double value) { |
| // if (_cursorWidth == value) |
| // return; |
| // _cursorWidth = value; |
| // markNeedsLayout(); |
| // } |
| |
| /** How rounded the corners of the cursor should be. */ |
| // Radius get cursorRadius => _cursorRadius; |
| // Radius _cursorRadius; |
| // set cursorRadius(Radius value) { |
| // if (_cursorRadius == value) |
| // return; |
| // _cursorRadius = value; |
| // markNeedsPaint(); |
| // } |
| |
| override fun describeSemanticsConfiguration(config: SemanticsConfiguration) { |
| TODO("Not yet implemented") |
| // super.describeSemanticsConfiguration(config); |
| // |
| // config |
| // ..value = obscureText |
| // ? obscuringCharacter * text.toPlainText().length |
| // : text.toPlainText() |
| // ..isObscured = obscureText |
| // ..textDirection = textDirection |
| // ..isFocused = hasFocus |
| // ..isTextField = true; |
| // |
| // if (hasFocus && enableInteractiveSelection) |
| // config.> |
| // |
| // if (enableInteractiveSelection && _selection?.isValid == true) { |
| // config.textSelection = _selection; |
| // if (_textPainter.getOffsetBefore(_selection.extentOffset) != null) { |
| // config |
| // ..> |
| // ..> |
| // } |
| // if (_textPainter.getOffsetAfter(_selection.extentOffset) != null) { |
| // config |
| // ..> |
| // ..> |
| // } |
| // } |
| } |
| |
| fun _handleSetSelection(selection: TextSelection) { |
| TODO("Not yet implemented") |
| // onSelectionChanged(selection, this, SelectionChangedCause.keyboard); |
| } |
| |
| fun _handleMoveCursorForwardByCharacter(extentSelection: Boolean) { |
| TODO("Not yet implemented") |
| // final int extentOffset = _textPainter.getOffsetAfter(_selection.extentOffset); |
| // if (extentOffset == null) |
| // return; |
| // final int baseOffset = !extentSelection ? extentOffset : _selection.baseOffset; |
| // onSelectionChanged( |
| // TextSelection(baseOffset: baseOffset, extentOffset: extentOffset), this, SelectionChangedCause.keyboard, |
| // ); |
| } |
| |
| fun _handleMoveCursorBackwardByCharacter(extentSelection: Boolean) { |
| TODO("Not yet implemented") |
| // final int extentOffset = _textPainter.getOffsetBefore(_selection.extentOffset); |
| // if (extentOffset == null) |
| // return; |
| // final int baseOffset = !extentSelection ? extentOffset : _selection.baseOffset; |
| // onSelectionChanged( |
| // TextSelection(baseOffset: baseOffset, extentOffset: extentOffset), this, SelectionChangedCause.keyboard, |
| // ); |
| } |
| |
| fun _handleMoveCursorForwardByWord(extentSelection: Boolean) { |
| TODO("Not yet implemented") |
| // final TextRange currentWord = _textPainter.getWordBoundary(_selection.extent); |
| // if (currentWord == null) |
| // return; |
| // final TextRange nextWord = _getNextWord(currentWord.end); |
| // if (nextWord == null) |
| // return; |
| // final int baseOffset = extentSelection ? _selection.baseOffset : nextWord.start; |
| // onSelectionChanged( |
| // TextSelection( |
| // baseOffset: baseOffset, |
| // extentOffset: nextWord.start, |
| // ), |
| // this, |
| // SelectionChangedCause.keyboard, |
| // ); |
| } |
| |
| fun _handleMoveCursorBackwardByWord(extentSelection: Boolean) { |
| TODO("Not yet implemented") |
| // final TextRange currentWord = _textPainter.getWordBoundary(_selection.extent); |
| // if (currentWord == null) |
| // return; |
| // final TextRange previousWord = _getPreviousWord(currentWord.start - 1); |
| // if (previousWord == null) |
| // return; |
| // final int baseOffset = extentSelection ? _selection.baseOffset : previousWord.start; |
| // onSelectionChanged( |
| // TextSelection( |
| // baseOffset: baseOffset, |
| // extentOffset: previousWord.start, |
| // ), |
| // this, |
| // SelectionChangedCause.keyboard, |
| // ); |
| } |
| |
| fun _getNextWord(offset: Int): TextRange { |
| TODO("Not yet implemented") |
| // |
| // while (true) { |
| // final TextRange range = _textPainter.getWordBoundary(TextPosition(offset: offset)); |
| // if (range == null || !range.isValid || range.isCollapsed) |
| // return null; |
| // if (!_onlyWhitespace(range)) |
| // return range; |
| // offset = range.end; |
| // } |
| } |
| |
| fun _getPreviousWord(offset: Int): TextRange { |
| TODO("Not yet implemented") |
| // while (offset >= 0) { |
| // final TextRange range = _textPainter.getWordBoundary(TextPosition(offset: offset)); |
| // if (range == null || !range.isValid || range.isCollapsed) |
| // return null; |
| // if (!_onlyWhitespace(range)) |
| // return range; |
| // offset = range.start - 1; |
| // } |
| // return null; |
| } |
| |
| // Check if the given text range only contains white space or separator |
| // characters. |
| // |
| // newline characters from ascii and separators from the |
| // [unicode separator category](https://www.compart.com/en/unicode/category/Zs) |
| // TODO(jonahwilliams): replace when we expose this ICU information. |
| fun _onlyWhitespace(ramge: TextRange): Boolean { |
| TODO("Not yet implemented") |
| // |
| // for (int i = range.start; i < range.end; i++) { |
| // final int codeUnit = text.codeUnitAt(i); |
| // switch (codeUnit) { |
| // case 0x9: // horizontal tab |
| // case 0xA: // line feed |
| // case 0xB: // vertical tab |
| // case 0xC: // form feed |
| // case 0xD: // carriage return |
| // case 0x1C: // file separator |
| // case 0x1D: // group separator |
| // case 0x1E: // record separator |
| // case 0x1F: // unit separator |
| // case 0x20: // space |
| // case 0xA0: // no-break space |
| // case 0x1680: // ogham space mark |
| // case 0x2000: // en quad |
| // case 0x2001: // em quad |
| // case 0x2002: // en space |
| // case 0x2003: // em space |
| // case 0x2004: // three-per-em space |
| // case 0x2005: // four-er-em space |
| // case 0x2006: // six-per-em space |
| // case 0x2007: // figure space |
| // case 0x2008: // punctuation space |
| // case 0x2009: // thin space |
| // case 0x200A: // hair space |
| // case 0x202F: // narrow no-break space |
| // case 0x205F: // medium mathematical space |
| // case 0x3000: // ideographic space |
| // break; |
| // default: |
| // return false; |
| // } |
| // } |
| // return true; |
| } |
| |
| override fun attach(owner: Any) { |
| super.attach(owner) |
| TODO("Not yet implemented") |
| // super.attach(owner); |
| // _offset.addListener(markNeedsPaint); |
| // _showCursor.addListener(markNeedsPaint); |
| } |
| |
| override fun detach() { |
| super.detach() |
| TODO("Not yet implemented") |
| // offset.removeListener(markNeedsPaint); |
| // showCursor.removeListener(markNeedsPaint); |
| // if (_listenerAttached) |
| // RawKeyboard.instance.removeListener(_handleKeyEvent); |
| // super.detach(); |
| } |
| |
| // bool get _isMultiline => maxLines != 1; |
| |
| // Axis get _viewportAxis => _isMultiline ? Axis.vertical : Axis.horizontal; |
| |
| // Offset get _paintOffset { |
| // switch (_viewportAxis) { |
| // case Axis.horizontal: |
| // return Offset(-offset.pixels, 0.0); |
| // case Axis.vertical: |
| // return Offset(0.0, -offset.pixels); |
| // } |
| // return null; |
| // } |
| |
| // double get _viewportExtent { |
| // assert(hasSize); |
| // switch (_viewportAxis) { |
| // case Axis.horizontal: |
| // return size.width; |
| // case Axis.vertical: |
| // return size.height; |
| // } |
| // return null; |
| // } |
| |
| fun _getMaxScrollExtent(contentSize: Size): Float { |
| TODO("Not yet implemented") |
| // assert(hasSize); |
| // switch (_viewportAxis) { |
| // case Axis.horizontal: |
| // return math.max(0.0, contentSize.width - size.width); |
| // case Axis.vertical: |
| // return math.max(0.0, contentSize.height - size.height); |
| // } |
| // return null; |
| } |
| |
| // double _maxScrollExtent = 0; |
| |
| // We need to check the paint offset here because during animation, the start of |
| // the text may position outside the visible region even when the text fits. |
| // bool get _hasVisualOverflow => _maxScrollExtent > 0 || _paintOffset != Offset.zero; |
| |
| /** |
| * Returns the local coordinates of the endpoints of the given selection. |
| * |
| * If the selection is collapsed (and therefore occupies a single point), the returned list is |
| * of length one. Otherwise, the selection is not collapsed and the returned list is of length |
| * two. In this case, however, the two points might actually be co-located (e.g., because of a |
| * bidirectional selection that contains some text but whose ends meet in the middle). |
| * |
| * See also: |
| * |
| * * [getLocalRectForCaret], which is the equivalent but for a [TextPosition] rather than a |
| * [TextSelection]. |
| */ |
| fun getEndpointsForSelection(selection: TextSelection): List<TextSelectionPoint> { |
| TODO("Not yet implemented") |
| // assert(constraints != null); |
| // _layoutText(constraints.maxWidth); |
| // |
| // final Offset paintOffset = _paintOffset; |
| // |
| // if (selection.isCollapsed) { |
| // // TODO(mpcomplete): This doesn't work well at an RTL/LTR boundary. |
| // final Offset caretOffset = _textPainter.getOffsetForCaret(selection.extent, _caretPrototype); |
| // final Offset start = Offset(0.0, preferredLineHeight) + caretOffset + paintOffset; |
| // return <TextSelectionPoint>[TextSelectionPoint(start, null)]; |
| // } else { |
| // final List<ui.TextBox> boxes = _textPainter.getBoxesForSelection(selection); |
| // final Offset start = Offset(boxes.first.start, boxes.first.bottom) + paintOffset; |
| // final Offset end = Offset(boxes.last.end, boxes.last.bottom) + paintOffset; |
| // return <TextSelectionPoint>[ |
| // TextSelectionPoint(start, boxes.first.direction), |
| // TextSelectionPoint(end, boxes.last.direction), |
| // ]; |
| // } |
| } |
| |
| /** |
| * Returns the position in the text for the given global coordinate. |
| * |
| * See also: |
| * |
| * * [getLocalRectForCaret], which is the reverse operation, taking a [TextPosition] and |
| * returning a [Rect]. |
| * * [TextPainter.getPositionForOffset], which is the equivalent method for a [TextPainter] |
| * object. |
| */ |
| fun getPositionForPoint(globalPosition: Offset): TextPosition { |
| TODO("Not yet implemented") |
| // _layoutText(constraints.maxWidth); |
| // globalPosition += -_paintOffset; |
| // return _textPainter.getPositionForOffset(globalToLocal(globalPosition)); |
| } |
| |
| /** |
| * Returns the [Rect] in local coordinates for the caret at the given text |
| * position. |
| * |
| * See also: |
| * |
| * * [getPositionForPoint], which is the reverse operation, taking |
| * an [Offset] in global coordinates and returning a [TextPosition]. |
| * * [getEndpointsForSelection], which is the equivalent but for |
| * a selection rather than a particular text position. |
| * * [TextPainter.getOffsetForCaret], the equivalent method for a |
| * [TextPainter] object. |
| */ |
| fun getLocalRectForCaret(caretPosition: TextPosition): Rect { |
| TODO("Not yet implemented") |
| // _layoutText(constraints.maxWidth); |
| // final Offset caretOffset = _textPainter.getOffsetForCaret(caretPosition, _caretPrototype); |
| // // This rect is the same as _caretPrototype but without the vertical padding. |
| // return Rect.fromLTWH(0.0, 0.0, cursorWidth, preferredLineHeight).shift(caretOffset + _paintOffset); |
| } |
| |
| override fun computeMinIntrinsicWidth(height: Float): Float { |
| TODO("Not yet implemented") |
| // _layoutText(double.infinity); |
| // return _textPainter.minIntrinsicWidth; |
| } |
| |
| override fun computeMaxIntrinsicWidth(height: Float): Float { |
| TODO("Not yet implemented") |
| // _layoutText(double.infinity); |
| // return _textPainter.maxIntrinsicWidth; |
| } |
| |
| /** |
| * An estimate of the height of a line in the text. See [TextPainter.preferredLineHeight]. |
| * This does not required the layout to be updated. |
| */ |
| // double get preferredLineHeight => _textPainter.preferredLineHeight; |
| |
| fun _preferredHeight(width: Float): Float { |
| TODO("Not yet implemented") |
| // if (maxLines != null) |
| // return preferredLineHeight * maxLines; |
| // if (width == double.infinity) { |
| // final String text = _textPainter.text.toPlainText(); |
| // int lines = 1; |
| // for (int index = 0; index < text.length; index += 1) { |
| // if (text.codeUnitAt(index) == 0x0A) // count explicit line breaks |
| // lines += 1; |
| // } |
| // return preferredLineHeight * lines; |
| // } |
| // _layoutText(width); |
| // return math.max(preferredLineHeight, _textPainter.height); |
| } |
| |
| override fun computeMinIntrinsicHeight(width: Float): Float { |
| TODO("Not yet implemented") |
| // return _preferredHeight(width); |
| } |
| |
| override fun computeMaxIntrinsicHeight(width: Float): Float { |
| TODO("Not yet implemented") |
| // return _preferredHeight(width); |
| } |
| |
| override fun computeDistanceToActualBaseline(baseline: TextBaseline): Float? { |
| TODO("Not yet implemented") |
| // _layoutText(constraints.maxWidth); |
| // return _textPainter.computeDistanceToActualBaseline(baseline); |
| } |
| |
| override fun hitTestSelf(position: Offset): Boolean = true |
| |
| // TapGestureRecognizer _tap; |
| // LongPressGestureRecognizer _longPress; |
| |
| override fun handleEvent(event: PointerEvent, entry: HitTestEntry) { |
| TODO("Not yet implemented") |
| // if (ignorePointer) |
| // return; |
| // assert(debugHandleEvent(event, entry)); |
| // if (event is PointerDownEvent && onSelectionChanged != null) { |
| // _tap.addPointer(event); |
| // _longPress.addPointer(event); |
| // } |
| } |
| |
| // Offset _lastTapDownPosition; |
| |
| /** |
| * If [ignorePointer] is false (the default) then this method is called by the internal gesture |
| * recognizer's [TapGestureRecognizer.onTapDown] callback. |
| * |
| * When [ignorePointer] is true, an ancestor widget must respond to tap down events by calling |
| * this method. |
| */ |
| fun handleTapDown(details: TapDownDetails) { |
| TODO("Not yet implemented") |
| // _lastTapDownPosition = details.globalPosition + -_paintOffset; |
| } |
| |
| fun _handleTapDown(details: TapDownDetails) { |
| TODO("Not yet implemented") |
| // assert(!ignorePointer); |
| // handleTapDown(details); |
| } |
| |
| /** |
| * If [ignorePointer] is false (the default) then this method is called by the internal gesture |
| * recognizer's [TapGestureRecognizer.onTap] callback. |
| * |
| * When [ignorePointer] is true, an ancestor widget must respond to tap events by calling this |
| * method. |
| */ |
| fun handleTap() { |
| TODO("Not yet implemented") |
| // selectPosition(cause: SelectionChangedCause.tap); |
| } |
| |
| fun _handleTap() { |
| TODO("Not yet implemented") |
| // assert(!ignorePointer); |
| // handleTap(); |
| } |
| |
| /** |
| * If [ignorePointer] is false (the default) then this method is called by the internal gesture |
| * recognizer's [DoubleTapGestureRecognizer.onDoubleTap] callback. |
| * |
| * When [ignorePointer] is true, an ancestor widget must respond to double tap events by calling |
| * this method. |
| */ |
| fun handleDoubleTap() { |
| TODO("Not yet implemented") |
| // selectWord(cause: SelectionChangedCause.doubleTap); |
| } |
| |
| /** |
| * If [ignorePointer] is false (the default) then this method is called by the internal gesture |
| * recognizer's [LongPressRecognizer.onLongPress] callback. |
| * |
| * When [ignorePointer] is true, an ancestor widget must respond to long press events by calling |
| * this method. |
| */ |
| fun handleLongPress() { |
| TODO("Not yet implemented") |
| // selectWord(cause: SelectionChangedCause.longPress); |
| } |
| |
| fun _handleLongPress() { |
| TODO("Not yet implemented") |
| // assert(!ignorePointer); |
| // handleLongPress(); |
| } |
| |
| /** Move selection to the location of the last tap down. */ |
| fun selectPosition(cause: SelectionChangedCause) { |
| TODO("Not yet implemented") |
| // assert(cause != null); |
| // _layoutText(constraints.maxWidth); |
| // assert(_lastTapDownPosition != null); |
| // if (onSelectionChanged != null) { |
| // final TextPosition position = _textPainter.getPositionForOffset(globalToLocal(_lastTapDownPosition)); |
| // onSelectionChanged(TextSelection.fromPosition(position), this, cause); |
| // } |
| } |
| |
| /** Select a word around the location of the last tap down. */ |
| fun selectWord(cause: SelectionChangedCause) { |
| TODO("Not yet implemented") |
| // assert(cause != null); |
| // _layoutText(constraints.maxWidth); |
| // assert(_lastTapDownPosition != null); |
| // if (onSelectionChanged != null) { |
| // final TextPosition position = _textPainter.getPositionForOffset(globalToLocal(_lastTapDownPosition)); |
| // onSelectionChanged(_selectWordAtOffset(position), this, cause); |
| // } |
| } |
| |
| /** Move the selection to the beginning or end of a word. */ |
| fun selectWordEdge(cause: SelectionChangedCause) { |
| TODO("Not yet implemented") |
| // assert(cause != null); |
| // _layoutText(constraints.maxWidth); |
| // assert(_lastTapDownPosition != null); |
| // if (onSelectionChanged != null) { |
| // final TextPosition position = _textPainter.getPositionForOffset(globalToLocal(_lastTapDownPosition)); |
| // final TextRange word = _textPainter.getWordBoundary(position); |
| // if (position.offset - word.start <= 1) { |
| // onSelectionChanged( |
| // TextSelection.collapsed(offset: word.start, affinity: TextAffinity.downstream), |
| // this, |
| // cause, |
| // ); |
| // } else { |
| // onSelectionChanged( |
| // TextSelection.collapsed(offset: word.end, affinity: TextAffinity.upstream), |
| // this, |
| // cause, |
| // ); |
| // } |
| // } |
| } |
| |
| fun _selectWordAtOffset(position: TextPosition): TextSelection { |
| TODO("Not yet implemented") |
| // assert(_textLayoutLastWidth == constraints.maxWidth); |
| // final TextRange word = _textPainter.getWordBoundary(position); |
| // // When long-pressing past the end of the text, we want a collapsed cursor. |
| // if (position.offset >= word.end) |
| // return TextSelection.fromPosition(position); |
| // return TextSelection(baseOffset: word.start, extentOffset: word.end); |
| } |
| |
| // Rect _caretPrototype; |
| |
| fun _layoutText(constraintWidth: Float) { |
| TODO("Not yet implemented") |
| // assert(constraintWidth != null); |
| // if (_textLayoutLastWidth == constraintWidth) |
| // return; |
| // final double caretMargin = _kCaretGap + cursorWidth; |
| // final double availableWidth = math.max(0.0, constraintWidth - caretMargin); |
| // final double maxWidth = _isMultiline ? availableWidth : double.infinity; |
| // _textPainter.layout(minWidth: availableWidth, maxWidth: maxWidth); |
| // _textLayoutLastWidth = constraintWidth; |
| } |
| |
| override fun performLayout() { |
| TODO("Not yet implemented") |
| // _layoutText(constraints.maxWidth); |
| // _caretPrototype = Rect.fromLTWH(0.0, _kCaretHeightOffset, cursorWidth, preferredLineHeight - 2.0 * _kCaretHeightOffset); |
| // _selectionRects = null; |
| // // We grab _textPainter.size here because assigning to `size` on the next |
| // // line will trigger us to validate our intrinsic sizes, which will change |
| // // _textPainter's layout because the intrinsic size calculations are |
| // // destructive, which would mean we would get different results if we later |
| // // used properties on _textPainter in this method. |
| // // Other _textPainter state like didExceedMaxLines will also be affected, |
| // // though we currently don't use those here. |
| // // See also RenderParagraph which has a similar issue. |
| // final Size textPainterSize = _textPainter.size; |
| // size = Size(constraints.maxWidth, constraints.constrainHeight(_preferredHeight(constraints.maxWidth))); |
| // final Size contentSize = Size(textPainterSize.width + _kCaretGap + cursorWidth, textPainterSize.height); |
| // _maxScrollExtent = _getMaxScrollExtent(contentSize); |
| // offset.applyViewportDimension(_viewportExtent); |
| // offset.applyContentDimensions(0.0, _maxScrollExtent); |
| } |
| |
| fun _paintCaret(canvas: Canvas, effectiveOffset: Offset) { |
| TODO("Not yet implemented") |
| // assert(_textLayoutLastWidth == constraints.maxWidth); |
| // final Offset caretOffset = _textPainter.getOffsetForCaret(_selection.extent, _caretPrototype); |
| // final Paint paint = Paint() |
| // ..color = _cursorColor; |
| // |
| // final Rect caretRect = _caretPrototype.shift(caretOffset + effectiveOffset); |
| // |
| // if (cursorRadius == null) { |
| // canvas.drawRect(caretRect, paint); |
| // } else { |
| // final RRect caretRRect = RRect.fromRectAndRadius(caretRect, cursorRadius); |
| // canvas.drawRRect(caretRRect, paint); |
| // } |
| // |
| // if (caretRect != _lastCaretRect) { |
| // _lastCaretRect = caretRect; |
| // if (onCaretChanged != null) |
| // onCaretChanged(caretRect); |
| // } |
| } |
| |
| fun _paintSelection(canvas: Canvas, effectiveOffset: Offset) { |
| TODO("Not yet implemented") |
| // assert(_textLayoutLastWidth == constraints.maxWidth); |
| // assert(_selectionRects != null); |
| // final Paint paint = Paint()..color = _selectionColor; |
| // for (ui.TextBox box in _selectionRects) |
| // canvas.drawRect(box.toRect().shift(effectiveOffset), paint); |
| } |
| |
| fun _paintContents(context: PaintingContext, offset: Offset) { |
| TODO("Not yet implemented") |
| // assert(_textLayoutLastWidth == constraints.maxWidth); |
| // final Offset effectiveOffset = offset + _paintOffset; |
| // |
| // if (_selection != null) { |
| // if (_selection.isCollapsed && _showCursor.value && cursorColor != null) { |
| // _paintCaret(context.canvas, effectiveOffset); |
| // } else if (!_selection.isCollapsed && _selectionColor != null) { |
| // _selectionRects ??= _textPainter.getBoxesForSelection(_selection); |
| // _paintSelection(context.canvas, effectiveOffset); |
| // } |
| // } |
| // |
| // _textPainter.paint(context.canvas, effectiveOffset); |
| } |
| |
| override fun paint(context: PaintingContext, offset: Offset) { |
| TODO("Not yet implemented") |
| // _layoutText(constraints.maxWidth); |
| // if (_hasVisualOverflow) |
| // context.pushClipRect(needsCompositing, offset, Offset.zero & size, _paintContents); |
| // else |
| // _paintContents(context, offset); |
| } |
| |
| override fun describeApproximatePaintClip(child: RenderObject): Rect? { |
| TODO("Not yet implemented") |
| } |
| // @override |
| // Rect describeApproximatePaintClip(RenderObject child) => _hasVisualOverflow ? Offset.zero & size : null; |
| |
| override fun debugFillProperties(properties: DiagnosticPropertiesBuilder) { |
| TODO("Not yet implemented") |
| // super.debugFillProperties(properties); |
| // properties.add(DiagnosticsProperty<Color>('cursorColor', cursorColor)); |
| // properties.add(DiagnosticsProperty<ValueNotifier<bool>>('showCursor', showCursor)); |
| // properties.add(IntProperty('maxLines', maxLines)); |
| // properties.add(DiagnosticsProperty<Color>('selectionColor', selectionColor)); |
| // properties.add(FloatProperty('textScaleFactor', textScaleFactor)); |
| // properties.add(DiagnosticsProperty<Locale>('locale', locale, defaultValue: null)); |
| // properties.add(DiagnosticsProperty<TextSelection>('selection', selection)); |
| // properties.add(DiagnosticsProperty<ViewportOffset>('offset', offset)); |
| } |
| |
| override fun debugDescribeChildren(): List<DiagnosticsNode> { |
| TODO("Not yet implemented") |
| // return <DiagnosticsNode>[ |
| // text.toDiagnosticsNode( |
| // name: 'text', |
| // style: DiagnosticsTreeStyle.transition, |
| // ), |
| // ]; |
| } |
| } |