37#include <QApplication>
39#include <QKeySequence>
42#include <QInputMethodEvent>
47#include <config-qt-patches-present.h>
61 if (s == QTextCharFormat::DotLine) {
63 }
else if (s == QTextCharFormat::DashUnderline) {
65 }
else if (s == QTextCharFormat::WaveUnderline) {
67 }
else if (s == QTextCharFormat::SpellCheckUnderline) {
78 if (format.hasProperty(QTextFormat::FontUnderline)) {
81 if (format.hasProperty(QTextFormat::FontOverline)) {
84 if (format.hasProperty(QTextFormat::FontStrikeOut)) {
88 if (format.hasProperty(QTextFormat::TextUnderlineStyle)) {
97 if (format.hasProperty(QTextFormat::BackgroundBrush)) {
98 thick = format.background().isOpaque();
117 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>
baselines;
118 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>
paths;
121 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>
parentPaths;
128 for (
int i = 0; i<
paths.values().size(); i++) {
129 total |=
paths.values().at(i).boundingRect();
131 for (
int i = 0; i<
baselines.values().size(); i++) {
132 total |=
baselines.values().at(i).boundingRect();
134 for (
int i = 0; i<
parentPaths.values().size(); i++) {
135 total |=
parentPaths.values().at(i).boundingRect();
140 total |=
edges.boundingRect();
141 QRectF
rect(0, 0, handleRadius, handleRadius);
150 return (modifiers & Qt::ShiftModifier);
162 , m_unblockQueryUpdates(!
std::exchange(d->blockQueryUpdates, true))
174 QInputMethod *inputMethod = QGuiApplication::inputMethod();
176 if (m_unblockQueryUpdates) {
177 m_d->blockQueryUpdates =
false;
178 inputMethod->update(Qt::ImQueryInput);
181 if (m_changeVisibility) {
182 inputMethod->setVisible(m_d->shape !=
nullptr);
189 m_changeVisibility = changeVisibility;
195 bool m_changeVisibility =
false;
199 bool isAddingCommand =
false;
206 bool cursorVisible =
false;
207 bool hasFocus =
false;
215 bool drawCursorInAdditionToSelection =
false;
224 bool visualNavigation =
true;
225 bool pasteRichText =
true;
229 bool typeSettingMode =
false;
231 bool drawTypeSettingHandle =
true;
232 qreal handleRadius = 7;
237 int preEditStart = -1;
238 int preEditLength = -1;
242 bool blockQueryUpdates =
false;
256 if (
d->canvas->canvasController()) {
259 connect(
d->canvas->canvasController()->proxyObject,
260 SIGNAL(moveDocumentOffset(QPointF, QPointF)),
263 connect(
d->canvas->canvasController()->proxyObject,
264 SIGNAL(effectiveZoomChanged(qreal)),
267 connect(
d->canvas->canvasController()->proxyObject,
268 SIGNAL(documentRotationChanged(qreal)),
271 connect(
d->canvas->canvasController()->proxyObject,
272 SIGNAL(documentMirrorStatusChanged(
bool,
bool)),
275 d->resourceManagerAcyclicConnector.connectBackwardResourcePair(
278 d->resourceManagerAcyclicConnector.connectForwardVoid(
d->interface, SIGNAL(textCharacterSelectionChanged()),
this, SLOT(
updateCanvasResources()));
286 d->cursorFlash.stop();
287 d->cursorFlashLimit.stop();
298 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
299 inputQueryUpdateBlocker.setChangeVisibility(
true);
303 d->shape->removeShapeChangeListener(
this);
305 d->shape = textShape;
309 d->pos =
d->shape->posForIndex(
d->shape->plainText().size());
317 d->interface->emitSelectionChange();
326 connect(&
d->cursorFlash, SIGNAL(timeout()),
this, SLOT(
blinkCursor()));
327 connect(&
d->cursorFlashLimit, SIGNAL(timeout()),
this, SLOT(
stopBlinkCursor()));
332 d->visualNavigation = visualMode;
342 d->typeSettingMode = activate;
358 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
368 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
369 int pos =
d->shape->posForPointLineSensitive(
d->shape->documentToShape(point));
370 if (
d->preEditCommand) {
371 int start =
d->shape->indexForPos(
d->preEditStart);
372 int end = start +
d->preEditLength;
375 qApp->inputMethod()->invokeAction(QInputMethod::Click,
posIndex - start);
382 const int finalPos =
d->shape->posForIndex(
d->shape->plainText().size());
383 d->pos = qBound(0,
pos, finalPos);
384 if (moveAnchor ||
d->anchor < 0 ||
d->anchor > finalPos) {
396 if (!(
d->typeSettingMode &&
d->shape &&
d->canvas))
return handle;
398 const QRectF roiInShape =
d->shape->absoluteTransformation().inverted().mapRect(regionOfInterest);
400 if (
d->typeSettingDecor.handlesEnabled) {
401 if (roiInShape.contains(
d->typeSettingDecor.handles.first)) {
403 }
else if (roiInShape.contains(
d->typeSettingDecor.handles.second)) {
407 if (handle !=
NoHandle)
return handle;
408 if (!
d->typeSettingDecor.boundingRect(
d->handleRadius).intersects(roiInShape))
return handle;
410 qreal closest = std::numeric_limits<qreal>::max();
411 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath> paths
412 =
d->typeSettingDecor.testBaselines(
d->lastKnownModifiers)?
d->typeSettingDecor.baselines:
d->typeSettingDecor.paths;
414 const QPainterPath path = paths.value(baseline);
415 if (!path.intersects(roiInShape))
continue;
418 Q_FOREACH(
const QPolygonF poly, polys) {
419 if (poly.size() < 2)
continue;
420 for (
int i = 1; i < poly.size(); i++) {
421 QLineF l(poly.at(i-1), poly.at(i));
426 d->typeSettingDecor.closestBaselinePoint =
438 d->hoveredTypeSettingHandle = hovered;
443 d->drawTypeSettingHandle = draw;
451 && !(
d->shape->topLevelNodeForPos(
d->pos).textPath()));
457 if (
d->hoveredTypeSettingHandle ==
StartPos ||
458 d->hoveredTypeSettingHandle ==
StartPos ||
459 d->typeSettingDecor.testBaselines(
d->lastKnownModifiers)) {
460 return Qt::ArrowCursor;
461 }
else if (
d->shape) {
464 return Qt::ArrowCursor;
469 bool baseline =
d->typeSettingDecor.testBaselines(
d->lastKnownModifiers);
472 return i18nc(
"Type setting mode line name",
"Text Top");
474 return i18nc(
"Type setting mode line name",
"Font Size");
478 return i18nc(
"Type setting mode line name",
"Text Bottom");
480 return i18nc(
"Type setting mode line name",
"Font Size");
483 return i18nc(
"Type setting mode line name",
"Alphabetic");
485 return i18nc(
"Type setting mode line name",
"Ideographic");
487 return i18nc(
"Type setting mode line name",
"Hanging");
489 return i18nc(
"Type setting mode line name",
"Middle");
491 return i18nc(
"Type setting mode line name",
"Mathematical");
493 return i18nc(
"Type setting mode line name",
"Central");
495 return i18nc(
"Type setting mode line name",
"Line Height");
498 return i18nc(
"Type setting mode line name",
"Current Baseline");
500 return i18nc(
"Type setting mode line name",
"Baseline Shift");
509 if (handle ==
NoHandle)
return false;
510 if (!
d->typeSettingDecor.testBaselines(
d->lastKnownModifiers))
return false;
539 return QMap<SvgTextCursor::TypeSettingModeHandle, int> {
556 if (!
d->shape)
return 0;
559 d->shape->getPositionsAndRotationsForRange(
d->pos,
d->anchor);
560 if (infos.size() < 1)
return 0;
562 const QRectF roi =
d->shape->documentToShape(regionOfInterest);
564 for (
auto it = infos.begin(); it != infos.end(); it++) {
565 const int currentPos = (
d->pos ==
d->anchor)? -1 :
d->shape->posForIndex(it->logicalIndex);
572 const qreal scaleMetrics = props.
fontSize().
value/qreal(metrics.fontSize);
573 const int lineGap = lineHeight.
isNormal? metrics.lineGap: (lineHeight.
length.
value/scaleMetrics)-(metrics.ascender-metrics.descender);
575 QTransform t = QTransform::fromTranslate(it->finalPos.x(), it->finalPos.y());
576 t.rotate(it->rotateDeg);
578 const QMap<SvgTextCursor::TypeSettingModeHandle, int> types
581 const int metric = types.value(handle);
582 QPointF offset = isHorizontal? QPointF(0, -(metric*scaleMetrics)): QPointF(metric*scaleMetrics, 0);
583 QLineF line = t.map(QLineF(offset, offset+it->advance));
596 const int finalPos =
d->shape->posForIndex(
d->shape->plainText().size());
649 int posStart = qMin(posA, posB);
650 int posEnd = qMax(posA, posB);
651 int indexEnd =
d->shape->indexForPos(posEnd);
652 int length = indexEnd -
d->shape->indexForPos(posStart);
668 int lastIndex =
d->shape->indexForPos(
d->pos);
678 return QPair<KoSvgTextProperties, KoSvgTextProperties>(
d->shape->propertiesForPos(
d->pos),
d->shape->propertiesForPos(
d->pos,
true));
680 return QPair<KoSvgTextProperties, KoSvgTextProperties>();
688 start = qMin(
d->pos,
d->anchor);
689 end = qMax(
d->pos,
d->anchor);
690 return d->shape->propertiesForRange(start, end);
696 return {
d->shape->propertiesForRange(-1, -1)};
704 if (!paragraphOnly) {
708 if (selectWord &&
d->pos ==
d->anchor) {
709 const int finalPos =
d->shape->posForIndex(
d->shape->plainText().size());
728 if (
d->anchor !=
d->pos) {
729 int end =
d->shape->indexForPos(qMax(
d->anchor,
d->pos));
730 int length =
d->shape->indexForPos(qMax(
d->anchor,
d->pos)) -
d->shape->indexForPos(qMin(
d->anchor,
d->pos));
740 int start =
d->shape->indexForPos(qMin(
d->anchor,
d->pos));
741 int length =
d->shape->indexForPos(qMax(
d->anchor,
d->pos)) - start;
742 QString copied =
d->shape->plainText().mid(start,
length);
743 std::unique_ptr<KoSvgTextShape> copy =
d->shape->copyRange(start,
length);
744 QClipboard *cb = QApplication::clipboard();
751 QMimeData *svgData =
new QMimeData();
753 QString svgDoc = QString(
"<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"2.0\">%1\n%2</svg>").arg(styles).arg(svg);
754 svgData->setData(QLatin1String(
"image/svg+xml"), svgDoc.toUtf8());
756 svgData->setText(copied);
758 svgData->setHtml(html);
759 cb->setMimeData(svgData);
775 bool success =
false;
777 QClipboard *cb = QApplication::clipboard();
778 const QMimeData *mimeData = cb->mimeData();
782 while (shapes.size() > 0) {
789 }
else if (mimeData->hasHtml()) {
790 QString html = mimeData->html();
795 if (converter.convertFromHtml(html, &svg, &styles)
796 && converter.convertFromSvg(svg, styles,
d->shape->boundingRect(), 72.0) ) {
811 bool success =
false;
812 QClipboard *cb = QApplication::clipboard();
813 const QMimeData *mimeData = cb->mimeData();
814 if (mimeData->hasText()) {
843 gc.setTransform(
d->shape->absoluteTransformation(),
true);
845 if (
d->pos !=
d->anchor && !
d->typeSettingMode) {
848 QBrush brush(selectionColor);
849 gc.fillPath(
d->selection, brush);
853 if ( (
d->drawCursorInAdditionToSelection ||
d->pos ==
d->anchor)
854 &&
d->cursorVisible) {
856 pen.setCosmetic(
true);
857 QColor c =
d->cursorColor.isValid()?
d->cursorColor: Qt::black;
859 pen.setWidth((
d->cursorWidth + 2) * decorationThickness);
861 gc.drawPath(
d->cursorShape);
863 pen.setWidth(
d->cursorWidth * decorationThickness);
865 gc.drawPath(
d->cursorShape);
869 if (
d->preEditCommand) {
871 QBrush brush(selectionColor);
873 gc.fillPath(
d->IMEDecoration, brush);
876 if (
d->typeSettingMode &&
d->drawTypeSettingHandle) {
878 QTransform painterTf = gc.transform();
883 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath> paths
884 =
d->typeSettingDecor.testBaselines(
d->lastKnownModifiers)?
d->typeSettingDecor.baselines:
d->typeSettingDecor.paths;
885 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath> parentPaths
886 =
d->typeSettingDecor.testBaselines(
d->lastKnownModifiers)?
d->typeSettingDecor.parentBaselines:
d->typeSettingDecor.parentPaths;
888 const QPainterPath
p = paths.value(handle);
889 const QPainterPath parent = parentPaths.value(handle);
890 if (
d->hoveredTypeSettingHandle == handle) {
896 QPen pen(selectionColor, decorationThickness, handle ==
BaselineShift? Qt::SolidLine: Qt::DashLine);
897 pen.setCosmetic(
true);
900 gc.drawPath(painterTf.map(parent));
901 gc.drawPath(painterTf.map(
p));
905 QPen pen(selectionColor, decorationThickness, Qt::SolidLine);
906 pen.setCosmetic(
true);
909 gc.drawPath(painterTf.map(
d->typeSettingDecor.edges));
913 if (
d->typeSettingDecor.handlesEnabled) {
919 QString name =
handleName(
d->hoveredTypeSettingHandle);
920 if (!name.isEmpty()) {
923 QFont font = gc.font();
924 font.setHintingPreference(QFont::PreferFullHinting);
925 textP.addText(painterTf.map(
d->typeSettingDecor.closestBaselinePoint).toPoint(), font, name);
928 pen.setCosmetic(
true);
929 pen.setWidth(decorationThickness);
932 gc.fillPath(textP, QBrush(selectionColor));
943 dbgTools <<
"receiving inputmethod query" << query;
949 return d->shape?
true:
false;
951 case Qt::ImCursorRectangle:
954 QPointF caret1(
d->cursorCaret.p1());
955 QPointF caret2(
d->cursorCaret.p2());
958 QRectF
rect = QRectF(caret1, caret2).normalized();
959 if (!
rect.isValid()) {
960 if (
rect.height() < 1) {
961 rect.adjust(0, -1, 0, 0);
963 if (
rect.width() < 1) {
964 rect.adjust(0, 0, 1, 0);
968 return rect.toAlignedRect();
971 case Qt::ImAnchorRectangle:
974 QPointF caret1(
d->anchorCaret.p1());
975 QPointF caret2(
d->anchorCaret.p2());
976 QRectF
rect = QRectF(caret1, caret2).normalized();
977 if (
rect.isEmpty()) {
978 if (
rect.height() < 1) {
979 rect.adjust(0, -1, 0, 0);
981 if (
rect.width() < 1) {
982 rect =
rect.adjusted(-1, 0, 0, 0).normalized();
985 return rect.toAlignedRect();
989 case Qt::ImAbsolutePosition:
990 case Qt::ImCursorPosition:
992 return d->shape->indexForPos(
d->pos);
995 case Qt::ImSurroundingText:
997 QString surroundingText =
d->shape->plainText();
998 int preEditIndex =
d->preEditCommand?
d->shape->indexForPos(
d->preEditStart): 0;
999 surroundingText.remove(preEditIndex,
d->preEditLength);
1000 return surroundingText;
1003 case Qt::ImCurrentSelection:
1005 QString surroundingText =
d->shape->plainText();
1006 int preEditIndex =
d->preEditCommand?
d->shape->indexForPos(
d->preEditStart): 0;
1007 surroundingText.remove(preEditIndex,
d->preEditLength);
1008 int start =
d->shape->indexForPos(qMin(
d->anchor,
d->pos));
1009 int length =
d->shape->indexForPos(qMax(
d->anchor,
d->pos)) - start;
1010 return surroundingText.mid(start,
length);
1013 case Qt::ImTextBeforeCursor:
1015 int start =
d->shape->indexForPos(
d->pos);
1016 QString surroundingText =
d->shape->plainText();
1017 int preEditIndex =
d->preEditCommand?
d->shape->indexForPos(
d->preEditStart): 0;
1018 surroundingText.remove(preEditIndex,
d->preEditLength);
1019 return surroundingText.left(start);
1022 case Qt::ImTextAfterCursor:
1024 int start =
d->shape->indexForPos(
d->pos);
1025 QString surroundingText =
d->shape->plainText();
1026 int preEditIndex =
d->preEditCommand?
d->shape->indexForPos(
d->preEditStart): 0;
1027 surroundingText.remove(preEditIndex,
d->preEditLength);
1028 return surroundingText.right(start);
1031 case Qt::ImMaximumTextLength:
1034 case Qt::ImAnchorPosition:
1036 return d->shape->indexForPos(
d->anchor);
1042 return Qt::ImhMultiLine;
1045#if defined(Q_OS_ANDROID) && KRITA_QT_HAS_ANDROID_INPUT_PLATFORM_DATA_SOFT_INPUT_ADJUST_NOTHING
1046 case Qt::ImPlatformData:
1055 return Qt::ANDROID_INPUT_PLATFORM_DATA_SOFT_INPUT_ADJUST_NOTHING;
1057 case Qt::ImEnterKeyType:
1059 return Qt::EnterKeyDefault;
1071 dbgTools <<
"Commit:"<<
event->commitString() <<
"predit:"<<
event->preeditString();
1072 dbgTools <<
"Replacement:"<<
event->replacementStart() <<
event->replacementLength();
1074 QRectF updateRect =
d->shape?
d->shape->boundingRect(): QRectF();
1075 SvgTextShapeManagerBlocker blocker(
d->canvas->shapeManager());
1077 bool isGettingInput = !
event->commitString().isEmpty() || !
event->preeditString().isEmpty()
1078 ||
event->replacementLength() > 0;
1081 if (
d->preEditCommand) {
1082 d->preEditCommand->undo();
1083 d->preEditCommand = 0;
1084 d->preEditStart = -1;
1085 d->preEditLength = -1;
1086 updateRect |=
d->shape?
d->shape->boundingRect(): QRectF();
1089 if (!
d->shape || !isGettingInput) {
1091 d->canvas->shapeManager()->update(updateRect);
1096 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
1102 int originalPos =
d->pos;
1103 int index =
d->shape->indexForPos(
d->pos) +
event->replacementStart();
1104 d->pos =
d->shape->posForIndex(index);
1105 if (event->replacementLength() > 0) {
1107 index + event->replacementLength(),
1110 event->replacementLength(),
1116 if (!event->commitString().isEmpty()) {
1121 Q_FOREACH(
const QInputMethodEvent::Attribute attribute, event->attributes()) {
1122 if (attribute.type == QInputMethodEvent::Selection) {
1123 d->pos =
d->shape->posForIndex(attribute.start);
1124 int index =
d->shape->indexForPos(
d->pos);
1125 d->anchor =
d->shape->posForIndex(index + attribute.length);
1131 if (!event->preeditString().isEmpty()) {
1132 int index =
d->shape->indexForPos(
d->pos);
1134 d->preEditCommand->redo();
1135 d->preEditLength =
event->preeditString().size();
1136 d->preEditStart =
d->shape->posForIndex(index,
true);
1138 d->preEditCommand = 0;
1143 Q_FOREACH(
const QInputMethodEvent::Attribute attribute, event->attributes()) {
1144 dbgTools <<
"attribute: "<< attribute.type <<
"start: " << attribute.start
1145 <<
"length: " << attribute.length <<
"val: " << attribute.value;
1151 if (attribute.type == QInputMethodEvent::TextFormat) {
1152 QVariant val = attribute.value;
1153 QTextCharFormat form = val.value<QTextFormat>().toCharFormat();
1155 if (attribute.length == 0 || attribute.start < 0 || !attribute.value.isValid()) {
1162 for (
int i = 0; i <
styleMap.size(); i++) {
1163 if (attribute.start >=
styleMap.at(i).start
1167 if (attribute.start + attribute.length >
styleMap.at(i).start
1168 && attribute.start + attribute.length <=
styleMap.at(i).start +
styleMap.at(i).length) {
1173 if (positionA > -1 && positionA == positionB) {
1177 decoration3.
start = (attribute.start+attribute.length);
1179 decoration1.
length = attribute.start - decoration1.
start;
1180 decoration2.
start = attribute.start;
1181 decoration2.
length = attribute.length;
1182 if (decoration1.
length > 0) {
1184 if (decoration2.
length > 0) {
1186 styleMap.insert(positionA, decoration2);
1191 if (decoration3.
length > 0) {
1192 styleMap.insert(positionA + 1, decoration3);
1194 }
else if (positionA > -1 && positionB > -1
1195 && positionA != positionB) {
1200 decoration2.
length = (decoration1.
start + decoration1.
length) - attribute.start;
1201 decoration1.
length = attribute.start - decoration1.
start;
1202 decoration2.
start = attribute.start;
1204 decoration4.
start = (attribute.start+attribute.length);
1207 if (decoration1.
length > 0) {
1209 if (decoration2.
length > 0) {
1211 styleMap.insert(positionA, decoration2);
1217 if (decoration3.
length > 0) {
1219 if (decoration4.
length > 0) {
1220 styleMap.insert(positionB + 1, decoration4);
1228 if (positionA > -1 && !
styleMap.isEmpty()) {
1230 for(
int i = positionA; i <= positionB; i++) {
1238 decoration.
start = attribute.start;
1239 decoration.
length = attribute.length;
1247 }
else if (attribute.type == QInputMethodEvent::Cursor) {
1248 if (
d->preEditStart < 0) {
1251 int index =
d->shape->indexForPos(
d->preEditStart);
1252 d->pos =
d->shape->posForIndex(index + attribute.start);
1262 updateRect |=
d->shape->boundingRect();
1264 d->shape->updateAbsolute(updateRect);
1276 d->cursorVisible = !
d->cursorVisible;
1282 d->cursorFlash.stop();
1283 d->cursorFlashLimit.stop();
1284 d->cursorVisible =
true;
1293 if (!
d->canvas->canvasWidget()) {
1296 QPoint
pos =
d->canvas->canvasWidget()->mapTo(
d->canvas->canvasWidget()->window(), QPoint());
1297 QTransform widgetToWindow = QTransform::fromTranslate(
pos.x(),
pos.y());
1298 QTransform inputItemTransform = widgetToWindow;
1299 QRectF inputRect =
d->canvas->canvasWidget()->geometry();
1301 inputRect =
d->shape->outlineRect().normalized();
1302 QTransform shapeTransform =
d->shape->absoluteTransformation();
1303 QTransform docToView =
d->canvas->viewConverter()->documentToView();
1304 QTransform viewToWidget =
d->canvas->viewConverter()->viewToWidget();
1305 inputItemTransform = shapeTransform * docToView * viewToWidget * widgetToWindow;
1308 QInputMethod *inputMethod = QGuiApplication::inputMethod();
1309 inputMethod->setInputItemTransform(inputItemTransform);
1310 inputMethod->setInputItemRectangle(inputRect);
1311 if (!
d->blockQueryUpdates) {
1312 inputMethod->update(Qt::ImQueryInput);
1327 if (!bg->compareTo(shapeProps.
background().data())
1336 if (shapeStroke->isVisible()) {
1353 QAction *action =
dynamic_cast<QAction*
>(QObject::sender());
1354 if (!action || !
d->shape)
return;
1358 if (properties.
isEmpty())
return;
1366 QSet<KoSvgTextProperties::PropertyId> ids;
1377 return d->pos !=
d->anchor;
1384 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
1385 d->pos =
d->shape->posForIndex(
d->posIndex);
1386 d->anchor =
d->shape->posForIndex(
d->anchorIndex);
1395 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
1405 d->interface->emitSelectionChange();
1406 d->interface->emitCharacterSelectionChange();
1418 if (
d->preEditCommand) {
1424 bool select =
event->modifiers().testFlag(Qt::ShiftModifier);
1426 if (!((Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier) & event->modifiers())) {
1428 switch (event->key()) {
1445 case Qt::Key_Delete:
1449 case Qt::Key_Backspace:
1453 case Qt::Key_Return:
1462 if (event->isAccepted()) {
1480 int newKey =
event->key();
1485 newKey = Qt::Key_Right;
1488 newKey = Qt::Key_Left;
1498 newKey = Qt::Key_Down;
1501 newKey = Qt::Key_Up;
1504 newKey = Qt::Key_Left;
1507 newKey = Qt::Key_Right;
1515 newKey = Qt::Key_Up;
1518 newKey = Qt::Key_Down;
1521 newKey = Qt::Key_Left;
1524 newKey = Qt::Key_Right;
1531 QKeySequence testSequence(event->modifiers() | newKey);
1539 Q_FOREACH(QAction *action,
d->actions) {
1540 if (action->shortcut() == testSequence) {
1551 if (testSequence == QKeySequence::MoveToNextChar) {
1554 }
else if (testSequence == QKeySequence::SelectNextChar) {
1557 }
else if (testSequence == QKeySequence::MoveToPreviousChar) {
1560 }
else if (testSequence == QKeySequence::SelectPreviousChar) {
1563 }
else if (testSequence == QKeySequence::MoveToNextLine) {
1566 }
else if (testSequence == QKeySequence::SelectNextLine) {
1569 }
else if (testSequence == QKeySequence::MoveToPreviousLine) {
1572 }
else if (testSequence == QKeySequence::SelectPreviousLine) {
1576 }
else if (testSequence == QKeySequence::MoveToNextWord) {
1579 }
else if (testSequence == QKeySequence::SelectNextWord) {
1582 }
else if (testSequence == QKeySequence::MoveToPreviousWord) {
1585 }
else if (testSequence == QKeySequence::SelectPreviousWord) {
1589 }
else if (testSequence == QKeySequence::MoveToStartOfLine) {
1592 }
else if (testSequence == QKeySequence::SelectStartOfLine) {
1595 }
else if (testSequence == QKeySequence::MoveToEndOfLine) {
1598 }
else if (testSequence == QKeySequence::SelectEndOfLine) {
1602 }
else if (testSequence == QKeySequence::MoveToStartOfBlock
1603 || testSequence == QKeySequence::MoveToStartOfDocument) {
1606 }
else if (testSequence == QKeySequence::SelectStartOfBlock
1607 || testSequence == QKeySequence::SelectStartOfDocument) {
1611 }
else if (testSequence == QKeySequence::MoveToEndOfBlock
1612 || testSequence == QKeySequence::MoveToEndOfDocument) {
1615 }
else if (testSequence == QKeySequence::SelectEndOfBlock
1616 || testSequence == QKeySequence::SelectEndOfDocument) {
1620 }
else if (testSequence == QKeySequence::DeleteStartOfWord) {
1623 }
else if (testSequence == QKeySequence::DeleteEndOfWord) {
1626 }
else if (testSequence == QKeySequence::DeleteEndOfLine) {
1629 }
else if (testSequence == QKeySequence::DeleteCompleteLine) {
1632 }
else if (testSequence == QKeySequence::Backspace) {
1635 }
else if (testSequence == QKeySequence::Delete) {
1639 }
else if (testSequence == QKeySequence::InsertLineSeparator
1640 || testSequence == QKeySequence::InsertParagraphSeparator) {
1650 d->lastKnownModifiers = modifiers;
1656 return d->isAddingCommand;
1661 d->cursorFlash.start();
1662 d->cursorFlashLimit.start();
1663 d->cursorVisible =
false;
1670 d->hasFocus =
false;
1677 d->actions.append(action);
1678 connect(action, SIGNAL(triggered(
bool)),
this, SLOT(
propertyAction()));
1680 }
else if (name ==
"svg_insert_special_character") {
1681 d->actions.append(action);
1684 }
else if (name ==
"svg_paste_rich_text") {
1685 d->actions.append(action);
1686 connect(action, SIGNAL(triggered(
bool)),
this, SLOT(
pasteRichText()));
1688 }
else if (name ==
"svg_paste_plain_text") {
1689 d->actions.append(action);
1690 connect(action, SIGNAL(triggered(
bool)),
this, SLOT(
pastePlainText()));
1692 }
else if (name ==
"svg_remove_transforms_from_range") {
1693 d->actions.append(action);
1696 }
else if (name ==
"svg_clear_formatting") {
1697 d->actions.append(action);
1700 }
else if (action) {
1701 d->actions.append(action);
1709 return d->interface;
1715 d->oldCursorRect =
d->shape->shapeToDocument(
d->cursorShape.boundingRect());
1716 d->posIndex =
d->shape->indexForPos(
d->pos);
1717 d->anchorIndex =
d->shape->indexForPos(
d->anchor);
1721 d->cursorColor = QColor();
1722 d->cursorShape =
d->shape?
d->shape->cursorForPos(
d->pos,
d->cursorCaret,
d->cursorColor): QPainterPath();
1724 if (!
d->blockQueryUpdates) {
1725 qApp->inputMethod()->update(Qt::ImQueryInput);
1727 d->interface->emitCharacterSelectionChange();
1728 if (!(
d->canvas->canvasWidget() &&
d->canvas->canvasController())) {
1732 if (
d->shape && !firstUpdate) {
1733 QRectF
rect =
d->shape->shapeToDocument(
d->cursorShape.boundingRect());
1734 d->canvas->canvasController()->ensureVisibleDoc(
rect,
false);
1736 if (
d->canvas->canvasWidget()->hasFocus()) {
1737 d->cursorFlash.start();
1738 d->cursorFlashLimit.start();
1739 d->cursorVisible =
false;
1747 d->oldSelectionRect =
d->shape->shapeToDocument(
d->selection.boundingRect());
1748 d->shape->cursorForPos(
d->anchor,
d->anchorCaret,
d->cursorColor);
1749 d->selection =
d->shape->selectionBoxes(
d->pos,
d->anchor);
1752 if (!
d->blockQueryUpdates) {
1753 QGuiApplication::inputMethod()->update(Qt::ImQueryInput);
1761 d->oldIMEDecorationRect =
d->shape->shapeToDocument(
d->IMEDecoration.boundingRect());
1762 KoSvgText::TextDecorations decor;
1764 d->IMEDecoration = QPainterPath();
1765 if (
d->preEditCommand) {
1768 int startIndex =
d->shape->indexForPos(
d->preEditStart) + info.
start;
1769 int endIndex = startIndex + info.
length;
1770 qreal minimum =
d->canvas->viewToDocument(QPointF(1, 1)).x();
1771 d->IMEDecoration.addPath(
d->shape->underlines(
d->shape->posForIndex(startIndex),
1772 d->shape->posForIndex(endIndex),
1777 d->IMEDecoration.setFillRule(Qt::WindingFill);
1799 const int metric,
const bool isHorizontal,
1801 const qreal scaleMetrics,
const QPointF &advance,
1802 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath> &decor){
1803 QPointF offset = isHorizontal? QPointF(0, -(metric*scaleMetrics)): QPointF(metric*scaleMetrics, 0);
1805 QPainterPath
p = decor.value(handle);
1807 const QPointF startPos = t.map(offset);
1808 const QPointF endPos = t.map(offset+advance);
1809 if (
p.currentPosition() != startPos) {
1814 decor.insert(handle,
p);
1817void processEdges(QTransform t, QMap<SvgTextCursor::TypeSettingModeHandle, int> values,
1818 const bool isHorizontal,
1819 const qreal scaleMetrics,
1820 const QPointF advance,
1821 QPainterPath &path) {
1822 QPointF
p1(values.first(), 0);
1823 QPointF
p2(values.last(), 0);
1824 Q_FOREACH(
const int val, values) {
1833 p1 = QPointF(
p1.y(), -
p1.x());
1834 p2 = QPointF(
p2.y(), -
p2.x());
1838 path.moveTo(t.map(
p1+advance));
1839 path.lineTo(t.map(
p2+advance));
1843 QTransform t = QTransform::fromTranslate(pos.x(), pos.y());
1844 t.rotate(rotateDeg);
1851 if (
d->shape &&
d->typeSettingMode) {
1854 d->shape->getPositionsAndRotationsForRange(
d->pos,
d->anchor);
1855 if (infos.size() < 1)
return;
1857 const bool rtl = infos.first().rtl;
1861 if (infos.size() > 1) {
1863 for (
auto it = infos.begin(); it != infos.end(); it++) {
1864 if (it->visualIndex >= 0) {
1869 for (
auto it = infos.rbegin(); it != infos.rend(); it++) {
1870 if (it->visualIndex >= 0) {
1877 QTransform t = QTransform::fromTranslate(last.
finalPos.x(), last.
finalPos.y());
1885 d->typeSettingDecor.paths = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1886 d->typeSettingDecor.baselines = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1887 d->typeSettingDecor.edges = QPainterPath();
1888 d->typeSettingDecor.parentPaths = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1889 d->typeSettingDecor.parentBaselines = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1891 if (
d->pos ==
d->anchor) {
1892 metricInfos =
d->shape->getPositionsAndRotationsForRange(0,
d->shape->posForIndex(
d->shape->plainText().size()));
1895 const int minPos = qMin(
d->pos,
d->anchor);
1896 const int maxPos = qMax(
d->pos,
d->anchor);
1897 const int endPos =
d->shape->posForIndex(
d->shape->plainText().size());
1900 if (minPos > 0 || maxPos < endPos) {
1904 const qreal scaleMetrics = props.
fontSize().
value/qreal(metrics.fontSize);
1905 const int lineGap =
calcLineHeight(lineHeight, metrics, scaleMetrics);
1907 const QMap<SvgTextCursor::TypeSettingModeHandle, int> types
1913 positions << qMax(0, minPos-1);
1914 positions << maxPos;
1915 positions << endPos;
1917 Q_FOREACH(
const int pos, positions) {
1919 d->shape->getPositionsAndRotationsForRange(
pos,
pos);
1920 parentInfos.append(info.first());
1923 QPointF drawOffset = isHorizontal? QPointF(
d->handleRadius*2, 0): QPointF(0,
d->handleRadius*2);
1925 drawOffset =
d->canvas->viewConverter()->viewToDocument().map(drawOffset);
1927 bool toggleOffset = rtl;
1929 for (
auto it = parentInfos.begin(); it != parentInfos.end(); it++) {
1930 const bool currentIsMin = (
d->shape->posForIndex(it->logicalIndex) == minPos);
1931 const bool currentIsMax = (
d->shape->posForIndex(it->logicalIndex) == maxPos);
1933 if ((currentIsMin && minPos == 0) || (currentIsMax && maxPos == endPos)) {
1934 toggleOffset = !toggleOffset;
1938 const QPointF finalPos = toggleOffset? it->finalPos + (it->advance - drawOffset): it->finalPos;
1939 const QPointF advance = drawOffset;
1944 const int metric = types.value(handle);
1945 processBaseline(handle, metric, isHorizontal, t, scaleMetrics, advance,
d->typeSettingDecor.parentBaselines);
1949 if (currentIsMin && minPos == maxPos && !toggleOffset) {
1950 toggleOffset = !toggleOffset;
1953 const QPointF advance = toggleOffset? it->advance: QPointF();
1955 processEdges(t, types, isHorizontal, scaleMetrics, advance,
d->typeSettingDecor.edges);
1958 toggleOffset = !toggleOffset;
1963 bool toggleOffset =
false;
1964 for (
auto it = metricInfos.begin(); it != metricInfos.end(); it++) {
1965 const int currentPos = (
d->pos ==
d->anchor)? -1 :
d->shape->posForIndex(it->logicalIndex);
1974 const int lineGap =
calcLineHeight(lineHeight, metrics, scaleMetrics);
1978 const QMap<SvgTextCursor::TypeSettingModeHandle, int> types
1982 const int metric = types.value(handle);
1983 processBaseline(handle, metric, isHorizontal, t, scaleMetrics, it->advance,
d->typeSettingDecor.baselines);
1985 if ((currentPos == minPos || currentPos+1 == maxPos) && minPos != maxPos) {
1986 const QPointF advance = toggleOffset? it->advance: QPointF();
1987 toggleOffset = !toggleOffset;
1988 processEdges(t, types, isHorizontal, scaleMetrics, advance,
d->typeSettingDecor.edges);
1997 d->typeSettingDecor.paths.insert(handle,
d->typeSettingDecor.baselines.value(handle));
1998 d->typeSettingDecor.parentPaths.insert(handle,
d->typeSettingDecor.parentBaselines.value(handle));
2005 updateRect =
d->shape->shapeToDocument(
d->typeSettingDecor.boundingRect(
d->handleRadius));
2009 d->oldTypeSettingRect = updateRect;
2016 d->isAddingCommand =
true;
2017 d->canvas->addCommand(cmd);
2018 d->isAddingCommand =
false;
2030 newPos =
d->shape->posLeft(
pos, visual);
2033 newPos =
d->shape->posRight(
pos, visual);
2036 newPos =
d->shape->posUp(
pos, visual);
2039 newPos =
d->shape->posDown(
pos, visual);
2042 newPos =
d->shape->previousIndex(
pos);
2045 newPos =
d->shape->nextIndex(
pos);
2048 newPos =
d->shape->previousLine(
pos);
2051 newPos =
d->shape->nextLine(
pos);
2054 newPos =
d->shape->wordLeft(
pos, visual);
2055 if (newPos ==
pos) {
2056 newPos =
d->shape->posLeft(
pos, visual);
2057 newPos =
d->shape->wordLeft(newPos, visual);
2061 newPos =
d->shape->wordRight(
pos, visual);
2062 if (newPos ==
pos) {
2063 newPos =
d->shape->posRight(
pos, visual);
2064 newPos =
d->shape->wordRight(newPos, visual);
2068 newPos =
d->shape->wordStart(
pos);
2069 if (newPos ==
pos) {
2070 newPos =
d->shape->previousIndex(
pos);
2071 newPos =
d->shape->wordStart(newPos);
2075 newPos =
d->shape->wordEnd(
pos);
2076 if (newPos ==
pos) {
2077 newPos =
d->shape->nextIndex(
pos);
2078 newPos =
d->shape->wordEnd(newPos);
2082 newPos =
d->shape->lineStart(
pos);
2085 newPos =
d->shape->lineEnd(
pos);
2091 newPos =
d->shape->posForIndex(
d->shape->plainText().size());
2100 const QString text =
event->text();
2103 const QChar c = text.at(0);
2106 if (c.category() == QChar::Other_Format)
2109 if (event->modifiers() == Qt::ControlModifier
2110 || event->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier)) {
2115 if (c.category() == QChar::Other_PrivateUse)
2117 if (c == QLatin1Char(
'\t'))
2124 if (!
d->preEditCommand) {
2128 qApp->inputMethod()->commit();
2130 if (!
d->preEditCommand) {
2134 d->preEditCommand->undo();
2135 d->preEditCommand =
nullptr;
2136 d->preEditStart = -1;
2137 d->preEditLength = 0;
2146 if (
d->shape &&
d->canvas->resourceManager() &&
d->pos ==
d->anchor) {
2153 if (c !=
d->canvas->resourceManager()->foregroundColor()) {
2154 d->canvas->resourceManager()->setForegroundColor(c);
2162 if (c !=
d->canvas->resourceManager()->backgroundColor()) {
2163 d->canvas->resourceManager()->setBackgroundColor(c);
2167 Q_FOREACH (QAction *action,
d->actions) {
2169 action->blockSignals(
true);
2173 if (action->isChecked() != checked) {
2174 action->setChecked(checked);
2177 action->blockSignals(
false);
2205 return d->parent->propertiesForShape();
2212 if (
d->parent->shape()->singleNode()) {
2215 return d->parent->propertiesForRange();
2227 d->parent->mergePropertiesIntoSelection(properties, removeProperties,
true);
2232 d->parent->mergePropertiesIntoSelection(properties, removeProperties,
false,
true);
2237 return d->parent->hasSelection();
2249 if (!
d->parent->shape())
return;
2250 d->compressor.start();
2255 d->characterCompressor.start();
qreal length(const QPointF &vec)
float value(const T *src, size_t ch)
VertexDescriptor get(PredecessorMap const &m, VertexDescriptor v)
qreal distance(const QPointF &p1, const QPointF &p2)
static QColor bgColorForCaret(QColor c, int opacity=64)
QTransform posAndRotateTransform(const QPointF pos, const qreal rotateDeg)
QMap< SvgTextCursor::TypeSettingModeHandle, int > typeSettingBaselinesFromMetrics(const KoSvgText::FontMetrics metrics, const qreal lineGap, const bool isHorizontal)
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 KisHandlePainterHelper class is a special helper for painting handles around objects....
void drawPath(const QPainterPath &path)
void drawHandleRect(const QPointF ¢er, qreal radius)
void setHandleStyle(const KisHandleStyle &style)
void drawHandleCircle(const QPointF ¢er, qreal radius)
static KisHandleStyle & partiallyHighlightedPrimaryHandles()
static KisHandleStyle & secondarySelection()
A simple solid color shape background.
QColor color() const
Returns the background color.
void setOpacity(quint8 alpha)
void fromQColor(const QColor &c)
Convenient function for converting from a QColor.
void toQColor(QColor *c) const
a convenience method for the above.
bool isVisible() const override
void addShapeChangeListener(ShapeChangeListener *listener)
KoShapeAnchor * anchor() const
ChangeType
Used by shapeChanged() to select which change was made.
QList< KoShape * > fetchShapes(QRectF viewportInPx, qreal resolutionPPI, QSizeF *fragmentSize=nullptr)
The KoSvgTextPropertiesInterface class.
void textCharacterSelectionChanged()
void textSelectionChanged()
Emit to signal to KisTextPropertiesManager to call getSelectedProperties.
@ DominantBaselineId
KoSvgText::Baseline.
@ AlignmentBaselineId
KoSvgText::Baseline.
@ LineHeightId
KoSvgText::AutoValue.
@ StrokeId
KoSvgText::StrokeProperty.
@ FillId
KoSvgText::BackgroundProperty.
@ WritingModeId
KoSvgText::WritingMode.
@ DirectionId
KoSvgText::Direction.
@ LastPropertyId
Last Property ID, used for iteration.
QSharedPointer< KoShapeBackground > background() const
KoShapeStrokeModelSP stroke() const
KoSvgText::FontMetrics metrics(const bool withResolvedLineHeight=true, const bool offsetByBaseline=false) const
metrics Return the metrics of the first available font.
bool hasProperty(PropertyId id) const
void setProperty(PropertyId id, const QVariant &value)
QVariant propertyOrDefault(PropertyId id) const
KoSvgText::CssLengthPercentage fontSize() const
bool convertToSvg(QString *svgText, QString *stylesText)
bool convertToHtml(QString *htmlText)
convertToHtml convert the text in the text shape to html
@ PreformattedText
Text-on-Path falls under this or PrePositionedText depending on collapse of lines.
Interface to interact with the text property manager.
const QScopedPointer< Private > d
virtual bool spanSelection() override
Whether the tool is currently selecting a set of characters instead of whole paragraphs.
SvgTextCursorPropertyInterface(SvgTextCursor *parent)
virtual void setCharacterPropertiesOnSelected(KoSvgTextProperties properties, QSet< KoSvgTextProperties::PropertyId > removeProperties=QSet< KoSvgTextProperties::PropertyId >()) override
setCharacterPropertiesOnSelected This sets the properties for a character selection instead of the fu...
virtual KoSvgTextProperties getInheritedProperties() override
getInheritedProperties The properties that should be visible when a given property isn't available in...
virtual QList< KoSvgTextProperties > getSelectedProperties() override
getSelectedProperties
virtual void setPropertiesOnSelected(KoSvgTextProperties properties, QSet< KoSvgTextProperties::PropertyId > removeProperties=QSet< KoSvgTextProperties::PropertyId >()) override
setPropertiesOnSelected This sets the properties on the selection. The implementation is responsible ...
~SvgTextCursorPropertyInterface()
void emitSelectionChange()
virtual bool characterPropertiesEnabled() override
Whether character selections are possible at all.
virtual QList< KoSvgTextProperties > getCharacterProperties() override
getSelectedProperties
void emitCharacterSelectionChange()
InputQueryUpdateBlocker(SvgTextCursor::Private *d)
void setChangeVisibility(bool changeVisibility)
InputQueryUpdateBlocker(const QScopedPointer< Private > &d)
bool m_unblockQueryUpdates
~InputQueryUpdateBlocker()
The SvgTextMergePropertiesRangeCommand class This sets properties on a specific range in a single tex...
The SvgTextRemoveTransformsFromRange class Removes the SVG 1.1 character transforms from the range.
static bool actionEnabled(QAction *action, const QList< KoSvgTextProperties > currentProperties)
static QStringList possibleActions()
static KoSvgTextProperties getModifiedProperties(const QAction *action, QList< KoSvgTextProperties > currentProperties)
static bool configureAction(QAction *action, const QString &name)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
qreal kisDistanceToLine(const QPointF &m, const QLineF &line)
QPointF kisProjectOnVector(const QPointF &base, const QPointF &v)
bool intersectLineRect(QLineF &line, const QRect rect, bool extend)
qreal luminosityCoarse(const QColor &c, bool sRGBtrc)
luminosityCoarse This calculates the luminosity of the given QColor. It uses a very coarse (10 step) ...
@ BackgroundColor
The active background color selected for this canvas.
@ ForegroundColor
The active foreground color selected for this canvas.
TextDecorationStyle
Style of the text-decoration.
@ Solid
Draw a solid line.Ex: --—.
@ Dashed
Draw a dashed line. Ex: - - - - -.
@ Wavy
Draw a wavy line. We currently make a zigzag, ex: ^^^^^.
@ Dotted
Draw a dotted line. Ex: .....
Direction
Base direction used by Bidi algorithm.
Baseline
Baseline values used by dominant-baseline and baseline-align.
@ BaselineAlphabetic
Use 'romn' or the baseline for LCG scripts.
@ BaselineTextBottom
Bottom side of the inline line-box.
@ BaselineTextTop
Top side of the inline line-box.
@ BaselineCentral
Use the center between the ideographic over and under.
int start
The startPos from the attribute.
void setDecorationFromQTextCharFormat(QTextCharFormat format)
void setDecorationFromQStyle(QTextCharFormat::UnderlineStyle s)
bool thick
Whether the decoration needs to be doubled in size.
int length
The length from the attribute.
KoSvgText::TextDecorationStyle style
The style.
KoSvgText::TextDecorations decor
Which sides get decorated.
The KoSvgTextCharacterInfo class This is a small struct to convey information about character positio...
static bool visualLessThan(const KoSvgTextCharacterInfo &a, const KoSvgTextCharacterInfo &b)
BackgroundProperty is a special wrapper around KoShapeBackground for managing it in KoSvgTextProperti...
The FontMetrics class A class to keep track of a variety of font metrics. Note that values are in Fre...
qint32 ideographicCenterBaseline
default baseline for vertical, centered between over and under.
qint32 ideographicUnderBaseline
location of ideographic under baseline from origin, may fall back to descender.
qint32 xHeight
height of X, defaults to 0.5 fontsize.
qint32 lineGap
additional linegap between consecutive lines.
qint32 fontSize
Currently set size, CSS unit 'em'.
qint32 alphabeticBaseline
location of alphabetic baseline from origin.
qint32 descender
distance for origin to bottom.
qint32 ascender
distance from origin to top.
qint32 mathematicalBaseline
location of mathematical baseline from origin.
qint32 hangingBaseline
location of the hanging baseline used in north brahmic scripts.
bool isNumber
Length or number.
CssLengthPercentage length
bool isNormal
It's a number indicating the lineHeight;.
StrokeProperty is a special wrapper around KoShapeStrokeModel for managing it in KoSvgTextProperties.
KisSignalCompressor characterCompressor
KisSignalCompressor compressor
Private(SvgTextCursor *parent)
void setTypeSettingHandleHovered(TypeSettingModeHandle hovered=TypeSettingModeHandle::NoHandle)
Set a given typesetting handle as hovered, so it will be drawn as such.
void setVisualMode(const bool visualMode=true)
setVisualMode set whether the navigation mode is visual or logical. This right now primarily affects ...
void keyPressEvent(QKeyEvent *event)
Handle the cursor-related key events.
KoSvgTextPropertiesInterface * textPropertyInterface()
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...
void stopBlinkCursor()
Called by timer, stops the text blinking animation.
QList< QAction * > actions
int getAnchor()
Get the current selection anchor. This is the same as position, unless there's a selection.
void insertText(QString text)
Insert text at getPos()
void removeTransformsFromRange()
removeTransformsFromRange Called by actions to remove svg character transforms from range.
bool drawCursorInAdditionToSelection
QPair< KoSvgTextProperties, KoSvgTextProperties > currentTextProperties() const
currentTextProperties
void updateIMEDecoration()
void paintDecorations(QPainter &gc, QColor selectionColor, int decorationThickness=1, qreal handleRadius=5.0)
Paint all decorations and blinkingcursors.
QVector< IMEDecorationInfo > styleMap
Decoration info (underlines) for the preEdit string to differentiate it from regular text.
const QScopedPointer< Private > d
void deselectText()
Deselect all text. This effectively makes anchor the same as pos.
bool hasSelection() override
return true if the tool currently has something selected that can be copied or deleted.
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,...
void setPos(int pos, int anchor)
Set the pos and the anchor.
void addCommandToUndoAdapter(KUndo2Command *cmd)
Adds a command to the canvas of the parent tool.
void clearFormattingAction()
Called by the clear formatting action.
void notifyShapeChanged(KoShape::ChangeType type, KoShape *shape) override
QRectF oldIMEDecorationRect
Update Rectangle of previous decoration.
QString handleName(TypeSettingModeHandle handle) const
handleName
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.
void blinkCursor()
Called by timer, toggles the text cursor visible or invisible.
void updateCanvasResources()
Update the canvas resources with fore and background color.
SvgTextCursor(KoCanvasBase *canvas)
TypeSettingModeHandle
Handles used by type setting mode.
@ BaselineAlphabetic
Baselines.
@ BaselineShift
The text properties handles.
void inputMethodEvent(QInputMethodEvent *event)
Process an input method event. This is used by IME like virtual keyboards.
void canvasResourceChanged(int key, const QVariant &value)
Called when the canvas resources (foreground/background) change.
void setPosToPoint(QPointF point, bool moveAnchor=true)
Set the pos from a point. This currently does a search inside the text shape.
QCursor cursorTypeForTypeSetting() const
Return appropriate typeSetting cursor;.
void moveCursor(MoveMode mode, bool moveAnchor=true)
Move the cursor, and, if you don't want a selection, move the anchor.
void setPasteRichTextByDefault(const bool pasteRichText=true)
setPasteRichText
bool acceptableInput(const QKeyEvent *event) const
More or less copied from bool QInputControl::isAcceptableInput(const QKeyEvent *event) const.
QList< KoSvgTextProperties > propertiesForRange() const
propertiesForRange
TypeSettingDecorInfo typeSettingDecor
QVariant inputMethodQuery(Qt::InputMethodQuery query) const
Process an input method query and return the requested result.
void removeSelection()
removeSelection if there's a selection, creates a text-removal command.
void setTypeSettingModeActive(bool activate)
Set type setting mode active.
void updateTypeSettingDecoration()
void removeText(MoveMode first, MoveMode second)
removeText remove text relative to the current position. This will move the cursor according to the m...
bool setDominantBaselineFromHandle(const TypeSettingModeHandle handle)
setDominantBaselineFromHandle Set the dominant baseline from a given handle.
int moveModeResult(const MoveMode mode, int &pos, bool visual=false) const
Processes a move action, returns the input.
int getPos()
Get the current position.
void focusOut()
Stops blinking cursor.
void removeLastCodePoint()
removeLastCodePoint Special function to remove the last code point. Triggered by backspace....
int posForTypeSettingHandleAndRect(const TypeSettingModeHandle handle, const QRectF regionOfInterest)
posForHandleAndRect Returns the closest cursor position for a given region and typesetting handle....
QRectF oldTypeSettingRect
TypeSettingModeHandle typeSettingHandleAtPos(const QRectF regionOfInterest)
Get typeSettingMode handle for text;.
void notifyMarkupChanged() override
bool pastePlainText()
pastePlainText Explicitely paste plaintext at pos.
bool registerPropertyAction(QAction *action, const QString &name)
Register an action.
void selectionChanged()
Sents an update selection was changed.
void focusIn()
Turns on blinking cursor.
void updateCursorDecoration(QRectF updateRect)
Sents an update to the parent tool to update it's decorations.
void setDrawTypeSettingHandle(bool draw)
bool paste()
paste pastes plain text in the clipboard at pos. Uses pasteRichTextByDefault to determine whether to ...
QPainterPath IMEDecoration
The decorations for the current preedit string.
void updateTypeSettingDecorFromShape()
Update the type setting decorations.
void updateModifiers(const Qt::KeyboardModifiers modifiers)
KisAcyclicSignalConnector resourceManagerAcyclicConnector
QList< KoSvgTextProperties > propertiesForShape() const
propertiesForShape
void setShape(KoSvgTextShape *textShape)
setShape
void updateInputMethodItemTransform()
Qt::KeyboardModifiers lastKnownModifiers
void insertRichText(KoSvgTextShape *insert, bool inheritPropertiesIfPossible=false)
Insert rich text at getPos();.
SvgTextRemoveCommand * removeSelectionImpl(bool allowCleanUp, KUndo2Command *parent=0)
removeSelection if there's a selection, creates a text-removal command.
void notifyCursorPosChanged(int pos, int anchor) override
void copy() const
copy copies plain text into the clipboard between anchor and pos.
void updateCursor(bool firstUpdate=false)
update the cursor shape. First update will block ensuring the canvas is visible so setShape won't cau...
QPointF closestBaselinePoint
QMap< SvgTextCursor::TypeSettingModeHandle, QPainterPath > paths
QMap< SvgTextCursor::TypeSettingModeHandle, QPainterPath > baselines
QMap< SvgTextCursor::TypeSettingModeHandle, QPainterPath > parentBaselines
QPair< QPointF, QPointF > handles
QMap< SvgTextCursor::TypeSettingModeHandle, QPainterPath > parentPaths
QRectF boundingRect(qreal handleRadius)
bool testBaselines(Qt::KeyboardModifiers modifiers)