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 }