Source code for TermTk.TTkWidgets.texedit

# MIT License
#
# Copyright (c) 2021 Eugenio Parodi <ceccopierangiolieugenio AT googlemail DOT com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

__all__ = ['TTkTextEditView', 'TTkTextEdit', 'TTkTextEditRuler']

from typing import List,Optional,Union,Dict,Any,TYPE_CHECKING

from TermTk.TTkCore.log import TTkLog
from TermTk.TTkCore.cfg import TTkCfg
from TermTk.TTkCore.constant import TTkK
from TermTk.TTkCore.color import TTkColor
from TermTk.TTkCore.string import TTkString, TTkStringType
from TermTk.TTkCore.canvas import TTkCanvas
from TermTk.TTkCore.signal import pyTTkSignal, pyTTkSlot
from TermTk.TTkCore.TTkTerm.inputkey import TTkKeyEvent
from TermTk.TTkCore.TTkTerm.inputmouse import TTkMouseEvent

from TermTk.TTkGui.clipboard import TTkClipboard
from TermTk.TTkGui.textwrap1 import TTkTextWrap
from TermTk.TTkGui.textcursor import TTkTextCursor
from TermTk.TTkGui.textdocument import TTkTextDocument

from TermTk.TTkWidgets.widget import TTkWidget

from TermTk.TTkAbstract.abstractscrollarea import TTkAbstractScrollArea, _ForwardData
from TermTk.TTkAbstract.abstractscrollview import TTkAbstractScrollView, TTkAbstractScrollViewGridLayout

[docs] class TTkTextEditRuler(TTkAbstractScrollView): class MarkRuler(): class States(int): NONE = 0x00 FLAGGED = 0x01 UNFLAGGED = NONE # class MarkRulerType(int): # ALLOW_EMPTY = 0x01 # SINGLE_STATE = 0x02 # MULTI_STATE = 0x04 __slots__ = ('_markers','_states','_width','_lines','_defaultState') def __init__(self, markers:dict[int,TTkString]) -> None: self._lines:Dict[int,int] = {} self._markers = markers self._states = len(markers) self._defaultState = next(iter(markers)) self._width = max(v.termWidth() for v in markers.values()) def width(self) -> int: return self._width def nextState(self, state:int) -> int: return (state+1)%self._states def setState(self, line:int, state:int) -> None: if state == self._defaultState: if line in self._lines: del self._lines[line] self._lines[line] = state def getState(self, line:int) -> int: return self._lines.get(line, self._defaultState) def getTTkStr(self, line:int) -> TTkString: state=self._lines.get(line, self._defaultState) return self._markers.get(state, TTkString()) classStyle = { 'default': { 'color': TTkColor.fg("#88aaaa")+TTkColor.bg("#333333"), 'wrapColor': TTkColor.fg("#888888")+TTkColor.bg("#333333"), 'separatorColor': TTkColor.fg("#444444")}, 'disabled': { 'color': TTkColor.fg('#888888'), 'wrapColor': TTkColor.fg('#888888'), 'separatorColor': TTkColor.fg("#888888")}, } __slots__ = ('_textWrap','_startingNumber', '_markRuler', '_markRulerSizes') def __init__(self, startingNumber=0, **kwargs) -> None: self._startingNumber:int = startingNumber self._textWrap:Optional[TTkTextWrap] = None self._markRuler:List[TTkTextEditRuler.MarkRuler] = [] self._markRulerSizes:List[int] = [] super().__init__(**kwargs) self.setMaximumWidth(2) def _wrapChanged(self) -> None: if not self._textWrap: return dt = max(1,self._textWrap._lines[-1][0]) off = self._startingNumber width = 2+max(len(str(int(dt+off))),len(str(int(off)))) width += sum(self._markRulerSizes) self.setMaximumWidth(width) self.update()
[docs] def addMarkRuler(self, markRuler:MarkRuler) -> None: self._markRuler.append(markRuler) self._markRulerSizes.append(markRuler.width()) self._wrapChanged()
[docs] def setTextWrap(self, tw:TTkTextWrap) -> None: if self._textWrap: self._textWrap.wrapChanged.disconnect(self._wrapChanged) self._textWrap = tw tw.wrapChanged.connect(self._wrapChanged) self._wrapChanged()
def viewFullAreaSize(self) -> tuple[int,int]: if self._textWrap: return 5, self._textWrap.size() else: return self.size() def mousePressEvent(self, evt:TTkMouseEvent) -> bool: if not self._markRuler: return True ox, oy = self.getViewOffsets() w, h = self.size() mx,my = evt.x+ox, evt.y+oy for mk in self._markRuler: mx -= mk.width() if mx < 0: break if self._textWrap and my < len(self._textWrap._lines): dt = self._textWrap._lines[my][0] mk.setState(dt, mk.nextState(mk.getState(dt))) else: mk.setState(my, mk.nextState(mk.getState(my))) self.update() return True def paintEvent(self, canvas: TTkCanvas) -> None: if not self._textWrap: return _, oy = self.getViewOffsets() w, h = self.size() off = self._startingNumber leftOff = sum(self._markRulerSizes) sum(self._markRulerSizes) style = self.currentStyle() color = style['color'] wrapColor = style['wrapColor'] separatorColor = style['separatorColor'] if self._textWrap: for i, (dt, (fr, _)) in enumerate(self._textWrap._lines[oy:oy+h]): if fr: canvas.drawText(pos=(leftOff,i), text='<', width=w, color=wrapColor) else: canvas.drawText(pos=(leftOff,i), text=f"{dt+off}", width=w, color=color) canvas.drawChar(pos=(w-1,i), char='▌', color=separatorColor) else: for y in range(h): canvas.drawText(pos=(leftOff,y), text=f"{y+oy+off}", width=w, color=color) canvas.drawChar(pos=(w-1,y), char='▌', color=separatorColor) ox = 0 for mk in self._markRuler: if self._textWrap: for i, (dt, (fr, _)) in enumerate(self._textWrap._lines[oy:oy+h]): if not fr: canvas.drawText(pos=(ox,i), text=mk.getTTkStr(dt+off)) else: for y in range(h): canvas.drawText(pos=(ox,y), text=mk.getTTkStr(dt+off)) ox += mk.width()
[docs] class TTkTextEditView(TTkAbstractScrollView): ''' :py:class:`TTkTextEditView` :: ╔═══════════════════════════════════════════════════════════════════════════════════════╗ ║ 0▌"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ╥ ║ ║ <▌incididunt ut labore et dolore magna aliqua. ║ ║ ║ 1▌ ║ ║ ║ 2▌Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliqu║ ║ ║ <▌ip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate ║ ║ ║ <▌velit esse cillum dolore eu fugiat nulla pariatur. ║ ║ ║ 3▌ ║ ║ ║ 4▌Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deseru║ ║ ║ <▌nt mollit anim id est laborum." ╨ ║ ╚═══════════════════════════════════════════════════════════════════════════════════════╝ Demo: :ttk:sbIntLink:`demo/showcase,textedit.py` :ref:`ttkdesigner Tutorial <TextEdit_ttkDesigner-Tutorial_Intro>` ''' class ExtraSelection(): ''' The :py:class:`ExtraSelection` structure provides a way of specifying a character format for a given selection in a document. :param format: A format that is used to specify the type of selection, defaults to :py:class:`TTkK.NONE`. :type format: :py:class:`TTkK.SelectionFormat` :param color: The color used to specify the foreground/background color/mod for the selection. :type color: :py:class:`TTkColor` :param cursor: A cursor that contains a selection in a :py:class:`QTextDocument`. :type cursor: :py:class:`TTkTextCursor` ''' __slots__ = ('_format', '_color', '_cursor') def __init__(self, cursor:TTkTextCursor, format:TTkK.SelectionFormat=TTkK.SelectionFormat.NONE, color:TTkColor=TTkColor.RST) -> None: self._color = color self._format = format self._cursor = cursor def color(self) -> TTkColor: ''' This propery holds the color that is used for the selection. :rtype: :py:class:`TTkColor` ''' return self._color def setColor(self, color:TTkColor) -> None: ''' Set the color. :param color: A color that is used for the selection. :type color: :py:class:`TTkColor` ''' self._color = color def format(self) -> TTkK.SelectionFormat: ''' This propery holds the format that is used to specify the type of selection. :rtype: :py:class:`TTkK.SelectionFormat` ''' return self._format def setFormat(self, format:TTkK.SelectionFormat) -> None: ''' Set the format. :param format: A format that is used to specify the type of selection. :type format: :py:class:`TTkK.SelectionFormat` ''' self._format = format def cursor(self) -> TTkTextCursor: ''' This propery holds the fcursor that contains a selection in a :py:class:`QTextDocument`. :rtype: :py:class:`TTkTextCursor` ''' return self._cursor def setCursor(self, cursor:TTkTextCursor) -> None: ''' Set the cursor. :param cursor: A cursor that contains a selection in a :py:class:`QTextDocument`. :type cursor: :py:class:`TTkTextCursor` ''' self._cursor = cursor @property def currentColorChanged(self) -> pyTTkSignal: ''' This signal is emitted if the current character color has changed, for example caused by a change of the cursor position. :param color: the new color :type color: :py:class:`TTkColor` ''' return self._currentColorChanged @property def cursorPositionChanged(self) -> pyTTkSignal: ''' This signal is emitted whenever the position of the cursor changed. :param cursor: the cursor changed. :type cursor: :py:class:`TTkTextCursor` ''' return self._cursorPositionChanged_sig @property def undoAvailable(self) -> pyTTkSignal: ''' This signal is emitted whenever undo operations become available (available is true) or unavailable (available is false). :param available: the availability of undo :type available: bool ''' return self._undoAvailable_sig @property def redoAvailable(self) -> pyTTkSignal: ''' This signal is emitted whenever redo operations become available (available is true) or unavailable (available is false). :param available: the availability of redo :type available: bool ''' return self._redoAvailable_sig @property def textChanged(self) -> pyTTkSignal: ''' This signal is emitted whenever the document's content changes; for example, when text is inserted or deleted, or when formatting is applied. ''' return self._textChanged classStyle = { 'default': {'color': TTkColor.fg("#dddddd")+TTkColor.bg("#222222"), 'selectedColor': TTkColor.fg("#ffffff")+TTkColor.bg("#008844"), 'lineColor': TTkColor.fg("#444444"), 'wrapLineColor': TTkColor.fg("#888888")+TTkColor.bg("#333333")}, 'disabled': {'color': TTkColor.fg('#888888'), 'selectedColor': TTkColor.bg("#888888"), 'lineColor': TTkColor.fg("#888888"), 'wrapLineColor': TTkColor.fg('#888888')}, 'focus': {'selectedColor': TTkColor.fg("#ffffff")+TTkColor.bg("#008888")}, } __slots__ = ( '_textDocument', '_hsize', '_textCursor', '_extraSelections', '_textWrap', '_lineWrapMode', '_lastWrapUsed', '_replace', '_readOnly', '_multiCursor', '_clipboard', # '_preview', '_previewWidth', '_multiLine', # # Forwarded Methods # 'wrapWidth', 'setWrapWidth', # 'wordWrapMode', 'setWordWrapMode', # Signals '_currentColorChanged', '_cursorPositionChanged_sig', '_undoAvailable_sig', '_redoAvailable_sig', '_textChanged' ) _textWrap:TTkTextWrap _textDocument:TTkTextDocument _textCursor:TTkTextCursor # in order to support the line wrap, I need to divide the full data text in; # _textDocument = the entire text divided in lines, easy to add/remove/append lines # _textWrap._lines = an array of tuples for each displayed line with a pointer to a # specific line and its slice to be shown at this coordinate; # [ (line, (posFrom, posTo)), ... ] # This is required to support the wrap feature def __init__(self, *, readOnly:bool=False, multiLine:bool=True, document:Optional[TTkTextDocument]=None, **kwargs) -> None: ''' :param lineNumber: Show the line number on the left, defaults to **False** :type lineNumber: bool, optional :param readOnly: In a read-only text edit the user can only navigate through the text and select text; modifying the text is not possible, defaults to **True** :type readOnly: bool, optional :param multiLine: In a multiline text edit the user can split the text in multiple lines, defaults to **True** :type multiLine: bool, optional :param document: If required an external Document can be used in this text editor, this option is useful if multiple editors share the same document as in the `demo <https://ceccopierangiolieugenio.github.io/pyTermTk-Docs/sandbox/sandbox.html?filePath=demo/showcase/textedit.py>`__, defaults to a new Document :type document: :py:class:`TTkTextDocument`, optional ''' self._currentColorChanged = pyTTkSignal(TTkColor) self._cursorPositionChanged_sig = pyTTkSignal(TTkTextCursor) self._undoAvailable_sig = pyTTkSignal(bool) self._redoAvailable_sig = pyTTkSignal(bool) self._textChanged = pyTTkSignal() self._readOnly:bool = readOnly self._multiLine:bool = multiLine self._multiCursor:bool = True self._extraSelections:List[TTkTextEditView.ExtraSelection] = [] self._hsize:int = 0 self._lastWrapUsed = 0 self._lineWrapMode = TTkK.NoWrap self._replace = False self._clipboard = TTkClipboard() self._setDocument(document) super().__init__(**kwargs) self.setFocusPolicy(TTkK.ClickFocus | TTkK.TabFocus) self.disableWidgetCursor(self._readOnly) self._updateSize() self.viewChanged.connect(self._pushCursor)
[docs] def multiLine(self) -> bool: ''' This property define if the text edit area will use a single line, like in the line-edit or it allows multilines like a normal text edit area. :rtype: bool ''' return self._multiLine
@pyTTkSlot(bool) def _undoAvailable(self, available) -> None: self.undoAvailable.emit(available) @pyTTkSlot(bool) def _redoAvailable(self, available) -> None: self.redoAvailable.emit(available) # def toHtml(self, encoding): pass # if self._textDocument: # return self._textDocument.toHtml() # return "" # def toMarkdown(self, features): pass # if self._textDocument: # return self._textDocument.toMarkdown() # return ""
[docs] def toAnsi(self) -> str: ''' Returns the text of the text edit as ANSI test string. This string will insluce the ANSI escape codes for color and text formatting. :rtype: str ''' if self._textDocument: return self._textDocument.toAnsi() return ""
[docs] def toPlainText(self) ->str: ''' Returns the text of the text edit as plain text string. :rtype: str ''' if self._textDocument: return self._textDocument.toPlainText() return ""
[docs] def toRawText(self) -> TTkString: ''' Return :py:class:`TTkString` representing the document :rtype: :py:class:`TTkString` ''' if self._textDocument: return self._textDocument.toRawText() return TTkString()
[docs] def isUndoAvailable(self) -> bool: ''' This property holds whether undo is available. :return: the undo available status :rtype: bool ''' if self._textDocument: return self._textDocument.isUndoAvailable() return False
[docs] def isRedoAvailable(self) -> bool: ''' This property holds whether redo is available. :return: the redo available status :rtype: bool ''' if self._textDocument: return self._textDocument.isRedoAvailable() return False
[docs] def document(self) -> TTkTextDocument: ''' This property holds the underlying document of the text editor. :rtype: :py:class:`TTkTextDocument` ''' return self._textDocument
def _setDocument(self, document:Optional[TTkTextDocument]) -> None: if not document: document = TTkTextDocument() self._textDocument = document self._textCursor = TTkTextCursor(document=self._textDocument) self._textWrap = TTkTextWrap(document=self._textDocument) self._textWrap.wrapChanged.connect(self.update) self._textDocument.contentsChanged.connect(self._documentChanged) self._textDocument.cursorPositionChanged.connect(self._cursorPositionChanged) self._textDocument.undoAvailable.connect(self._undoAvailable) self._textDocument.redoAvailable.connect(self._redoAvailable) self._textDocument.formatChanged.connect(self.update)
[docs] def setDocument(self, document:TTkTextDocument) -> None: ''' Set the underlying document of the text editor. :param document: the text document :type document: :py:class:`TTkTextDocument` ''' self._textDocument.contentsChanged.disconnect(self._documentChanged) self._textDocument.cursorPositionChanged.disconnect(self._cursorPositionChanged) self._textDocument.undoAvailable.disconnect(self._undoAvailable) self._textDocument.redoAvailable.disconnect(self._redoAvailable) self._textDocument.formatChanged.disconnect(self.update) self._textWrap.wrapChanged.disconnect(self.update) self._setDocument(document)
# forward textWrap Methods
[docs] def wrapWidth(self, *args, **kwargs) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextWrap.wrapWidth` ''' return self._textWrap.wrapWidth(*args, **kwargs)
[docs] def setWrapWidth(self, *args, **kwargs) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextWrap.setWrapWidth` ''' return self._textWrap.setWrapWidth(*args, **kwargs)
[docs] def wordWrapMode(self, *args, **kwargs) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextWrap.wordWrapMode` ''' return self._textWrap.wordWrapMode(*args, **kwargs)
[docs] def setWordWrapMode(self, *args, **kwargs) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextWrap.setWordWrapMode` ''' return self._textWrap.setWordWrapMode(*args, **kwargs)
[docs] def extraSelections(self) -> List[ExtraSelection]: ''' Returns previously set extra selections. :rtype: List[:py:class:`ExtraSelection`] ''' return self._extraSelections
[docs] def setExtraSelections(self, extraSelections:List[ExtraSelection]) -> None: ''' This function allows temporarily marking certain regions in the document with a given color, specified as selections. This can be useful for example in a programming editor to mark a whole line of text with a given background color to indicate the existence of a breakpoint. :param extraSelections: the list of extra selections. :type extraSelections: List[:py:class:`ExtraSelection`] ''' self._extraSelections = extraSelections self.update()
[docs] def textCursor(self) -> TTkTextCursor: ''' This property holds the underlying text cursor. :rtype: :py:class:`TTkTextCursor` ''' return self._textCursor
[docs] def isReadOnly(self) -> bool: ''' This property holds whether the text edit is read-only In a read-only text edit the user can only navigate through the text and select text; modifying the text is not possible. This property's default is false. :rtype: bool ''' return self._readOnly
[docs] def setReadOnly(self, ro:bool) -> None: ''' This property holds whether the text edit is read-only In a read-only text edit the user can only navigate through the text and select text; modifying the text is not possible. :param ro: the readonly status :type ro: bool ''' self._readOnly = ro self.disableWidgetCursor(ro)
[docs] def clear(self) -> None: ''' Deletes all the text in the text edit. .. note:: The undo/redo history is also cleared. ''' self.viewMoveTo(0, 0) self._textDocument.clear() self._updateSize()
[docs] def lineWrapMode(self) -> TTkK.LineWrapMode: ''' This property holds the line wrap mode The default mode is :py:class:`TTkK.LineWrapMode.WidgetWidth` which causes words to be wrapped at the right edge of the text edit. Wrapping occurs at whitespace, keeping whole words intact. :rtype: :py:class:`TTkK.LineWrapMode` ''' return self._lineWrapMode
[docs] def setLineWrapMode(self, mode:TTkK.LineWrapMode): ''' Set the wrapping method :param mode: the line wrap mode :type mode: :py:class:`TTkK.LineWrapMode` ''' self._lineWrapMode = mode if mode == TTkK.LineWrapMode.NoWrap: self._textWrap.disable() else: self._textWrap.enable() if mode == TTkK.LineWrapMode.WidgetWidth: self._textWrap.setWrapWidth(self.width()) self._textWrap.rewrap()
[docs] @pyTTkSlot(TTkStringType) def setText(self, text:TTkStringType) -> None: ''' Sets the text edit's text. The text can be plain text or :py:class:`TTkString` and the text edit will try to guess the right format. :param text: the text :type text: str or :py:class:`TTkString` ''' self.viewMoveTo(0, 0) self._textDocument.setText(text) self._updateSize()
[docs] @pyTTkSlot(TTkStringType) def append(self, text:TTkStringType) -> None: ''' Appends a new paragraph with text to the end of the text edit. The text can be plain text or :py:class:`TTkString`. :param text: the text :type text: str or :py:class:`TTkString` ''' self._textDocument.appendText(text) self._updateSize()
[docs] @pyTTkSlot() def undo(self) -> None: ''' Undoes the last operation. If there is no operation to undo, i.e. there is no undo step in the undo/redo history, nothing happens. ''' if c := self._textDocument.restoreSnapshotPrev(): self._textCursor.restore(c)
[docs] @pyTTkSlot() def redo(self) -> None: ''' Redoes the last operation. If there is no operation to redo, i.e. there is no redo step in the undo/redo history, nothing happens. ''' if c := self._textDocument.restoreSnapshotNext(): self._textCursor.restore(c)
[docs] @pyTTkSlot(TTkStringType) def find(self, exp:TTkStringType) -> bool: ''' Search the match word in the document and place the cursor at the beginning of the matched word. :param exp: The match word :type exp: str or :py:class:`TTkString` :return: `True` if the operation is successful, `False` otherwise :rtype: bool ''' if not (cursor := self._textDocument.find(exp)): return False self._textCursor = cursor self._textDocument.cursorPositionChanged.emit(self._textCursor) return True
[docs] @pyTTkSlot() def copy(self) -> None: ''' Copies any selected text to the clipboard. ''' if not self._textCursor.hasSelection(): txt = TTkString('\n').join(self._textCursor.getLinesUnderCursor()) else: txt = self._textCursor.selectedText() self._clipboard.setText(txt)
[docs] @pyTTkSlot() def cut(self) -> None: ''' Copies the selected text to the clipboard and deletes it from the text edit. If there is no selected text nothing happens. ''' if not self._textCursor.hasSelection(): self._textCursor.movePosition(moveMode=TTkTextCursor.MoveAnchor, operation=TTkTextCursor.StartOfLine) self._textCursor.movePosition(moveMode=TTkTextCursor.KeepAnchor, operation=TTkTextCursor.EndOfLine) self._textCursor.movePosition(moveMode=TTkTextCursor.KeepAnchor, operation=TTkTextCursor.Right) self.copy() self._textCursor.removeSelectedText()
[docs] @pyTTkSlot() def paste(self) -> None: ''' Pastes the text from the clipboard into the text edit at the current cursor position. If there is no text in the clipboard nothing happens. ''' txt = self._clipboard.text() self.pasteEvent(txt)
@pyTTkSlot() def _documentChanged(self) -> None: self._rewrap() self.textChanged.emit() def _rewrap(self) -> None: self._textWrap.rewrap() self.viewChanged.emit() self.update()
[docs] @pyTTkSlot(TTkColor) def setColor(self, color:TTkColor) -> None: ''' Change the color used by the cursor to input new text or change the color of the selection :param color: the color to be used :type color: :py:class:`TTkColor` ''' self.textCursor().setColor(color)
@pyTTkSlot(TTkTextCursor) def _cursorPositionChanged(self, cursor:TTkTextCursor) -> None: if cursor == self._textCursor: self.currentColorChanged.emit(cursor.positionColor()) self.cursorPositionChanged.emit(cursor) self._pushCursor() def resizeEvent(self, w:int, h:int) -> None: if ( self.lineWrapMode() == TTkK.WidgetWidth and w != self._lastWrapUsed and w > self._textWrap._tabSpaces ): self._textWrap.setWrapWidth(w) self._lastWrapUsed = w self._rewrap() return super().resizeEvent(w,h) def _updateSize(self) -> None: self._hsize = max( len(l) for l in self._textDocument._dataLines ) + 1 def viewFullAreaSize(self) -> tuple[int,int]: if self.lineWrapMode() == TTkK.NoWrap: return self._hsize, self._textWrap.size() elif self.lineWrapMode() == TTkK.WidgetWidth: return self.width(), self._textWrap.size() elif self.lineWrapMode() == TTkK.FixedWidth: return self.width(), self._textWrap.size() return self.width(), self._textWrap.size() def _pushCursor(self) -> None: ox, oy = self.getViewOffsets() x,y = self._textWrap.dataToScreenPosition( self._textCursor.position().line, self._textCursor.position().pos) y -= oy x -= ox if self._replace: self.setWidgetCursor(pos=(x,y), type=TTkK.Cursor_Blinking_Block) else: self.setWidgetCursor(pos=(x,y), type=TTkK.Cursor_Blinking_Bar) self.update() def _setCursorPos(self, x, y, moveAnchor=True, addCursor=False) -> tuple[int,int]: x,y = self._textWrap.normalizeScreenPosition(x,y) line, pos = self._textWrap.screenToDataPosition(x,y) if addCursor: self._textCursor.addCursor(line, pos) else: self._textCursor.clearCursors() self._textCursor.setPosition(line, pos, moveMode=TTkTextCursor.MoveAnchor if moveAnchor else TTkTextCursor.KeepAnchor ) self._scrolToInclude(x,y) return x, y
[docs] @pyTTkSlot() def ensureCursorVisible(self): cp = self._textCursor.position() self._scrolToInclude(cp.pos,cp.line)
def _scrolToInclude(self, x, y) -> None: # Scroll the area (if required) to include the position x,y _,_,w,h = self.geometry() offx, offy = self.getViewOffsets() offx = max(min(offx, x),x-w+1) offy = max(min(offy, y),y-h+1) self.viewMoveTo(offx, offy) def mousePressEvent(self, evt:TTkMouseEvent) -> bool: if self._readOnly: return super().mousePressEvent(evt) ox, oy = self.getViewOffsets() self._setCursorPos(evt.x + ox, evt.y + oy, addCursor=evt.mod&TTkK.ControlModifier==TTkK.ControlModifier) self._textCursor.clearColor() self._pushCursor() self.update() return True def mouseReleaseEvent(self, evt:TTkMouseEvent) -> bool: if self._textCursor.hasSelection(): self.copy() return True def mouseDragEvent(self, evt:TTkMouseEvent) -> bool: if self._readOnly: return super().mouseDragEvent(evt) ox, oy = self.getViewOffsets() x,y = self._setCursorPos(evt.x + ox, evt.y + oy, moveAnchor=False) self._textCursor.clearColor() self._scrolToInclude(x,y) self._pushCursor() self.update() return True def mouseDoubleClickEvent(self, evt:TTkMouseEvent) -> bool: if self._readOnly: return super().mouseDoubleClickEvent(evt) self._textCursor.select(TTkTextCursor.WordUnderCursor) if self._textCursor.hasSelection(): self.copy() self._textCursor.clearColor() self._pushCursor() self.update() return True def mouseTapEvent(self, evt:TTkMouseEvent) -> bool: if self._readOnly: return super().mouseTapEvent(evt) self._textCursor.select(TTkTextCursor.LineUnderCursor) if self._textCursor.hasSelection(): self.copy() self._textCursor.clearColor() self._pushCursor() self.update() return True def pasteEvent(self, txt:TTkStringType) -> bool: txt = TTkString(txt) if not self._multiLine: txt = TTkString().join(txt.split('\n')) if self._replace: self._textCursor.replaceText(txt, moveCursor=True) else: self._textCursor.insertText(txt, moveCursor=True) # Scroll to align to the cursor p = self._textCursor.position() cx, cy = self._textWrap.dataToScreenPosition(p.line, p.pos) self._updateSize() self._scrolToInclude(cx,cy) self._pushCursor() self.update() return True def keyEvent(self, evt: TTkKeyEvent) -> bool: if self._readOnly: return super().keyEvent(evt) # Keep a snapshot in case of those actions if (( evt.type == TTkK.Character and ( ( evt.key == ' ' ) or ( evt.key == '\n') or ( evt.key == '\t') or ( self._textCursor.hasSelection() ) ) ) or ( evt.type == TTkK.SpecialKey and ( ( evt.key == TTkK.Key_Enter ) or ( evt.key == TTkK.Key_Delete ) or ( evt.key == TTkK.Key_Backspace ) or ( self._textDocument.changed() and evt.key == TTkK.Key_Z ) or ( evt.mod==TTkK.ControlModifier and ( evt.key == TTkK.Key_V or evt.key == TTkK.Key_X or ( evt.key == TTkK.Key_Z and self._textDocument.changed() ) ) ) ) ) ): # TTkLog.debug(f"Saving {self._textCursor.selectedText()} {self._textCursor._properties[0].anchor.pos}") self._textDocument.saveSnapshot(self._textCursor.copy()) if evt.key == TTkK.Key_Tab and evt.mod==TTkK.NoModifier: evt = TTkKeyEvent(TTkK.Character, '\t', '\t', TTkK.NoModifier) if evt.type == TTkK.SpecialKey: _,_,w,h = self.geometry() # TODO: Remove this HACK As soon as possible # Due to the lack of 'INS' key on many laptops # I emulate this key using # CTRL + HOME if evt.key == TTkK.Key_Home and evt.mod==TTkK.ControlModifier: evt.key = TTkK.Key_Insert evt.mod = TTkK.NoModifier moveMode = TTkTextCursor.MoveAnchor if evt.mod==TTkK.ShiftModifier: moveMode = TTkTextCursor.KeepAnchor ctrl = evt.mod==TTkK.ControlModifier if ctrl: p = self._textCursor.position() cx, cy = self._textWrap.dataToScreenPosition(p.line, p.pos) if evt.key == TTkK.Key_Up: self._setCursorPos(cx, cy-1, addCursor=True) self._textCursor.clearColor() elif evt.key == TTkK.Key_Down: self._setCursorPos(cx, cy+1, addCursor=True) self._textCursor.clearColor() elif evt.key == TTkK.Key_C: self.copy() elif evt.key == TTkK.Key_V: self.paste() elif evt.key == TTkK.Key_X: self.cut() elif evt.key == TTkK.Key_Z: self.undo() elif evt.key == TTkK.Key_Y: self.redo() elif evt.key == TTkK.Key_A: self._textCursor.select(TTkTextCursor.SelectionType.Document) else: # No action performed return super().keyEvent(evt) elif evt.key == TTkK.Key_Up: self._textCursor.movePosition(moveMode=moveMode, operation=TTkTextCursor.Up, textWrap=self._textWrap) self._textCursor.clearColor() elif evt.key == TTkK.Key_Down: self._textCursor.movePosition(moveMode=moveMode, operation=TTkTextCursor.Down, textWrap=self._textWrap) self._textCursor.clearColor() elif evt.key == TTkK.Key_Left: self._textCursor.movePosition(moveMode=moveMode, operation=TTkTextCursor.Left) self._textCursor.clearColor() elif evt.key == TTkK.Key_Right: self._textCursor.movePosition(moveMode=moveMode, operation=TTkTextCursor.Right) self._textCursor.clearColor() elif evt.key == TTkK.Key_End: self._textCursor.movePosition(moveMode=moveMode, operation=TTkTextCursor.EndOfLine) self._textCursor.clearColor() elif evt.key == TTkK.Key_Home: self._textCursor.movePosition(moveMode=moveMode, operation=TTkTextCursor.StartOfLine) self._textCursor.clearColor() elif evt.key == TTkK.Key_PageUp: self._textCursor.movePosition(moveMode=moveMode, operation=TTkTextCursor.Up, textWrap=self._textWrap, n=h) #self._setCursorPos(cx , cy - h) self._textCursor.clearColor() elif evt.key == TTkK.Key_PageDown: self._textCursor.movePosition(moveMode=moveMode, operation=TTkTextCursor.Down, textWrap=self._textWrap, n=h) #self._setCursorPos(cx , cy + h) self._textCursor.clearColor() elif evt.key == TTkK.Key_Escape: self._textCursor.clearCursors() self._textCursor.clearSelection() self._textCursor.clearColor() elif evt.key == TTkK.Key_Insert: self._replace = not self._replace elif evt.key == TTkK.Key_Delete: if not self._textCursor.hasSelection(): self._textCursor.movePosition(TTkTextCursor.Right, TTkTextCursor.KeepAnchor) self._textCursor.removeSelectedText() elif evt.key == TTkK.Key_Backspace: if not self._textCursor.hasSelection(): self._textCursor.movePosition(TTkTextCursor.Left, TTkTextCursor.KeepAnchor) self._textCursor.removeSelectedText() elif evt.key == TTkK.Key_Enter: if self._multiLine: self._textCursor.insertText('\n', moveCursor=True) else: # No action performed return super().keyEvent(evt) # Scroll to align to the cursor p = self._textCursor.position() cx, cy = self._textWrap.dataToScreenPosition(p.line, p.pos) self._updateSize() self._scrolToInclude(cx,cy) self._pushCursor() self.update() return True else: # Input char if self._replace: self._textCursor.replaceText(str(evt.key), moveCursor=True) else: self._textCursor.insertText(str(evt.key), moveCursor=True) # Scroll to align to the cursor p = self._textCursor.position() cx, cy = self._textWrap.dataToScreenPosition(p.line, p.pos) self._updateSize() self._scrolToInclude(cx,cy) self._pushCursor() self.update() return True return super().keyEvent(evt) def paintEvent(self, canvas: TTkCanvas) -> None: ox, oy = self.getViewOffsets() w,h = self.size() style = self.currentStyle() color = style['color'] selectColor = style['selectedColor'] lineColor = style['lineColor'] backgroundColors = [self._textDocument._backgroundColor]*h subLines = self._textWrap._lines[oy:oy+h] if not subLines: return fr = subLines[0][0] to = subLines[-1][0] outLines = self._textDocument._dataLines[fr:to+1] outLines = self._textCursor._getHighlightedLines(fr, to, outLines, selectColor) for extraSelection in self._extraSelections: esCursor = extraSelection._cursor esColor = extraSelection._color esFormat = extraSelection._format if esFormat == TTkK.SelectionFormat.FullWidthSelection: backgroundColors = esCursor._getCoveredLines(fr, to, backgroundColors, esColor) outLines = esCursor._getHighlightedLines(fr, to, outLines, esColor) outLines = self._textCursor._getBlinkingCursors(fr, to, outLines, selectColor) for y, l in enumerate(subLines): t = outLines[l[0]-subLines[0][0]] bg = backgroundColors[l[0]-subLines[0][0]] text:TTkString = t.substring(l[1][0],l[1][1]).tab2spaces(self._textWrap._tabSpaces) if bg != TTkColor.RST: canvas.fill(color=bg,pos=(0,y), size=(w,1)) text = text.completeColor(bg) canvas.drawTTkString(pos=(-ox,y), text=text) if self._lineWrapMode == TTkK.FixedWidth: canvas.drawVLine(pos=(self._textWrap._wrapWidth,0), size=h, color=lineColor)
[docs] class TTkTextEdit(TTkAbstractScrollArea): __doc__ = ''' :py:class:`TTkTextEdit` is a container widget which place :py:class:`TTkTextEditView` in a scrolling area with on-demand scroll bars. ''' + (TTkTextEditView.__doc__ if TTkTextEditView.__doc__ else '') if TYPE_CHECKING: from typing import TypeAlias ExtraSelection: TypeAlias = TTkTextEditView.ExtraSelection else: # TODO: remove this once Python 3.9 will disappear from the world ExtraSelection = TTkTextEditView.ExtraSelection _ttk_forward:_ForwardData = _ForwardData( forwardClass=TTkTextEditView , instance="self._textEditView", signals=[ # Forwarded Signals From TTkTexteditView 'currentColorChanged', 'cursorPositionChanged', 'undoAvailable', 'redoAvailable', 'textChanged'], methods=[ # Forwarded Methods From TTkTexteditView "clear", "setText", "append", "isReadOnly", "setReadOnly", "document", "wrapWidth", "setWrapWidth", "multiLine", "lineWrapMode", "setLineWrapMode", "wordWrapMode", "setWordWrapMode", "textCursor", "setFocus", "setColor", "extraSelections", "setExtraSelections", "cut", "copy", "paste", "undo", "redo", "isUndoAvailable", "isRedoAvailable", "find", "ensureCursorVisible", # Exported Methods "toAnsi", "toRawText", "toPlainText" # , "toHtml", "toMarkdown", ] ) __slots__ = ( '_textEditView', '_lineNumberView', '_lineNumber') def __init__(self, *, # TTkWidget init parent:Optional[TTkWidget]=None, visible:bool=True, # TTkTextEditView init readOnly:bool=False, multiLine:bool=True, document:Optional[TTkTextDocument]=None, # TTkText init textEditView:Optional[TTkTextEditView]=None, lineNumber:bool=False, lineNumberStarting:int=0, **kwargs) -> None: ''' :param textEditView: a custom TextEdit View to be used instead of the default one. :type textEditView: :py:class:`TTkTextEditView`, optional :param lineNumber: show the line number on the left side, defaults to False :type lineNumber: bool, optional :param lineNumberStarting: set the starting number of the left line number column, defaults to 0 :type lineNumberStarting: int, optional ''' super().__init__(parent=parent, visible=visible, **kwargs) self._textEditView = textEditView if textEditView else TTkTextEditView(readOnly=readOnly, multiLine=multiLine, document=document) # self.setFocusPolicy(self._textEditView.focusPolicy()) # self._textEditView.setFocusPolicy(TTkK.ParentFocus) self._lineNumber = lineNumber textEditLayout = TTkAbstractScrollViewGridLayout() textEditLayout.addWidget(self._textEditView,0,1) self._lineNumberView = TTkTextEditRuler(visible=self._lineNumber, startingNumber=lineNumberStarting) self._lineNumberView.setTextWrap(self._textEditView._textWrap) textEditLayout.addWidget(self._lineNumberView,0,0) self.setViewport(textEditLayout) self.focusChanged = self._textEditView.focusChanged
[docs] def ruler(self) -> TTkTextEditRuler: '''ruler''' return self._lineNumberView
[docs] def textEditView(self): '''textEditView''' return self._textEditView
[docs] def getLineNumber(self): '''getLineNumber''' return self._lineNumberView.isVisible()
[docs] @pyTTkSlot(bool) def setLineNumber(self, ln): '''setLineNumber''' self._lineNumberView.setVisible(ln)
[docs] def lineNumberStarting(self): '''lineNumberStarting''' return self._lineNumberView._startingNumber
[docs] @pyTTkSlot(int) def setLineNumberStarting(self, starting): '''setLineNumberStarting''' self._lineNumberView._startingNumber = starting self._lineNumberView._wrapChanged()
[docs] def setDocument(self, document): '''setDocument''' self._textEditView.setDocument(document) self._lineNumberView.setTextWrap(self._textEditView._textWrap)
#--FORWARD-AUTOGEN-START--# @property def currentColorChanged(self) -> pyTTkSignal: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.currentColorChanged` This signal is emitted if the current character color has changed, for example caused by a change of the cursor position. :param color: the new color :type color: :py:class:`TTkColor` ''' return self._textEditView.currentColorChanged @property def cursorPositionChanged(self) -> pyTTkSignal: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.cursorPositionChanged` This signal is emitted whenever the position of the cursor changed. :param cursor: the cursor changed. :type cursor: :py:class:`TTkTextCursor` ''' return self._textEditView.cursorPositionChanged @property def undoAvailable(self) -> pyTTkSignal: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.undoAvailable` This signal is emitted whenever undo operations become available (available is true) or unavailable (available is false). :param available: the availability of undo :type available: bool ''' return self._textEditView.undoAvailable @property def redoAvailable(self) -> pyTTkSignal: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.redoAvailable` This signal is emitted whenever redo operations become available (available is true) or unavailable (available is false). :param available: the availability of redo :type available: bool ''' return self._textEditView.redoAvailable @property def textChanged(self) -> pyTTkSignal: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.textChanged` This signal is emitted whenever the document's content changes; for example, when text is inserted or deleted, or when formatting is applied. ''' return self._textEditView.textChanged
[docs] def clear(self) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.clear` Deletes all the text in the text edit. .. note:: The undo/redo history is also cleared. ''' return self._textEditView.clear()
[docs] @pyTTkSlot(TTkStringType) def setText(self, text:TTkStringType) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setText` Sets the text edit's text. The text can be plain text or :py:class:`TTkString` and the text edit will try to guess the right format. :param text: the text :type text: str or :py:class:`TTkString` ''' return self._textEditView.setText(text=text)
[docs] @pyTTkSlot(TTkStringType) def append(self, text:TTkStringType) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.append` Appends a new paragraph with text to the end of the text edit. The text can be plain text or :py:class:`TTkString`. :param text: the text :type text: str or :py:class:`TTkString` ''' return self._textEditView.append(text=text)
[docs] def isReadOnly(self) -> bool: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.isReadOnly` This property holds whether the text edit is read-only In a read-only text edit the user can only navigate through the text and select text; modifying the text is not possible. This property's default is false. :rtype: bool ''' return self._textEditView.isReadOnly()
[docs] def setReadOnly(self, ro:bool) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setReadOnly` This property holds whether the text edit is read-only In a read-only text edit the user can only navigate through the text and select text; modifying the text is not possible. :param ro: the readonly status :type ro: bool ''' return self._textEditView.setReadOnly(ro=ro)
[docs] def document(self) -> TTkTextDocument: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.document` This property holds the underlying document of the text editor. :rtype: :py:class:`TTkTextDocument` ''' return self._textEditView.document()
[docs] def wrapWidth(self, *args, **kwargs) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.wrapWidth` .. seealso:: this method is forwarded to :py:meth:`TTkTextWrap.wrapWidth` ''' return self._textEditView.wrapWidth(*args, **kwargs)
[docs] def setWrapWidth(self, *args, **kwargs) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setWrapWidth` .. seealso:: this method is forwarded to :py:meth:`TTkTextWrap.setWrapWidth` ''' return self._textEditView.setWrapWidth(*args, **kwargs)
[docs] def multiLine(self) -> bool: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.multiLine` This property define if the text edit area will use a single line, like in the line-edit or it allows multilines like a normal text edit area. :rtype: bool ''' return self._textEditView.multiLine()
[docs] def lineWrapMode(self) -> TTkK.LineWrapMode: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.lineWrapMode` This property holds the line wrap mode The default mode is :py:class:`TTkK.LineWrapMode.WidgetWidth` which causes words to be wrapped at the right edge of the text edit. Wrapping occurs at whitespace, keeping whole words intact. :rtype: :py:class:`TTkK.LineWrapMode` ''' return self._textEditView.lineWrapMode()
[docs] def setLineWrapMode(self, mode:TTkK.LineWrapMode): ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setLineWrapMode` Set the wrapping method :param mode: the line wrap mode :type mode: :py:class:`TTkK.LineWrapMode` ''' return self._textEditView.setLineWrapMode(mode=mode)
[docs] def wordWrapMode(self, *args, **kwargs) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.wordWrapMode` .. seealso:: this method is forwarded to :py:meth:`TTkTextWrap.wordWrapMode` ''' return self._textEditView.wordWrapMode(*args, **kwargs)
[docs] def setWordWrapMode(self, *args, **kwargs) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setWordWrapMode` .. seealso:: this method is forwarded to :py:meth:`TTkTextWrap.setWordWrapMode` ''' return self._textEditView.setWordWrapMode(*args, **kwargs)
[docs] def textCursor(self) -> TTkTextCursor: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.textCursor` This property holds the underlying text cursor. :rtype: :py:class:`TTkTextCursor` ''' return self._textEditView.textCursor()
@pyTTkSlot() def setFocus(self) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setFocus` Focus the widget ''' return self._textEditView.setFocus()
[docs] @pyTTkSlot(TTkColor) def setColor(self, color:TTkColor) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setColor` Change the color used by the cursor to input new text or change the color of the selection :param color: the color to be used :type color: :py:class:`TTkColor` ''' return self._textEditView.setColor(color=color)
[docs] def extraSelections(self) -> List[ExtraSelection]: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.extraSelections` Returns previously set extra selections. :rtype: List[:py:class:`ExtraSelection`] ''' return self._textEditView.extraSelections()
[docs] def setExtraSelections(self, extraSelections:List[ExtraSelection]) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.setExtraSelections` This function allows temporarily marking certain regions in the document with a given color, specified as selections. This can be useful for example in a programming editor to mark a whole line of text with a given background color to indicate the existence of a breakpoint. :param extraSelections: the list of extra selections. :type extraSelections: List[:py:class:`ExtraSelection`] ''' return self._textEditView.setExtraSelections(extraSelections=extraSelections)
[docs] @pyTTkSlot() def cut(self) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.cut` Copies the selected text to the clipboard and deletes it from the text edit. If there is no selected text nothing happens. ''' return self._textEditView.cut()
[docs] @pyTTkSlot() def copy(self) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.copy` Copies any selected text to the clipboard. ''' return self._textEditView.copy()
[docs] @pyTTkSlot() def paste(self) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.paste` Pastes the text from the clipboard into the text edit at the current cursor position. If there is no text in the clipboard nothing happens. ''' return self._textEditView.paste()
[docs] @pyTTkSlot() def undo(self) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.undo` Undoes the last operation. If there is no operation to undo, i.e. there is no undo step in the undo/redo history, nothing happens. ''' return self._textEditView.undo()
[docs] @pyTTkSlot() def redo(self) -> None: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.redo` Redoes the last operation. If there is no operation to redo, i.e. there is no redo step in the undo/redo history, nothing happens. ''' return self._textEditView.redo()
[docs] def isUndoAvailable(self) -> bool: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.isUndoAvailable` This property holds whether undo is available. :return: the undo available status :rtype: bool ''' return self._textEditView.isUndoAvailable()
[docs] def isRedoAvailable(self) -> bool: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.isRedoAvailable` This property holds whether redo is available. :return: the redo available status :rtype: bool ''' return self._textEditView.isRedoAvailable()
[docs] @pyTTkSlot(TTkStringType) def find(self, exp:TTkStringType) -> bool: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.find` Search the match word in the document and place the cursor at the beginning of the matched word. :param exp: The match word :type exp: str or :py:class:`TTkString` :return: `True` if the operation is successful, `False` otherwise :rtype: bool ''' return self._textEditView.find(exp=exp)
[docs] @pyTTkSlot() def ensureCursorVisible(self): ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.ensureCursorVisible` ''' return self._textEditView.ensureCursorVisible()
[docs] def toAnsi(self) -> str: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.toAnsi` Returns the text of the text edit as ANSI test string. This string will insluce the ANSI escape codes for color and text formatting. :rtype: str ''' return self._textEditView.toAnsi()
[docs] def toRawText(self) -> TTkString: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.toRawText` Return :py:class:`TTkString` representing the document :rtype: :py:class:`TTkString` ''' return self._textEditView.toRawText()
[docs] def toPlainText(self) ->str: ''' .. seealso:: this method is forwarded to :py:meth:`TTkTextEditView.toPlainText` Returns the text of the text edit as plain text string. :rtype: str ''' return self._textEditView.toPlainText()
#--FORWARD-AUTOGEN-END--#