File indexing completed on 2024-06-09 04:28:39
0001 /* 0002 * SPDX-FileCopyrightText: 2023 Alvin Wong <alvin@alvinhc.com> 0003 * 0004 * SPDX-License-Identifier: GPL-3.0-or-later 0005 */ 0006 0007 #include "SvgCreateTextStrategy.h" 0008 #include "SvgTextTool.h" 0009 0010 #include <QFontDatabase> 0011 #include <QRectF> 0012 #include <QTimer> 0013 0014 #include "KisHandlePainterHelper.h" 0015 #include "KoCanvasBase.h" 0016 #include "KoProperties.h" 0017 #include "KoSelection.h" 0018 #include "KoShapeController.h" 0019 #include "KoShapeFactoryBase.h" 0020 #include "KoShapeRegistry.h" 0021 #include "KoToolBase.h" 0022 #include "KoViewConverter.h" 0023 #include "KoSnapGuide.h" 0024 #include "commands/KoKeepShapesSelectedCommand.h" 0025 #include "kis_global.h" 0026 #include "kundo2command.h" 0027 0028 SvgCreateTextStrategy::SvgCreateTextStrategy(SvgTextTool *tool, const QPointF &clicked) 0029 : KoInteractionStrategy(tool) 0030 , m_dragStart(clicked) 0031 , m_dragEnd(clicked) 0032 { 0033 const QFontMetrics fontMetrics = QFontMetrics(tool->defaultFont()); 0034 double lineHeight = (fontMetrics.lineSpacing() / fontMetrics.fontDpi()) * 72.0; 0035 m_minSizeInline = {lineHeight, lineHeight}; 0036 } 0037 0038 void SvgCreateTextStrategy::paint(QPainter &painter, const KoViewConverter &converter) 0039 { 0040 const QTransform originalPainterTransform = painter.transform(); 0041 painter.setTransform(converter.documentToView(), true); 0042 KisHandlePainterHelper handlePainter(&painter, originalPainterTransform, 0.0, decorationThickness()); 0043 0044 const QPolygonF poly(QRectF(m_dragStart, m_dragEnd)); 0045 handlePainter.setHandleStyle(KisHandleStyle::primarySelection()); 0046 handlePainter.drawRubberLine(poly); 0047 } 0048 0049 void SvgCreateTextStrategy::handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers) 0050 { 0051 m_dragEnd = this->tool()->canvas()->snapGuide()->snap(mouseLocation, modifiers); 0052 m_modifiers = modifiers; 0053 const QRectF updateRect = QRectF(m_dragStart, m_dragEnd).normalized(); 0054 tool()->canvas()->updateCanvas(kisGrowRect(updateRect, 100)); 0055 } 0056 0057 KUndo2Command *SvgCreateTextStrategy::createCommand() 0058 { 0059 SvgTextTool *const tool = qobject_cast<SvgTextTool *>(this->tool()); 0060 0061 QRectF rectangle = QRectF(m_dragStart, m_dragEnd).normalized(); 0062 0063 const QFontMetrics fontMetrics = QFontMetrics(tool->defaultFont()); 0064 double ascender = fontMetrics.ascent(); 0065 ascender += fontMetrics.leading()/2; 0066 ascender = (ascender / fontMetrics.fontDpi()) * 72.0; // 72 points in an inch. 0067 double lineHeight = (fontMetrics.lineSpacing() / fontMetrics.fontDpi()) * 72.0; 0068 const KoSvgText::WritingMode writingMode = KoSvgText::WritingMode(tool->writingMode()); 0069 0070 bool unwrappedText = m_modifiers.testFlag(Qt::ControlModifier); 0071 if (rectangle.width() < m_minSizeInline.width() && rectangle.height() < m_minSizeInline.height()) { 0072 unwrappedText = true; 0073 } 0074 QString extraProperties; 0075 if (!unwrappedText) { 0076 if (writingMode == KoSvgText::HorizontalTB) { 0077 extraProperties = QLatin1String("inline-size:%1;").arg(QString::number(rectangle.width())); 0078 } else { 0079 extraProperties = QLatin1String("inline-size:%1;").arg(QString::number(rectangle.height())); 0080 } 0081 } 0082 KoShapeFactoryBase *factory = KoShapeRegistry::instance()->value("KoSvgTextShapeID"); 0083 KoProperties *params = new KoProperties();//Fill these with "svgText", "defs" and "shapeRect" 0084 params->setProperty("defs", QVariant(tool->generateDefs(extraProperties))); 0085 0086 QPointF origin = rectangle.topLeft(); 0087 0088 { 0089 const Qt::Alignment halign = tool->horizontalAlign(); 0090 const bool isRtl = tool->isRtl(); 0091 0092 if (writingMode == KoSvgText::HorizontalTB) { 0093 origin.setY(rectangle.top() + ascender); 0094 if (halign & Qt::AlignCenter) { 0095 origin.setX(rectangle.center().x()); 0096 } else if ((halign & Qt::AlignRight && !isRtl) || (halign & Qt::AlignLeft && isRtl)) { 0097 origin.setX(rectangle.right()); 0098 } 0099 } else { 0100 if (writingMode == KoSvgText::VerticalRL) { 0101 origin.setX(rectangle.right() - (lineHeight*0.5)); 0102 } else { 0103 origin.setX(rectangle.left() + (lineHeight*0.5)); 0104 } 0105 0106 if (halign & Qt::AlignCenter) { 0107 origin.setY(rectangle.center().y()); 0108 } else if (halign & Qt::AlignRight) { 0109 origin.setY(rectangle.bottom()); 0110 } 0111 } 0112 } 0113 if (!rectangle.contains(origin) && unwrappedText) { 0114 origin = writingMode == KoSvgText::HorizontalTB? QPointF(origin.x(), rectangle.bottom()): QPointF(rectangle.center().x(), origin.y()); 0115 } 0116 params->setProperty("shapeRect", QVariant(rectangle)); 0117 params->setProperty("origin", QVariant(origin)); 0118 0119 KoShape *textShape = factory->createShape( params, tool->canvas()->shapeController()->resourceManager()); 0120 0121 KUndo2Command *parentCommand = new KUndo2Command(); 0122 0123 new KoKeepShapesSelectedCommand(tool->koSelection()->selectedShapes(), {}, tool->canvas()->selectedShapesProxy(), false, parentCommand); 0124 0125 KUndo2Command *cmd = tool->canvas()->shapeController()->addShape(textShape, 0, parentCommand); 0126 parentCommand->setText(cmd->text()); 0127 0128 new KoKeepShapesSelectedCommand({}, {textShape}, tool->canvas()->selectedShapesProxy(), true, parentCommand); 0129 tool->canvas()->snapGuide()->reset(); 0130 0131 return parentCommand; 0132 } 0133 0134 void SvgCreateTextStrategy::cancelInteraction() 0135 { 0136 tool()->canvas()->snapGuide()->reset(); 0137 const QRectF updateRect = QRectF(m_dragStart, m_dragEnd).normalized(); 0138 tool()->canvas()->updateCanvas(updateRect); 0139 } 0140 0141 void SvgCreateTextStrategy::finishInteraction(Qt::KeyboardModifiers modifiers) 0142 { 0143 m_modifiers = modifiers; 0144 } 0145 0146 bool SvgCreateTextStrategy::draggingInlineSize() 0147 { 0148 QRectF rectangle = QRectF(m_dragStart, m_dragEnd).normalized(); 0149 return (rectangle.width() >= m_minSizeInline.width() || rectangle.height() >= m_minSizeInline.height()) && !m_modifiers.testFlag(Qt::ControlModifier); 0150 }