File indexing completed on 2024-12-22 04:16:42
0001 /* 0002 * SPDX-FileCopyrightText: 2023 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #ifndef SVGTEXTCURSOR_H 0008 #define SVGTEXTCURSOR_H 0009 0010 #include <KoSvgTextShape.h> 0011 #include <KoToolSelection.h> 0012 #include <QPainter> 0013 #include <KoShape.h> 0014 #include "kritatoolsvgtext_export.h" 0015 0016 class KoCanvasBase; 0017 class SvgTextInsertCommand; 0018 class SvgTextRemoveCommand; 0019 class KUndo2Command; 0020 class QKeyEvent; 0021 class QInputMethodEvent; 0022 0023 /** 0024 * @brief The SvgTextCursor class 0025 * 0026 * This class handles cursor movement and text editing operations. 0027 * 0028 * It acts as the KoToolSelection for SvgTextTool, allowing it to 0029 * integrate with the basic KoToolBase functionality for copy, cut 0030 * paste and clear. 0031 * 0032 * A selection is defined as the anchor being different from the cursor 0033 * position, with the move operation accepting whether you want to shift 0034 * the cursor position. 0035 * 0036 * It is also a shape listener to allow the textcursor to update itself 0037 * whenever the corresponding text shape changes. 0038 */ 0039 0040 class KRITATOOLSVGTEXT_EXPORT SvgTextCursor : public KoToolSelection, public KoSvgTextShape::TextCursorChangeListener 0041 { 0042 Q_OBJECT 0043 public: 0044 explicit SvgTextCursor(KoCanvasBase *canvas); 0045 0046 enum MoveMode { 0047 MoveNone, 0048 MoveLeft, 0049 MoveRight, 0050 MoveUp, 0051 MoveDown, 0052 MoveNextChar, 0053 MovePreviousChar, 0054 MoveNextLine, 0055 MovePreviousLine, 0056 MoveWordLeft, 0057 MoveWordRight, 0058 MoveWordEnd, 0059 MoveWordStart, 0060 MoveLineStart, 0061 MoveLineEnd, 0062 ParagraphStart, 0063 ParagraphEnd, 0064 }; 0065 0066 ~SvgTextCursor(); 0067 0068 /** 0069 * @brief Get the current text shape 0070 * @return KoSvgTextShape * 0071 */ 0072 KoSvgTextShape *shape() const; 0073 0074 /** 0075 * @brief setShape 0076 * @param textShape KoSvgTextShape to set, is allowed to be a nullptr, the cursor just won't do anything. 0077 */ 0078 void setShape(KoSvgTextShape *textShape); 0079 0080 /** 0081 * @brief setCaretSetting 0082 * Set the caret settings for the cursor. Qt has some standard functionality associated, which we pass via this. 0083 * @param cursorWidth - Cursor width from the style. 0084 * @param cursorFlash - the total time it takes for a cursor to hide reapear. 0085 * @param cursorFlashLimit - maximum amount of time a cursor is allowed to flash. 0086 */ 0087 void setCaretSetting(int cursorWidth = 1, int cursorFlash = 1000, int cursorFlashLimit = 5000); 0088 0089 /** 0090 * @brief setVisualMode 0091 * set whether the navigation mode is visual or logical. 0092 * This right now primarily affects Bidirectional text. 0093 * @param mode whether to turn off visual mode. 0094 */ 0095 void setVisualMode(bool visualMode = true); 0096 0097 /// Get the current position. 0098 int getPos(); 0099 0100 /// Get the current selection anchor. This is the same as position, unless there's a selection. 0101 int getAnchor(); 0102 0103 /// Set the pos and the anchor. 0104 void setPos(int pos, int anchor); 0105 0106 /// Set the pos from a point. This currently does a search inside the text shape. 0107 void setPosToPoint(QPointF point, bool moveAnchor = true); 0108 0109 /// Move the cursor, and, if you don't want a selection, move the anchor. 0110 void moveCursor(MoveMode mode, bool moveAnchor = true); 0111 0112 /// Insert text at getPos() 0113 void insertText(QString text); 0114 0115 /** 0116 * @brief removeText 0117 * remove text relative to the current position. 0118 * This will move the cursor according to the move modes and then 0119 * remove the text between the two positions. 0120 * @param first how the cursor should move to get to the start position. 0121 * @param second how the cursor should move to get to the end position. 0122 */ 0123 void removeText(MoveMode first, MoveMode second); 0124 0125 void removeLastCodePoint(); 0126 0127 /** 0128 * @brief removeSelection 0129 * if there's a selection, creates a text-removal command. 0130 * @param parent 0131 * @return the text-removal command, if possible, if there's no selection or shape, it'll return 0; 0132 */ 0133 void removeSelection(); 0134 0135 /** 0136 * @brief copy 0137 * copies plain text into the clipboard between anchor and pos. 0138 */ 0139 void copy() const; 0140 /** 0141 * @brief paste 0142 * @return pastes plain text in the clipboard at pos. 0143 */ 0144 bool paste(); 0145 0146 void deselectText(); 0147 0148 void paintDecorations(QPainter &gc, QColor selectionColor, int decorationThickness = 1); 0149 0150 QVariant inputMethodQuery(Qt::InputMethodQuery query) const; 0151 void inputMethodEvent(QInputMethodEvent *event); 0152 0153 // Reimplemented. 0154 bool hasSelection() override; 0155 0156 /// ShapeChangeListener reimplementation. This will update the cursor position 0157 /// when the shape was updated. 0158 void notifyShapeChanged(KoShape::ChangeType type, KoShape *shape) override; 0159 0160 /// TextCursorChangeListener reimplementation, this allows undo commands 0161 /// to update the cursor without having the cursor owned by the command. 0162 void notifyCursorPosChanged(int pos, int anchor) override; 0163 0164 /// Handle the cursor-related key events. 0165 void keyPressEvent(QKeyEvent *event); 0166 0167 /// the cursor is currently adding a command 0168 bool isAddingCommand() const; 0169 0170 /// Turns on blinking cursor. 0171 void focusIn(); 0172 0173 /// Stops blinking cursor. 0174 void focusOut(); 0175 0176 Q_SIGNALS: 0177 0178 void updateCursorDecoration(QRectF updateRect); 0179 private Q_SLOTS: 0180 void blinkCursor(); 0181 void stopBlinkCursor(); 0182 0183 void updateInputMethodItemTransform(); 0184 0185 private: 0186 0187 /** 0188 * @brief removeSelection 0189 * if there's a selection, creates a text-removal command. 0190 * @param parent 0191 * @return the text-removal command, if possible, if there's no selection or shape, it'll return 0; 0192 */ 0193 SvgTextRemoveCommand *removeSelectionImpl(KUndo2Command *parent = 0); 0194 0195 0196 /// update the cursor shape. First update will block ensuring the canvas is visible so setShape won't cause this. 0197 void updateCursor(bool firstUpdate = false); 0198 void updateSelection(); 0199 void updateIMEDecoration(); 0200 void addCommandToUndoAdapter(KUndo2Command *cmd); 0201 0202 int moveModeResult(MoveMode &mode, int &pos, bool visual = false) const; 0203 bool acceptableInput(const QKeyEvent *event) const; 0204 0205 void commitIMEPreEdit(); 0206 0207 struct Private; 0208 const QScopedPointer<Private> d; 0209 }; 0210 0211 Q_DECLARE_METATYPE(SvgTextCursor::MoveMode) 0212 0213 0214 #endif // SVGTEXTCURSOR_H