Krita Source Code Documentation
Loading...
Searching...
No Matches
SvgTextTool.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2
3 SPDX-FileCopyrightText: 2017 Boudewijn Rempt <boud@valdyas.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "SvgTextTool.h"
10#include "KoSvgTextShape.h"
16#include "SvgInlineSizeHelper.h"
17#include "SvgMoveTextCommand.h"
18#include "SvgMoveTextStrategy.h"
20#include "SvgTextEditor.h"
23#include "SvgTextShortCuts.h"
30
31#include <QPainterPath>
32#include <QDesktopServices>
33#include <QApplication>
34#include <QStyle>
35#include <QDockWidget>
36#include <QQuickItem>
37#include <QActionGroup>
38
39#include <klocalizedstring.h>
40
41#include <KisPart.h>
42#include <kis_canvas2.h>
43#include <KSharedConfig>
44#include "kis_assert.h"
46
47#include <KoFileDialog.h>
48#include <KoIcon.h>
49#include <KoCanvasBase.h>
50#include <KoSelection.h>
51#include <KoShapeManager.h>
52#include <KoShapeController.h>
53#include <KoShapeRegistry.h>
54#include <KoShapeFactoryBase.h>
55#include <KoPointerEvent.h>
56#include <KoProperties.h>
58#include "KoToolManager.h"
59#include <KoShapeFillWrapper.h>
61#include <KoPathShape.h>
62#include <KoPathSegment.h>
63
65#include <KoCssStylePreset.h>
67#include <KoColorBackground.h>
68#include <KisResourceModel.h>
69
71#include <KisViewManager.h>
72#include <KisQQuickWidget.h>
73#include <QQmlError>
74#include <KisMainWindow.h>
75
77#include "kis_tool_utils.h"
78#include "kis_debug.h"
81
82#ifdef Q_OS_ANDROID
83#include <QMenuBar>
84#endif
85
86
88
89constexpr double INLINE_SIZE_DASHES_PATTERN_A = 4.0;
90constexpr double INLINE_SIZE_DASHES_PATTERN_B = 8.0;
92constexpr double INLINE_SIZE_HANDLE_THICKNESS = 1.0;
93
94
95static bool debugEnabled()
96{
97 static const bool debugEnabled = !qEnvironmentVariableIsEmpty("KRITA_DEBUG_TEXTTOOL");
98 return debugEnabled;
99}
100
102 : KoToolBase(canvas)
103 , m_optionManager(new SvgTextToolOptionsManager(this))
104 , m_textCursor(canvas)
105 , m_textOutlineHelper(new KoSvgTextShapeOutlineHelper(canvas))
106{
107 // TODO: figure out whether we should use system config for this, Windows and GTK have values for it, but Qt and MacOS don't(?).
108 const int cursorFlashLimit = 5000;
109 const bool enableCursorWithSelection = QApplication::style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected);
110 m_textCursor.setCaretSetting(QApplication::style()->pixelMetric(QStyle::PM_TextCursorWidth)
111 , qApp->cursorFlashTime()
112 , cursorFlashLimit
113 , enableCursorWithSelection);
114 connect(&m_textCursor, SIGNAL(updateCursorDecoration(QRectF)), this, SLOT(slotUpdateCursorDecoration(QRectF)));
115
116 Q_FOREACH(const QString name, SvgTextShortCuts::possibleActions()) {
117 QAction *a = action(name);
119 dbgTools << "registered" << name << a->shortcut();
120 }
121 }
122
123 const QStringList extraActions = {
124 "svg_insert_special_character",
125 "svg_paste_rich_text",
126 "svg_paste_plain_text",
127 "svg_remove_transforms_from_range",
128 "svg_clear_formatting"
129 };
130 connect(&m_textCursor, SIGNAL(sigOpenGlyphPalette()), this, SLOT(showGlyphPalette()));
131 Q_FOREACH (const QString name, extraActions) {
132 QAction *a = action(name);
133 if (a) {
135 qWarning() << "could not register" << name << a->shortcut();
136 }
137 }
138 }
139
141 QActionGroup *textTypeActions = new QActionGroup(this);
142 addMappedAction(m_textTypeSignalsMapper.data(), "text_type_preformatted", KoSvgTextShape::PreformattedText, textTypeActions);
143 addMappedAction(m_textTypeSignalsMapper.data(), "text_type_inline_wrap", KoSvgTextShape::InlineWrap, textTypeActions);
144 addMappedAction(m_textTypeSignalsMapper.data(), "text_type_pre_positioned", KoSvgTextShape::PrePositionedText, textTypeActions);
145
147 QActionGroup *typeSettingActions = new QActionGroup(this);
148 addMappedAction(m_typeSettingMovementMapper.data(), "svg_type_setting_move_selection_start_down_1_px", Qt::Key_Down, typeSettingActions);
149 addMappedAction(m_typeSettingMovementMapper.data(), "svg_type_setting_move_selection_start_up_1_px", Qt::Key_Up, typeSettingActions);
150 addMappedAction(m_typeSettingMovementMapper.data(), "svg_type_setting_move_selection_start_left_1_px", Qt::Key_Left, typeSettingActions);
151 addMappedAction(m_typeSettingMovementMapper.data(), "svg_type_setting_move_selection_start_right_1_px", Qt::Key_Right, typeSettingActions);
152
153 m_textOutlineHelper->setDrawBoundingRect(false);
154 m_textOutlineHelper->setDrawTextWrappingArea(true);
155
156 connect(&m_textCursor, SIGNAL(selectionChanged()), this, SLOT(updateTextPathHelper()));
157
158 m_base_cursor = QCursor(QIcon(":/tool_text_basic.svg").pixmap(32), 7, 7);
159 m_text_inline_horizontal = QCursor(QIcon(":/tool_text_inline_horizontal.svg").pixmap(32), 7, 7);
160 m_text_inline_vertical = QCursor(QIcon(":/tool_text_inline_vertical.svg").pixmap(32), 7, 7);
161 m_text_on_path = QCursor(QIcon(":/tool_text_on_path.svg").pixmap(32), 7, 7);
162 m_text_in_shape = QCursor(QIcon(":/tool_text_in_shape.svg").pixmap(32), 7, 7);
163 m_ibeam_horizontal = QCursor(QIcon(":/tool_text_i_beam_horizontal.svg").pixmap(22), 11, 11);
164 m_ibeam_vertical = QCursor(QIcon(":/tool_text_i_beam_vertical.svg").pixmap(22), 11, 11);
165 m_ibeam_horizontal_done = QCursor(QIcon(":/tool_text_i_beam_horizontal_done.svg").pixmap(22), 5, 11);
166}
167
169{
170 if(m_editor) {
171 m_editor->close();
172 }
173 if(m_glyphPalette) {
174 m_glyphPalette->close();
175 }
176}
177
178void SvgTextTool::activate(const QSet<KoShape *> &shapes)
179{
180 KoToolBase::activate(shapes);
181 m_canvasConnections.addConnection(canvas()->selectedShapesProxy(), SIGNAL(selectionChanged()), this, SLOT(slotShapeSelectionChanged()));
182
183 KisCanvas2 *canvas2 = qobject_cast<KisCanvas2 *>(this->canvas());
184 if (canvas2) {
185 canvas2->setCurrentShapeManagerOwnerShape(nullptr);
187 QDockWidget *docker = canvas2->viewManager()->mainWindow()->dockWidget("TextProperties");
188 if (docker && m_optionManager) {
189 m_optionManager->setTextPropertiesOpen(docker->isVisible());
190 }
191 }
192
193 connect(m_textTypeSignalsMapper.data(), SIGNAL(mapped(int)), this, SLOT(slotConvertType(int)));
194 connect(m_typeSettingMovementMapper.data(), SIGNAL(mapped(int)), this, SLOT(slotMoveTextSelection(int)));
195
198
200}
201
203{
206 m_textCursor.setShape(nullptr);
207 const KisCanvas2 *canvas2 = qobject_cast<const KisCanvas2 *>(this->canvas());
208 if (canvas2) {
210 }
211 // Exiting text editing mode is handled by requestStrokeEnd
212 disconnect(m_textTypeSignalsMapper.data(), 0, this, 0);
213 disconnect(m_typeSettingMovementMapper.data(), 0, this, 0);
214
215 m_hoveredShapeHighlightRect = QPainterPath();
216
218}
219
221{
222 return nullptr;
223}
224
225QVariant SvgTextTool::inputMethodQuery(Qt::InputMethodQuery query) const
226{
227 if (canvas()) {
228 return m_textCursor.inputMethodQuery(query);
229 } else {
230 return KoToolBase::inputMethodQuery(query);
231 }
232}
233
234void SvgTextTool::inputMethodEvent(QInputMethodEvent *event)
235{
237 inputMethodEvent(event);
238}
239
241{
242 KisQQuickWidget *optionWidget = new KisQQuickWidget();
243 optionWidget->setMinimumWidth(100);
244 optionWidget->setMinimumHeight(100);
245
246 optionWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
247 optionWidget->setSource(QUrl("qrc:/SvgTextToolOptions.qml"));
248
249 m_optionManager->optionsModel()->setConfigName(this->toolId());
250 m_optionManager->setShowDebug(debugEnabled());
251 if (optionWidget->errors().isEmpty()) {
252 optionWidget->rootObject()->setProperty("manager", QVariant::fromValue(m_optionManager.data()));
253 optionWidget->connectMinimumHeightToRootObject();
254 } else {
255 qWarning() << optionWidget->errors();
256 }
257
258
259 connect(m_optionManager.data(), SIGNAL(openTextEditor()), SLOT(showEditor()));
260 connect(m_optionManager.data(), SIGNAL(openGlyphPalette()), SLOT(showGlyphPalette()));
261
262 connect(m_optionManager.data(), SIGNAL(convertTextType(int)), SLOT(slotConvertType(int)));
263 connect(m_optionManager.data(), SIGNAL(typeSettingModeChanged()), SLOT(slotUpdateTypeSettingMode()));
264 connect(m_optionManager->optionsModel(), SIGNAL(useVisualBidiCursorChanged(bool)), this, SLOT(slotUpdateVisualCursor()));
265 connect(m_optionManager->optionsModel(), SIGNAL(pasteRichtTextByDefaultChanged(bool)), this, SLOT(slotUpdateTextPasteBehaviour()));
266 const KisCanvas2 *canvas2 = qobject_cast<const KisCanvas2 *>(this->canvas());
267 if (canvas2 && canvas2->viewManager()->mainWindow()) {
268 QDockWidget *docker = canvas2->viewManager()->mainWindow()->dockWidget("TextProperties");
269 m_optionManager->setShowTextPropertyButton((docker));
270 if (docker) {
271 optionWidget->setPalette(docker->palette());
272 m_optionManager->setTextPropertiesOpen(docker->isVisible());
274 docker->setVisible(!docker->isVisible());
275 });
276 // Once we have docker toggling actions, we should revisit this.
277 }
278 }
282
283
284 return optionWidget;
285}
286
294
296{
298 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(canvas()->selectedShapesProxy(), 0);
299
301 if (shapes.isEmpty()) return 0;
302
303 KoSvgTextShape *textShape = dynamic_cast<KoSvgTextShape*>(shapes.first());
304
305 return textShape;
306}
307
309{
310 KoSvgTextShape *shape = selectedShape();
311 if (!shape) return;
312
313 if (!m_editor) {
314 m_editor = new SvgTextEditor(QApplication::activeWindow());
315 m_editor->setWindowTitle(i18nc("@title:window", "Krita - Edit Text"));
316 m_editor->setWindowModality(Qt::ApplicationModal);
317 m_editor->setAttribute( Qt::WA_QuitOnClose, false );
318
319 connect(m_editor, SIGNAL(textUpdated(KoSvgTextShape*,QString,QString)), SLOT(textUpdated(KoSvgTextShape*,QString,QString)));
320
321 m_editor->activateWindow(); // raise on creation only
322 }
323 if (!m_editor->isVisible()) {
324 m_editor->setInitialShape(shape);
325#ifdef Q_OS_ANDROID
326 // for window manager
327 m_editor->setWindowFlags(Qt::Dialog);
328 m_editor->menuBar()->setNativeMenuBar(false);
329#endif
330 m_editor->show();
331 }
332}
333
334void SvgTextTool::textUpdated(KoSvgTextShape *shape, const QString &svg, const QString &defs)
335{
336 SvgTextChangeCommand *cmd = new SvgTextChangeCommand(shape, svg, defs);
337 canvas()->addCommand(cmd);
338}
339
341{
342 if (!m_glyphPalette) {
343 m_glyphPalette = new GlyphPaletteDialog(QApplication::activeWindow());
344 m_glyphPalette->setAttribute( Qt::WA_QuitOnClose, false );
345
346 connect(&m_textCursor, SIGNAL(selectionChanged()), this, SLOT(updateGlyphPalette()));
347 connect(m_glyphPalette, SIGNAL(signalInsertRichText(KoSvgTextShape*, bool)), this, SLOT(insertRichText(KoSvgTextShape*, bool)));
348
349 m_glyphPalette->activateWindow();
350 }
351 if (!m_glyphPalette->isVisible()) {
352 m_glyphPalette->show();
354 }
355}
356
358{
359 if (m_glyphPalette && m_glyphPalette->isVisible()) {
360 QString grapheme = QString();
361 if (m_textCursor.shape()) {
362 int pos = m_textCursor.getPos();
363 int pos2 = pos > 0? m_textCursor.shape()->posLeft(pos, false): m_textCursor.shape()->posRight(pos, false);
364 int start = m_textCursor.shape()->indexForPos(qMin(pos, pos2));
365 int end = m_textCursor.shape()->indexForPos(qMax(pos, pos2));
366 grapheme = m_textCursor.shape()->plainText().mid(start, end-start);
367 }
368 m_glyphPalette->setGlyphModelFromProperties(m_textCursor.currentTextProperties(), grapheme);
369 }
370}
371
376
377void SvgTextTool::insertRichText(KoSvgTextShape *richText, bool replaceLastGlyph)
378{
379 if (replaceLastGlyph) {
382 }
383 m_textCursor.insertRichText(richText, true);
384}
385
387{
388 QStringList propStrings;
389 QMap<QString, QString> paraProps = properties.convertParagraphProperties();
390 for (auto it = paraProps.constBegin(); it != paraProps.constEnd(); it++) {
391 propStrings.append(QString("%1: %2;").arg(it.key()).arg(it.value()));
392 }
393 paraProps = properties.convertToSvgTextAttributes();
394 for (auto it = paraProps.constBegin(); it != paraProps.constEnd(); it++) {
395 propStrings.append(QString("%1: %2;").arg(it.key()).arg(it.value()));
396 }
397
398 return QString("<defs>\n <style>\n text {\n %1\n }\n </style>\n</defs>").arg(propStrings.join("\n "));
399}
400
402{
403 const bool useCurrent = m_optionManager->optionsModel()->useCurrentTextProperties();
404 const QString presetName = m_optionManager->optionsModel()->cssStylePresetName();
405
407 if (useCurrent || presetName.isEmpty()) {
409 props = textData.commonProperties;
410 } else {
412 QVector<KoResourceSP> res = model->resourcesForName(presetName);
413 if (res.first()) {
414 KoCssStylePresetSP style = res.first().staticCast<KoCssStylePreset>();
415 qreal dpi = 72;
416 KisCanvas2 *canvas2 = qobject_cast<KisCanvas2 *>(this->canvas());
417 if (canvas2) {
418 dpi = canvas2->image()->xRes() * 72.0;
419 }
420 if (style) {
421 props = style->properties(dpi, true);
422 }
423 }
424 }
425
426 QColor fontColor = (canvas()->resourceManager()->isUsingOtherColor()
427 ? canvas()->resourceManager()->backgroundColor()
428 : canvas()->resourceManager()->foregroundColor()).toQColor();
430 bg->setColor(fontColor);
432 props.setProperty(KoSvgTextProperties::FillId, QVariant::fromValue(bgProp));
433 return props;
434}
435
437{
439 if (shapes.size() == 1) {
440 KoSvgTextShape *textShape = selectedShape();
441 if (!textShape) {
443 return;
444 }
445 } else if (shapes.size() > 1) {
446 KoSvgTextShape *foundTextShape = nullptr;
447
448 Q_FOREACH (KoShape *shape, shapes) {
449 KoSvgTextShape *textShape = dynamic_cast<KoSvgTextShape*>(shape);
450 if (textShape) {
451 foundTextShape = textShape;
452 break;
453 }
454 }
455
457 if (foundTextShape) {
458 koSelection()->select(foundTextShape);
459 }
460 return;
461 }
462 KoSvgTextShape *const shape = selectedShape();
463 if (shape != m_textCursor.shape()) {
464 m_textCursor.setShape(shape);
466 if (shape) {
467 setTextMode(true);
468 } else {
469 setTextMode(false);
470 }
471 }
473}
474
476{
478}
479
484
486{
487 return m_textCursor.paste();
488}
489
494
501
506
511
513{
514 if (!isActivated()) return;
518 m_interactionStrategy->cancelInteraction();
519 m_interactionStrategy = nullptr;
520 useCursor(Qt::ArrowCursor);
522 }
523 }
524}
525
534
536{
537 if (canvas()) {
538 canvas()->updateCanvas(updateRect);
539 }
540}
541
543 KoSvgTextShape *shape = selectedShape();
544 if (shape) {
545 if (index == shape->textType()) return;
547 KUndo2Command *parentCommand = new KUndo2Command();
550 KoSvgConvertTextTypeCommand *cmd = new KoSvgConvertTextTypeCommand(shape, type, m_textCursor.getPos(), parentCommand);
551 parentCommand->setText(cmd->text());
555 canvas()->addCommand(parentCommand);
557 }
558}
559
561{
562 m_textCursor.setVisualMode(m_optionManager->optionsModel()->useVisualBidiCursor());
563}
564
566{
567 m_textCursor.setPasteRichTextByDefault(m_optionManager->optionsModel()->pasteRichtTextByDefault());
568}
569
571{
572 KoSvgTextShape *shape = selectedShape();
573 QActionGroup *typeConvertGroup = action("text_type_preformatted")->actionGroup();
574 if (typeConvertGroup) {
575 typeConvertGroup->setExclusive(true);
576 Q_FOREACH (QAction *a, typeConvertGroup->actions()) {
577 a->setCheckable(true);
578 }
579 }
580 if (m_optionManager) {
581 if (shape) {
582 m_optionManager->convertToTextType(int(shape->textType()));
583 if (typeConvertGroup) {
584 typeConvertGroup->setEnabled(true);
585 }
586 action("text_type_preformatted")->setChecked(shape->textType() == KoSvgTextShape::PreformattedText);
587 action("text_type_pre_positioned")->setChecked(shape->textType() == KoSvgTextShape::PrePositionedText);
588 action("text_type_inline_wrap")->setChecked(shape->textType() == KoSvgTextShape::InlineWrap);
589
590 } else {
591 m_optionManager->convertToTextType(-1);
592 if (typeConvertGroup) {
593 typeConvertGroup->setEnabled(false);
594 }
595 }
596 const bool enableTypeSetting = (m_optionManager->typeSettingMode() && shape && (shape->textType() == KoSvgTextShape::PreformattedText ||shape->textType() == KoSvgTextShape::PrePositionedText));
597 QActionGroup *svgTypeSettingGroup = action("svg_type_setting_move_selection_start_down_1_px")->actionGroup();
598 if (svgTypeSettingGroup) {
599 svgTypeSettingGroup->setEnabled(enableTypeSetting);
600 }
602 }
603}
604
606{
607 KoSvgTextShape *shape = selectedShape();
608 if (!shape) return;
609 QPointF offset;
610 // test type setting mode.
611 if (index == Qt::Key_Down) {
612 offset = QPointF(0, 1);
613 } else if (index == Qt::Key_Up) {
614 offset = QPointF(0, -1);
615 } else if (index == Qt::Key_Right) {
616 offset = QPointF(-1, 0);
617 } else if (index == Qt::Key_Left) {
618 offset = QPointF(1, 0);
619 } else {
620 return;
621 }
622 const KisCanvas2 *canvas2 = qobject_cast<const KisCanvas2 *>(this->canvas());
623 if (canvas2) {
624 offset = canvas2->coordinatesConverter()->imageToDocumentTransform().map(offset);
625 }
626 KUndo2Command *parentCommand = new KUndo2Command();
630 parentCommand->setText(cmd->text());
631 canvas()->addCommand(parentCommand);
632}
633
639
641{
643 if (!node->isEditable(true)) {
644 KisCanvas2 * kiscanvas = static_cast<KisCanvas2*>(canvas());
645 if (kiscanvas) {
646 QString message = KisToolUtils::nodeEditableMessage(node);
647 kiscanvas->viewManager()->showFloatingMessage(message, KisIconUtils::loadIcon("object-locked"));
648 }
649 return false;
650 }
651 return true;
652}
653
655{
656 QRectF rect;
657 KoSvgTextShape *const shape = selectedShape();
658 if (shape) {
659 rect |= shape->boundingRect();
660
661 const QPointF anchor = shape->absoluteTransformation().map(QPointF());
662 rect |= kisGrowRect(QRectF(anchor, anchor), handleRadius());
663
664 qreal pxlToPt = canvas()->viewConverter()->viewToDocumentX(1.0);
666
667 if (std::optional<InlineSizeInfo> info = InlineSizeInfo::fromShape(shape, length * pxlToPt)) {
668 rect |= kisGrowRect(info->boundingRect(), handleRadius() * 2);
669 }
670
671 if (canvas()->snapGuide()->isSnapping()) {
673 }
674 }
675
676 rect |= m_hoveredShapeHighlightRect.boundingRect();
677
678 rect |= m_textOutlineHelper->decorationRect();
679 rect |= m_textOnPathHelper.decorationRect(canvas()->viewConverter()->documentToView());
680
681 return rect;
682}
683
684void SvgTextTool::paint(QPainter &gc, const KoViewConverter &converter)
685{
686 if (!isActivated()) return;
687
690
692 m_interactionStrategy->paint(gc, converter, canvas()->displayRendererInterface());
693 }
694
695 KoSvgTextShape *shape = selectedShape();
696 if (shape) {
697 KisHandlePainterHelper handlePainter =
699
701 handlePainter.setHandleStyle(KisHandleStyle::primarySelection(handlePalette));
702 QPainterPath path;
703 path.addRect(shape->outlineRect());
704 handlePainter.drawPath(path);
705 }
706
707 qreal pxlToPt = canvas()->viewConverter()->viewToDocumentX(1.0);
709 if (std::optional<InlineSizeInfo> info = InlineSizeInfo::fromShape(shape, length * pxlToPt)) {
710 handlePainter.setHandleStyle(KisHandleStyle::secondarySelection(handlePalette));
711 handlePainter.drawConnectionLine(info->baselineLineLocal());
712
716 }
718 handlePainter.drawHandleLine(info->startLineLocal());
719 handlePainter.drawHandleLine(info->startLineDashes(), INLINE_SIZE_HANDLE_THICKNESS, dashPattern, INLINE_SIZE_DASHES_PATTERN_A);
720
721 handlePainter.setHandleStyle(KisHandleStyle::secondarySelection(handlePalette));
725 }
726 handlePainter.drawHandleLine(info->endLineLocal());
727 handlePainter.drawHandleLine(info->endLineDashes(), INLINE_SIZE_HANDLE_THICKNESS, dashPattern, INLINE_SIZE_DASHES_PATTERN_A);
728 }
729
731 handlePainter.setHandleStyle(KisHandleStyle::highlightedPrimaryHandles(handlePalette));
732 } else {
733 handlePainter.setHandleStyle(KisHandleStyle::primarySelection(handlePalette));
734 }
735 handlePainter.drawHandleCircle(QPointF(), KoToolBase::handleRadius() * 0.75);
736 }
737
738 m_textOutlineHelper->setDecorationThickness(decorationThickness());
739 m_textOutlineHelper->setHandleRadius(handleRadius());
740 m_textOutlineHelper->paint(&gc, converter);
743 m_textOnPathHelper.paint(&gc, converter, handlePalette);
744 gc.setTransform(converter.documentToView(), true);
745 {
747 if (!m_hoveredShapeHighlightRect.isEmpty()) {
749 QPainterPath path;
750 path.addPath(m_hoveredShapeHighlightRect);
751 handlePainter.drawPath(path);
752 }
753 }
754 if (shape) {
755 m_textCursor.paintDecorations(gc, systemPalette.color(QPalette::Highlight), decorationThickness(), handleRadius(), handlePalette);
756 }
758 gc.save();
759 canvas()->snapGuide()->paint(gc, converter, canvas()->displayRendererInterface());
760 gc.restore();
761 }
762
763 // Paint debug outline
764 if (debugEnabled() && shape) {
765 gc.save();
766 using Element = KoSvgTextShape::DebugElement;
767 KoSvgTextShape::DebugElements el{};
768 if (m_optionManager->showCharacterDebug()) {
769 el |= Element::CharBbox;
770 }
771 if (m_optionManager->showLineDebug()) {
772 el |= Element::LineBox;
773 }
774
775 gc.setTransform(shape->absoluteTransformation(), true);
776 shape->paintDebug(gc, el);
777 gc.restore();
778 }
779}
780
782{
783 // When using touch drawing, we only ever receive move events after the
784 // finger has pressed down. We have to issue an artificial move here so that
785 // the tool's state is updated properly to handle the press.
786 if (event->isTouchEvent()) {
787 mouseMoveEvent(event);
788 }
789
790 if (!nodeEditable()) {
791 event->accept();
792 return;
793 }
794
795 KisHandlePalette handlePalette;
796 KisCanvas2* kisCanvas = dynamic_cast<KisCanvas2*>(canvas());
797 if (kisCanvas) {
798 handlePalette = kisCanvas->displayColorConverter()->handlePaletteForDisplayColorSpace();
799 }
800
802
803 if (selectedShape) {
804 if (m_textOutlineHelper->contourModeButtonHovered(event->point)) {
805 m_textOutlineHelper->toggleTextContourMode(selectedShape);
806 event->accept();
807 KoToolManager::instance()->switchToolRequested("InteractionTool");
808 return;
809 }
810
813 if (handle != SvgTextCursor::NoHandle) {
818 }
819 event->accept();
820 return;
821 }
825 m_textOutlineHelper->setDrawTextWrappingArea(false);
826 event->accept();
827 return;
828 } else if (m_textOnPathHelper.hitTest(event->point, canvas()->viewConverter()->viewToDocument())) {
832 event->accept();
833 return;
837 event->accept();
838 return;
842 event->accept();
843 return;
847 event->accept();
848 return;
849 }
850 }
851
852 KoSvgTextShape *hoveredShape = dynamic_cast<KoSvgTextShape *>(canvas()->shapeManager()->shapeAt(event->point));
853 KoPathShape *hoveredFlowShape = dynamic_cast<KoPathShape *>(canvas()->shapeManager()->shapeAt(event->point));
854 QString shapeType;
855 QPainterPath hoverPath = KisToolUtils::shapeHoverInfoCrossLayer(canvas(), event->point, shapeType);
856 bool crossLayerPossible = !hoverPath.isEmpty() && shapeType == KoSvgTextShape_SHAPEID;
857
858 if (!selectedShape && !hoveredShape && !hoveredFlowShape && !crossLayerPossible) {
859 QPointF point = canvas()->snapGuide()->snap(event->point, event->modifiers());
860 m_interactionStrategy.reset(new SvgCreateTextStrategy(this, point));
862 event->accept();
863 } else if (hoveredShape) {
864 if (hoveredShape != selectedShape) {
866 canvas()->shapeManager()->selection()->select(hoveredShape);
867 m_hoveredShapeHighlightRect = QPainterPath();
868 }
869 m_interactionStrategy.reset(new SvgSelectTextStrategy(this, &m_textCursor, event->point, event->modifiers()));
871 event->accept();
872 } else if (hoveredFlowShape) {
873 QPointF point = canvas()->snapGuide()->snap(event->point, event->modifiers());
874 m_interactionStrategy.reset(new SvgCreateTextStrategy(this, point, hoveredFlowShape));
876 event->accept();
877 } else if (crossLayerPossible) {
879 m_interactionStrategy.reset(new SvgSelectTextStrategy(this, &m_textCursor, event->point, event->modifiers()));
881 m_hoveredShapeHighlightRect = QPainterPath();
882 } else {
884 }
885 event->accept();
886 } else { // if there's a selected shape but no hovered shape...
888 event->accept();
889 }
890
892}
893
894static inline Qt::CursorShape angleToCursor(const QVector2D unit)
895{
896 constexpr float SIN_PI_8 = 0.382683432;
897 if (unit.y() < SIN_PI_8 && unit.y() > -SIN_PI_8) {
898 return Qt::SizeHorCursor;
899 } else if (unit.x() < SIN_PI_8 && unit.x() > -SIN_PI_8) {
900 return Qt::SizeVerCursor;
901 } else if ((unit.x() > 0 && unit.y() > 0) || (unit.x() < 0 && unit.y() < 0)) {
902 return Qt::SizeFDiagCursor;
903 } else {
904 return Qt::SizeBDiagCursor;
905 }
906}
907
908static inline Qt::CursorShape lineToCursor(const QLineF line, const KoCanvasBase *const canvas)
909{
910 const KisCanvas2 *const canvas2 = qobject_cast<const KisCanvas2 *>(canvas);
911 KIS_ASSERT(canvas2);
912 const KisCoordinatesConverter *const converter = canvas2->coordinatesConverter();
913 QLineF wdgLine = converter->flakeToWidget(line);
914 return angleToCursor(QVector2D(wdgLine.p2() - wdgLine.p1()).normalized());
915}
916
918{
919 m_lastMousePos = event->point;
920 m_hoveredShapeHighlightRect = QPainterPath();
922
924 m_interactionStrategy->handleMouseMove(event->point, event->modifiers());
927 if (c && c->draggingInlineSize() && !c->hasWrappingShape()) {
928 if (this->writingMode() == KoSvgText::HorizontalTB) {
930 } else {
932 }
933 } else {
935 }
936 } else if (m_dragging == DragMode::Select && this->selectedShape()) {
938 // Todo: replace with something a little less hacky.
939 if (selectedShape->writingMode() == KoSvgText::HorizontalTB) {
941 } else {
943 }
944 } else if (m_dragging != DragMode::InShapeOffset) {
945 useCursor(Qt::ArrowCursor);
946 }
947 event->accept();
948 } else {
950
952 QCursor cursor = m_base_cursor;
953 if (selectedShape) {
955 const qreal sensitivity = grabSensitivityInPt();
956
959 if (handle != SvgTextCursor::NoHandle) {
962 }
963
965 if (std::optional<InlineSizeInfo> info = InlineSizeInfo::fromShape(selectedShape)) {
966 const QPolygonF zone = info->endLineGrabRect(sensitivity);
967 const QPolygonF startZone = info->startLineGrabRect(sensitivity);
968 if (zone.containsPoint(event->point, Qt::OddEvenFill)) {
970 cursor = lineToCursor(info->baselineLine(), canvas());
971 } else if (startZone.containsPoint(event->point, Qt::OddEvenFill)){
973 cursor = lineToCursor(info->baselineLine(), canvas());
974 }
975 }
976 }
977
979 const QPolygonF textOutline = selectedShape->absoluteTransformation().map(selectedShape->outlineRect());
980 const QPolygonF moveBorderRegion = selectedShape->absoluteTransformation().map(kisGrowRect(selectedShape->outlineRect(),
981 sensitivity * 2));
982 if (moveBorderRegion.containsPoint(event->point, Qt::OddEvenFill) && !textOutline.containsPoint(event->point, Qt::OddEvenFill)) {
984 cursor = Qt::SizeAllCursor;
985 }
986 }
987 }
988
989 QString shapeType;
990 bool isHorizontal = true;
991 const KoSvgTextShape *hoveredShape = dynamic_cast<KoSvgTextShape *>(canvas()->shapeManager()->shapeAt(event->point));
992 const KoPathShape *hoveredFlowShape = dynamic_cast<KoPathShape *>(canvas()->shapeManager()->shapeAt(event->point));
993 QPainterPath hoverPath = KisToolUtils::shapeHoverInfoCrossLayer(canvas(), event->point, shapeType, &isHorizontal);
994
995 bool textAreasHovered = false;
996 if (m_textOnPathHelper.hitTest(event->point, canvas()->viewConverter()->viewToDocument()) ) {
997 cursor = Qt::ArrowCursor;
998 } else if(std::optional<QPointF> offsetVector = SvgChangeTextPaddingMarginStrategy::hitTest(selectedShape, event->point, grabSensitivityInPt())) {
999 cursor = lineToCursor(QLineF(QPointF(0, 0), offsetVector.value()).normalVector(), canvas());
1000 textAreasHovered = true;
1001 } else if (selectedShape && selectedShape == hoveredShape && m_highlightItem == HighlightItem::None) {
1004 } else {
1006 }
1007 } else if (hoveredShape && m_highlightItem == HighlightItem::None) {
1008 if (!hoveredShape->textWrappingAreas().isEmpty()) {
1009 Q_FOREACH(QPainterPath path, hoveredShape->textWrappingAreas()) {
1010 m_hoveredShapeHighlightRect.addPath(hoveredShape->absoluteTransformation().map(path));
1011 }
1012 } else {
1013 m_hoveredShapeHighlightRect.addRect(hoveredShape->boundingRect());
1014 }
1015 if (hoveredShape->writingMode() == KoSvgText::HorizontalTB) {
1017 } else {
1019 }
1020 } else if (hoveredFlowShape) {
1021 m_hoveredShapeHighlightRect.addPath(hoveredFlowShape->absoluteTransformation().map(hoveredFlowShape->outline()));
1022 if (hoveredFlowShape->segmentAtPoint(event->point, handleGrabRect(event->point)).isValid()) {
1024 } else {
1026 }
1027 } else if (!hoverPath.isEmpty() && shapeType == KoSvgTextShape_SHAPEID && m_highlightItem == HighlightItem::None) {
1028 m_hoveredShapeHighlightRect = hoverPath;
1029 if (isHorizontal) {
1031 } else {
1033 }
1034 }
1035 m_textOutlineHelper->setTextAreasHovered(textAreasHovered);
1037 event->ignore();
1038 }
1039
1041}
1042
1044{
1046 m_interactionStrategy->finishInteraction(event->modifiers());
1047 KUndo2Command *const command = m_interactionStrategy->createCommand();
1048 if (command) {
1050 canvas()->addCommand(command);
1052 }
1053 m_interactionStrategy = nullptr;
1056 }
1058 m_textOutlineHelper->setDrawTextWrappingArea(true);
1061 event->accept();
1062 } else {
1064 }
1065 event->accept();
1066}
1067
1068void SvgTextTool::keyPressEvent(QKeyEvent *event)
1069{
1071 && (event->key() == Qt::Key_Control || event->key() == Qt::Key_Alt || event->key() == Qt::Key_Shift
1072 || event->key() == Qt::Key_Meta)) {
1073 m_interactionStrategy->handleMouseMove(m_lastMousePos, event->modifiers());
1074 event->accept();
1075 return;
1076 } else if (event->key() == Qt::Key_Escape) {
1078 } else if (selectedShape()) {
1080 }
1081
1082 event->ignore();
1083}
1084
1085void SvgTextTool::keyReleaseEvent(QKeyEvent *event)
1086{
1087 m_textCursor.updateModifiers(event->modifiers());
1089 && (event->key() == Qt::Key_Control || event->key() == Qt::Key_Alt || event->key() == Qt::Key_Shift
1090 || event->key() == Qt::Key_Meta)) {
1091 m_interactionStrategy->handleMouseMove(m_lastMousePos, event->modifiers());
1092 event->accept();
1093 } else {
1094 event->ignore();
1095 }
1096}
1097
1098void SvgTextTool::focusInEvent(QFocusEvent *event)
1099{
1101 event->accept();
1102}
1103
1104void SvgTextTool::focusOutEvent(QFocusEvent *event)
1105{
1107 event->accept();
1108}
1109
1111{
1112 if (canvas()->shapeManager()->shapeAt(event->point) != selectedShape()) {
1113 event->ignore(); // allow the event to be used by another
1114 return;
1115 } else {
1116 m_textCursor.setPosToPoint(event->point, true);
1119 }
1120 const QRectF updateRect = std::exchange(m_hoveredShapeHighlightRect, QPainterPath()).boundingRect();
1121 canvas()->updateCanvas(kisGrowRect(updateRect, 100));
1122 event->accept();
1123}
1124
1126{
1127 if (canvas()->shapeManager()->shapeAt(event->point) == selectedShape()) {
1128 // TODO: Consider whether we want to use sentence based selection instead:
1129 // QTextBoundaryFinder allows us to find sentences if necessary.
1132 event->accept();
1133 }
1134}
1135
1137{
1138 const int sensitivity = grabSensitivity();
1139 return canvas()->viewConverter()->viewToDocumentX(sensitivity);
1140}
1141
1147
1148void SvgTextTool::addMappedAction(KisSignalMapper *mapper, const QString &actionName, const int value, QActionGroup *group)
1149{
1150 QAction *a = action(actionName);
1151 if (a) {
1152 connect(a, SIGNAL(triggered()), mapper, SLOT(map()));
1153 mapper->setMapping(a, value);
1154 m_textCursor.registerPropertyAction(a, actionName);
1155 if (group && !a->actionGroup()) {
1156 group->addAction(a);
1157 }
1158 }
1159}
1160
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
float value(const T *src, size_t ch)
#define KoSvgTextShape_SHAPEID
constexpr double INLINE_SIZE_DASHES_PATTERN_A
static Qt::CursorShape lineToCursor(const QLineF line, const KoCanvasBase *const canvas)
constexpr int INLINE_SIZE_DASHES_PATTERN_LENGTH
Size of the hidden part of the inline-size handle dashes.
constexpr double INLINE_SIZE_HANDLE_THICKNESS
Total amount of trailing dashes on inline-size handles.
constexpr double INLINE_SIZE_DASHES_PATTERN_B
Size of the visible part of the inline-size handle dashes.
static Qt::CursorShape angleToCursor(const QVector2D unit)
static bool debugEnabled()
Linethickness.
The GlyphPaletteDialog class.
void setText(const KUndo2MagicString &text)
The KisAllresourcesModel class provides access to the cache database for a particular resource type....
QVector< KoResourceSP > resourcesForName(const QString &name) const
KisDisplayColorConverter displayColorConverter
KisCoordinatesConverter * coordinatesConverter
void setCurrentShapeManagerOwnerShape(KoShape *source) override
sets the group shape that is supposed to be "entered"
KisImageWSP image() const
KisViewManager * viewManager() const
_Private::Traits< T >::Result flakeToWidget(const T &obj) const
KisHandlePalette handlePaletteForDisplayColorSpace() const
handlePaletteForDisplayColorSpace
The KisHandlePainterHelper class is a special helper for painting handles around objects....
void drawPath(const QPainterPath &path)
void drawConnectionLine(const QLineF &line)
void setHandleStyle(const KisHandleStyle &style)
void drawHandleLine(const QLineF &line, qreal width=1.0, QVector< qreal > dashPattern={}, qreal dashOffset=0.0)
void drawHandleCircle(const QPointF &center, qreal radius)
static KisHandleStyle & partiallyHighlightedPrimaryHandles(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & highlightedPrimaryHandlesWithSolidOutline(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & secondarySelection(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & primarySelection(KisHandlePalette palette=KisHandlePalette())
static KisHandleStyle & highlightedPrimaryHandles(KisHandlePalette palette=KisHandlePalette())
double xRes() const
QDockWidget * dockWidget(const QString &id)
The PopupWidgetInterface abstract class defines the basic interface that will be used by all popup wi...
The KisQQuickWidget class.
void connectMinimumHeightToRootObject()
connectMinimumHeightToRootObject By default we scale rootObject to widget, but in some situations we ...
static KisAllResourcesModel * resourceModel(const QString &resourceType)
void addConnection(Sender sender, Signal signal, Receiver receiver, Method method, Qt::ConnectionType type=Qt::AutoConnection)
The KisSignalMapper class bundles signals from identifiable senders.
void setMapping(QObject *sender, int id)
void setTextPropertiesInterface(KoSvgTextPropertiesInterface *interface)
setTextPropertiesInterface set the text properties interface. This should be done on tool activation....
KisMainWindow * mainWindow() const
KisTextPropertiesManager * textPropertyManager() const
void showFloatingMessage(const QString &message, const QIcon &icon, int timeout=4500, KisFloatingMessage::Priority priority=KisFloatingMessage::Medium, int alignment=Qt::AlignCenter|Qt::TextWordWrap)
shows a floating message in the top right corner of the canvas
KoSnapGuide * snapGuide
virtual KoShapeManager * shapeManager() const =0
virtual const KoViewConverter * viewConverter() const =0
virtual void updateCanvas(const QRectF &rc)=0
virtual KoColorDisplayRendererInterface * displayRendererInterface() const
displayRendererInterface The display renderer interface has a number of color conversion functions wh...
virtual void addCommand(KUndo2Command *command)=0
QPointer< KoCanvasResourceProvider > resourceManager
virtual KoSelectedShapesProxy * selectedShapesProxy() const =0
selectedShapesProxy() is a special interface for keeping a persistent connections to selectionChanged...
A simple solid color shape background.
virtual KisHandlePalette handlePaletteForDisplayColorSpace() const =0
handlePaletteForDisplayColorSpace
virtual QPalette systemPaletteForDisplayColorSpace() const =0
systemPaletteForDisplayColorSpace
The KoCssStylePreset class.
bool isValid() const
Returns if segment is valid, e.g. has two valid points.
The position of a path point within a path shape.
Definition KoPathShape.h:63
KoPathSegment segmentAtPoint(const QPointF &point, const QRectF &grabRoi) const
QPainterPath outline() const override
reimplemented
bool isTouchEvent() const
Qt::KeyboardModifiers modifiers() const
QPointF point
The point in document coordinates.
virtual KoSelection * selection()=0
void deselectAll()
clear the selections list
void select(KoShape *shape)
const QList< KoShape * > selectedEditableShapes() const
KoShape * shapeAt(const QPointF &position, KoFlake::ShapeSelection selection=KoFlake::ShapeOnTop, bool omitHiddenShapes=true)
KoSelection * selection
QTransform absoluteTransformation() const
Definition KoShape.cpp:330
static KisHandlePainterHelper createHandlePainterHelperView(QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius=0.0, int decorationThickness=1)
Definition KoShape.cpp:977
void paint(QPainter &painter, const KoViewConverter &converter, const KoColorDisplayRendererInterface *displayRenderer)
paints the guide
QPointF snap(const QPointF &mousePosition, Qt::KeyboardModifiers modifiers)
snaps the mouse position, returns if mouse was snapped
QRectF boundingRect()
returns the bounding rect of the guide
The SvgConvertTextTypeCommand class This command allows textshapes to be converted between preformatt...
@ FillId
KoSvgText::BackgroundProperty.
@ WritingModeId
KoSvgText::WritingMode.
QMap< QString, QString > convertToSvgTextAttributes() const
QMap< QString, QString > convertParagraphProperties() const
convertParagraphProperties some properties only apply to the root shape, so we write those separately...
void setProperty(PropertyId id, const QVariant &value)
QVariant propertyOrDefault(PropertyId id) const
static void removeContourShapesFromFlow(KoSvgTextShape *textShape, KUndo2Command *parent, bool textInShape, bool textPaths)
removeContourShapesFromFlow Create a command to remove all contour shapes of a certain type from the ...
The KoSvgTextShapeOutlineHelper class helper class that draws the text outlines and contour mode butt...
int posLeft(int pos, bool visual=false)
QRectF boundingRect() const override
Get the bounding box of the shape.
QList< QPainterPath > textWrappingAreas() const
textWrappingAreas The text wrapping areas are computed from shapesInside() and shapesSubtract(),...
int indexForPos(int pos) const
indexForPos get the string index for a given cursor position.
@ PreformattedText
Text-on-Path falls under this or PrePositionedText depending on collapse of lines.
@ TextInShape
Uses shape-inside to wrap and preserves spaces.
@ InlineWrap
Uses inline size to wrap and preserves spaces.
TextType textType() const
textType This enum gives an indication of what kind of text this shape is. The different text types a...
int posRight(int pos, bool visual=false)
void paintDebug(QPainter &painter, DebugElements elements) const
KoSvgText::WritingMode writingMode() const
writingMode There's a number of places we need to check the writing mode to provide proper controls.
QRectF outlineRect() const override
KoCanvasBase * canvas() const
Returns the canvas the tool is working on.
void selectionChanged(bool hasSelection)
Q_INVOKABLE QString toolId() const
QCursor cursor() const
return the last emitted cursor
int grabSensitivity() const
Convenience function to get the current grab sensitivity.
void setTextMode(bool value)
virtual void repaintDecorations()
int handleRadius() const
Convenience function to get the current handle radius.
void useCursor(const QCursor &cursor)
virtual void activate(const QSet< KoShape * > &shapes)
QRectF handleGrabRect(const QPointF &position) const
virtual void deactivate()
QAction * action(const QString &name) const
bool isActivated() const
virtual QVariant inputMethodQuery(Qt::InputMethodQuery query) const
int decorationThickness() const
decorationThickness The minimum thickness for tool decoration lines, this is derived from the screen ...
void switchToolRequested(const QString &id)
static KoToolManager * instance()
Return the toolmanager singleton.
virtual qreal viewToDocumentX(qreal viewX) const
virtual QPointF documentToView(const QPointF &documentPoint) const
static std::optional< QPointF > hitTest(KoSvgTextShape *shape, const QPointF &mousePos, const qreal grabSensitivityInPts)
hitTest Tests whether the current mouse position is over a text wrapping area, and if so,...
QRectF decorationRect(const QTransform documentToView) const
decorationRect
void setShape(KoSvgTextShape *shape)
setShape Set the shape for which to draw the text path.
bool hitTest(QPointF mouseInPts, const QTransform viewToDocument)
hitTest
void setPos(int pos)
setPos the the position of the cursor, where the text path is sought. A single text shape can have mu...
void paint(QPainter *painter, const KoViewConverter &converter, KisHandlePalette handlePalette)
paint Paint the handles for the text path.
static QStringList possibleActions()
The SvgTextToolOptionsManager class.
void openTextPropertiesDocker(bool open)
void activate(const QSet< KoShape * > &shapes) override
reimplemented from KoToolBase
void mouseTripleClickEvent(KoPointerEvent *event) override
reimplemented from KoToolBase
void copy() const override
reimplemented from superclass
bool selectAll() override
selectAll select all data the tool can select.
KisSignalAutoConnectionsStore m_canvasConnections
~SvgTextTool() override
void requestStrokeCancellation() override
void inputMethodEvent(QInputMethodEvent *event) override
QScopedPointer< KisSignalMapper > m_textTypeSignalsMapper
void mouseMoveEvent(KoPointerEvent *event) override
reimplemented from KoToolBase
std::unique_ptr< KoInteractionStrategy > m_interactionStrategy
void keyPressEvent(QKeyEvent *event) override
void requestStrokeEnd() override
void slotTextTypeUpdated()
slotTextTypeUpdated Update the text type in the tool options.
QPointer< GlyphPaletteDialog > m_glyphPalette
QScopedPointer< SvgTextToolOptionsManager > m_optionManager
bool nodeEditable()
nodeEditable
QCursor m_base_cursor
KoSelection * koSelection() const
DragMode m_dragging
void mouseReleaseEvent(KoPointerEvent *event) override
reimplemented from KoToolBase
void slotUpdateVisualCursor()
slotUpdateVisualCursor update the visual cursor mode on the text cursor.
QString generateDefs(const KoSvgTextProperties &properties=KoSvgTextProperties())
generateDefs This generates a defs section with the appropriate css and css strings assigned.
qreal grabSensitivityInPt() const
void deleteSelection() override
reimplemented from superclass
QCursor m_text_inline_horizontal
QCursor m_ibeam_horizontal
KoSvgTextShape * selectedShape() const
QPointF m_lastMousePos
QCursor m_ibeam_horizontal_done
SvgTextTool(KoCanvasBase *canvas)
QVariant inputMethodQuery(Qt::InputMethodQuery query) const override
void slotShapeSelectionChanged()
selectionChanged called when the canvas selection is changed.
void showGlyphPalette()
showGlyphPalette Shows the glyph palette dialog.
QCursor m_text_inline_vertical
QPainterPath m_hoveredShapeHighlightRect
void focusInEvent(QFocusEvent *event) override
bool hasSelection() override
reimplemented from superclass
SvgTextOnPathDecorationHelper m_textOnPathHelper
KoSvgTextProperties propertiesForNewText() const
propertiesForNewText get the text properties that should be used for new text.
void updateGlyphPalette()
updateGlyphPalette update the glyph palette dialog from the current selection.
void mouseDoubleClickEvent(KoPointerEvent *event) override
reimplemented from superclass
bool m_strategyAddingCommand
KisPopupWidgetInterface * popupWidget() override
HighlightItem m_highlightItem
void focusOutEvent(QFocusEvent *event) override
void updateTextPathHelper()
KoToolSelection * selection() override
reimplemented from superclass
void slotUpdateTextPasteBehaviour()
slotUpdateTextPasteBehaviour update the default text paste behaviour.
void deselect() override
deselect the tool should clear the selection if it has one.
QCursor m_ibeam_vertical
virtual QWidget * createOptionWidget() override
reimplemented from KoToolBase
void insertRichText(KoSvgTextShape *richText, bool replaceLastGlyph=false)
insertRichText Insert a rich text shape, used by the glyph palette..
QCursor m_text_in_shape
void textUpdated(KoSvgTextShape *shape, const QString &svg, const QString &defs)
void deactivate() override
reimplemented from KoToolBase
void mousePressEvent(KoPointerEvent *event) override
reimplemented from KoToolBase
void slotUpdateCursorDecoration(QRectF updateRect)
updateCursor update the canvas decorations in a particular update rect for the text cursor.
QCursor m_text_on_path
void showEditor()
friend class SvgChangeTextPathInfoStrategy
Definition SvgTextTool.h:40
friend class SvgCreateTextStrategy
Definition SvgTextTool.h:39
QScopedPointer< KisSignalMapper > m_typeSettingMovementMapper
void slotMoveTextSelection(int index)
slotMoveTextSelection Move the start of the selection in typesetting mode by image 1 pix.
void paint(QPainter &gc, const KoViewConverter &converter) override
reimplemented from KoToolBase
SvgTextCursor m_textCursor
KoSvgText::WritingMode writingMode() const
QScopedPointer< KoSvgTextShapeOutlineHelper > m_textOutlineHelper
QRectF decorationsRect() const override
reimplemented from KoToolBase
bool paste() override
reimplemented from superclass
void slotUpdateTypeSettingMode()
slotUpdateTypeSettingMode Enable typesetting mode from the tool options.
void slotConvertType(int index)
slotConvertType
void addMappedAction(KisSignalMapper *mapper, const QString &actionName, const int value, QActionGroup *group=nullptr)
QPointer< SvgTextEditor > m_editor
void keyReleaseEvent(QKeyEvent *event) override
The SvgTextTypeSettingStrategy class This class encompasses the typesetting mode.
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
#define dbgTools
Definition kis_debug.h:48
T kisGrowRect(const T &rect, U offset)
Definition kis_global.h:186
QIcon loadIcon(const QString &name)
bool selectShapeCrossLayer(KoCanvasBase *canvas, const QPointF &point, const QString &shapeType, bool skipCurrentShapes)
selectShapeCrossLayer Tries to select a shape under the cursor regardless of which layer it is on,...
QString nodeEditableMessage(KisNodeSP node, bool blockedNoIndirectPainting)
nodeEditableMessage
QPainterPath shapeHoverInfoCrossLayer(KoCanvasBase *canvas, const QPointF &point, QString &shapeType, bool *isHorizontal, bool skipCurrentShapes)
shapeHoverInfoCrossLayer get hover info of shapes on all layers.
@ SvgTextPropertyData
KoSvgTextPropertyDataStruct.
@ HorizontalTB
Definition KoSvgText.h:38
const QString CssStyles
bool isEditable(bool checkVisibility=true) const
The KoSvgTextPropertyData struct.
KoSvgTextProperties commonProperties
The properties common between all the selected text.
BackgroundProperty is a special wrapper around KoShapeBackground for managing it in KoSvgTextProperti...
Definition KoSvgText.h:714
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()
int getAnchor()
Get the current selection anchor. This is the same as position, unless there's a selection.
QPair< KoSvgTextProperties, KoSvgTextProperties > currentTextProperties() const
currentTextProperties
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.
TypeSettingModeHandle
Handles used by type setting mode.
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
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.
bool setDominantBaselineFromHandle(const TypeSettingModeHandle handle)
setDominantBaselineFromHandle Set the dominant baseline from a given handle.
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.
TypeSettingModeHandle typeSettingHandleAtPos(const QRectF regionOfInterest)
Get typeSettingMode handle for text;.
bool registerPropertyAction(QAction *action, const QString &name)
Register an action.
void focusIn()
Turns on blinking cursor.
void setDrawTypeSettingHandle(bool draw)
bool paste()
paste pastes plain text in the clipboard at pos. Uses pasteRichTextByDefault to determine whether to ...
void updateTypeSettingDecorFromShape()
Update the type setting decorations.
void updateModifiers(const Qt::KeyboardModifiers modifiers)
void setShape(KoSvgTextShape *textShape)
setShape
void insertRichText(KoSvgTextShape *insert, bool inheritPropertiesIfPossible=false)
Insert rich text at getPos();.
KoSvgTextShape * shape
void copy() const
copy copies plain text into the clipboard between anchor and pos.