Krita Source Code Documentation
Loading...
Searching...
No Matches
SvgTextCursor Class Reference

The SvgTextCursor class. More...

#include <SvgTextCursor.h>

+ Inheritance diagram for SvgTextCursor:

Classes

class  InputQueryUpdateBlocker
 

Public Types

enum  MoveMode {
  MoveNone , MoveLeft , MoveRight , MoveUp ,
  MoveDown , MoveNextChar , MovePreviousChar , MoveNextLine ,
  MovePreviousLine , MoveWordLeft , MoveWordRight , MoveWordEnd ,
  MoveWordStart , MoveLineStart , MoveLineEnd , ParagraphStart ,
  ParagraphEnd
}
 
enum  TypeSettingModeHandle {
  NoHandle , StartPos , EndPos , BaselineShift ,
  Ascender , Descender , LineHeightTop , LineHeightBottom ,
  BaselineAlphabetic , BaselineIdeographic , BaselineMiddle , BaselineHanging ,
  BaselineMathematical , BaselineCentral
}
 Handles used by type setting mode. More...
 

Signals

void selectionChanged ()
 Sents an update selection was changed.
 
void sigOpenGlyphPalette ()
 Called by actions, tells the parent tool to open the glyph palette.
 
void updateCursorDecoration (QRectF updateRect)
 Sents an update to the parent tool to update it's decorations.
 

Public Member Functions

void copy () const
 copy copies plain text into the clipboard between anchor and pos.
 
QPair< KoSvgTextProperties, KoSvgTextPropertiescurrentTextProperties () const
 currentTextProperties
 
QCursor cursorTypeForTypeSetting () const
 Return appropriate typeSetting cursor;.
 
void deselectText ()
 Deselect all text. This effectively makes anchor the same as pos.
 
void focusIn ()
 Turns on blinking cursor.
 
void focusOut ()
 Stops blinking cursor.
 
int getAnchor ()
 Get the current selection anchor. This is the same as position, unless there's a selection.
 
int getPos ()
 Get the current position.
 
QString handleName (TypeSettingModeHandle handle) const
 handleName
 
bool hasSelection () override
 return true if the tool currently has something selected that can be copied or deleted.
 
void inputMethodEvent (QInputMethodEvent *event)
 Process an input method event. This is used by IME like virtual keyboards.
 
QVariant inputMethodQuery (Qt::InputMethodQuery query) const
 Process an input method query and return the requested result.
 
void insertRichText (KoSvgTextShape *insert, bool inheritPropertiesIfPossible=false)
 Insert rich text at getPos();.
 
void insertText (QString text)
 Insert text at getPos()
 
bool isAddingCommand () const
 the cursor is currently adding a command
 
void keyPressEvent (QKeyEvent *event)
 Handle the cursor-related key events.
 
void mergePropertiesIntoSelection (const KoSvgTextProperties props, const QSet< KoSvgTextProperties::PropertyId > removeProperties=QSet< KoSvgTextProperties::PropertyId >(), bool paragraphOnly=false, bool selectWord=false)
 mergePropertiesIntoSelection Within Krita's SVG/CSS text system, it is possible to apply incomplete properties to a whole range. In that case, only the existing properties are applied. Properties can also be removed this way.
 
void moveCursor (MoveMode mode, bool moveAnchor=true)
 Move the cursor, and, if you don't want a selection, move the anchor.
 
void notifyCursorPosChanged (int pos, int anchor) override
 
void notifyMarkupChanged () override
 
void notifyShapeChanged (KoShape::ChangeType type, KoShape *shape) override
 
void paintDecorations (QPainter &gc, QColor selectionColor, int decorationThickness=1, qreal handleRadius=5.0)
 Paint all decorations and blinkingcursors.
 
bool paste ()
 paste pastes plain text in the clipboard at pos. Uses pasteRichTextByDefault to determine whether to try and paste rich text.
 
int posForTypeSettingHandleAndRect (const TypeSettingModeHandle handle, const QRectF regionOfInterest)
 posForHandleAndRect Returns the closest cursor position for a given region and typesetting handle. Used by the type setting mode to find the relevant metrics to scale.
 
QList< KoSvgTextPropertiespropertiesForRange () const
 propertiesForRange
 
QList< KoSvgTextPropertiespropertiesForShape () const
 propertiesForShape
 
bool registerPropertyAction (QAction *action, const QString &name)
 Register an action.
 
void removeLastCodePoint ()
 removeLastCodePoint Special function to remove the last code point. Triggered by backspace. This is distinct from remove text, as some clusters have multiple code points, but it is generally expected backspace deletes the codepoints while delete with selection deletes the whole cluster.
 
void removeSelection ()
 removeSelection if there's a selection, creates a text-removal command.
 
void removeText (MoveMode first, MoveMode second)
 removeText remove text relative to the current position. This will move the cursor according to the move modes and then remove the text between the two positions.
 
void setCaretSetting (int cursorWidth=1, int cursorFlash=1000, int cursorFlashLimit=5000, bool drawCursorInAdditionToSelection=false)
 setCaretSetting Set the caret settings for the cursor. Qt has some standard functionality associated, which we pass via this.
 
bool setDominantBaselineFromHandle (const TypeSettingModeHandle handle)
 setDominantBaselineFromHandle Set the dominant baseline from a given handle.
 
void setDrawTypeSettingHandle (bool draw)
 
void setPasteRichTextByDefault (const bool pasteRichText=true)
 setPasteRichText
 
void setPos (int pos, int anchor)
 Set the pos and the anchor.
 
void setPosToPoint (QPointF point, bool moveAnchor=true)
 Set the pos from a point. This currently does a search inside the text shape.
 
void setShape (KoSvgTextShape *textShape)
 setShape
 
void setTypeSettingHandleHovered (TypeSettingModeHandle hovered=TypeSettingModeHandle::NoHandle)
 Set a given typesetting handle as hovered, so it will be drawn as such.
 
void setTypeSettingModeActive (bool activate)
 Set type setting mode active.
 
void setVisualMode (const bool visualMode=true)
 setVisualMode set whether the navigation mode is visual or logical. This right now primarily affects Bidirectional text.
 
KoSvgTextShapeshape () const
 Get the current text shape.
 
 SvgTextCursor (KoCanvasBase *canvas)
 
KoSvgTextPropertiesInterfacetextPropertyInterface ()
 
TypeSettingModeHandle typeSettingHandleAtPos (const QRectF regionOfInterest)
 Get typeSettingMode handle for text;.
 
void updateModifiers (const Qt::KeyboardModifiers modifiers)
 
void updateTypeSettingDecorFromShape ()
 Update the type setting decorations.
 
 ~SvgTextCursor ()
 
- Public Member Functions inherited from Private
 Private (KisCanvas2 *c)
 
- Public Member Functions inherited from KoToolSelection
 KoToolSelection (QObject *parent=0)
 
 ~KoToolSelection () override
 
- Public Member Functions inherited from KoSvgTextShape::TextCursorChangeListener
void notifyShapeChanged (ChangeType type, KoShape *shape) override
 
- Public Member Functions inherited from KoShape::ShapeChangeListener
virtual ~ShapeChangeListener ()
 

Public Attributes

QList< QAction * > actions
 
int anchor = 0
 
QLineF anchorCaret
 
int anchorIndex = 0
 
bool blockQueryUpdates = false
 Block qApp->inputMethod->update(), enabled during the inputmethod event flow.
 
KoCanvasBasecanvas
 
QLineF cursorCaret
 
QColor cursorColor
 
QTimer cursorFlash
 
QTimer cursorFlashLimit
 
QPainterPath cursorShape
 
bool cursorVisible = false
 
int cursorWidth = 1
 
bool drawCursorInAdditionToSelection = false
 
bool drawTypeSettingHandle = true
 
qreal handleRadius = 7
 
bool hasFocus = false
 
SvgTextCursor::TypeSettingModeHandle hoveredTypeSettingHandle = SvgTextCursor::NoHandle
 
QPainterPath IMEDecoration
 The decorations for the current preedit string.
 
SvgTextCursorPropertyInterfaceinterface {nullptr}
 
bool isAddingCommand = false
 
Qt::KeyboardModifiers lastKnownModifiers
 
QRectF oldCursorRect
 
QRectF oldIMEDecorationRect
 Update Rectangle of previous decoration.
 
QRectF oldSelectionRect
 
QRectF oldTypeSettingRect
 
bool pasteRichText = true
 
int pos = 0
 
int posIndex = 0
 
SvgTextInsertCommandpreEditCommand {nullptr}
 PreEdit string as an command provided by the input method.
 
int preEditLength = -1
 Length of the preEditString.
 
int preEditStart = -1
 Start of the preEdit string as a cursor pos.
 
KisAcyclicSignalConnector resourceManagerAcyclicConnector
 
QPainterPath selection
 
KoSvgTextShapeshape {nullptr}
 
QVector< IMEDecorationInfostyleMap
 Decoration info (underlines) for the preEdit string to differentiate it from regular text.
 
TypeSettingDecorInfo typeSettingDecor
 
bool typeSettingMode = false
 
bool visualNavigation = true
 
- Public Attributes inherited from Private
KisCanvas2canvas
 
int displayedFrame
 
int intendedFrame
 

Private Slots

void blinkCursor ()
 Called by timer, toggles the text cursor visible or invisible.
 
void canvasResourceChanged (int key, const QVariant &value)
 Called when the canvas resources (foreground/background) change.
 
void clearFormattingAction ()
 Called by the clear formatting action.
 
bool pastePlainText ()
 pastePlainText Explicitely paste plaintext at pos.
 
bool pasteRichText ()
 pasteRichText
 
void propertyAction ()
 Called by the actions to execute a property change based on their data.
 
void removeTransformsFromRange ()
 removeTransformsFromRange Called by actions to remove svg character transforms from range.
 
void stopBlinkCursor ()
 Called by timer, stops the text blinking animation.
 
void updateCanvasResources ()
 Update the canvas resources with fore and background color.
 
void updateInputMethodItemTransform ()
 

Private Member Functions

bool acceptableInput (const QKeyEvent *event) const
 More or less copied from bool QInputControl::isAcceptableInput(const QKeyEvent *event) const.
 
void addCommandToUndoAdapter (KUndo2Command *cmd)
 Adds a command to the canvas of the parent tool.
 
void commitIMEPreEdit ()
 
int moveModeResult (const MoveMode mode, int &pos, bool visual=false) const
 Processes a move action, returns the input.
 
SvgTextRemoveCommandremoveSelectionImpl (bool allowCleanUp, KUndo2Command *parent=0)
 removeSelection if there's a selection, creates a text-removal command.
 
void updateCursor (bool firstUpdate=false)
 update the cursor shape. First update will block ensuring the canvas is visible so setShape won't cause this.
 
void updateIMEDecoration ()
 
void updateSelection ()
 
void updateTypeSettingDecoration ()
 

Private Attributes

const QScopedPointer< Privated
 

Detailed Description

The SvgTextCursor class.

This class handles cursor movement and text editing operations.

It acts as the KoToolSelection for SvgTextTool, allowing it to integrate with the basic KoToolBase functionality for copy, cut paste and clear.

A selection is defined as the anchor being different from the cursor position, with the move operation accepting whether you want to shift the cursor position.

It is also a shape listener to allow the textcursor to update itself whenever the corresponding text shape changes.

Definition at line 151 of file SvgTextCursor.cpp.

Member Enumeration Documentation

◆ MoveMode

Enumerator
MoveNone 
MoveLeft 
MoveRight 
MoveUp 
MoveDown 
MoveNextChar 
MovePreviousChar 
MoveNextLine 
MovePreviousLine 
MoveWordLeft 
MoveWordRight 
MoveWordEnd 
MoveWordStart 
MoveLineStart 
MoveLineEnd 
ParagraphStart 
ParagraphEnd 

Definition at line 49 of file SvgTextCursor.h.

◆ TypeSettingModeHandle

Handles used by type setting mode.

Enumerator
NoHandle 
StartPos 
EndPos 
BaselineShift 

The text properties handles.

Ascender 
Descender 
LineHeightTop 
LineHeightBottom 
BaselineAlphabetic 

Baselines.

BaselineIdeographic 
BaselineMiddle 
BaselineHanging 
BaselineMathematical 
BaselineCentral 

Definition at line 70 of file SvgTextCursor.h.

Constructor & Destructor Documentation

◆ SvgTextCursor()

SvgTextCursor::SvgTextCursor ( KoCanvasBase * canvas)
explicit

Definition at line 247 of file SvgTextCursor.cpp.

247 :
248 d(new Private)
249{
250 d->canvas = canvas;
251 d->interface = new SvgTextCursorPropertyInterface(this);
252 if (d->canvas->canvasController()) {
253 // Mockcanvas in the tests has no canvas controller.
254 connect(d->canvas->canvasController()->proxyObject, SIGNAL(sizeChanged(QSize)), this, SLOT(updateInputMethodItemTransform()));
255 connect(d->canvas->canvasController()->proxyObject,
256 SIGNAL(moveDocumentOffset(QPointF, QPointF)),
257 this,
259 connect(d->canvas->canvasController()->proxyObject,
260 SIGNAL(effectiveZoomChanged(qreal)),
261 this,
263 connect(d->canvas->canvasController()->proxyObject,
264 SIGNAL(documentRotationChanged(qreal)),
265 this,
267 connect(d->canvas->canvasController()->proxyObject,
268 SIGNAL(documentMirrorStatusChanged(bool, bool)),
269 this,
271 d->resourceManagerAcyclicConnector.connectBackwardResourcePair(
272 d->canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)),
273 this, SLOT(canvasResourceChanged(int,QVariant)));
274 d->resourceManagerAcyclicConnector.connectForwardVoid(d->interface, SIGNAL(textCharacterSelectionChanged()), this, SLOT(updateCanvasResources()));
275 }
276
277}
Interface to interact with the text property manager.
const QScopedPointer< Private > d
void updateCanvasResources()
Update the canvas resources with fore and background color.
void canvasResourceChanged(int key, const QVariant &value)
Called when the canvas resources (foreground/background) change.
KoCanvasBase * canvas
void updateInputMethodItemTransform()

References canvas, canvasResourceChanged(), d, updateCanvasResources(), and updateInputMethodItemTransform().

◆ ~SvgTextCursor()

SvgTextCursor::~SvgTextCursor ( )

Definition at line 279 of file SvgTextCursor.cpp.

280{
282 d->cursorFlash.stop();
283 d->cursorFlashLimit.stop();
284 d->shape = nullptr;
285}

References commitIMEPreEdit(), and d.

Member Function Documentation

◆ acceptableInput()

bool SvgTextCursor::acceptableInput ( const QKeyEvent * event) const
private

More or less copied from bool QInputControl::isAcceptableInput(const QKeyEvent *event) const.

Tests whether the current keyboard input can be printed as text, or is probably a shortcut. This is so that various keyboard events, like print don't get inserted as text.

Definition at line 2075 of file SvgTextCursor.cpp.

2076{
2077 const QString text = event->text();
2078 if (text.isEmpty())
2079 return false;
2080 const QChar c = text.at(0);
2081 // Formatting characters such as ZWNJ, ZWJ, RLM, etc. This needs to go before the
2082 // next test, since CTRL+SHIFT is sometimes used to input it on Windows.
2083 if (c.category() == QChar::Other_Format)
2084 return true;
2085 // QTBUG-35734: ignore Ctrl/Ctrl+Shift; accept only AltGr (Alt+Ctrl) on German keyboards
2086 if (event->modifiers() == Qt::ControlModifier
2087 || event->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier)) {
2088 return false;
2089 }
2090 if (c.isPrint())
2091 return true;
2092 if (c.category() == QChar::Other_PrivateUse)
2093 return true;
2094 if (c == QLatin1Char('\t'))
2095 return true;
2096 return false;
2097}

◆ addCommandToUndoAdapter()

void SvgTextCursor::addCommandToUndoAdapter ( KUndo2Command * cmd)
private

Adds a command to the canvas of the parent tool.

Definition at line 1989 of file SvgTextCursor.cpp.

1990{
1991 if (d->canvas) {
1992 if (cmd) {
1993 d->isAddingCommand = true;
1994 d->canvas->addCommand(cmd);
1995 d->isAddingCommand = false;
1996 }
1997 }
1998}

References d.

◆ blinkCursor

void SvgTextCursor::blinkCursor ( )
privateslot

Called by timer, toggles the text cursor visible or invisible.

Definition at line 1257 of file SvgTextCursor.cpp.

1258{
1259 if (d->shape) {
1260 Q_EMIT updateCursorDecoration(d->shape->shapeToDocument(d->cursorShape.boundingRect()) | d->oldCursorRect);
1261 d->cursorVisible = !d->cursorVisible;
1262 }
1263}
void updateCursorDecoration(QRectF updateRect)
Sents an update to the parent tool to update it's decorations.

References d, and updateCursorDecoration().

◆ canvasResourceChanged

void SvgTextCursor::canvasResourceChanged ( int key,
const QVariant & value )
privateslot

Called when the canvas resources (foreground/background) change.

Definition at line 1303 of file SvgTextCursor.cpp.

1304{
1306 return;
1307
1308 KoSvgTextProperties props;
1309 KoSvgTextProperties shapeProps = hasSelection()? d->shape->propertiesForPos(qMin(d->pos, d->anchor), true): d->shape->textProperties();
1312 if (!bg->compareTo(shapeProps.background().data())
1313 || !shapeProps.hasProperty(KoSvgTextProperties::FillId)) {
1315 QVariant::fromValue(KoSvgText::BackgroundProperty(bg)));
1316 }
1317 } else if (key == KoCanvasResource::BackgroundColor) {
1320 KoShapeStrokeSP shapeStroke = qSharedPointerDynamicCast<KoShapeStroke>(shapeProps.stroke());
1321 if (shapeStroke->isVisible()) {
1322 stroke.reset(new KoShapeStroke(*shapeStroke));
1323 }
1324 }
1325 stroke->setColor(value.value<KoColor>().toQColor());
1326 if (!stroke->compareFillTo(shapeProps.stroke().data()) || !shapeProps.hasProperty(KoSvgTextProperties::StrokeId)) {
1328 QVariant::fromValue(KoSvgText::StrokeProperty(stroke)));
1329 }
1330 }
1331 if (!props.isEmpty()) {
1332 mergePropertiesIntoSelection(props, QSet<KoSvgTextProperties::PropertyId>(), !hasSelection());
1333 }
1334}
float value(const T *src, size_t ch)
A simple solid color shape background.
void toQColor(QColor *c) const
a convenience method for the above.
Definition KoColor.cpp:198
@ StrokeId
KoSvgText::StrokeProperty.
@ FillId
KoSvgText::BackgroundProperty.
QSharedPointer< KoShapeBackground > background() const
KoShapeStrokeModelSP stroke() const
bool hasProperty(PropertyId id) const
void setProperty(PropertyId id, const QVariant &value)
@ BackgroundColor
The active background color selected for this canvas.
@ ForegroundColor
The active foreground color selected for this canvas.
BackgroundProperty is a special wrapper around KoShapeBackground for managing it in KoSvgTextProperti...
Definition KoSvgText.h:714
StrokeProperty is a special wrapper around KoShapeStrokeModel for managing it in KoSvgTextProperties.
Definition KoSvgText.h:733
void mergePropertiesIntoSelection(const KoSvgTextProperties props, const QSet< KoSvgTextProperties::PropertyId > removeProperties=QSet< KoSvgTextProperties::PropertyId >(), bool paragraphOnly=false, bool selectWord=false)
mergePropertiesIntoSelection Within Krita's SVG/CSS text system, it is possible to apply incomplete p...
bool hasSelection() override
return true if the tool currently has something selected that can be copied or deleted.

References KoSvgTextProperties::background(), KoCanvasResource::BackgroundColor, d, KoSvgTextProperties::FillId, KoCanvasResource::ForegroundColor, KoSvgTextProperties::hasProperty(), hasSelection(), KoSvgTextProperties::isEmpty(), mergePropertiesIntoSelection(), KoSvgTextProperties::setProperty(), KoSvgTextProperties::stroke(), KoSvgTextProperties::StrokeId, KoColor::toQColor(), and value().

◆ clearFormattingAction

void SvgTextCursor::clearFormattingAction ( )
privateslot

Called by the clear formatting action.

Definition at line 1347 of file SvgTextCursor.cpp.

1348{
1349 KoSvgTextProperties props;
1350
1351 QSet<KoSvgTextProperties::PropertyId> ids;
1352
1353 for (int i = 0; i < int(KoSvgTextProperties::LastPropertyId); i++) {
1354 ids.insert(KoSvgTextProperties::PropertyId(i));
1355 }
1356
1357 mergePropertiesIntoSelection(props, ids);
1358}
@ LastPropertyId
Last Property ID, used for iteration.

References KoSvgTextProperties::LastPropertyId, and mergePropertiesIntoSelection().

◆ commitIMEPreEdit()

void SvgTextCursor::commitIMEPreEdit ( )
private

This applies any running IME interactions, used when the shape is deselected halfways through an IME interaction.

Definition at line 2099 of file SvgTextCursor.cpp.

2100{
2101 if (!d->preEditCommand) {
2102 return;
2103 }
2104
2105 qApp->inputMethod()->commit();
2106
2107 if (!d->preEditCommand) {
2108 return;
2109 }
2110
2111 d->preEditCommand->undo();
2112 d->preEditCommand = nullptr;
2113 d->preEditStart = -1;
2114 d->preEditLength = 0;
2116 updateCursor();
2117}
void updateCursor(bool firstUpdate=false)
update the cursor shape. First update will block ensuring the canvas is visible so setShape won't cau...

References d, updateCursor(), and updateIMEDecoration().

◆ copy()

void SvgTextCursor::copy ( ) const

copy copies plain text into the clipboard between anchor and pos.

Definition at line 733 of file SvgTextCursor.cpp.

734{
735 if (d->shape) {
736 int start = d->shape->indexForPos(qMin(d->anchor, d->pos));
737 int length = d->shape->indexForPos(qMax(d->anchor, d->pos)) - start;
738 QString copied = d->shape->plainText().mid(start, length);
739 std::unique_ptr<KoSvgTextShape> copy = d->shape->copyRange(start, length);
740 QClipboard *cb = QApplication::clipboard();
741
742 if (copy) {
743 KoSvgTextShapeMarkupConverter converter(copy.get());
744 QString svg;
745 QString styles;
746 QString html;
747 QMimeData *svgData = new QMimeData();
748 if (converter.convertToSvg(&svg, &styles)) {
749 QString svgDoc = QString("<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"2.0\">%1\n%2</svg>").arg(styles).arg(svg);
750 svgData->setData(QLatin1String("image/svg+xml"), svgDoc.toUtf8());
751 }
752 svgData->setText(copied);
753 if (converter.convertToHtml(&html))
754 svgData->setHtml(html);
755 cb->setMimeData(svgData);
756 } else {
757 cb->setText(copied);
758 }
759
760 }
761}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82

References KoSvgTextShapeMarkupConverter::convertToHtml(), KoSvgTextShapeMarkupConverter::convertToSvg(), d, and length().

◆ currentTextProperties()

QPair< KoSvgTextProperties, KoSvgTextProperties > SvgTextCursor::currentTextProperties ( ) const

currentTextProperties

Returns
a qpair, where the first is the properties without inheritance, and the second, with inheritance.

Definition at line 671 of file SvgTextCursor.cpp.

672{
673 if (d->shape) {
674 return QPair<KoSvgTextProperties, KoSvgTextProperties>(d->shape->propertiesForPos(d->pos), d->shape->propertiesForPos(d->pos, true));
675 }
676 return QPair<KoSvgTextProperties, KoSvgTextProperties>();
677}

References d.

◆ cursorTypeForTypeSetting()

QCursor SvgTextCursor::cursorTypeForTypeSetting ( ) const

Return appropriate typeSetting cursor;.

Definition at line 451 of file SvgTextCursor.cpp.

452{
453 if (d->hoveredTypeSettingHandle == StartPos ||
454 d->hoveredTypeSettingHandle == StartPos ||
455 d->typeSettingDecor.testBaselines(d->lastKnownModifiers)) {
456 return Qt::ArrowCursor;
457 } else if (d->shape) {
458 return (d->shape->writingMode() == KoSvgText::HorizontalTB)? Qt::SizeVerCursor: Qt::SizeHorCursor;
459 }
460 return Qt::ArrowCursor;
461}
@ HorizontalTB
Definition KoSvgText.h:38

References d, KoSvgText::HorizontalTB, and StartPos.

◆ deselectText()

void SvgTextCursor::deselectText ( )

Deselect all text. This effectively makes anchor the same as pos.

Definition at line 825 of file SvgTextCursor.cpp.

826{
827 setPos(d->pos, d->pos);
828}
void setPos(int pos, int anchor)
Set the pos and the anchor.

References d, and setPos().

◆ focusIn()

void SvgTextCursor::focusIn ( )

Turns on blinking cursor.

Definition at line 1642 of file SvgTextCursor.cpp.

1643{
1644 d->cursorFlash.start();
1645 d->cursorFlashLimit.start();
1646 d->cursorVisible = false;
1647 d->hasFocus = true;
1648 blinkCursor();
1649}
void blinkCursor()
Called by timer, toggles the text cursor visible or invisible.

References blinkCursor(), and d.

◆ focusOut()

void SvgTextCursor::focusOut ( )

Stops blinking cursor.

Definition at line 1651 of file SvgTextCursor.cpp.

1652{
1653 d->hasFocus = false;
1655}
void stopBlinkCursor()
Called by timer, stops the text blinking animation.

References d, and stopBlinkCursor().

◆ getAnchor()

int SvgTextCursor::getAnchor ( )

Get the current selection anchor. This is the same as position, unless there's a selection.

Definition at line 347 of file SvgTextCursor.cpp.

348{
349 return d->anchor;
350}

References d.

◆ getPos()

int SvgTextCursor::getPos ( )

Get the current position.

Definition at line 342 of file SvgTextCursor.cpp.

343{
344 return d->pos;
345}

References d.

◆ handleName()

QString SvgTextCursor::handleName ( TypeSettingModeHandle handle) const

handleName

Returns
translated name of a given handle.

Definition at line 463 of file SvgTextCursor.cpp.

464{
465 bool baseline = d->typeSettingDecor.testBaselines(d->lastKnownModifiers);
466 if (handle == Ascender) {
467 if (baseline) {
468 return i18nc("Type setting mode line name", "Text Top");
469 } else {
470 return i18nc("Type setting mode line name", "Font Size");
471 }
472 } else if (handle == Descender) {
473 if (baseline) {
474 return i18nc("Type setting mode line name", "Text Bottom");
475 } else {
476 return i18nc("Type setting mode line name", "Font Size");
477 }
478 } else if (handle == BaselineAlphabetic) {
479 return i18nc("Type setting mode line name", "Alphabetic");
480 } else if (handle == BaselineIdeographic) {
481 return i18nc("Type setting mode line name", "Ideographic");
482 } else if (handle == BaselineHanging) {
483 return i18nc("Type setting mode line name", "Hanging");
484 } else if (handle == BaselineMiddle) {
485 return i18nc("Type setting mode line name", "Middle");
486 } else if (handle == BaselineMathematical) {
487 return i18nc("Type setting mode line name", "Mathematical");
488 } else if (handle == BaselineCentral) {
489 return i18nc("Type setting mode line name", "Central");
490 } else if (handle == LineHeightTop || handle == LineHeightBottom) {
491 return i18nc("Type setting mode line name", "Line Height");
492 } else if (handle == BaselineShift) {
493 if (baseline) {
494 return i18nc("Type setting mode line name", "Current Baseline");
495 } else {
496 return i18nc("Type setting mode line name", "Baseline Shift");
497 }
498 } else {
499 return QString();
500 }
501}

References Ascender, BaselineAlphabetic, BaselineCentral, BaselineHanging, BaselineIdeographic, BaselineMathematical, BaselineMiddle, BaselineShift, d, Descender, LineHeightBottom, and LineHeightTop.

◆ hasSelection()

bool SvgTextCursor::hasSelection ( )
overridevirtual

return true if the tool currently has something selected that can be copied or deleted.

Reimplemented from KoToolSelection.

Definition at line 1360 of file SvgTextCursor.cpp.

1361{
1362 return d->pos != d->anchor;
1363}

References d.

◆ inputMethodEvent()

void SvgTextCursor::inputMethodEvent ( QInputMethodEvent * event)

Process an input method event. This is used by IME like virtual keyboards.

Definition at line 1054 of file SvgTextCursor.cpp.

1055{
1056 dbgTools << "Commit:"<< event->commitString() << "predit:"<< event->preeditString();
1057 dbgTools << "Replacement:"<< event->replacementStart() << event->replacementLength();
1058
1059 QRectF updateRect = d->shape? d->shape->boundingRect(): QRectF();
1060 SvgTextShapeManagerBlocker blocker(d->canvas->shapeManager());
1061
1062 bool isGettingInput = !event->commitString().isEmpty() || !event->preeditString().isEmpty()
1063 || event->replacementLength() > 0;
1064
1065 // Remove previous preedit string.
1066 if (d->preEditCommand) {
1067 d->preEditCommand->undo();
1068 d->preEditCommand = 0;
1069 d->preEditStart = -1;
1070 d->preEditLength = -1;
1071 updateRect |= d->shape? d->shape->boundingRect(): QRectF();
1072 }
1073
1074 if (!d->shape || !isGettingInput) {
1075 blocker.unlock();
1076 d->canvas->shapeManager()->update(updateRect);
1077 event->ignore();
1078 return;
1079 }
1080
1081 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(d);
1082
1083 // remove the selection if any.
1085
1086 // set the text insertion pos to replacement start and also remove replacement length, if any.
1087 int originalPos = d->pos;
1088 int index = d->shape->indexForPos(d->pos) + event->replacementStart();
1089 d->pos = d->shape->posForIndex(index);
1090 if (event->replacementLength() > 0) {
1092 index + event->replacementLength(),
1093 originalPos,
1094 d->anchor,
1095 event->replacementLength(),
1096 false);
1098 }
1099
1100 // add the commit string, if any.
1101 if (!event->commitString().isEmpty()) {
1102 insertText(event->commitString());
1103 }
1104
1105 // set the selection...
1106 Q_FOREACH(const QInputMethodEvent::Attribute attribute, event->attributes()) {
1107 if (attribute.type == QInputMethodEvent::Selection) {
1108 d->pos = d->shape->posForIndex(attribute.start);
1109 int index = d->shape->indexForPos(d->pos);
1110 d->anchor = d->shape->posForIndex(index + attribute.length);
1111 }
1112 }
1113
1114
1115 // insert a preedit string, if any.
1116 if (!event->preeditString().isEmpty()) {
1117 int index = d->shape->indexForPos(d->pos);
1118 d->preEditCommand = new SvgTextInsertCommand(d->shape, d->pos, d->anchor, event->preeditString());
1119 d->preEditCommand->redo();
1120 d->preEditLength = event->preeditString().size();
1121 d->preEditStart = d->shape->posForIndex(index, true);
1122 } else {
1123 d->preEditCommand = 0;
1124 }
1125
1126 // Apply the cursor offset for the preedit.
1128 Q_FOREACH(const QInputMethodEvent::Attribute attribute, event->attributes()) {
1129 dbgTools << "attribute: "<< attribute.type << "start: " << attribute.start
1130 << "length: " << attribute.length << "val: " << attribute.value;
1131 // Text Format is about setting the look of the preedit string, and there can be multiple per event
1132 // we primarily interpret the underline. When a background color is set, we increase the underline
1133 // thickness, as that's what is actually supposed to happen according to the comments in the
1134 // platform input contexts for both macOS and Windows.
1135
1136 if (attribute.type == QInputMethodEvent::TextFormat) {
1137 QVariant val = attribute.value;
1138 QTextCharFormat form = val.value<QTextFormat>().toCharFormat();
1139
1140 if (attribute.length == 0 || attribute.start < 0 || !attribute.value.isValid()) {
1141 continue;
1142 }
1143
1144 int positionA = -1;
1145 int positionB = -1;
1146 if (!styleMap.isEmpty()) {
1147 for (int i = 0; i < styleMap.size(); i++) {
1148 if (attribute.start >= styleMap.at(i).start
1149 && attribute.start < styleMap.at(i).start + styleMap.at(i).length) {
1150 positionA = i;
1151 }
1152 if (attribute.start + attribute.length > styleMap.at(i).start
1153 && attribute.start + attribute.length <= styleMap.at(i).start + styleMap.at(i).length) {
1154 positionB = i;
1155 }
1156 }
1157
1158 if (positionA > -1 && positionA == positionB) {
1159 IMEDecorationInfo decoration1 = styleMap.at(positionA);
1160 IMEDecorationInfo decoration2 = decoration1;
1161 IMEDecorationInfo decoration3 = decoration1;
1162 decoration3.start = (attribute.start+attribute.length);
1163 decoration3.length = (decoration1.start + decoration1.length) - decoration3.start;
1164 decoration1.length = attribute.start - decoration1.start;
1165 decoration2.start = attribute.start;
1166 decoration2.length = attribute.length;
1167 if (decoration1.length > 0) {
1168 styleMap[positionA] = decoration1;
1169 if (decoration2.length > 0) {
1170 positionA += 1;
1171 styleMap.insert(positionA, decoration2);
1172 }
1173 } else {
1174 styleMap[positionA] = decoration2;
1175 }
1176 if (decoration3.length > 0) {
1177 styleMap.insert(positionA + 1, decoration3);
1178 }
1179 } else if (positionA > -1 && positionB > -1
1180 && positionA != positionB) {
1181 IMEDecorationInfo decoration1 = styleMap.at(positionA);
1182 IMEDecorationInfo decoration2 = decoration1;
1183 IMEDecorationInfo decoration3 = styleMap.at(positionB);
1184 IMEDecorationInfo decoration4 = decoration3;
1185 decoration2.length = (decoration1.start + decoration1.length) - attribute.start;
1186 decoration1.length = attribute.start - decoration1.start;
1187 decoration2.start = attribute.start;
1188
1189 decoration4.start = (attribute.start+attribute.length);
1190 decoration3.length = (decoration3.start + decoration3.length) - decoration4.start;
1191 decoration3.length = decoration4.start - decoration3.start;
1192 if (decoration1.length > 0) {
1193 styleMap[positionA] = decoration1;
1194 if (decoration2.length > 0) {
1195 positionA += 1;
1196 styleMap.insert(positionA, decoration2);
1197 }
1198 } else {
1199 styleMap[positionA] = decoration2;
1200 }
1201
1202 if (decoration3.length > 0) {
1203 styleMap[positionB] = decoration3;
1204 if (decoration4.length > 0) {
1205 styleMap.insert(positionB + 1, decoration4);
1206 }
1207 } else {
1208 styleMap[positionB] = decoration4;
1209 }
1210 }
1211 }
1212
1213 if (positionA > -1 && !styleMap.isEmpty()) {
1214
1215 for(int i = positionA; i <= positionB; i++) {
1216 IMEDecorationInfo decoration = styleMap.at(i);
1217 decoration.setDecorationFromQTextCharFormat(form);
1218 styleMap[i] = decoration;
1219 }
1220
1221 } else {
1222 IMEDecorationInfo decoration;
1223 decoration.start = attribute.start;
1224 decoration.length = attribute.length;
1225 decoration.setDecorationFromQTextCharFormat(form);
1226 styleMap.append(decoration);
1227 }
1228
1229 // QInputMethodEvent::Language is about setting the locale on the given preedit string, which is not possible yet.
1230 // QInputMethodEvent::Ruby is supposedly ruby info for the preedit string, but none of the platform integrations
1231 // actually implement this at time of writing, and it may have been something from a previous live of Qt's.
1232 } else if (attribute.type == QInputMethodEvent::Cursor) {
1233 if (d->preEditStart < 0) {
1234 d->anchor = d->pos;
1235 } else {
1236 int index = d->shape->indexForPos(d->preEditStart);
1237 d->pos = d->shape->posForIndex(index + attribute.start);
1238 d->anchor = d->pos;
1239 }
1240
1241 // attribute value is the cursor color, and should be used to paint the cursor.
1242 // attribute length is about whether the cursor should be visible at all...
1243 }
1244 }
1245
1246 blocker.unlock();
1247 updateRect |= d->shape->boundingRect();
1248 // TODO: replace with KoShapeBulkActionLock
1249 d->shape->updateAbsolute(updateRect);
1250 d->styleMap = styleMap;
1253 updateCursor();
1254 event->accept();
1255}
#define dbgTools
Definition kis_debug.h:48
int start
The startPos from the attribute.
void setDecorationFromQTextCharFormat(QTextCharFormat format)
int length
The length from the attribute.
void insertText(QString text)
Insert text at getPos()
QVector< IMEDecorationInfo > styleMap
Decoration info (underlines) for the preEdit string to differentiate it from regular text.
void addCommandToUndoAdapter(KUndo2Command *cmd)
Adds a command to the canvas of the parent tool.
SvgTextRemoveCommand * removeSelectionImpl(bool allowCleanUp, KUndo2Command *parent=0)
removeSelection if there's a selection, creates a text-removal command.

References addCommandToUndoAdapter(), d, dbgTools, insertText(), IMEDecorationInfo::length, removeSelectionImpl(), IMEDecorationInfo::setDecorationFromQTextCharFormat(), IMEDecorationInfo::start, styleMap, updateCursor(), updateIMEDecoration(), and updateSelection().

◆ inputMethodQuery()

QVariant SvgTextCursor::inputMethodQuery ( Qt::InputMethodQuery query) const

Process an input method query and return the requested result.

Definition at line 937 of file SvgTextCursor.cpp.

938{
939 dbgTools << "receiving inputmethod query" << query;
940
941 // Because we set the input item transform to be shape->document->view->widget->window,
942 // the coordinates here should be in shape coordinates.
943 switch(query) {
944 case Qt::ImEnabled:
945 return d->shape? true: false;
946 break;
947 case Qt::ImCursorRectangle:
948 // The platform integration will always define the cursor as the 'left side' handle.
949 if (d->shape) {
950 QPointF caret1(d->cursorCaret.p1());
951 QPointF caret2(d->cursorCaret.p2());
952
953
954 QRectF rect = QRectF(caret1, caret2).normalized();
955 if (!rect.isValid()) {
956 if (rect.height() < 1) {
957 rect.adjust(0, -1, 0, 0);
958 }
959 if (rect.width() < 1) {
960 rect.adjust(0, 0, 1, 0);
961 }
962
963 }
964 return rect.toAlignedRect();
965 }
966 break;
967 case Qt::ImAnchorRectangle:
968 // The platform integration will always define the anchor as the 'right side' handle.
969 if (d->shape) {
970 QPointF caret1(d->anchorCaret.p1());
971 QPointF caret2(d->anchorCaret.p2());
972 QRectF rect = QRectF(caret1, caret2).normalized();
973 if (rect.isEmpty()) {
974 if (rect.height() < 1) {
975 rect.adjust(0, -1, 0, 0);
976 }
977 if (rect.width() < 1) {
978 rect = rect.adjusted(-1, 0, 0, 0).normalized();
979 }
980 }
981 return rect.toAlignedRect();
982 }
983 break;
984 //case Qt::ImFont: // not sure what this is used for, but we cannot sent out without access to properties.
985 case Qt::ImAbsolutePosition:
986 case Qt::ImCursorPosition:
987 if (d->shape) {
988 return d->shape->indexForPos(d->pos);
989 }
990 break;
991 case Qt::ImSurroundingText:
992 if (d->shape) {
993 QString surroundingText = d->shape->plainText();
994 int preEditIndex = d->preEditCommand? d->shape->indexForPos(d->preEditStart): 0;
995 surroundingText.remove(preEditIndex, d->preEditLength);
996 return surroundingText;
997 }
998 break;
999 case Qt::ImCurrentSelection:
1000 if (d->shape) {
1001 QString surroundingText = d->shape->plainText();
1002 int preEditIndex = d->preEditCommand? d->shape->indexForPos(d->preEditStart): 0;
1003 surroundingText.remove(preEditIndex, d->preEditLength);
1004 int start = d->shape->indexForPos(qMin(d->anchor, d->pos));
1005 int length = d->shape->indexForPos(qMax(d->anchor, d->pos)) - start;
1006 return surroundingText.mid(start, length);
1007 }
1008 break;
1009 case Qt::ImTextBeforeCursor:
1010 if (d->shape) {
1011 int start = d->shape->indexForPos(d->pos);
1012 QString surroundingText = d->shape->plainText();
1013 int preEditIndex = d->preEditCommand? d->shape->indexForPos(d->preEditStart): 0;
1014 surroundingText.remove(preEditIndex, d->preEditLength);
1015 return surroundingText.left(start);
1016 }
1017 break;
1018 case Qt::ImTextAfterCursor:
1019 if (d->shape) {
1020 int start = d->shape->indexForPos(d->pos);
1021 QString surroundingText = d->shape->plainText();
1022 int preEditIndex = d->preEditCommand? d->shape->indexForPos(d->preEditStart): 0;
1023 surroundingText.remove(preEditIndex, d->preEditLength);
1024 return surroundingText.right(start);
1025 }
1026 break;
1027 case Qt::ImMaximumTextLength:
1028 return QVariant(); // infinite text length!
1029 break;
1030 case Qt::ImAnchorPosition:
1031 if (d->shape) {
1032 return d->shape->indexForPos(d->anchor);
1033 }
1034 break;
1035 case Qt::ImHints:
1036 // It would be great to use Qt::ImhNoTextHandles or Qt::ImhNoEditMenu,
1037 // but neither are implemented for anything but web platform integration
1038 return Qt::ImhMultiLine;
1039 break;
1040 // case Qt::ImPreferredLanguage: // requires access to properties.
1041 // case Qt::ImPlatformData: // this is only for iOS at time of writing.
1042 case Qt::ImEnterKeyType:
1043 if (d->shape) {
1044 return Qt::EnterKeyDefault; // because input method hint is always multiline, this will show a return key.
1045 }
1046 break;
1047 // case Qt::ImInputItemClipRectangle // whether the input item is clipped?
1048 default:
1049 return QVariant();
1050 }
1051 return QVariant();
1052}

References d, dbgTools, and length().

◆ insertRichText()

void SvgTextCursor::insertRichText ( KoSvgTextShape * insert,
bool inheritPropertiesIfPossible = false )

Insert rich text at getPos();.

Definition at line 619 of file SvgTextCursor.cpp.

620{
621 if (d->shape) {
622 //KUndo2Command *parentCmd = new KUndo2Command;
623 if (hasSelection()) {
624 SvgTextRemoveCommand *removeCmd = removeSelectionImpl(false);
625 addCommandToUndoAdapter(removeCmd);
626 }
627
628 SvgTextInsertRichCommand *cmd = new SvgTextInsertRichCommand(d->shape, insert, d->pos, d->anchor, inheritPropertiesIfPossible);
630
631 }
632}

References addCommandToUndoAdapter(), KoShape::anchor(), d, hasSelection(), and removeSelectionImpl().

◆ insertText()

void SvgTextCursor::insertText ( QString text)

Insert text at getPos()

Definition at line 603 of file SvgTextCursor.cpp.

604{
605
606 if (d->shape) {
607 //KUndo2Command *parentCmd = new KUndo2Command;
608 if (hasSelection()) {
609 SvgTextRemoveCommand *removeCmd = removeSelectionImpl(false);
610 addCommandToUndoAdapter(removeCmd);
611 }
612
613 SvgTextInsertCommand *insertCmd = new SvgTextInsertCommand(d->shape, d->pos, d->anchor, text);
614 addCommandToUndoAdapter(insertCmd);
615
616 }
617}

References addCommandToUndoAdapter(), d, hasSelection(), and removeSelectionImpl().

◆ isAddingCommand()

bool SvgTextCursor::isAddingCommand ( ) const

the cursor is currently adding a command

◆ keyPressEvent()

void SvgTextCursor::keyPressEvent ( QKeyEvent * event)

Handle the cursor-related key events.

Definition at line 1395 of file SvgTextCursor.cpp.

1396{
1398
1399 updateModifiers(event->modifiers());
1400
1401 if (d->preEditCommand) {
1402 //MacOS will keep sending keyboard events during IME handling.
1403 event->accept();
1404 return;
1405 }
1406
1407 bool select = event->modifiers().testFlag(Qt::ShiftModifier);
1408
1409 if (!((Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier) & event->modifiers())) {
1410
1411 switch (event->key()) {
1412 case Qt::Key_Right:
1414 event->accept();
1415 break;
1416 case Qt::Key_Left:
1418 event->accept();
1419 break;
1420 case Qt::Key_Up:
1422 event->accept();
1423 break;
1424 case Qt::Key_Down:
1426 event->accept();
1427 break;
1428 case Qt::Key_Delete:
1430 event->accept();
1431 break;
1432 case Qt::Key_Backspace:
1434 event->accept();
1435 break;
1436 case Qt::Key_Return:
1437 case Qt::Key_Enter:
1438 insertText("\n");
1439 event->accept();
1440 break;
1441 default:
1442 event->ignore();
1443 }
1444
1445 if (event->isAccepted()) {
1446 return;
1447 }
1448 }
1449 if (acceptableInput(event)) {
1450 insertText(event->text());
1451 event->accept();
1452 return;
1453 }
1454
1455 KoSvgTextProperties props = d->shape->textProperties();
1456
1459
1460 // Qt's keysequence stuff doesn't handle vertical, so to test all the standard keyboard shortcuts as if it did,
1461 // we reinterpret the direction keys according to direction and writing mode, and test against that.
1462
1463 int newKey = event->key();
1464
1465 if (direction == KoSvgText::DirectionRightToLeft) {
1466 switch (newKey) {
1467 case Qt::Key_Left:
1468 newKey = Qt::Key_Right;
1469 break;
1470 case Qt::Key_Right:
1471 newKey = Qt::Key_Left;
1472 break;
1473 default:
1474 break;
1475 }
1476 }
1477
1478 if (mode == KoSvgText::VerticalRL) {
1479 switch (newKey) {
1480 case Qt::Key_Left:
1481 newKey = Qt::Key_Down;
1482 break;
1483 case Qt::Key_Right:
1484 newKey = Qt::Key_Up;
1485 break;
1486 case Qt::Key_Up:
1487 newKey = Qt::Key_Left;
1488 break;
1489 case Qt::Key_Down:
1490 newKey = Qt::Key_Right;
1491 break;
1492 default:
1493 break;
1494 }
1495 } else if (mode == KoSvgText::VerticalRL) {
1496 switch (newKey) {
1497 case Qt::Key_Left:
1498 newKey = Qt::Key_Up;
1499 break;
1500 case Qt::Key_Right:
1501 newKey = Qt::Key_Down;
1502 break;
1503 case Qt::Key_Up:
1504 newKey = Qt::Key_Left;
1505 break;
1506 case Qt::Key_Down:
1507 newKey = Qt::Key_Right;
1508 break;
1509 default:
1510 break;
1511 }
1512 }
1513
1514 QKeySequence testSequence(event->modifiers() | newKey);
1515
1516
1517 // Note for future, when we have format changing actions:
1518 // We'll need to test format change actions before the standard
1519 // keys, as one of the standard keys for deleting a line is ctrl+u
1520 // which would probably be expected to do underline before deleting.
1521
1522 Q_FOREACH(QAction *action, d->actions) {
1523 if (action->shortcut() == testSequence) {
1524 event->accept();
1525 action->trigger();
1526 return;
1527 }
1528 }
1529
1530 // This first set is already tested above, however, if they still
1531 // match, then it's one of the extra sequences for MacOs, which
1532 // seem to be purely logical, instead of the visual set we tested
1533 // above.
1534 if (testSequence == QKeySequence::MoveToNextChar) {
1536 event->accept();
1537 } else if (testSequence == QKeySequence::SelectNextChar) {
1539 event->accept();
1540 } else if (testSequence == QKeySequence::MoveToPreviousChar) {
1542 event->accept();
1543 } else if (testSequence == QKeySequence::SelectPreviousChar) {
1545 event->accept();
1546 } else if (testSequence == QKeySequence::MoveToNextLine) {
1548 event->accept();
1549 } else if (testSequence == QKeySequence::SelectNextLine) {
1551 event->accept();
1552 } else if (testSequence == QKeySequence::MoveToPreviousLine) {
1554 event->accept();
1555 } else if (testSequence == QKeySequence::SelectPreviousLine) {
1557 event->accept();
1558
1559 } else if (testSequence == QKeySequence::MoveToNextWord) {
1561 event->accept();
1562 } else if (testSequence == QKeySequence::SelectNextWord) {
1564 event->accept();
1565 } else if (testSequence == QKeySequence::MoveToPreviousWord) {
1567 event->accept();
1568 } else if (testSequence == QKeySequence::SelectPreviousWord) {
1570 event->accept();
1571
1572 } else if (testSequence == QKeySequence::MoveToStartOfLine) {
1574 event->accept();
1575 } else if (testSequence == QKeySequence::SelectStartOfLine) {
1577 event->accept();
1578 } else if (testSequence == QKeySequence::MoveToEndOfLine) {
1580 event->accept();
1581 } else if (testSequence == QKeySequence::SelectEndOfLine) {
1583 event->accept();
1584
1585 } else if (testSequence == QKeySequence::MoveToStartOfBlock
1586 || testSequence == QKeySequence::MoveToStartOfDocument) {
1588 event->accept();
1589 } else if (testSequence == QKeySequence::SelectStartOfBlock
1590 || testSequence == QKeySequence::SelectStartOfDocument) {
1592 event->accept();
1593
1594 } else if (testSequence == QKeySequence::MoveToEndOfBlock
1595 || testSequence == QKeySequence::MoveToEndOfDocument) {
1597 event->accept();
1598 } else if (testSequence == QKeySequence::SelectEndOfBlock
1599 || testSequence == QKeySequence::SelectEndOfDocument) {
1601 event->accept();
1602
1603 }else if (testSequence == QKeySequence::DeleteStartOfWord) {
1605 event->accept();
1606 } else if (testSequence == QKeySequence::DeleteEndOfWord) {
1608 event->accept();
1609 } else if (testSequence == QKeySequence::DeleteEndOfLine) {
1611 event->accept();
1612 } else if (testSequence == QKeySequence::DeleteCompleteLine) {
1614 event->accept();
1615 } else if (testSequence == QKeySequence::Backspace) {
1617 event->accept();
1618 } else if (testSequence == QKeySequence::Delete) {
1620 event->accept();
1621
1622 } else if (testSequence == QKeySequence::InsertLineSeparator
1623 || testSequence == QKeySequence::InsertParagraphSeparator) {
1624 insertText("\n");
1625 event->accept();
1626 } else {
1627 event->ignore();
1628 }
1629}
@ WritingModeId
KoSvgText::WritingMode.
@ DirectionId
KoSvgText::Direction.
QVariant propertyOrDefault(PropertyId id) const
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
Direction
Base direction used by Bidi algorithm.
Definition KoSvgText.h:48
@ DirectionRightToLeft
Definition KoSvgText.h:50
void moveCursor(MoveMode mode, bool moveAnchor=true)
Move the cursor, and, if you don't want a selection, move the anchor.
bool acceptableInput(const QKeyEvent *event) const
More or less copied from bool QInputControl::isAcceptableInput(const QKeyEvent *event) const.
void removeText(MoveMode first, MoveMode second)
removeText remove text relative to the current position. This will move the cursor according to the m...
void removeLastCodePoint()
removeLastCodePoint Special function to remove the last code point. Triggered by backspace....
void updateModifiers(const Qt::KeyboardModifiers modifiers)

References acceptableInput(), d, KoSvgTextProperties::DirectionId, KoSvgText::DirectionRightToLeft, insertText(), KIS_SAFE_ASSERT_RECOVER_RETURN, moveCursor(), MoveDown, MoveLeft, MoveLineEnd, MoveLineStart, MoveNextChar, MoveNextLine, MoveNone, MovePreviousChar, MovePreviousLine, MoveRight, MoveUp, MoveWordEnd, MoveWordStart, ParagraphEnd, ParagraphStart, KoSvgTextProperties::propertyOrDefault(), removeLastCodePoint(), removeText(), updateModifiers(), KoSvgText::VerticalRL, and KoSvgTextProperties::WritingModeId.

◆ mergePropertiesIntoSelection()

void SvgTextCursor::mergePropertiesIntoSelection ( const KoSvgTextProperties props,
const QSet< KoSvgTextProperties::PropertyId > removeProperties = QSet<KoSvgTextProperties::PropertyId>(),
bool paragraphOnly = false,
bool selectWord = false )

mergePropertiesIntoSelection Within Krita's SVG/CSS text system, it is possible to apply incomplete properties to a whole range. In that case, only the existing properties are applied. Properties can also be removed this way.

Parameters
props– properties to apply.
removeProperties– properties to be removed.
paragraphOnly– whether to apply to the paragraph.
selectWord– whether to select the word if there's no selection.

Definition at line 695 of file SvgTextCursor.cpp.

696{
697 if (d->shape) {
698 int start = -1;
699 int end = -1;
700 if (!paragraphOnly) {
701 start = d->pos;
702 end = d->anchor;
703 }
704 if (selectWord && d->pos == d->anchor) {
705 const int finalPos = d->shape->posForIndex(d->shape->plainText().size());
706 start = qBound(0, moveModeResult(MoveWordStart, d->pos, d->visualNavigation), finalPos);
707 end = qBound(0, moveModeResult(MoveWordEnd, d->pos, d->visualNavigation), finalPos);
708 }
709 KUndo2Command *cmd = new SvgTextMergePropertiesRangeCommand(d->shape, props, start, end, removeProperties);
711 }
712}
The SvgTextMergePropertiesRangeCommand class This sets properties on a specific range in a single tex...
int moveModeResult(const MoveMode mode, int &pos, bool visual=false) const
Processes a move action, returns the input.

References addCommandToUndoAdapter(), d, moveModeResult(), MoveWordEnd, and MoveWordStart.

◆ moveCursor()

void SvgTextCursor::moveCursor ( MoveMode mode,
bool moveAnchor = true )

Move the cursor, and, if you don't want a selection, move the anchor.

Definition at line 588 of file SvgTextCursor.cpp.

589{
590 if (d->shape) {
591
592 const int finalPos = d->shape->posForIndex(d->shape->plainText().size());
593 d->pos = qBound(0, moveModeResult(mode, d->pos, d->visualNavigation), finalPos);
594
595 if (moveAnchor) {
596 d->anchor = d->pos;
597 }
599 updateCursor();
600 }
601}

References d, moveModeResult(), updateCursor(), and updateSelection().

◆ moveModeResult()

int SvgTextCursor::moveModeResult ( const MoveMode mode,
int & pos,
bool visual = false ) const
private

Processes a move action, returns the input.

Definition at line 2000 of file SvgTextCursor.cpp.

2001{
2002 int newPos = pos;
2003 switch (mode) {
2004 case MoveNone:
2005 break;
2006 case MoveLeft:
2007 newPos = d->shape->posLeft(pos, visual);
2008 break;
2009 case MoveRight:
2010 newPos = d->shape->posRight(pos, visual);
2011 break;
2012 case MoveUp:
2013 newPos = d->shape->posUp(pos, visual);
2014 break;
2015 case MoveDown:
2016 newPos = d->shape->posDown(pos, visual);
2017 break;
2018 case MovePreviousChar:
2019 newPos = d->shape->previousIndex(pos);
2020 break;
2021 case MoveNextChar:
2022 newPos = d->shape->nextIndex(pos);
2023 break;
2024 case MovePreviousLine:
2025 newPos = d->shape->previousLine(pos);
2026 break;
2027 case MoveNextLine:
2028 newPos = d->shape->nextLine(pos);
2029 break;
2030 case MoveWordLeft:
2031 newPos = d->shape->wordLeft(pos, visual);
2032 if (newPos == pos) {
2033 newPos = d->shape->posLeft(pos, visual);
2034 newPos = d->shape->wordLeft(newPos, visual);
2035 }
2036 break;
2037 case MoveWordRight:
2038 newPos = d->shape->wordRight(pos, visual);
2039 if (newPos == pos) {
2040 newPos = d->shape->posRight(pos, visual);
2041 newPos = d->shape->wordRight(newPos, visual);
2042 }
2043 break;
2044 case MoveWordStart:
2045 newPos = d->shape->wordStart(pos);
2046 if (newPos == pos) {
2047 newPos = d->shape->previousIndex(pos);
2048 newPos = d->shape->wordStart(newPos);
2049 }
2050 break;
2051 case MoveWordEnd:
2052 newPos = d->shape->wordEnd(pos);
2053 if (newPos == pos) {
2054 newPos = d->shape->nextIndex(pos);
2055 newPos = d->shape->wordEnd(newPos);
2056 }
2057 break;
2058 case MoveLineStart:
2059 newPos = d->shape->lineStart(pos);
2060 break;
2061 case MoveLineEnd:
2062 newPos = d->shape->lineEnd(pos);
2063 break;
2064 case ParagraphStart:
2065 newPos = 0;
2066 break;
2067 case ParagraphEnd:
2068 newPos = d->shape->posForIndex(d->shape->plainText().size());
2069 break;
2070 }
2071 return newPos;
2072}

References d, MoveDown, MoveLeft, MoveLineEnd, MoveLineStart, MoveNextChar, MoveNextLine, MoveNone, MovePreviousChar, MovePreviousLine, MoveRight, MoveUp, MoveWordEnd, MoveWordLeft, MoveWordRight, MoveWordStart, ParagraphEnd, ParagraphStart, and pos.

◆ notifyCursorPosChanged()

void SvgTextCursor::notifyCursorPosChanged ( int pos,
int anchor )
overridevirtual

TextCursorChangeListener reimplementation, this allows undo commands to update the cursor without having the cursor owned by the command.

Implements KoSvgTextShape::TextCursorChangeListener.

Definition at line 1378 of file SvgTextCursor.cpp.

1379{
1380 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(d);
1381 d->pos = pos;
1382 d->anchor = anchor;
1383 updateCursor();
1386}
void updateTypeSettingDecoration()

References anchor, d, pos, updateCursor(), updateSelection(), and updateTypeSettingDecoration().

◆ notifyMarkupChanged()

void SvgTextCursor::notifyMarkupChanged ( )
overridevirtual

Implements KoSvgTextShape::TextCursorChangeListener.

Definition at line 1388 of file SvgTextCursor.cpp.

1389{
1390 d->interface->emitSelectionChange();
1391 d->interface->emitCharacterSelectionChange();
1393}

References d, and updateTypeSettingDecoration().

◆ notifyShapeChanged()

void SvgTextCursor::notifyShapeChanged ( KoShape::ChangeType type,
KoShape * shape )
overridevirtual

ShapeChangeListener reimplementation. This will update the cursor position when the shape was updated.

Implements KoShape::ShapeChangeListener.

Definition at line 1365 of file SvgTextCursor.cpp.

1366{
1367 Q_UNUSED(type);
1368 Q_UNUSED(shape);
1369 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(d);
1370 d->pos = d->shape->posForIndex(d->posIndex);
1371 d->anchor = d->shape->posForIndex(d->anchorIndex);
1372 updateCursor(true);
1376}
KoSvgTextShape * shape

References d, shape, updateCursor(), updateInputMethodItemTransform(), updateSelection(), and updateTypeSettingDecoration().

◆ paintDecorations()

void SvgTextCursor::paintDecorations ( QPainter & gc,
QColor selectionColor,
int decorationThickness = 1,
qreal handleRadius = 5.0 )

Paint all decorations and blinkingcursors.

Definition at line 835 of file SvgTextCursor.cpp.

836{
837 if (d->shape) {
838 gc.save();
839 gc.setTransform(d->shape->absoluteTransformation(), true);
840
841 if (d->pos != d->anchor && !d->typeSettingMode) {
842 gc.save();
843 gc.setOpacity(0.5);
844 QBrush brush(selectionColor);
845 gc.fillPath(d->selection, brush);
846 gc.restore();
847 }
848
849 if ( (d->drawCursorInAdditionToSelection || d->pos == d->anchor)
850 && d->cursorVisible) {
851 QPen pen;
852 pen.setCosmetic(true);
853 QColor c = d->cursorColor.isValid()? d->cursorColor: Qt::black;
854 pen.setColor(bgColorForCaret(c));
855 pen.setWidth((d->cursorWidth + 2) * decorationThickness);
856 gc.setPen(pen);
857 gc.drawPath(d->cursorShape);
858 pen.setColor(c);
859 pen.setWidth(d->cursorWidth * decorationThickness);
860 gc.setPen(pen);
861 gc.drawPath(d->cursorShape);
862
863 }
864
865 if (d->preEditCommand) {
866 gc.save();
867 QBrush brush(selectionColor);
868 gc.setOpacity(0.5);
869 gc.fillPath(d->IMEDecoration, brush);
870 gc.restore();
871 }
872 if (d->typeSettingMode && d->drawTypeSettingHandle) {
873 d->handleRadius = handleRadius;
874 QTransform painterTf = gc.transform();
875 KisHandlePainterHelper helper(&gc, handleRadius, decorationThickness);
878
879 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath> paths
880 = d->typeSettingDecor.testBaselines(d->lastKnownModifiers)? d->typeSettingDecor.baselines: d->typeSettingDecor.paths;
881 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath> parentPaths
882 = d->typeSettingDecor.testBaselines(d->lastKnownModifiers)? d->typeSettingDecor.parentBaselines: d->typeSettingDecor.parentPaths;
883 Q_FOREACH(SvgTextCursor::TypeSettingModeHandle handle, paths.keys()) {
884 const QPainterPath p = paths.value(handle);
885 const QPainterPath parent = parentPaths.value(handle);
886 if (d->hoveredTypeSettingHandle == handle) {
887 helper.setHandleStyle(highlight);
888 helper.drawPath(parent);
889 helper.drawPath(p);
890 } else {
891 gc.save();
892 QPen pen(selectionColor, decorationThickness, handle == BaselineShift? Qt::SolidLine: Qt::DashLine);
893 pen.setCosmetic(true);
894 gc.setPen(pen);
895 gc.setOpacity(0.5);
896 gc.drawPath(painterTf.map(parent));
897 gc.drawPath(painterTf.map(p));
898 gc.restore();
899 }
900 gc.save();
901 QPen pen(selectionColor, decorationThickness, Qt::SolidLine);
902 pen.setCosmetic(true);
903 gc.setPen(pen);
904 gc.setOpacity(0.5);
905 gc.drawPath(painterTf.map(d->typeSettingDecor.edges));
906 gc.restore();
907 }
908
909 if (d->typeSettingDecor.handlesEnabled) {
910 helper.setHandleStyle(d->hoveredTypeSettingHandle == EndPos? highlight: regular);
911 helper.drawHandleCircle(d->typeSettingDecor.handles.second);
912 helper.setHandleStyle(d->hoveredTypeSettingHandle == StartPos? highlight: regular);
913 helper.drawHandleRect(d->typeSettingDecor.handles.first);
914 }
915 QString name = handleName(d->hoveredTypeSettingHandle);
916 if (!name.isEmpty()) {
917 QPainterPath textP;
918 // When we're drawing on opengl, there's no anti-aliasing, so we should have full hinting for readabiltiy.
919 QFont font = gc.font();
920 font.setHintingPreference(QFont::PreferFullHinting);
921 textP.addText(painterTf.map(d->typeSettingDecor.closestBaselinePoint).toPoint(), font, name);
922 gc.save();
923 QPen pen(bgColorForCaret(selectionColor, 255));
924 pen.setCosmetic(true);
925 pen.setWidth(decorationThickness);
926 gc.setPen(pen);
927 gc.drawPath(textP);
928 gc.fillPath(textP, QBrush(selectionColor));
929 gc.restore();
930 }
931
932 }
933 gc.restore();
934 }
935}
const Params2D p
static QColor bgColorForCaret(QColor c, int opacity=64)
The KisHandlePainterHelper class is a special helper for painting handles around objects....
static KisHandleStyle & partiallyHighlightedPrimaryHandles()
static KisHandleStyle & secondarySelection()
const char * name(StandardAction id)
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327
QString handleName(TypeSettingModeHandle handle) const
handleName
TypeSettingModeHandle
Handles used by type setting mode.

References BaselineShift, bgColorForCaret(), d, KisHandlePainterHelper::drawHandleCircle(), KisHandlePainterHelper::drawHandleRect(), KisHandlePainterHelper::drawPath(), EndPos, handleName(), handleRadius, p, KisHandleStyle::partiallyHighlightedPrimaryHandles(), KisHandleStyle::secondarySelection(), KisHandlePainterHelper::setHandleStyle(), and StartPos.

◆ paste()

bool SvgTextCursor::paste ( )

paste pastes plain text in the clipboard at pos. Uses pasteRichTextByDefault to determine whether to try and paste rich text.

Returns
true when successfull.

Definition at line 763 of file SvgTextCursor.cpp.

764{
765 bool success = d->pasteRichText? pasteRichText(): pastePlainText();
766 return success;
767}
bool pastePlainText()
pastePlainText Explicitely paste plaintext at pos.

References d, pastePlainText(), and pasteRichText.

◆ pastePlainText

bool SvgTextCursor::pastePlainText ( )
privateslot

pastePlainText Explicitely paste plaintext at pos.

Returns
true when successfull.

Definition at line 805 of file SvgTextCursor.cpp.

806{
807 bool success = false;
808 QClipboard *cb = QApplication::clipboard();
809 const QMimeData *mimeData = cb->mimeData();
810 if (mimeData->hasText()) {
811 insertText(mimeData->text());
812 success = true;
813 }
814 return success;
815}

References insertText().

◆ pasteRichText

bool SvgTextCursor::pasteRichText ( )
privateslot

pasteRichText

Returns
try to paste rich text at pos.

◆ posForTypeSettingHandleAndRect()

int SvgTextCursor::posForTypeSettingHandleAndRect ( const TypeSettingModeHandle handle,
const QRectF regionOfInterest )

posForHandleAndRect Returns the closest cursor position for a given region and typesetting handle. Used by the type setting mode to find the relevant metrics to scale.

Returns
cursor pos closest.

Definition at line 550 of file SvgTextCursor.cpp.

551{
552 if (!d->shape) return 0;
553
555 d->shape->getPositionsAndRotationsForRange(d->pos, d->anchor);
556 if (infos.size() < 1) return 0;
557
558 const QRectF roi = d->shape->documentToShape(regionOfInterest);
559
560 for (auto it = infos.begin(); it != infos.end(); it++) {
561 const int currentPos = (d->pos == d->anchor)? -1 :d->shape->posForIndex(it->logicalIndex);
562 const KoSvgTextProperties props = d->shape->propertiesForPos(currentPos, true);
564
565 KoSvgText::FontMetrics metrics = (d->pos == d->anchor)? props.metrics(true, true): it->metrics;
566 const bool isHorizontal = d->shape->writingMode() == KoSvgText::HorizontalTB;
567
568 const qreal scaleMetrics = props.fontSize().value/qreal(metrics.fontSize);
569 const int lineGap = lineHeight.isNormal? metrics.lineGap: (lineHeight.length.value/scaleMetrics)-(metrics.ascender-metrics.descender);
570
571 QTransform t = QTransform::fromTranslate(it->finalPos.x(), it->finalPos.y());
572 t.rotate(it->rotateDeg);
573
574 const QMap<SvgTextCursor::TypeSettingModeHandle, int> types
575 = typeSettingBaselinesFromMetrics(metrics, lineGap, isHorizontal);
576
577 const int metric = types.value(handle);
578 QPointF offset = isHorizontal? QPointF(0, -(metric*scaleMetrics)): QPointF(metric*scaleMetrics, 0);
579 QLineF line = t.map(QLineF(offset, offset+it->advance));
580 if (KisAlgebra2D::intersectLineRect(line, roi.toAlignedRect(), false)) return d->shape->posForIndex(it->logicalIndex);
581 }
582
583 return 0;
584}
QMap< SvgTextCursor::TypeSettingModeHandle, int > typeSettingBaselinesFromMetrics(const KoSvgText::FontMetrics metrics, const qreal lineGap, const bool isHorizontal)
@ LineHeightId
KoSvgText::AutoValue.
KoSvgText::FontMetrics metrics(const bool withResolvedLineHeight=true, const bool offsetByBaseline=false) const
metrics Return the metrics of the first available font.
KoSvgText::CssLengthPercentage fontSize() const
bool intersectLineRect(QLineF &line, const QRect rect, bool extend)
The FontMetrics class A class to keep track of a variety of font metrics. Note that values are in Fre...
Definition KoSvgText.h:327
CssLengthPercentage length
Definition KoSvgText.h:693
bool isNormal
It's a number indicating the lineHeight;.
Definition KoSvgText.h:696

References d, KoSvgTextProperties::fontSize(), KoSvgText::HorizontalTB, KisAlgebra2D::intersectLineRect(), KoSvgText::LineHeightInfo::isNormal, KoSvgText::LineHeightInfo::length, KoSvgTextProperties::LineHeightId, KoSvgTextProperties::metrics(), KoSvgTextProperties::propertyOrDefault(), typeSettingBaselinesFromMetrics(), and KoSvgText::CssLengthPercentage::value.

◆ propertiesForRange()

QList< KoSvgTextProperties > SvgTextCursor::propertiesForRange ( ) const

propertiesForRange

Returns
properties for the current range defined by the cursor pos and anchor.

Definition at line 679 of file SvgTextCursor.cpp.

680{
681 if (!d->shape) return QList<KoSvgTextProperties>();
682 int start = -1;
683 int end = -1;
684 start = qMin(d->pos, d->anchor);
685 end = qMax(d->pos, d->anchor);
686 return d->shape->propertiesForRange(start, end);
687}

References d.

◆ propertiesForShape()

QList< KoSvgTextProperties > SvgTextCursor::propertiesForShape ( ) const

propertiesForShape

Returns
properties for the current shape.

Definition at line 689 of file SvgTextCursor.cpp.

690{
691 if (!d->shape) return QList<KoSvgTextProperties>();
692 return {d->shape->propertiesForRange(-1, -1)};
693}

References d.

◆ propertyAction

void SvgTextCursor::propertyAction ( )
privateslot

Called by the actions to execute a property change based on their data.

Definition at line 1336 of file SvgTextCursor.cpp.

1337{
1338 QAction *action = dynamic_cast<QAction*>(QObject::sender());
1339 if (!action || !d->shape) return;
1340
1341 const QList<KoSvgTextProperties> p = d->shape->propertiesForRange(qMin(d->pos, d->anchor), qMax(d->pos, d->anchor));
1343 if (properties.isEmpty()) return;
1344 mergePropertiesIntoSelection(properties);
1345}
static KoSvgTextProperties getModifiedProperties(const QAction *action, QList< KoSvgTextProperties > currentProperties)

References d, SvgTextShortCuts::getModifiedProperties(), KoSvgTextProperties::isEmpty(), mergePropertiesIntoSelection(), and p.

◆ registerPropertyAction()

bool SvgTextCursor::registerPropertyAction ( QAction * action,
const QString & name )

Register an action.

Definition at line 1657 of file SvgTextCursor.cpp.

1658{
1659 if (SvgTextShortCuts::configureAction(action, name)) {
1660 d->actions.append(action);
1661 connect(action, SIGNAL(triggered(bool)), this, SLOT(propertyAction()));
1662 return true;
1663 } else if (name == "svg_insert_special_character") {
1664 d->actions.append(action);
1665 connect(action, SIGNAL(triggered(bool)), this, SIGNAL(sigOpenGlyphPalette()));
1666 return true;
1667 } else if (name == "svg_paste_rich_text") {
1668 d->actions.append(action);
1669 connect(action, SIGNAL(triggered(bool)), this, SLOT(pasteRichText()));
1670 return true;
1671 } else if (name == "svg_paste_plain_text") {
1672 d->actions.append(action);
1673 connect(action, SIGNAL(triggered(bool)), this, SLOT(pastePlainText()));
1674 return true;
1675 } else if (name == "svg_remove_transforms_from_range") {
1676 d->actions.append(action);
1677 connect(action, SIGNAL(triggered(bool)), this, SLOT(removeTransformsFromRange()));
1678 return true;
1679 } else if (name == "svg_clear_formatting") {
1680 d->actions.append(action);
1681 connect(action, SIGNAL(triggered(bool)), this, SLOT(clearFormattingAction()));
1682 return true;
1683 } else if (action) {
1684 d->actions.append(action);
1685 return true;
1686 }
1687 return false;
1688}
static bool configureAction(QAction *action, const QString &name)
void removeTransformsFromRange()
removeTransformsFromRange Called by actions to remove svg character transforms from range.
void clearFormattingAction()
Called by the clear formatting action.
void sigOpenGlyphPalette()
Called by actions, tells the parent tool to open the glyph palette.
void propertyAction()
Called by the actions to execute a property change based on their data.

References clearFormattingAction(), SvgTextShortCuts::configureAction(), d, pastePlainText(), pasteRichText, propertyAction(), removeTransformsFromRange(), and sigOpenGlyphPalette().

◆ removeLastCodePoint()

void SvgTextCursor::removeLastCodePoint ( )

removeLastCodePoint Special function to remove the last code point. Triggered by backspace. This is distinct from remove text, as some clusters have multiple code points, but it is generally expected backspace deletes the codepoints while delete with selection deletes the whole cluster.

Definition at line 656 of file SvgTextCursor.cpp.

657{
658 if (d->shape) {
659 SvgTextRemoveCommand *removeCmd;
660 if (hasSelection()) {
661 removeCmd = removeSelectionImpl(true);
662 addCommandToUndoAdapter(removeCmd);
663 } else {
664 int lastIndex = d->shape->indexForPos(d->pos);
665 removeCmd = new SvgTextRemoveCommand(d->shape, lastIndex, d->pos, d->anchor, 1, true);
666 addCommandToUndoAdapter(removeCmd);
667 }
668 }
669}

References addCommandToUndoAdapter(), d, hasSelection(), and removeSelectionImpl().

◆ removeSelection()

void SvgTextCursor::removeSelection ( )

removeSelection if there's a selection, creates a text-removal command.

Parameters
parent
Returns
the text-removal command, if possible, if there's no selection or shape, it'll return 0;

Definition at line 714 of file SvgTextCursor.cpp.

715{
716 KUndo2Command *removeCmd = removeSelectionImpl(true);
717 addCommandToUndoAdapter(removeCmd);
718}

References addCommandToUndoAdapter(), and removeSelectionImpl().

◆ removeSelectionImpl()

SvgTextRemoveCommand * SvgTextCursor::removeSelectionImpl ( bool allowCleanUp,
KUndo2Command * parent = 0 )
private

removeSelection if there's a selection, creates a text-removal command.

Parameters
parent
Returns
the text-removal command, if possible, if there's no selection or shape, it'll return 0;

Definition at line 720 of file SvgTextCursor.cpp.

721{
722 SvgTextRemoveCommand *removeCmd = nullptr;
723 if (d->shape) {
724 if (d->anchor != d->pos) {
725 int end = d->shape->indexForPos(qMax(d->anchor, d->pos));
726 int length = d->shape->indexForPos(qMax(d->anchor, d->pos)) - d->shape->indexForPos(qMin(d->anchor, d->pos));
727 removeCmd = new SvgTextRemoveCommand(d->shape, end, d->pos, d->anchor, length, allowCleanUp, parent);
728 }
729 }
730 return removeCmd;
731}

References d, and length().

◆ removeText()

void SvgTextCursor::removeText ( SvgTextCursor::MoveMode first,
SvgTextCursor::MoveMode second )

removeText remove text relative to the current position. This will move the cursor according to the move modes and then remove the text between the two positions.

Parameters
firsthow the cursor should move to get to the start position.
secondhow the cursor should move to get to the end position.

Definition at line 634 of file SvgTextCursor.cpp.

635{
636 if (d->shape) {
637 SvgTextRemoveCommand *removeCmd;
638 if (hasSelection()) {
639 removeCmd = removeSelectionImpl(true);
640 addCommandToUndoAdapter(removeCmd);
641 } else {
642 int posA = moveModeResult(first, d->pos, d->visualNavigation);
643 int posB = moveModeResult(second, d->pos, d->visualNavigation);
644
645 int posStart = qMin(posA, posB);
646 int posEnd = qMax(posA, posB);
647 int indexEnd = d->shape->indexForPos(posEnd);
648 int length = indexEnd - d->shape->indexForPos(posStart);
649
650 removeCmd = new SvgTextRemoveCommand(d->shape, indexEnd, d->pos, d->anchor, length, true);
651 addCommandToUndoAdapter(removeCmd);
652 }
653 }
654}

References addCommandToUndoAdapter(), d, hasSelection(), length(), moveModeResult(), and removeSelectionImpl().

◆ removeTransformsFromRange

void SvgTextCursor::removeTransformsFromRange ( )
privateslot

removeTransformsFromRange Called by actions to remove svg character transforms from range.

Definition at line 817 of file SvgTextCursor.cpp.

818{
819 if (d->shape) {
820 KUndo2Command *cmd = new SvgTextRemoveTransformsFromRange(d->shape, d->pos, d->anchor);
822 }
823}
The SvgTextRemoveTransformsFromRange class Removes the SVG 1.1 character transforms from the range.

References addCommandToUndoAdapter(), and d.

◆ selectionChanged

void SvgTextCursor::selectionChanged ( )
signal

Sents an update selection was changed.

◆ setCaretSetting()

void SvgTextCursor::setCaretSetting ( int cursorWidth = 1,
int cursorFlash = 1000,
int cursorFlashLimit = 5000,
bool drawCursorInAdditionToSelection = false )

setCaretSetting Set the caret settings for the cursor. Qt has some standard functionality associated, which we pass via this.

Parameters
cursorWidth- Cursor width from the style.
cursorFlash- the total time it takes for a cursor to hide reapear.
cursorFlashLimit- maximum amount of time a cursor is allowed to flash.

Definition at line 316 of file SvgTextCursor.cpp.

317{
318 d->cursorFlash.setInterval(cursorFlash/2);
319 d->cursorFlashLimit.setInterval(cursorFlashLimit);
320 d->cursorWidth = cursorWidth;
321 d->drawCursorInAdditionToSelection = drawCursorInAdditionToSelection;
322 connect(&d->cursorFlash, SIGNAL(timeout()), this, SLOT(blinkCursor()));
323 connect(&d->cursorFlashLimit, SIGNAL(timeout()), this, SLOT(stopBlinkCursor()));
324}
bool drawCursorInAdditionToSelection

References blinkCursor(), cursorFlash, cursorFlashLimit, cursorWidth, d, drawCursorInAdditionToSelection, and stopBlinkCursor().

◆ setDominantBaselineFromHandle()

bool SvgTextCursor::setDominantBaselineFromHandle ( const TypeSettingModeHandle handle)

setDominantBaselineFromHandle Set the dominant baseline from a given handle.

Returns
true if dominant baseline was set, false if the handle doesn't correspond to a baseline.

Definition at line 503 of file SvgTextCursor.cpp.

504{
505 if (handle == NoHandle) return false;
506 if (!d->typeSettingDecor.testBaselines(d->lastKnownModifiers)) return false;
508 if (handle == Ascender) {
510 } else if (handle == Descender) {
512 } else if (handle == BaselineAlphabetic) {
514 } else if (handle == BaselineIdeographic) {
516 } else if (handle == BaselineHanging) {
518 } else if (handle == BaselineMiddle) {
519 baseline = KoSvgText::BaselineMiddle;
520 } else if (handle == BaselineMathematical) {
522 } else if (handle == BaselineCentral) {
524 } else {
525 return false;
526 }
528 props.setProperty(KoSvgTextProperties::DominantBaselineId, QVariant::fromValue(baseline));
529 props.setProperty(KoSvgTextProperties::AlignmentBaselineId, QVariant::fromValue(baseline));
531 return true;
532}
@ DominantBaselineId
KoSvgText::Baseline.
@ AlignmentBaselineId
KoSvgText::Baseline.
Baseline
Baseline values used by dominant-baseline and baseline-align.
Definition KoSvgText.h:213
@ BaselineAlphabetic
Use 'romn' or the baseline for LCG scripts.
Definition KoSvgText.h:225
@ BaselineHanging
Definition KoSvgText.h:226
@ BaselineMiddle
Definition KoSvgText.h:232
@ BaselineTextBottom
Bottom side of the inline line-box.
Definition KoSvgText.h:234
@ BaselineIdeographic
Definition KoSvgText.h:223
@ BaselineMathematical
Definition KoSvgText.h:228
@ BaselineTextTop
Top side of the inline line-box.
Definition KoSvgText.h:235
@ BaselineCentral
Use the center between the ideographic over and under.
Definition KoSvgText.h:231

References KoSvgTextProperties::AlignmentBaselineId, Ascender, KoSvgText::BaselineAlphabetic, BaselineAlphabetic, KoSvgText::BaselineAuto, KoSvgText::BaselineCentral, BaselineCentral, KoSvgText::BaselineHanging, BaselineHanging, KoSvgText::BaselineIdeographic, BaselineIdeographic, KoSvgText::BaselineMathematical, BaselineMathematical, KoSvgText::BaselineMiddle, BaselineMiddle, KoSvgText::BaselineTextBottom, KoSvgText::BaselineTextTop, d, Descender, KoSvgTextProperties::DominantBaselineId, mergePropertiesIntoSelection(), NoHandle, and KoSvgTextProperties::setProperty().

◆ setDrawTypeSettingHandle()

void SvgTextCursor::setDrawTypeSettingHandle ( bool draw)

Whether to draw the type setting handles. Turned off when the typesetting strategy is active to give artists more control.

Definition at line 437 of file SvgTextCursor.cpp.

438{
439 d->drawTypeSettingHandle = draw;
440}

References d.

◆ setPasteRichTextByDefault()

void SvgTextCursor::setPasteRichTextByDefault ( const bool pasteRichText = true)

setPasteRichText

Parameters
pasteRichText– whether to paste rich text when possible.

Definition at line 331 of file SvgTextCursor.cpp.

332{
333 d->pasteRichText = pasteRichText;
334}

References d, and pasteRichText.

◆ setPos()

void SvgTextCursor::setPos ( int pos,
int anchor )

Set the pos and the anchor.

Definition at line 352 of file SvgTextCursor.cpp.

353{
354 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(d);
355 d->pos = pos;
356 d->anchor = anchor;
357 updateCursor();
359}

References anchor, d, pos, updateCursor(), and updateSelection().

◆ setPosToPoint()

void SvgTextCursor::setPosToPoint ( QPointF point,
bool moveAnchor = true )

Set the pos from a point. This currently does a search inside the text shape.

Definition at line 361 of file SvgTextCursor.cpp.

362{
363 if (d->shape) {
364 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(d);
365 int pos = d->shape->posForPointLineSensitive(d->shape->documentToShape(point));
366 if (d->preEditCommand) {
367 int start = d->shape->indexForPos(d->preEditStart);
368 int end = start + d->preEditLength;
369 int posIndex = d->shape->indexForPos(pos);
370 if (posIndex > start && posIndex <= end) {
371 qApp->inputMethod()->invokeAction(QInputMethod::Click, posIndex - start);
372 return;
373 } else {
375 }
376 }
377
378 const int finalPos = d->shape->posForIndex(d->shape->plainText().size());
379 d->pos = qBound(0, pos, finalPos);
380 if (moveAnchor || d->anchor < 0 || d->anchor > finalPos) {
381 d->anchor = d->pos;
382 }
383 updateCursor();
385 }
386}

References commitIMEPreEdit(), d, pos, posIndex, updateCursor(), and updateSelection().

◆ setShape()

void SvgTextCursor::setShape ( KoSvgTextShape * textShape)

setShape

Parameters
textShapeKoSvgTextShape to set, is allowed to be a nullptr, the cursor just won't do anything.

Definition at line 292 of file SvgTextCursor.cpp.

293{
294 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(d);
295 inputQueryUpdateBlocker.setChangeVisibility(true);
296
297 if (d->shape) {
299 d->shape->removeShapeChangeListener(this);
300 }
301 d->shape = textShape;
302 if (d->shape) {
303 d->shape->addShapeChangeListener(this);
305 d->pos = d->shape->posForIndex(d->shape->plainText().size());
307 } else {
308 d->pos = 0;
309 }
310 d->anchor = 0;
311 updateCursor(true);
313 d->interface->emitSelectionChange();
314}
void addShapeChangeListener(ShapeChangeListener *listener)
Definition KoShape.cpp:1157
void updateTypeSettingDecorFromShape()
Update the type setting decorations.

References KoShape::addShapeChangeListener(), commitIMEPreEdit(), d, updateCursor(), updateInputMethodItemTransform(), updateSelection(), and updateTypeSettingDecorFromShape().

◆ setTypeSettingHandleHovered()

void SvgTextCursor::setTypeSettingHandleHovered ( TypeSettingModeHandle hovered = TypeSettingModeHandle::NoHandle)

Set a given typesetting handle as hovered, so it will be drawn as such.

Definition at line 432 of file SvgTextCursor.cpp.

433{
434 d->hoveredTypeSettingHandle = hovered;
435}

References d.

◆ setTypeSettingModeActive()

void SvgTextCursor::setTypeSettingModeActive ( bool activate)

Set type setting mode active.

Definition at line 336 of file SvgTextCursor.cpp.

337{
338 d->typeSettingMode = activate;
340}

References d, and updateTypeSettingDecoration().

◆ setVisualMode()

void SvgTextCursor::setVisualMode ( const bool visualMode = true)

setVisualMode set whether the navigation mode is visual or logical. This right now primarily affects Bidirectional text.

Parameters
modewhether to turn off visual mode.

Definition at line 326 of file SvgTextCursor.cpp.

327{
328 d->visualNavigation = visualMode;
329}

References d.

◆ shape()

KoSvgTextShape * SvgTextCursor::shape ( ) const

Get the current text shape.

Returns
KoSvgTextShape *

◆ sigOpenGlyphPalette

void SvgTextCursor::sigOpenGlyphPalette ( )
signal

Called by actions, tells the parent tool to open the glyph palette.

◆ stopBlinkCursor

void SvgTextCursor::stopBlinkCursor ( )
privateslot

Called by timer, stops the text blinking animation.

Definition at line 1265 of file SvgTextCursor.cpp.

1266{
1267 d->cursorFlash.stop();
1268 d->cursorFlashLimit.stop();
1269 d->cursorVisible = true;
1270 if (d->shape) {
1271 Q_EMIT updateCursorDecoration(d->shape->shapeToDocument(d->cursorShape.boundingRect()) | d->oldCursorRect);
1272 }
1273}

References d, and updateCursorDecoration().

◆ textPropertyInterface()

KoSvgTextPropertiesInterface * SvgTextCursor::textPropertyInterface ( )

The text properties interface. This is how the text properties docker communicates with the text tool.

Definition at line 1690 of file SvgTextCursor.cpp.

1691{
1692 return d->interface;
1693}

References d.

◆ typeSettingHandleAtPos()

SvgTextCursor::TypeSettingModeHandle SvgTextCursor::typeSettingHandleAtPos ( const QRectF regionOfInterest)

Get typeSettingMode handle for text;.

Definition at line 388 of file SvgTextCursor.cpp.

389{
391
392 if (!(d->typeSettingMode && d->shape && d->canvas)) return handle;
393
394 const QRectF roiInShape = d->shape->absoluteTransformation().inverted().mapRect(regionOfInterest);
395
396 if (d->typeSettingDecor.handlesEnabled) {
397 if (roiInShape.contains(d->typeSettingDecor.handles.first)) {
399 } else if (roiInShape.contains(d->typeSettingDecor.handles.second)) {
400 handle = SvgTextCursor::EndPos;
401 }
402 }
403 if (handle != NoHandle) return handle;
404 if (!d->typeSettingDecor.boundingRect(d->handleRadius).intersects(roiInShape)) return handle;
405
406 qreal closest = std::numeric_limits<qreal>::max();
407 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath> paths
408 = d->typeSettingDecor.testBaselines(d->lastKnownModifiers)? d->typeSettingDecor.baselines: d->typeSettingDecor.paths;
409 Q_FOREACH (const SvgTextCursor::TypeSettingModeHandle baseline, paths.keys()) {
410 const QPainterPath path = paths.value(baseline);
411 if (!path.intersects(roiInShape)) continue;
412
413 const QList<QPolygonF> polys = path.toSubpathPolygons();
414 Q_FOREACH(const QPolygonF poly, polys) {
415 if (poly.size() < 2) continue;
416 for (int i = 1; i < poly.size(); i++) {
417 QLineF l(poly.at(i-1), poly.at(i));
418 qreal distance = kisDistanceToLine(roiInShape.center(), l);
419 if (distance < closest) {
420 handle = baseline;
421 closest = distance;
422 d->typeSettingDecor.closestBaselinePoint =
423 kisProjectOnVector(l.p2() - l.p1(), roiInShape.center() - l.p1()) + l.p1();
424 }
425 }
426 }
427 }
428
429 return handle;
430}
qreal distance(const QPointF &p1, const QPointF &p2)
qreal kisDistanceToLine(const QPointF &m, const QLineF &line)
Definition kis_global.h:234
QPointF kisProjectOnVector(const QPointF &base, const QPointF &v)
Definition kis_global.h:280

References d, distance(), EndPos, kisDistanceToLine(), kisProjectOnVector(), NoHandle, and StartPos.

◆ updateCanvasResources

void SvgTextCursor::updateCanvasResources ( )
privateslot

Update the canvas resources with fore and background color.

Definition at line 2119 of file SvgTextCursor.cpp.

2120{
2121 // Only update canvas resources when there's no selection.
2122 // This relies on Krita not setting anything on the text when there's no selection.
2123 if (d->shape && d->canvas->resourceManager() && d->pos == d->anchor) {
2124 KoSvgTextProperties props = hasSelection()? d->shape->propertiesForPos(qMin(d->pos, d->anchor), true): d->shape->textProperties();
2125 KoColorBackground *bg = dynamic_cast<KoColorBackground *>(props.background().data());
2126 if (bg && props.hasProperty(KoSvgTextProperties::FillId)) {
2127 KoColor c;
2128 c.fromQColor(bg->color());
2129 c.setOpacity(1.0);
2130 if (c != d->canvas->resourceManager()->foregroundColor()) {
2131 d->canvas->resourceManager()->setForegroundColor(c);
2132 }
2133 }
2134 KoShapeStroke *stroke = dynamic_cast<KoShapeStroke *>(props.stroke().data());
2135 if (stroke && stroke->isVisible() && stroke->color().isValid() && props.hasProperty(KoSvgTextProperties::StrokeId)) {
2136 KoColor c;
2137 c.fromQColor(stroke->color());
2138 c.setOpacity(1.0);
2139 if (c != d->canvas->resourceManager()->backgroundColor()) {
2140 d->canvas->resourceManager()->setBackgroundColor(c);
2141 }
2142 }
2143
2144 Q_FOREACH (QAction *action, d->actions) {
2145 // Blocking signals so that we don't get a toggle action while evaluating the checked-ness.
2146 action->blockSignals(true);
2147 const QList<KoSvgTextProperties> r = d->shape->propertiesForRange(qMin(d->pos, d->anchor), qMax(d->pos, d->anchor), true);
2148 if (action->isCheckable() && SvgTextShortCuts::possibleActions().contains(action->objectName())) {
2149 const bool checked = SvgTextShortCuts::actionEnabled(action, r);
2150 if (action->isChecked() != checked) {
2151 action->setChecked(checked);
2152 }
2153 }
2154 action->blockSignals(false);
2155 }
2156 }
2157}
QColor color() const
Returns the background color.
void setOpacity(quint8 alpha)
Definition KoColor.cpp:333
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
Definition KoColor.cpp:213
bool isVisible() const override
static bool actionEnabled(QAction *action, const QList< KoSvgTextProperties > currentProperties)
static QStringList possibleActions()

References SvgTextShortCuts::actionEnabled(), KoSvgTextProperties::background(), KoColorBackground::color(), KoShapeStroke::color, d, KoSvgTextProperties::FillId, KoColor::fromQColor(), KoSvgTextProperties::hasProperty(), hasSelection(), KoShapeStroke::isVisible(), SvgTextShortCuts::possibleActions(), KoColor::setOpacity(), KoSvgTextProperties::stroke(), and KoSvgTextProperties::StrokeId.

◆ updateCursor()

void SvgTextCursor::updateCursor ( bool firstUpdate = false)
private

update the cursor shape. First update will block ensuring the canvas is visible so setShape won't cause this.

Definition at line 1695 of file SvgTextCursor.cpp.

1696{
1697 if (d->shape) {
1698 d->oldCursorRect = d->shape->shapeToDocument(d->cursorShape.boundingRect());
1699 d->posIndex = d->shape->indexForPos(d->pos);
1700 d->anchorIndex = d->shape->indexForPos(d->anchor);
1701 emit selectionChanged();
1703 }
1704 d->cursorColor = QColor();
1705 d->cursorShape = d->shape? d->shape->cursorForPos(d->pos, d->cursorCaret, d->cursorColor): QPainterPath();
1706
1707 if (!d->blockQueryUpdates) {
1708 qApp->inputMethod()->update(Qt::ImQueryInput);
1709 }
1710 d->interface->emitCharacterSelectionChange();
1711 if (!(d->canvas->canvasWidget() && d->canvas->canvasController())) {
1712 // Mockcanvas in the tests has neither.
1713 return;
1714 }
1715 if (d->shape && !firstUpdate) {
1716 QRectF rect = d->shape->shapeToDocument(d->cursorShape.boundingRect());
1717 d->canvas->canvasController()->ensureVisibleDoc(rect, false);
1718 }
1719 if (d->canvas->canvasWidget()->hasFocus()) {
1720 d->cursorFlash.start();
1721 d->cursorFlashLimit.start();
1722 d->cursorVisible = false;
1723 blinkCursor();
1724 }
1725}
void selectionChanged()
Sents an update selection was changed.

References blinkCursor(), d, selectionChanged(), and updateTypeSettingDecoration().

◆ updateCursorDecoration

void SvgTextCursor::updateCursorDecoration ( QRectF updateRect)
signal

Sents an update to the parent tool to update it's decorations.

◆ updateIMEDecoration()

void SvgTextCursor::updateIMEDecoration ( )
private

Definition at line 1741 of file SvgTextCursor.cpp.

1742{
1743 if (d->shape) {
1744 d->oldIMEDecorationRect = d->shape->shapeToDocument(d->IMEDecoration.boundingRect());
1745 KoSvgText::TextDecorations decor;
1746 decor.setFlag(KoSvgText::DecorationUnderline, true);
1747 d->IMEDecoration = QPainterPath();
1748 if (d->preEditCommand) {
1749 Q_FOREACH(const IMEDecorationInfo info, d->styleMap) {
1750
1751 int startIndex = d->shape->indexForPos(d->preEditStart) + info.start;
1752 int endIndex = startIndex + info.length;
1753 qreal minimum = d->canvas->viewToDocument(QPointF(1, 1)).x();
1754 d->IMEDecoration.addPath(d->shape->underlines(d->shape->posForIndex(startIndex),
1755 d->shape->posForIndex(endIndex),
1756 info.decor,
1757 info.style,
1758 minimum,
1759 info.thick));
1760 d->IMEDecoration.setFillRule(Qt::WindingFill);
1761 }
1762 }
1763
1764 Q_EMIT updateCursorDecoration(d->shape->shapeToDocument(d->IMEDecoration.boundingRect()) | d->oldIMEDecorationRect);
1765 }
1766}
@ DecorationUnderline
Definition KoSvgText.h:259
bool thick
Whether the decoration needs to be doubled in size.
KoSvgText::TextDecorationStyle style
The style.
KoSvgText::TextDecorations decor
Which sides get decorated.

References d, IMEDecorationInfo::decor, KoSvgText::DecorationUnderline, IMEDecorationInfo::length, IMEDecorationInfo::start, IMEDecorationInfo::style, IMEDecorationInfo::thick, and updateCursorDecoration().

◆ updateInputMethodItemTransform

void SvgTextCursor::updateInputMethodItemTransform ( )
privateslot

Definition at line 1275 of file SvgTextCursor.cpp.

1276{
1277 // Mockcanvas in the tests has no window.
1278 if (!d->canvas->canvasWidget()) {
1279 return;
1280 }
1281 QPoint pos = d->canvas->canvasWidget()->mapTo(d->canvas->canvasWidget()->window(), QPoint());
1282 QTransform widgetToWindow = QTransform::fromTranslate(pos.x(), pos.y());
1283 QTransform inputItemTransform = widgetToWindow;
1284 QRectF inputRect = d->canvas->canvasWidget()->geometry();
1285 if (d->shape) {
1286 inputRect = d->shape->outlineRect().normalized();
1287 QTransform shapeTransform = d->shape->absoluteTransformation();
1288 QTransform docToView = d->canvas->viewConverter()->documentToView();
1289 QTransform viewToWidget = d->canvas->viewConverter()->viewToWidget();
1290 inputItemTransform = shapeTransform * docToView * viewToWidget * widgetToWindow;
1291 // Only mess with IME if we're actually the thing being typed at.
1292 if (d->hasFocus) {
1293 QInputMethod *inputMethod = QGuiApplication::inputMethod();
1294 inputMethod->setInputItemTransform(inputItemTransform);
1295 inputMethod->setInputItemRectangle(inputRect);
1296 if (!d->blockQueryUpdates) {
1297 inputMethod->update(Qt::ImQueryInput);
1298 }
1299 }
1300 }
1301}

References d, and pos.

◆ updateModifiers()

void SvgTextCursor::updateModifiers ( const Qt::KeyboardModifiers modifiers)

Definition at line 1631 of file SvgTextCursor.cpp.

1632{
1633 d->lastKnownModifiers = modifiers;
1635}

References d, and updateTypeSettingDecoration().

◆ updateSelection()

void SvgTextCursor::updateSelection ( )
private

Definition at line 1727 of file SvgTextCursor.cpp.

1728{
1729 if (d->shape) {
1730 d->oldSelectionRect = d->shape->shapeToDocument(d->selection.boundingRect());
1731 d->shape->cursorForPos(d->anchor, d->anchorCaret, d->cursorColor);
1732 d->selection = d->shape->selectionBoxes(d->pos, d->anchor);
1733 Q_EMIT updateCursorDecoration(d->shape->shapeToDocument(d->selection.boundingRect()) | d->oldSelectionRect);
1734
1735 if (!d->blockQueryUpdates) {
1736 QGuiApplication::inputMethod()->update(Qt::ImQueryInput);
1737 }
1738 }
1739}

References d, and updateCursorDecoration().

◆ updateTypeSettingDecoration()

void SvgTextCursor::updateTypeSettingDecoration ( )
private

This adds the start and end decoration...

This could be better but requires better nodeindex retrieval...

Split up baselines into paths and baselines.

Definition at line 1831 of file SvgTextCursor.cpp.

1832{
1833 QRectF updateRect;
1834 if (d->shape && d->typeSettingMode) {
1835
1837 d->shape->getPositionsAndRotationsForRange(d->pos, d->anchor);
1838 if (infos.size() < 1) return;
1839
1840 const bool rtl = infos.first().rtl;
1841
1842 KoSvgTextCharacterInfo first = infos.first();
1843 KoSvgTextCharacterInfo last = infos.last();
1844 if (infos.size() > 1) {
1845 std::sort(infos.begin(), infos.end(), KoSvgTextCharacterInfo::visualLessThan);
1846 for (auto it = infos.begin(); it != infos.end(); it++) {
1847 if (it->visualIndex >= 0) {
1848 first = *it;
1849 break;
1850 }
1851 }
1852 for (auto it = infos.rbegin(); it != infos.rend(); it++) {
1853 if (it->visualIndex >= 0) {
1854 last = *it;
1855 break;
1856 }
1857 }
1858 }
1859
1860 QTransform t = QTransform::fromTranslate(last.finalPos.x(), last.finalPos.y());
1861 t.rotate(last.rotateDeg);
1862 last.finalPos = t.map(last.advance);
1863
1864 d->typeSettingDecor.handles.first = rtl? last.finalPos: first.finalPos;
1865 d->typeSettingDecor.handles.second = rtl? first.finalPos: last.finalPos;
1866
1867 //Start collecting the metrics decoration...
1868 d->typeSettingDecor.paths = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1869 d->typeSettingDecor.baselines = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1870 d->typeSettingDecor.edges = QPainterPath();
1871 d->typeSettingDecor.parentPaths = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1872 d->typeSettingDecor.parentBaselines = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1873 QList<KoSvgTextCharacterInfo> metricInfos = infos;
1874 if (d->pos == d->anchor) {
1875 metricInfos = d->shape->getPositionsAndRotationsForRange(0, d->shape->posForIndex(d->shape->plainText().size()));
1876 }
1877 const bool isHorizontal = d->shape->writingMode() == KoSvgText::HorizontalTB;
1878 const int minPos = qMin(d->pos, d->anchor);
1879 const int maxPos = qMax(d->pos, d->anchor);
1880 const int endPos = d->shape->posForIndex(d->shape->plainText().size());
1881
1883 if (minPos > 0 || maxPos < endPos) {
1884 const KoSvgTextProperties props = d->shape->textProperties();
1886 KoSvgText::FontMetrics metrics = props.metrics(true, true);
1887 const qreal scaleMetrics = props.fontSize().value/qreal(metrics.fontSize);
1888 const int lineGap = calcLineHeight(lineHeight, metrics, scaleMetrics);
1889
1890 const QMap<SvgTextCursor::TypeSettingModeHandle, int> types
1891 = typeSettingBaselinesFromMetrics(metrics, lineGap, isHorizontal);
1892
1894 QList<int> positions;
1895 positions << 0;
1896 positions << qMax(0, minPos-1);
1897 positions << maxPos;
1898 positions << endPos;
1899
1900 Q_FOREACH(const int pos, positions) {
1902 d->shape->getPositionsAndRotationsForRange(pos, pos);
1903 parentInfos.append(info.first());
1904 }
1905
1906 QPointF drawOffset = isHorizontal? QPointF(d->handleRadius*2, 0): QPointF(0, d->handleRadius*2);
1907 if (d->canvas) {
1908 drawOffset = d->canvas->viewConverter()->viewToDocument().map(drawOffset);
1909 }
1910 bool toggleOffset = rtl;
1911
1912 for (auto it = parentInfos.begin(); it != parentInfos.end(); it++) {
1913 const bool currentIsMin = (d->shape->posForIndex(it->logicalIndex) == minPos);
1914 const QPointF finalPos = toggleOffset? it->finalPos + (it->advance - drawOffset): it->finalPos;
1915 const QPointF advance = drawOffset;
1916
1917 const QTransform t = posAndRotateTransform(finalPos, it->rotateDeg);
1918
1919 Q_FOREACH(SvgTextCursor::TypeSettingModeHandle handle, types.keys()) {
1920 const int metric = types.value(handle);
1921 processBaseline(handle, metric, isHorizontal, t, scaleMetrics, advance, d->typeSettingDecor.parentBaselines);
1922 }
1923
1924 {
1925
1926 if (currentIsMin && minPos == maxPos && !toggleOffset) {
1927 toggleOffset = !toggleOffset;
1928 continue;
1929 }
1930 const QPointF advance = toggleOffset? it->advance: QPointF();
1931 const QTransform t = posAndRotateTransform(it->finalPos, it->rotateDeg);
1932 processEdges(t, types, isHorizontal, scaleMetrics, advance, d->typeSettingDecor.edges);
1933 }
1934
1935 toggleOffset = !toggleOffset;
1936 }
1937 }
1938
1940 bool toggleOffset = false; // MetricInfos are visually-ordered.
1941 for (auto it = metricInfos.begin(); it != metricInfos.end(); it++) {
1942 const int currentPos = (d->pos == d->anchor)? -1 :d->shape->posForIndex(it->logicalIndex);
1943
1944 KoSvgTextProperties props = d->shape->propertiesForPos(currentPos, true);
1946 KoSvgText::FontMetrics propMetrics = props.metrics(true, true);
1947
1948 KoSvgText::FontMetrics metrics = (d->pos == d->anchor)? propMetrics :it->metrics;
1949
1950 const qreal scaleMetrics = props.fontSize().value/qreal(metrics.fontSize);
1951 const int lineGap = calcLineHeight(lineHeight, metrics, scaleMetrics);
1952
1953 const QTransform t = posAndRotateTransform(it->finalPos, it->rotateDeg);
1954
1955 const QMap<SvgTextCursor::TypeSettingModeHandle, int> types
1956 = typeSettingBaselinesFromMetrics(metrics, lineGap, isHorizontal);
1957
1958 Q_FOREACH(SvgTextCursor::TypeSettingModeHandle handle, types.keys()) {
1959 const int metric = types.value(handle);
1960 processBaseline(handle, metric, isHorizontal, t, scaleMetrics, it->advance, d->typeSettingDecor.baselines);
1961 }
1962 if ((currentPos == minPos || currentPos+1 == maxPos) && minPos != maxPos) {
1963 const QPointF advance = toggleOffset? it->advance: QPointF();
1964 toggleOffset = !toggleOffset;
1965 processEdges(t, types, isHorizontal, scaleMetrics, advance, d->typeSettingDecor.edges);
1966 }
1967 }
1968
1970 const QList<SvgTextCursor::TypeSettingModeHandle> nonBaselines = {
1972 };
1973 Q_FOREACH(SvgTextCursor::TypeSettingModeHandle handle, nonBaselines) {
1974 d->typeSettingDecor.paths.insert(handle, d->typeSettingDecor.baselines.value(handle));
1975 d->typeSettingDecor.parentPaths.insert(handle, d->typeSettingDecor.parentBaselines.value(handle));
1976 }
1977 d->typeSettingDecor.baselines.remove(LineHeightTop);
1978 d->typeSettingDecor.baselines.remove(LineHeightBottom);
1979 d->typeSettingDecor.parentBaselines.remove(LineHeightTop);
1980 d->typeSettingDecor.parentBaselines.remove(LineHeightBottom);
1981
1982 updateRect = d->shape->shapeToDocument(d->typeSettingDecor.boundingRect(d->handleRadius));
1983 }
1984 updateTypeSettingDecorFromShape(); // To remove the text-in-path nodes..
1985 Q_EMIT updateCursorDecoration(updateRect | d->oldTypeSettingRect);
1986 d->oldTypeSettingRect = updateRect;
1987}
QTransform posAndRotateTransform(const QPointF pos, const qreal rotateDeg)
int calcLineHeight(const KoSvgText::LineHeightInfo &lineHeight, const KoSvgText::FontMetrics &metrics, const qreal scaleMetrics)
void processBaseline(const SvgTextCursor::TypeSettingModeHandle handle, const int metric, const bool isHorizontal, QTransform t, const qreal scaleMetrics, const QPointF &advance, QMap< SvgTextCursor::TypeSettingModeHandle, QPainterPath > &decor)
void processEdges(QTransform t, QMap< SvgTextCursor::TypeSettingModeHandle, int > values, const bool isHorizontal, const qreal scaleMetrics, const QPointF advance, QPainterPath &path)
The KoSvgTextCharacterInfo class This is a small struct to convey information about character positio...
static bool visualLessThan(const KoSvgTextCharacterInfo &a, const KoSvgTextCharacterInfo &b)
qint32 fontSize
Currently set size, CSS unit 'em'.
Definition KoSvgText.h:329

References KoSvgTextCharacterInfo::advance, Ascender, BaselineShift, calcLineHeight(), d, Descender, KoSvgTextCharacterInfo::finalPos, KoSvgText::FontMetrics::fontSize, KoSvgTextProperties::fontSize(), KoSvgText::HorizontalTB, LineHeightBottom, KoSvgTextProperties::LineHeightId, LineHeightTop, KoSvgTextProperties::metrics(), pos, posAndRotateTransform(), processBaseline(), processEdges(), KoSvgTextProperties::propertyOrDefault(), KoSvgTextCharacterInfo::rotateDeg, typeSettingBaselinesFromMetrics(), updateCursorDecoration(), updateTypeSettingDecorFromShape(), KoSvgText::CssLengthPercentage::value, and KoSvgTextCharacterInfo::visualLessThan().

◆ updateTypeSettingDecorFromShape()

void SvgTextCursor::updateTypeSettingDecorFromShape ( )

Update the type setting decorations.

Definition at line 442 of file SvgTextCursor.cpp.

443{
444 if (d->shape) {
445 d->typeSettingDecor.handlesEnabled = ((d->shape->textType() == KoSvgTextShape::PreformattedText
446 || d->shape->textType() == KoSvgTextShape::PrePositionedText)
447 && !(d->shape->topLevelNodeForPos(d->pos).textPath()));
448 }
449}
@ PreformattedText
Text-on-Path falls under this or PrePositionedText depending on collapse of lines.

References d, KoSvgTextShape::PreformattedText, and KoSvgTextShape::PrePositionedText.

Member Data Documentation

◆ actions

QList<QAction*> SvgTextCursor::actions

Definition at line 242 of file SvgTextCursor.cpp.

◆ anchor

int SvgTextCursor::anchor = 0

Definition at line 197 of file SvgTextCursor.cpp.

◆ anchorCaret

QLineF SvgTextCursor::anchorCaret

Definition at line 209 of file SvgTextCursor.cpp.

◆ anchorIndex

int SvgTextCursor::anchorIndex = 0

Definition at line 218 of file SvgTextCursor.cpp.

◆ blockQueryUpdates

bool SvgTextCursor::blockQueryUpdates = false

Block qApp->inputMethod->update(), enabled during the inputmethod event flow.

Definition at line 238 of file SvgTextCursor.cpp.

◆ canvas

KoCanvasBase* SvgTextCursor::canvas

Definition at line 194 of file SvgTextCursor.cpp.

◆ cursorCaret

QLineF SvgTextCursor::cursorCaret

Definition at line 208 of file SvgTextCursor.cpp.

◆ cursorColor

QColor SvgTextCursor::cursorColor

Definition at line 206 of file SvgTextCursor.cpp.

◆ cursorFlash

QTimer SvgTextCursor::cursorFlash

Definition at line 200 of file SvgTextCursor.cpp.

◆ cursorFlashLimit

QTimer SvgTextCursor::cursorFlashLimit

Definition at line 201 of file SvgTextCursor.cpp.

◆ cursorShape

QPainterPath SvgTextCursor::cursorShape

Definition at line 205 of file SvgTextCursor.cpp.

◆ cursorVisible

bool SvgTextCursor::cursorVisible = false

Definition at line 202 of file SvgTextCursor.cpp.

◆ cursorWidth

int SvgTextCursor::cursorWidth = 1

Definition at line 210 of file SvgTextCursor.cpp.

◆ d

const QScopedPointer<Private> SvgTextCursor::d
private

Definition at line 388 of file SvgTextCursor.h.

◆ drawCursorInAdditionToSelection

bool SvgTextCursor::drawCursorInAdditionToSelection = false

Definition at line 211 of file SvgTextCursor.cpp.

◆ drawTypeSettingHandle

bool SvgTextCursor::drawTypeSettingHandle = true

Definition at line 227 of file SvgTextCursor.cpp.

◆ handleRadius

qreal SvgTextCursor::handleRadius = 7

Definition at line 228 of file SvgTextCursor.cpp.

◆ hasFocus

bool SvgTextCursor::hasFocus = false

Definition at line 203 of file SvgTextCursor.cpp.

◆ hoveredTypeSettingHandle

SvgTextCursor::TypeSettingModeHandle SvgTextCursor::hoveredTypeSettingHandle = SvgTextCursor::NoHandle

Definition at line 226 of file SvgTextCursor.cpp.

◆ IMEDecoration

QPainterPath SvgTextCursor::IMEDecoration

The decorations for the current preedit string.

Definition at line 236 of file SvgTextCursor.cpp.

◆ interface

SvgTextCursorPropertyInterface* SvgTextCursor::interface {nullptr}

Definition at line 240 of file SvgTextCursor.cpp.

240{nullptr};

◆ isAddingCommand

bool SvgTextCursor::isAddingCommand = false

Definition at line 195 of file SvgTextCursor.cpp.

◆ lastKnownModifiers

Qt::KeyboardModifiers SvgTextCursor::lastKnownModifiers

Definition at line 223 of file SvgTextCursor.cpp.

◆ oldCursorRect

QRectF SvgTextCursor::oldCursorRect

Definition at line 207 of file SvgTextCursor.cpp.

◆ oldIMEDecorationRect

QRectF SvgTextCursor::oldIMEDecorationRect

Update Rectangle of previous decoration.

Definition at line 237 of file SvgTextCursor.cpp.

◆ oldSelectionRect

QRectF SvgTextCursor::oldSelectionRect

Definition at line 213 of file SvgTextCursor.cpp.

◆ oldTypeSettingRect

QRectF SvgTextCursor::oldTypeSettingRect

Definition at line 229 of file SvgTextCursor.cpp.

◆ pasteRichText

bool SvgTextCursor::pasteRichText = true

Definition at line 221 of file SvgTextCursor.cpp.

◆ pos

int SvgTextCursor::pos = 0

Definition at line 196 of file SvgTextCursor.cpp.

◆ posIndex

int SvgTextCursor::posIndex = 0

Definition at line 217 of file SvgTextCursor.cpp.

◆ preEditCommand

SvgTextInsertCommand* SvgTextCursor::preEditCommand {nullptr}

PreEdit string as an command provided by the input method.

Definition at line 232 of file SvgTextCursor.cpp.

232{nullptr};

◆ preEditLength

int SvgTextCursor::preEditLength = -1

Length of the preEditString.

Definition at line 234 of file SvgTextCursor.cpp.

◆ preEditStart

int SvgTextCursor::preEditStart = -1

Start of the preEdit string as a cursor pos.

Definition at line 233 of file SvgTextCursor.cpp.

◆ resourceManagerAcyclicConnector

KisAcyclicSignalConnector SvgTextCursor::resourceManagerAcyclicConnector

Definition at line 244 of file SvgTextCursor.cpp.

◆ selection

QPainterPath SvgTextCursor::selection

Definition at line 212 of file SvgTextCursor.cpp.

◆ shape

KoSvgTextShape * SvgTextCursor::shape {nullptr}

Definition at line 198 of file SvgTextCursor.cpp.

198{nullptr};

◆ styleMap

QVector<IMEDecorationInfo> SvgTextCursor::styleMap

Decoration info (underlines) for the preEdit string to differentiate it from regular text.

Definition at line 235 of file SvgTextCursor.cpp.

◆ typeSettingDecor

TypeSettingDecorInfo SvgTextCursor::typeSettingDecor

Definition at line 230 of file SvgTextCursor.cpp.

◆ typeSettingMode

bool SvgTextCursor::typeSettingMode = false

Definition at line 225 of file SvgTextCursor.cpp.

◆ visualNavigation

bool SvgTextCursor::visualNavigation = true

Definition at line 220 of file SvgTextCursor.cpp.


The documentation for this class was generated from the following files: