38#include <QApplication>
40#include <QKeySequence>
43#include <QInputMethodEvent>
48#include <config-qt-patches-present.h>
62 if (s == QTextCharFormat::DotLine) {
64 }
else if (s == QTextCharFormat::DashUnderline) {
66 }
else if (s == QTextCharFormat::WaveUnderline) {
68 }
else if (s == QTextCharFormat::SpellCheckUnderline) {
79 if (format.hasProperty(QTextFormat::FontUnderline)) {
82 if (format.hasProperty(QTextFormat::FontOverline)) {
85 if (format.hasProperty(QTextFormat::FontStrikeOut)) {
89 if (format.hasProperty(QTextFormat::TextUnderlineStyle)) {
98 if (format.hasProperty(QTextFormat::BackgroundBrush)) {
99 thick = format.background().isOpaque();
118 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>
baselines;
119 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>
paths;
122 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>
parentPaths;
129 for (
int i = 0; i<
paths.values().size(); i++) {
130 total |=
paths.values().at(i).boundingRect();
132 for (
int i = 0; i<
baselines.values().size(); i++) {
133 total |=
baselines.values().at(i).boundingRect();
135 for (
int i = 0; i<
parentPaths.values().size(); i++) {
136 total |=
parentPaths.values().at(i).boundingRect();
141 total |=
edges.boundingRect();
142 QRectF
rect(0, 0, handleRadius, handleRadius);
151 return (modifiers & Qt::ShiftModifier);
163 , m_unblockQueryUpdates(!
std::exchange(d->blockQueryUpdates, true))
175 QInputMethod *inputMethod = QGuiApplication::inputMethod();
177 if (m_unblockQueryUpdates) {
178 m_d->blockQueryUpdates =
false;
179 inputMethod->update(Qt::ImQueryInput);
182 if (m_changeVisibility) {
183 inputMethod->setVisible(m_d->shape !=
nullptr);
190 m_changeVisibility = changeVisibility;
196 bool m_changeVisibility =
false;
200 bool isAddingCommand =
false;
207 bool cursorVisible =
false;
208 bool hasFocus =
false;
216 bool drawCursorInAdditionToSelection =
false;
225 bool visualNavigation =
true;
226 bool pasteRichText =
true;
230 bool typeSettingMode =
false;
232 bool drawTypeSettingHandle =
true;
233 qreal handleRadius = 7;
238 int preEditStart = -1;
239 int preEditLength = -1;
243 bool blockQueryUpdates =
false;
257 if (
d->canvas->canvasController()) {
260 connect(
d->canvas->canvasController()->proxyObject,
261 SIGNAL(moveDocumentOffset(QPointF, QPointF)),
264 connect(
d->canvas->canvasController()->proxyObject,
265 SIGNAL(effectiveZoomChanged(qreal)),
268 connect(
d->canvas->canvasController()->proxyObject,
269 SIGNAL(documentRotationChanged(qreal)),
272 connect(
d->canvas->canvasController()->proxyObject,
273 SIGNAL(documentMirrorStatusChanged(
bool,
bool)),
276 d->resourceManagerAcyclicConnector.connectBackwardResourcePair(
279 d->resourceManagerAcyclicConnector.connectForwardVoid(
d->interface, SIGNAL(textCharacterSelectionChanged()),
this, SLOT(
updateCanvasResources()));
287 d->cursorFlash.stop();
288 d->cursorFlashLimit.stop();
299 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
300 inputQueryUpdateBlocker.setChangeVisibility(
true);
304 d->shape->removeShapeChangeListener(
this);
306 d->shape = textShape;
310 d->pos =
d->shape->posForIndex(
d->shape->plainText().size());
318 d->interface->emitSelectionChange();
327 connect(&
d->cursorFlash, SIGNAL(timeout()),
this, SLOT(
blinkCursor()));
328 connect(&
d->cursorFlashLimit, SIGNAL(timeout()),
this, SLOT(
stopBlinkCursor()));
333 d->visualNavigation = visualMode;
343 d->typeSettingMode = activate;
359 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
369 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
370 int pos =
d->shape->posForPointLineSensitive(
d->shape->documentToShape(point));
371 if (
d->preEditCommand) {
372 int start =
d->shape->indexForPos(
d->preEditStart);
373 int end = start +
d->preEditLength;
376 qApp->inputMethod()->invokeAction(QInputMethod::Click,
posIndex - start);
383 const int finalPos =
d->shape->posForIndex(
d->shape->plainText().size());
384 d->pos = qBound(0,
pos, finalPos);
385 if (moveAnchor ||
d->anchor < 0 ||
d->anchor > finalPos) {
397 if (!(
d->typeSettingMode &&
d->shape &&
d->canvas))
return handle;
399 const QRectF roiInShape =
d->shape->absoluteTransformation().inverted().mapRect(regionOfInterest);
401 if (
d->typeSettingDecor.handlesEnabled) {
402 if (roiInShape.contains(
d->typeSettingDecor.handles.first)) {
404 }
else if (roiInShape.contains(
d->typeSettingDecor.handles.second)) {
408 if (handle !=
NoHandle)
return handle;
409 if (!
d->typeSettingDecor.boundingRect(
d->handleRadius).intersects(roiInShape))
return handle;
411 qreal closest = std::numeric_limits<qreal>::max();
412 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath> paths
413 =
d->typeSettingDecor.testBaselines(
d->lastKnownModifiers)?
d->typeSettingDecor.baselines:
d->typeSettingDecor.paths;
415 const QPainterPath path = paths.value(baseline);
416 if (!path.intersects(roiInShape))
continue;
419 Q_FOREACH(
const QPolygonF poly, polys) {
420 if (poly.size() < 2)
continue;
421 for (
int i = 1; i < poly.size(); i++) {
422 QLineF l(poly.at(i-1), poly.at(i));
427 d->typeSettingDecor.closestBaselinePoint =
439 d->hoveredTypeSettingHandle = hovered;
444 d->drawTypeSettingHandle = draw;
452 && !(
d->shape->topLevelNodeForPos(
d->pos).textPath()));
458 if (
d->hoveredTypeSettingHandle ==
StartPos ||
459 d->hoveredTypeSettingHandle ==
StartPos ||
460 d->typeSettingDecor.testBaselines(
d->lastKnownModifiers)) {
461 return Qt::ArrowCursor;
462 }
else if (
d->shape) {
465 return Qt::ArrowCursor;
470 bool baseline =
d->typeSettingDecor.testBaselines(
d->lastKnownModifiers);
473 return i18nc(
"Type setting mode line name",
"Text Top");
475 return i18nc(
"Type setting mode line name",
"Font Size");
479 return i18nc(
"Type setting mode line name",
"Text Bottom");
481 return i18nc(
"Type setting mode line name",
"Font Size");
484 return i18nc(
"Type setting mode line name",
"Alphabetic");
486 return i18nc(
"Type setting mode line name",
"Ideographic");
488 return i18nc(
"Type setting mode line name",
"Hanging");
490 return i18nc(
"Type setting mode line name",
"Middle");
492 return i18nc(
"Type setting mode line name",
"Mathematical");
494 return i18nc(
"Type setting mode line name",
"Central");
496 return i18nc(
"Type setting mode line name",
"Line Height");
499 return i18nc(
"Type setting mode line name",
"Current Baseline");
501 return i18nc(
"Type setting mode line name",
"Baseline Shift");
510 if (handle ==
NoHandle)
return false;
511 if (!
d->typeSettingDecor.testBaselines(
d->lastKnownModifiers))
return false;
540 return QMap<SvgTextCursor::TypeSettingModeHandle, int> {
557 if (!
d->shape)
return 0;
560 d->shape->getPositionsAndRotationsForRange(
d->pos,
d->anchor);
561 if (infos.size() < 1)
return 0;
563 const QRectF roi =
d->shape->documentToShape(regionOfInterest);
565 for (
auto it = infos.begin(); it != infos.end(); it++) {
566 const int currentPos = (
d->pos ==
d->anchor)? -1 :
d->shape->posForIndex(it->logicalIndex);
573 const qreal scaleMetrics = props.
fontSize().
value/qreal(metrics.fontSize);
574 const int lineGap = lineHeight.
isNormal? metrics.lineGap: (lineHeight.
length.
value/scaleMetrics)-(metrics.ascender-metrics.descender);
576 QTransform t = QTransform::fromTranslate(it->finalPos.x(), it->finalPos.y());
577 t.rotate(it->rotateDeg);
579 const QMap<SvgTextCursor::TypeSettingModeHandle, int> types
582 const int metric = types.value(handle);
583 QPointF offset = isHorizontal? QPointF(0, -(metric*scaleMetrics)): QPointF(metric*scaleMetrics, 0);
584 QLineF line = t.map(QLineF(offset, offset+it->advance));
597 const int finalPos =
d->shape->posForIndex(
d->shape->plainText().size());
650 int posStart = qMin(posA, posB);
651 int posEnd = qMax(posA, posB);
652 int indexEnd =
d->shape->indexForPos(posEnd);
653 int length = indexEnd -
d->shape->indexForPos(posStart);
669 int lastIndex =
d->shape->indexForPos(
d->pos);
679 return QPair<KoSvgTextProperties, KoSvgTextProperties>(
d->shape->propertiesForPos(
d->pos),
d->shape->propertiesForPos(
d->pos,
true));
681 return QPair<KoSvgTextProperties, KoSvgTextProperties>();
689 start = qMin(
d->pos,
d->anchor);
690 end = qMax(
d->pos,
d->anchor);
691 return d->shape->propertiesForRange(start, end);
697 return {
d->shape->propertiesForRange(-1, -1)};
705 if (!paragraphOnly) {
709 if (selectWord &&
d->pos ==
d->anchor) {
710 const int finalPos =
d->shape->posForIndex(
d->shape->plainText().size());
729 if (
d->anchor !=
d->pos) {
730 int end =
d->shape->indexForPos(qMax(
d->anchor,
d->pos));
731 int length =
d->shape->indexForPos(qMax(
d->anchor,
d->pos)) -
d->shape->indexForPos(qMin(
d->anchor,
d->pos));
741 int start =
d->shape->indexForPos(qMin(
d->anchor,
d->pos));
742 int length =
d->shape->indexForPos(qMax(
d->anchor,
d->pos)) - start;
743 QString copied =
d->shape->plainText().mid(start,
length);
744 std::unique_ptr<KoSvgTextShape> copy =
d->shape->copyRange(start,
length);
745 QClipboard *cb = QApplication::clipboard();
752 QMimeData *svgData =
new QMimeData();
754 QString svgDoc = QString(
"<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"2.0\">%1\n%2</svg>").arg(styles).arg(svg);
755 svgData->setData(QLatin1String(
"image/svg+xml"), svgDoc.toUtf8());
757 svgData->setText(copied);
759 svgData->setHtml(html);
760 cb->setMimeData(svgData);
776 bool success =
false;
778 QClipboard *cb = QApplication::clipboard();
779 const QMimeData *mimeData = cb->mimeData();
783 while (shapes.size() > 0) {
790 }
else if (mimeData->hasHtml()) {
791 QString html = mimeData->html();
796 if (converter.convertFromHtml(html, &svg, &styles)
797 && converter.convertFromSvg(svg, styles,
d->shape->boundingRect(), 72.0) ) {
812 bool success =
false;
813 QClipboard *cb = QApplication::clipboard();
814 const QMimeData *mimeData = cb->mimeData();
815 if (mimeData->hasText()) {
838 return QColor(handlePalette.
black.red(), handlePalette.
black.green(), handlePalette.
black.blue(), opacity);
840 return QColor(handlePalette.
white.red(), handlePalette.
white.green(), handlePalette.
white.blue(), opacity);
848 gc.setTransform(
d->shape->absoluteTransformation(),
true);
850 if (
d->pos !=
d->anchor && !
d->typeSettingMode) {
853 QBrush brush(selectionColor);
854 gc.fillPath(
d->selection, brush);
858 if ( (
d->drawCursorInAdditionToSelection ||
d->pos ==
d->anchor)
859 &&
d->cursorVisible) {
861 pen.setCosmetic(
true);
862 QColor c =
d->cursorColor.isValid()?
d->cursorColor: Qt::black;
864 pen.setWidth((
d->cursorWidth + 2) * decorationThickness);
866 gc.drawPath(
d->cursorShape);
868 pen.setWidth(
d->cursorWidth * decorationThickness);
870 gc.drawPath(
d->cursorShape);
874 if (
d->preEditCommand) {
876 QBrush brush(selectionColor);
878 gc.fillPath(
d->IMEDecoration, brush);
881 if (
d->typeSettingMode &&
d->drawTypeSettingHandle) {
883 QTransform painterTf = gc.transform();
888 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath> paths
889 =
d->typeSettingDecor.testBaselines(
d->lastKnownModifiers)?
d->typeSettingDecor.baselines:
d->typeSettingDecor.paths;
890 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath> parentPaths
891 =
d->typeSettingDecor.testBaselines(
d->lastKnownModifiers)?
d->typeSettingDecor.parentBaselines:
d->typeSettingDecor.parentPaths;
893 const QPainterPath
p = paths.value(handle);
894 const QPainterPath parent = parentPaths.value(handle);
895 if (
d->hoveredTypeSettingHandle == handle) {
901 QPen pen(selectionColor, decorationThickness, handle ==
BaselineShift? Qt::SolidLine: Qt::DashLine);
902 pen.setCosmetic(
true);
905 gc.drawPath(painterTf.map(parent));
906 gc.drawPath(painterTf.map(
p));
910 QPen pen(selectionColor, decorationThickness, Qt::SolidLine);
911 pen.setCosmetic(
true);
914 gc.drawPath(painterTf.map(
d->typeSettingDecor.edges));
918 if (
d->typeSettingDecor.handlesEnabled) {
924 QString name =
handleName(
d->hoveredTypeSettingHandle);
925 if (!name.isEmpty()) {
928 QFont font = gc.font();
929 font.setHintingPreference(QFont::PreferFullHinting);
930 textP.addText(painterTf.map(
d->typeSettingDecor.closestBaselinePoint).toPoint(), font, name);
933 pen.setCosmetic(
true);
934 pen.setWidth(decorationThickness);
937 gc.fillPath(textP, QBrush(selectionColor));
948 dbgTools <<
"receiving inputmethod query" << query;
954 return d->shape?
true:
false;
956 case Qt::ImCursorRectangle:
959 QPointF caret1(
d->cursorCaret.p1());
960 QPointF caret2(
d->cursorCaret.p2());
963 QRectF
rect = QRectF(caret1, caret2).normalized();
964 if (!
rect.isValid()) {
965 if (
rect.height() < 1) {
966 rect.adjust(0, -1, 0, 0);
968 if (
rect.width() < 1) {
969 rect.adjust(0, 0, 1, 0);
973 return rect.toAlignedRect();
976 case Qt::ImAnchorRectangle:
979 QPointF caret1(
d->anchorCaret.p1());
980 QPointF caret2(
d->anchorCaret.p2());
981 QRectF
rect = QRectF(caret1, caret2).normalized();
982 if (
rect.isEmpty()) {
983 if (
rect.height() < 1) {
984 rect.adjust(0, -1, 0, 0);
986 if (
rect.width() < 1) {
987 rect =
rect.adjusted(-1, 0, 0, 0).normalized();
990 return rect.toAlignedRect();
994 case Qt::ImAbsolutePosition:
995 case Qt::ImCursorPosition:
997 return d->shape->indexForPos(
d->pos);
1000 case Qt::ImSurroundingText:
1002 QString surroundingText =
d->shape->plainText();
1003 int preEditIndex =
d->preEditCommand?
d->shape->indexForPos(
d->preEditStart): 0;
1004 surroundingText.remove(preEditIndex,
d->preEditLength);
1005 return surroundingText;
1008 case Qt::ImCurrentSelection:
1010 QString surroundingText =
d->shape->plainText();
1011 int preEditIndex =
d->preEditCommand?
d->shape->indexForPos(
d->preEditStart): 0;
1012 surroundingText.remove(preEditIndex,
d->preEditLength);
1013 int start =
d->shape->indexForPos(qMin(
d->anchor,
d->pos));
1014 int length =
d->shape->indexForPos(qMax(
d->anchor,
d->pos)) - start;
1015 return surroundingText.mid(start,
length);
1018 case Qt::ImTextBeforeCursor:
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.left(start);
1027 case Qt::ImTextAfterCursor:
1029 int start =
d->shape->indexForPos(
d->pos);
1030 QString surroundingText =
d->shape->plainText();
1031 int preEditIndex =
d->preEditCommand?
d->shape->indexForPos(
d->preEditStart): 0;
1032 surroundingText.remove(preEditIndex,
d->preEditLength);
1033 return surroundingText.right(start);
1036 case Qt::ImMaximumTextLength:
1039 case Qt::ImAnchorPosition:
1041 return d->shape->indexForPos(
d->anchor);
1047 return Qt::ImhMultiLine;
1050#if defined(Q_OS_ANDROID) && KRITA_QT_HAS_ANDROID_INPUT_PLATFORM_DATA_SOFT_INPUT_ADJUST_NOTHING
1051 case Qt::ImPlatformData:
1060 return Qt::ANDROID_INPUT_PLATFORM_DATA_SOFT_INPUT_ADJUST_NOTHING;
1062 case Qt::ImEnterKeyType:
1064 return Qt::EnterKeyDefault;
1076 dbgTools <<
"Commit:"<<
event->commitString() <<
"predit:"<<
event->preeditString();
1077 dbgTools <<
"Replacement:"<<
event->replacementStart() <<
event->replacementLength();
1079 QRectF updateRect =
d->shape?
d->shape->boundingRect(): QRectF();
1080 SvgTextShapeManagerBlocker blocker(
d->canvas->shapeManager());
1082 bool isGettingInput = !
event->commitString().isEmpty() || !
event->preeditString().isEmpty()
1083 ||
event->replacementLength() > 0;
1086 if (
d->preEditCommand) {
1087 d->preEditCommand->undo();
1088 d->preEditCommand = 0;
1089 d->preEditStart = -1;
1090 d->preEditLength = -1;
1091 updateRect |=
d->shape?
d->shape->boundingRect(): QRectF();
1094 if (!
d->shape || !isGettingInput) {
1096 d->canvas->shapeManager()->update(updateRect);
1101 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
1107 int originalPos =
d->pos;
1108 int index =
d->shape->indexForPos(
d->pos) +
event->replacementStart();
1109 d->pos =
d->shape->posForIndex(index);
1110 if (event->replacementLength() > 0) {
1112 index + event->replacementLength(),
1115 event->replacementLength(),
1121 if (!event->commitString().isEmpty()) {
1126 Q_FOREACH(
const QInputMethodEvent::Attribute attribute, event->attributes()) {
1127 if (attribute.type == QInputMethodEvent::Selection) {
1128 d->pos =
d->shape->posForIndex(attribute.start);
1129 int index =
d->shape->indexForPos(
d->pos);
1130 d->anchor =
d->shape->posForIndex(index + attribute.length);
1136 if (!event->preeditString().isEmpty()) {
1137 int index =
d->shape->indexForPos(
d->pos);
1139 d->preEditCommand->redo();
1140 d->preEditLength =
event->preeditString().size();
1141 d->preEditStart =
d->shape->posForIndex(index,
true);
1143 d->preEditCommand = 0;
1148 Q_FOREACH(
const QInputMethodEvent::Attribute attribute, event->attributes()) {
1149 dbgTools <<
"attribute: "<< attribute.type <<
"start: " << attribute.start
1150 <<
"length: " << attribute.length <<
"val: " << attribute.value;
1156 if (attribute.type == QInputMethodEvent::TextFormat) {
1157 QVariant val = attribute.value;
1158 QTextCharFormat form = val.value<QTextFormat>().toCharFormat();
1160 if (attribute.length == 0 || attribute.start < 0 || !attribute.value.isValid()) {
1167 for (
int i = 0; i <
styleMap.size(); i++) {
1168 if (attribute.start >=
styleMap.at(i).start
1172 if (attribute.start + attribute.length >
styleMap.at(i).start
1173 && attribute.start + attribute.length <=
styleMap.at(i).start +
styleMap.at(i).length) {
1178 if (positionA > -1 && positionA == positionB) {
1182 decoration3.
start = (attribute.start+attribute.length);
1184 decoration1.
length = attribute.start - decoration1.
start;
1185 decoration2.
start = attribute.start;
1186 decoration2.
length = attribute.length;
1187 if (decoration1.
length > 0) {
1189 if (decoration2.
length > 0) {
1191 styleMap.insert(positionA, decoration2);
1196 if (decoration3.
length > 0) {
1197 styleMap.insert(positionA + 1, decoration3);
1199 }
else if (positionA > -1 && positionB > -1
1200 && positionA != positionB) {
1205 decoration2.
length = (decoration1.
start + decoration1.
length) - attribute.start;
1206 decoration1.
length = attribute.start - decoration1.
start;
1207 decoration2.
start = attribute.start;
1209 decoration4.
start = (attribute.start+attribute.length);
1212 if (decoration1.
length > 0) {
1214 if (decoration2.
length > 0) {
1216 styleMap.insert(positionA, decoration2);
1222 if (decoration3.
length > 0) {
1224 if (decoration4.
length > 0) {
1225 styleMap.insert(positionB + 1, decoration4);
1233 if (positionA > -1 && !
styleMap.isEmpty()) {
1235 for(
int i = positionA; i <= positionB; i++) {
1243 decoration.
start = attribute.start;
1244 decoration.
length = attribute.length;
1252 }
else if (attribute.type == QInputMethodEvent::Cursor) {
1253 if (
d->preEditStart < 0) {
1256 int index =
d->shape->indexForPos(
d->preEditStart);
1257 d->pos =
d->shape->posForIndex(index + attribute.start);
1267 updateRect |=
d->shape->boundingRect();
1269 d->shape->updateAbsolute(updateRect);
1281 d->cursorVisible = !
d->cursorVisible;
1287 d->cursorFlash.stop();
1288 d->cursorFlashLimit.stop();
1289 d->cursorVisible =
true;
1298 if (!
d->canvas->canvasWidget()) {
1301 QPoint
pos =
d->canvas->canvasWidget()->mapTo(
d->canvas->canvasWidget()->window(), QPoint());
1302 QTransform widgetToWindow = QTransform::fromTranslate(
pos.x(),
pos.y());
1303 QTransform inputItemTransform = widgetToWindow;
1304 QRectF inputRect =
d->canvas->canvasWidget()->geometry();
1306 inputRect =
d->shape->outlineRect().normalized();
1307 QTransform shapeTransform =
d->shape->absoluteTransformation();
1308 QTransform docToView =
d->canvas->viewConverter()->documentToView();
1309 QTransform viewToWidget =
d->canvas->viewConverter()->viewToWidget();
1310 inputItemTransform = shapeTransform * docToView * viewToWidget * widgetToWindow;
1313 QInputMethod *inputMethod = QGuiApplication::inputMethod();
1314 inputMethod->setInputItemTransform(inputItemTransform);
1315 inputMethod->setInputItemRectangle(inputRect);
1316 if (!
d->blockQueryUpdates) {
1317 inputMethod->update(Qt::ImQueryInput);
1332 if (!bg->compareTo(shapeProps.
background().data())
1341 if (shapeStroke->isVisible()) {
1358 QAction *action =
dynamic_cast<QAction*
>(QObject::sender());
1359 if (!action || !
d->shape)
return;
1363 if (properties.
isEmpty())
return;
1371 QSet<KoSvgTextProperties::PropertyId> ids;
1382 return d->pos !=
d->anchor;
1389 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
1390 d->pos =
d->shape->posForIndex(
d->posIndex);
1391 d->anchor =
d->shape->posForIndex(
d->anchorIndex);
1400 Private::InputQueryUpdateBlocker inputQueryUpdateBlocker(
d);
1410 d->interface->emitSelectionChange();
1411 d->interface->emitCharacterSelectionChange();
1423 if (
d->preEditCommand) {
1429 bool select =
event->modifiers().testFlag(Qt::ShiftModifier);
1431 if (!((Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier) & event->modifiers())) {
1433 switch (event->key()) {
1450 case Qt::Key_Delete:
1454 case Qt::Key_Backspace:
1458 case Qt::Key_Return:
1467 if (event->isAccepted()) {
1485 int newKey =
event->key();
1490 newKey = Qt::Key_Right;
1493 newKey = Qt::Key_Left;
1503 newKey = Qt::Key_Down;
1506 newKey = Qt::Key_Up;
1509 newKey = Qt::Key_Left;
1512 newKey = Qt::Key_Right;
1520 newKey = Qt::Key_Up;
1523 newKey = Qt::Key_Down;
1526 newKey = Qt::Key_Left;
1529 newKey = Qt::Key_Right;
1536 QKeySequence testSequence(event->modifiers() | newKey);
1544 Q_FOREACH(QAction *action,
d->actions) {
1545 if (action->shortcut() == testSequence) {
1556 if (testSequence == QKeySequence::MoveToNextChar) {
1559 }
else if (testSequence == QKeySequence::SelectNextChar) {
1562 }
else if (testSequence == QKeySequence::MoveToPreviousChar) {
1565 }
else if (testSequence == QKeySequence::SelectPreviousChar) {
1568 }
else if (testSequence == QKeySequence::MoveToNextLine) {
1571 }
else if (testSequence == QKeySequence::SelectNextLine) {
1574 }
else if (testSequence == QKeySequence::MoveToPreviousLine) {
1577 }
else if (testSequence == QKeySequence::SelectPreviousLine) {
1581 }
else if (testSequence == QKeySequence::MoveToNextWord) {
1584 }
else if (testSequence == QKeySequence::SelectNextWord) {
1587 }
else if (testSequence == QKeySequence::MoveToPreviousWord) {
1590 }
else if (testSequence == QKeySequence::SelectPreviousWord) {
1594 }
else if (testSequence == QKeySequence::MoveToStartOfLine) {
1597 }
else if (testSequence == QKeySequence::SelectStartOfLine) {
1600 }
else if (testSequence == QKeySequence::MoveToEndOfLine) {
1603 }
else if (testSequence == QKeySequence::SelectEndOfLine) {
1607 }
else if (testSequence == QKeySequence::MoveToStartOfBlock
1608 || testSequence == QKeySequence::MoveToStartOfDocument) {
1611 }
else if (testSequence == QKeySequence::SelectStartOfBlock
1612 || testSequence == QKeySequence::SelectStartOfDocument) {
1616 }
else if (testSequence == QKeySequence::MoveToEndOfBlock
1617 || testSequence == QKeySequence::MoveToEndOfDocument) {
1620 }
else if (testSequence == QKeySequence::SelectEndOfBlock
1621 || testSequence == QKeySequence::SelectEndOfDocument) {
1625 }
else if (testSequence == QKeySequence::DeleteStartOfWord) {
1628 }
else if (testSequence == QKeySequence::DeleteEndOfWord) {
1631 }
else if (testSequence == QKeySequence::DeleteEndOfLine) {
1634 }
else if (testSequence == QKeySequence::DeleteCompleteLine) {
1637 }
else if (testSequence == QKeySequence::Backspace) {
1640 }
else if (testSequence == QKeySequence::Delete) {
1644 }
else if (testSequence == QKeySequence::InsertLineSeparator
1645 || testSequence == QKeySequence::InsertParagraphSeparator) {
1655 d->lastKnownModifiers = modifiers;
1661 return d->isAddingCommand;
1666 d->cursorFlash.start();
1667 d->cursorFlashLimit.start();
1668 d->cursorVisible =
false;
1675 d->hasFocus =
false;
1682 d->actions.append(action);
1683 connect(action, SIGNAL(triggered(
bool)),
this, SLOT(
propertyAction()));
1685 }
else if (name ==
"svg_insert_special_character") {
1686 d->actions.append(action);
1689 }
else if (name ==
"svg_paste_rich_text") {
1690 d->actions.append(action);
1691 connect(action, SIGNAL(triggered(
bool)),
this, SLOT(
pasteRichText()));
1693 }
else if (name ==
"svg_paste_plain_text") {
1694 d->actions.append(action);
1695 connect(action, SIGNAL(triggered(
bool)),
this, SLOT(
pastePlainText()));
1697 }
else if (name ==
"svg_remove_transforms_from_range") {
1698 d->actions.append(action);
1701 }
else if (name ==
"svg_clear_formatting") {
1702 d->actions.append(action);
1705 }
else if (action) {
1706 d->actions.append(action);
1714 return d->interface;
1720 d->oldCursorRect =
d->shape->shapeToDocument(
d->cursorShape.boundingRect());
1721 d->posIndex =
d->shape->indexForPos(
d->pos);
1722 d->anchorIndex =
d->shape->indexForPos(
d->anchor);
1726 d->cursorColor = QColor();
1727 d->cursorShape =
d->shape?
d->shape->cursorForPos(
d->pos,
d->cursorCaret,
d->cursorColor): QPainterPath();
1729 if (!
d->blockQueryUpdates) {
1730 qApp->inputMethod()->update(Qt::ImQueryInput);
1732 d->interface->emitCharacterSelectionChange();
1733 if (!(
d->canvas->canvasWidget() &&
d->canvas->canvasController())) {
1737 if (
d->shape && !firstUpdate) {
1738 QRectF
rect =
d->shape->shapeToDocument(
d->cursorShape.boundingRect());
1739 d->canvas->canvasController()->ensureVisibleDoc(
rect,
false);
1741 if (
d->canvas->canvasWidget()->hasFocus()) {
1742 d->cursorFlash.start();
1743 d->cursorFlashLimit.start();
1744 d->cursorVisible =
false;
1752 d->oldSelectionRect =
d->shape->shapeToDocument(
d->selection.boundingRect());
1753 d->shape->cursorForPos(
d->anchor,
d->anchorCaret,
d->cursorColor);
1754 d->selection =
d->shape->selectionBoxes(
d->pos,
d->anchor);
1757 if (!
d->blockQueryUpdates) {
1758 QGuiApplication::inputMethod()->update(Qt::ImQueryInput);
1766 d->oldIMEDecorationRect =
d->shape->shapeToDocument(
d->IMEDecoration.boundingRect());
1767 KoSvgText::TextDecorations decor;
1769 d->IMEDecoration = QPainterPath();
1770 if (
d->preEditCommand) {
1773 int startIndex =
d->shape->indexForPos(
d->preEditStart) + info.
start;
1774 int endIndex = startIndex + info.
length;
1775 qreal minimum =
d->canvas->viewToDocument(QPointF(1, 1)).x();
1776 d->IMEDecoration.addPath(
d->shape->underlines(
d->shape->posForIndex(startIndex),
1777 d->shape->posForIndex(endIndex),
1782 d->IMEDecoration.setFillRule(Qt::WindingFill);
1804 const int metric,
const bool isHorizontal,
1806 const qreal scaleMetrics,
const QPointF &advance,
1807 QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath> &decor){
1808 QPointF offset = isHorizontal? QPointF(0, -(metric*scaleMetrics)): QPointF(metric*scaleMetrics, 0);
1810 QPainterPath
p = decor.value(handle);
1812 const QPointF startPos = t.map(offset);
1813 const QPointF endPos = t.map(offset+advance);
1814 if (
p.currentPosition() != startPos) {
1819 decor.insert(handle,
p);
1822void processEdges(QTransform t, QMap<SvgTextCursor::TypeSettingModeHandle, int> values,
1823 const bool isHorizontal,
1824 const qreal scaleMetrics,
1825 const QPointF advance,
1826 QPainterPath &path) {
1827 QPointF
p1(values.first(), 0);
1828 QPointF
p2(values.last(), 0);
1829 Q_FOREACH(
const int val, values) {
1838 p1 = QPointF(
p1.y(), -
p1.x());
1839 p2 = QPointF(
p2.y(), -
p2.x());
1843 path.moveTo(t.map(
p1+advance));
1844 path.lineTo(t.map(
p2+advance));
1848 QTransform t = QTransform::fromTranslate(pos.x(), pos.y());
1849 t.rotate(rotateDeg);
1856 if (
d->shape &&
d->typeSettingMode) {
1859 d->shape->getPositionsAndRotationsForRange(
d->pos,
d->anchor);
1860 if (infos.size() < 1)
return;
1862 const bool rtl = infos.first().rtl;
1866 if (infos.size() > 1) {
1868 for (
auto it = infos.begin(); it != infos.end(); it++) {
1869 if (it->visualIndex >= 0) {
1874 for (
auto it = infos.rbegin(); it != infos.rend(); it++) {
1875 if (it->visualIndex >= 0) {
1882 QTransform t = QTransform::fromTranslate(last.
finalPos.x(), last.
finalPos.y());
1890 d->typeSettingDecor.paths = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1891 d->typeSettingDecor.baselines = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1892 d->typeSettingDecor.edges = QPainterPath();
1893 d->typeSettingDecor.parentPaths = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1894 d->typeSettingDecor.parentBaselines = QMap<SvgTextCursor::TypeSettingModeHandle, QPainterPath>();
1896 if (
d->pos ==
d->anchor) {
1897 metricInfos =
d->shape->getPositionsAndRotationsForRange(0,
d->shape->posForIndex(
d->shape->plainText().size()));
1900 const int minPos = qMin(
d->pos,
d->anchor);
1901 const int maxPos = qMax(
d->pos,
d->anchor);
1902 const int endPos =
d->shape->posForIndex(
d->shape->plainText().size());
1905 if (minPos > 0 || maxPos < endPos) {
1909 const qreal scaleMetrics = props.
fontSize().
value/qreal(metrics.fontSize);
1910 const int lineGap =
calcLineHeight(lineHeight, metrics, scaleMetrics);
1912 const QMap<SvgTextCursor::TypeSettingModeHandle, int> types
1918 positions << qMax(0, minPos-1);
1919 positions << maxPos;
1920 positions << endPos;
1922 Q_FOREACH(
const int pos, positions) {
1924 d->shape->getPositionsAndRotationsForRange(
pos,
pos);
1925 parentInfos.append(info.first());
1928 QPointF drawOffset = isHorizontal? QPointF(
d->handleRadius*2, 0): QPointF(0,
d->handleRadius*2);
1930 drawOffset =
d->canvas->viewConverter()->viewToDocument().map(drawOffset);
1932 bool toggleOffset = rtl;
1934 for (
auto it = parentInfos.begin(); it != parentInfos.end(); it++) {
1935 const bool currentIsMin = (
d->shape->posForIndex(it->logicalIndex) == minPos);
1936 const bool currentIsMax = (
d->shape->posForIndex(it->logicalIndex) == maxPos);
1938 if ((currentIsMin && minPos == 0) || (currentIsMax && maxPos == endPos)) {
1939 toggleOffset = !toggleOffset;
1943 const QPointF finalPos = toggleOffset? it->finalPos + (it->advance - drawOffset): it->finalPos;
1944 const QPointF advance = drawOffset;
1949 const int metric = types.value(handle);
1950 processBaseline(handle, metric, isHorizontal, t, scaleMetrics, advance,
d->typeSettingDecor.parentBaselines);
1954 if (currentIsMin && minPos == maxPos && !toggleOffset) {
1955 toggleOffset = !toggleOffset;
1958 const QPointF advance = toggleOffset? it->advance: QPointF();
1960 processEdges(t, types, isHorizontal, scaleMetrics, advance,
d->typeSettingDecor.edges);
1963 toggleOffset = !toggleOffset;
1968 bool toggleOffset =
false;
1969 for (
auto it = metricInfos.begin(); it != metricInfos.end(); it++) {
1970 const int currentPos = (
d->pos ==
d->anchor)? -1 :
d->shape->posForIndex(it->logicalIndex);
1979 const int lineGap =
calcLineHeight(lineHeight, metrics, scaleMetrics);
1983 const QMap<SvgTextCursor::TypeSettingModeHandle, int> types
1987 const int metric = types.value(handle);
1988 processBaseline(handle, metric, isHorizontal, t, scaleMetrics, it->advance,
d->typeSettingDecor.baselines);
1990 if ((currentPos == minPos || currentPos+1 == maxPos) && minPos != maxPos) {
1991 const QPointF advance = toggleOffset? it->advance: QPointF();
1992 toggleOffset = !toggleOffset;
1993 processEdges(t, types, isHorizontal, scaleMetrics, advance,
d->typeSettingDecor.edges);
2002 d->typeSettingDecor.paths.insert(handle,
d->typeSettingDecor.baselines.value(handle));
2003 d->typeSettingDecor.parentPaths.insert(handle,
d->typeSettingDecor.parentBaselines.value(handle));
2010 updateRect =
d->shape->shapeToDocument(
d->typeSettingDecor.boundingRect(
d->handleRadius));
2014 d->oldTypeSettingRect = updateRect;
2021 d->isAddingCommand =
true;
2022 d->canvas->addCommand(cmd);
2023 d->isAddingCommand =
false;
2035 newPos =
d->shape->posLeft(
pos, visual);
2038 newPos =
d->shape->posRight(
pos, visual);
2041 newPos =
d->shape->posUp(
pos, visual);
2044 newPos =
d->shape->posDown(
pos, visual);
2047 newPos =
d->shape->previousIndex(
pos);
2050 newPos =
d->shape->nextIndex(
pos);
2053 newPos =
d->shape->previousLine(
pos);
2056 newPos =
d->shape->nextLine(
pos);
2059 newPos =
d->shape->wordLeft(
pos, visual);
2060 if (newPos ==
pos) {
2061 newPos =
d->shape->posLeft(
pos, visual);
2062 newPos =
d->shape->wordLeft(newPos, visual);
2066 newPos =
d->shape->wordRight(
pos, visual);
2067 if (newPos ==
pos) {
2068 newPos =
d->shape->posRight(
pos, visual);
2069 newPos =
d->shape->wordRight(newPos, visual);
2073 newPos =
d->shape->wordStart(
pos);
2074 if (newPos ==
pos) {
2075 newPos =
d->shape->previousIndex(
pos);
2076 newPos =
d->shape->wordStart(newPos);
2080 newPos =
d->shape->wordEnd(
pos);
2081 if (newPos ==
pos) {
2082 newPos =
d->shape->nextIndex(
pos);
2083 newPos =
d->shape->wordEnd(newPos);
2087 newPos =
d->shape->lineStart(
pos);
2090 newPos =
d->shape->lineEnd(
pos);
2096 newPos =
d->shape->posForIndex(
d->shape->plainText().size());
2105 const QString text =
event->text();
2108 const QChar c = text.at(0);
2111 if (c.category() == QChar::Other_Format)
2114 if (event->modifiers() == Qt::ControlModifier
2115 || event->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier)) {
2120 if (c.category() == QChar::Other_PrivateUse)
2122 if (c == QLatin1Char(
'\t'))
2129 if (!
d->preEditCommand) {
2133 qApp->inputMethod()->commit();
2135 if (!
d->preEditCommand) {
2139 d->preEditCommand->undo();
2140 d->preEditCommand =
nullptr;
2141 d->preEditStart = -1;
2142 d->preEditLength = 0;
2151 if (
d->shape &&
d->canvas->resourceManager() &&
d->pos ==
d->anchor) {
2158 if (c !=
d->canvas->resourceManager()->foregroundColor()) {
2159 d->canvas->resourceManager()->setForegroundColor(c);
2167 if (c !=
d->canvas->resourceManager()->backgroundColor()) {
2168 d->canvas->resourceManager()->setBackgroundColor(c);
2172 Q_FOREACH (QAction *action,
d->actions) {
2174 action->blockSignals(
true);
2178 if (action->isChecked() != checked) {
2179 action->setChecked(checked);
2182 action->blockSignals(
false);
2210 return d->parent->propertiesForShape();
2217 if (
d->parent->shape()->singleNode()) {
2220 return d->parent->propertiesForRange();
2232 d->parent->mergePropertiesIntoSelection(properties, removeProperties,
true);
2237 d->parent->mergePropertiesIntoSelection(properties, removeProperties,
false,
true);
2242 return d->parent->hasSelection();
2254 if (!
d->parent->shape())
return;
2255 d->compressor.start();
2260 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)
QTransform posAndRotateTransform(const QPointF pos, const qreal rotateDeg)
static QColor bgColorForCaret(QColor c, KisHandlePalette handlePalette, int opacity=64)
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(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & secondarySelection(KisHandlePalette palette=KisHandlePalette())
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.
static KoColorSpaceRegistry * instance()
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()
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.
void paintDecorations(QPainter &gc, QColor selectionColor, int decorationThickness=1, qreal handleRadius=5.0, KisHandlePalette handlePalette=KisHandlePalette())
Paint all decorations and blinkingcursors.
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)