File indexing completed on 2024-05-12 16:33:19

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2007-2008,2011 Jan Hambrecht <jaham@gmx.net>
0003  * Copyright (C) 2008 Rob Buis <buis@kde.org>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Library General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2 of the License, or (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, write to
0017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  */
0020 
0021 #ifndef ARTISTICTEXTSHAPE_H
0022 #define ARTISTICTEXTSHAPE_H
0023 
0024 #include "ArtisticTextRange.h"
0025 #include <KoShape.h>
0026 #include <KoPostscriptPaintDevice.h>
0027 #include <SvgShape.h>
0028 #include <QFont>
0029 #include <QPainterPath>
0030 #include <QVector>
0031 
0032 class QPainter;
0033 class KoPathShape;
0034 class ArtisticTextLoadingContext;
0035 class SvgGraphicsContext;
0036 
0037 #define ArtisticTextShapeID "ArtisticText"
0038 
0039 /// Character position within text shape (range index, range character index)
0040 typedef QPair<int, int> CharIndex;
0041 
0042 class ArtisticTextShape : public KoShape, public SvgShape
0043 {
0044 public:
0045     enum TextAnchor { AnchorStart, AnchorMiddle, AnchorEnd };
0046 
0047     enum LayoutMode {
0048         Straight,    ///< baseline is a straight line
0049         OnPath,      ///< baseline is a QPainterPath
0050         OnPathShape  ///< baseline is the outline of a path shape
0051     };
0052 
0053     ArtisticTextShape();
0054     ~ArtisticTextShape() override;
0055 
0056     /// reimplemented
0057     void paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintContext) override;
0058     /// reimplemented
0059     void saveOdf(KoShapeSavingContext & context) const override;
0060     /// reimplemented
0061     bool loadOdf( const KoXmlElement & element, KoShapeLoadingContext &context ) override;
0062     /// reimplemented
0063     QSizeF size() const override;
0064     /// reimplemented
0065     void setSize( const QSizeF &size ) override;
0066     /// reimplemented
0067     QPainterPath outline() const override;
0068     /// reimplemented from SvgShape
0069     bool saveSvg(SvgSavingContext &context) override;
0070     /// reimplemented from SvgShape
0071     bool loadSvg(const KoXmlElement &element, SvgLoadingContext &context) override;
0072 
0073     /// Sets the plain text to display
0074     void setPlainText(const QString &newText);
0075 
0076     /// Returns the plain text content
0077     QString plainText() const;
0078 
0079     /// Returns formatted text
0080     QList<ArtisticTextRange> text() const;
0081 
0082     /// Returns if text shape is empty, i.e. no text
0083     bool isEmpty() const;
0084 
0085     /// Clears the text shape
0086     void clear();
0087 
0088     /**
0089      * Sets the font used for drawing
0090      * Note that it is expected that the font has its point size set
0091      * in postscript points.
0092      */
0093     void setFont(const QFont &font);
0094 
0095     /**
0096      * Sets the font for the specified range of characters
0097      * @param charIndex the index of the first character of the range
0098      * @param charCount the number of characters of the range
0099      * @param font the new font to set
0100      */
0101     void setFont(int charIndex, int charCount, const QFont &font);
0102 
0103     /**
0104      * Returns the font at the specified character position
0105      * If the text shape is empty it will return the default font.
0106      * If the character index is smaller than zero it will return the font
0107      * of the first character. If the character index is greater than the
0108      * last character index it will return the font of the last character.
0109      */
0110     QFont fontAt(int charIndex) const;
0111 
0112     /// Returns the default font
0113     QFont defaultFont() const;
0114 
0115     /// Attaches this text shape to the given path shape
0116     bool putOnPath(KoPathShape *path);
0117 
0118     /// Puts the text on the given path, the path is expected to be in document coordinates
0119     bool putOnPath(const QPainterPath &path);
0120 
0121     /// Detaches this text shape from an already attached path shape
0122     void removeFromPath();
0123 
0124     /// Returns if shape is attached to a path shape
0125     bool isOnPath() const;
0126 
0127     /// Sets the offset for for text on path
0128     void setStartOffset(qreal offset);
0129 
0130     /// Returns the start offset for text on path
0131     qreal startOffset() const;
0132 
0133     /**
0134      * Returns the y-offset from the top-left corner to the baseline.
0135      * This is usable for being able to exactly position the texts baseline.
0136      * Note: The value makes only sense for text not attached to a path.
0137      */
0138     qreal baselineOffset() const;
0139 
0140     /// Sets the text anchor
0141     void setTextAnchor(TextAnchor anchor);
0142 
0143     /// Returns the actual text anchor
0144     TextAnchor textAnchor() const;
0145 
0146     /// Returns the current layout mode
0147     LayoutMode layout() const;
0148 
0149     /// Returns the baseline path
0150     QPainterPath baseline() const;
0151 
0152     /// Returns a pointer to the shape used as baseline
0153     KoPathShape * baselineShape() const;
0154 
0155     /// Removes a range of text starting from the given character
0156     QList<ArtisticTextRange> removeText(int charIndex, int charCount);
0157 
0158     /// Copies a range of text starting from the given character
0159     QList<ArtisticTextRange> copyText(int charIndex, int charCount);
0160 
0161     /// Adds a range of text at the given index
0162     void insertText(int charIndex, const QString &plainText);
0163 
0164     /// Adds range of text at the given index
0165     void insertText(int charIndex, const ArtisticTextRange &textRange);
0166 
0167     /// Adds ranges of text at the given index
0168     void insertText(int charIndex, const QList<ArtisticTextRange> &textRanges);
0169 
0170     /// Appends plain text to the last text range
0171     void appendText(const QString &plainText);
0172 
0173     /// Appends a single formatted range of text
0174     void appendText(const ArtisticTextRange &text);
0175 
0176     /// Replaces a range of text with the specified text range
0177     bool replaceText(int charIndex, int charCount, const ArtisticTextRange &textRange);
0178 
0179     /// Replaces a range of text with the specified text ranges
0180     bool replaceText(int charIndex, int charCount, const QList<ArtisticTextRange> &textRanges);
0181 
0182     /// Gets the angle of the char with the given index
0183     qreal charAngleAt(int charIndex) const;
0184 
0185     /// Gets the position of the char with the given index in shape coordinates
0186     QPointF charPositionAt(int charIndex) const;
0187 
0188     /// Gets the extents of the char with the given index
0189     QRectF charExtentsAt(int charIndex) const;
0190 
0191     /// Returns index of range and index within range of specified character
0192     CharIndex indexOfChar(int charIndex) const;
0193 
0194     /// reimplemented from KoShape
0195     void shapeChanged(ChangeType type, KoShape * shape) override;
0196 
0197 private:
0198     void updateSizeAndPosition( bool global = false );
0199     bool pathHasChanged() const;
0200     void createOutline();
0201 
0202     void beginTextUpdate();
0203     void finishTextUpdate();
0204 
0205     /// Calculates abstract character positions in baseline coordinates
0206     QVector<QPointF> calculateAbstractCharacterPositions();
0207 
0208     /// Returns the bounding box for an empty text shape
0209     QRectF nullBoundBox() const;
0210 
0211     /// Saves svg font
0212     void saveSvgFont(const QFont &font, SvgSavingContext &context);
0213     /// Saves svg text range
0214     void saveSvgTextRange(const ArtisticTextRange &range, SvgSavingContext &context, bool saveFont, qreal baselineOffset);
0215     /// Parse nested text ranges
0216     void parseTextRanges(const KoXmlElement &element, SvgLoadingContext &context, ArtisticTextLoadingContext &textContext);
0217     /// Creates text range
0218     ArtisticTextRange createTextRange(const QString &text, ArtisticTextLoadingContext &context, SvgGraphicsContext *gc);
0219 
0220     QList<ArtisticTextRange> m_ranges;
0221     KoPostscriptPaintDevice m_paintDevice;
0222     KoPathShape * m_path; ///< the path shape we are attached to
0223     qreal m_startOffset; ///< the offset from the attached path start point
0224     QPointF m_outlineOrigin; ///< the top-left corner of the non-normalized text outline
0225     QPainterPath m_outline; ///< the actual text outline
0226     QPainterPath m_baseline; ///< the baseline path the text is put on
0227     TextAnchor m_textAnchor; ///< the actual text anchor
0228     QVector<qreal> m_charOffsets; ///< char positions [0..1] on baseline path
0229     QVector<QPointF> m_charPositions; ///< char positions in shape coordinates
0230     int m_textUpdateCounter;
0231     QFont m_defaultFont;
0232     bool m_drawBoundaryLines;
0233 };
0234 
0235 #endif // ARTISTICTEXTSHAPE_H