31#include <QPainterPath>
32#include <QDesktopServices>
33#include <QApplication>
37#include <QActionGroup>
39#include <klocalizedstring.h>
43#include <KSharedConfig>
97 static const bool debugEnabled = !qEnvironmentVariableIsEmpty(
"KRITA_DEBUG_TEXTTOOL");
104 , m_textCursor(canvas)
108 const int cursorFlashLimit = 5000;
109 const bool enableCursorWithSelection = QApplication::style()->styleHint(QStyle::SH_BlinkCursorWhenTextSelected);
111 , qApp->cursorFlashTime()
113 , enableCursorWithSelection);
117 QAction *a =
action(name);
119 dbgTools <<
"registered" << name << a->shortcut();
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"
131 Q_FOREACH (
const QString name, extraActions) {
132 QAction *a =
action(name);
135 qWarning() <<
"could not register" << name << a->shortcut();
141 QActionGroup *textTypeActions =
new QActionGroup(
this);
147 QActionGroup *typeSettingActions =
new QActionGroup(
this);
158 m_base_cursor = QCursor(QIcon(
":/tool_text_basic.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);
207 const KisCanvas2 *canvas2 = qobject_cast<const KisCanvas2 *>(this->
canvas());
243 optionWidget->setMinimumWidth(100);
244 optionWidget->setMinimumHeight(100);
246 optionWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
247 optionWidget->setSource(QUrl(
"qrc:/SvgTextToolOptions.qml"));
251 if (optionWidget->errors().isEmpty()) {
252 optionWidget->rootObject()->setProperty(
"manager", QVariant::fromValue(
m_optionManager.data()));
255 qWarning() << optionWidget->errors();
266 const KisCanvas2 *canvas2 = qobject_cast<const KisCanvas2 *>(this->
canvas());
271 optionWidget->setPalette(docker->palette());
274 docker->setVisible(!docker->isVisible());
301 if (shapes.isEmpty())
return 0;
315 m_editor->setWindowTitle(i18nc(
"@title:window",
"Krita - Edit Text"));
316 m_editor->setWindowModality(Qt::ApplicationModal);
317 m_editor->setAttribute( Qt::WA_QuitOnClose,
false );
327 m_editor->setWindowFlags(Qt::Dialog);
328 m_editor->menuBar()->setNativeMenuBar(
false);
360 QString grapheme = QString();
379 if (replaceLastGlyph) {
390 for (
auto it = paraProps.constBegin(); it != paraProps.constEnd(); it++) {
391 propStrings.append(QString(
"%1: %2;").arg(it.key()).arg(it.value()));
394 for (
auto it = paraProps.constBegin(); it != paraProps.constEnd(); it++) {
395 propStrings.append(QString(
"%1: %2;").arg(it.key()).arg(it.value()));
398 return QString(
"<defs>\n <style>\n text {\n %1\n }\n </style>\n</defs>").arg(propStrings.join(
"\n "));
403 const bool useCurrent =
m_optionManager->optionsModel()->useCurrentTextProperties();
404 const QString presetName =
m_optionManager->optionsModel()->cssStylePresetName();
407 if (useCurrent || presetName.isEmpty()) {
421 props = style->properties(dpi,
true);
430 bg->setColor(fontColor);
439 if (shapes.size() == 1) {
445 }
else if (shapes.size() > 1) {
448 Q_FOREACH (
KoShape *shape, shapes) {
451 foundTextShape = textShape;
457 if (foundTextShape) {
545 if (index == shape->
textType())
return;
551 parentCommand->
setText(cmd->text());
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);
583 if (typeConvertGroup) {
584 typeConvertGroup->setEnabled(
true);
592 if (typeConvertGroup) {
593 typeConvertGroup->setEnabled(
false);
597 QActionGroup *svgTypeSettingGroup =
action(
"svg_type_setting_move_selection_start_down_1_px")->actionGroup();
598 if (svgTypeSettingGroup) {
599 svgTypeSettingGroup->setEnabled(enableTypeSetting);
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);
622 const KisCanvas2 *canvas2 = qobject_cast<const KisCanvas2 *>(this->
canvas());
630 parentCommand->
setText(cmd->text());
667 if (std::optional<InlineSizeInfo> info = InlineSizeInfo::fromShape(shape,
length * pxlToPt)) {
671 if (
canvas()->snapGuide()->isSnapping()) {
709 if (std::optional<InlineSizeInfo> info = InlineSizeInfo::fromShape(shape,
length * pxlToPt)) {
767 KoSvgTextShape::DebugElements el{};
769 el |= Element::CharBbox;
772 el |= Element::LineBox;
858 if (!
selectedShape && !hoveredShape && !hoveredFlowShape && !crossLayerPossible) {
863 }
else if (hoveredShape) {
872 }
else if (hoveredFlowShape) {
877 }
else if (crossLayerPossible) {
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;
904 return Qt::SizeBDiagCursor;
910 const KisCanvas2 *
const canvas2 = qobject_cast<const KisCanvas2 *>(canvas);
914 return angleToCursor(QVector2D(wdgLine.p2() - wdgLine.p1()).normalized());
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)) {
971 }
else if (startZone.containsPoint(event->
point, Qt::OddEvenFill)){
982 if (moveBorderRegion.containsPoint(event->
point, Qt::OddEvenFill) && !textOutline.containsPoint(event->
point, Qt::OddEvenFill)) {
984 cursor = Qt::SizeAllCursor;
990 bool isHorizontal =
true;
995 bool textAreasHovered =
false;
1000 textAreasHovered =
true;
1020 }
else if (hoveredFlowShape) {
1071 && (event->key() == Qt::Key_Control || event->key() == Qt::Key_Alt || event->key() == Qt::Key_Shift
1072 || event->key() == Qt::Key_Meta)) {
1076 }
else if (event->key() == Qt::Key_Escape) {
1089 && (event->key() == Qt::Key_Control || event->key() == Qt::Key_Alt || event->key() == Qt::Key_Shift
1090 || event->key() == Qt::Key_Meta)) {
1150 QAction *a =
action(actionName);
1152 connect(a, SIGNAL(triggered()), mapper, SLOT(map()));
1155 if (group && !a->actionGroup()) {
1156 group->addAction(a);
qreal length(const QPointF &vec)
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
QTransform imageToDocumentTransform() 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 ¢er, 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())
QDockWidget * dockWidget(const QString &id)
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
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.
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)
QTransform absoluteTransformation() const
static KisHandlePainterHelper createHandlePainterHelperView(QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius=0.0, int decorationThickness=1)
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
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,...
bool draggingInlineSize()
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 setStrategyActive(bool isActive)
void setHandleRadius(qreal radius)
void setDecorationThickness(qreal thickness)
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
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
KoSelection * koSelection() const
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
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.
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..
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.
friend class SvgChangeTextPathInfoStrategy
friend class SvgCreateTextStrategy
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)
T kisGrowRect(const T &rect, U offset)
QIcon loadIcon(const QString &name)
@ SvgTextPropertyData
KoSvgTextPropertyDataStruct.
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...
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();.
void copy() const
copy copies plain text into the clipboard between anchor and pos.