File indexing completed on 2024-04-21 04:32:15

0001 /*
0002  * Copyright (C) 2011-2015 by Stephen Allewell
0003  * steve.allewell@gmail.com
0004  *
0005  * This program is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU General Public License as published by
0007  * the Free Software Foundation; either version 2 of the License, or
0008  * (at your option) any later version.
0009  */
0010 
0011 /**
0012  * @file
0013  * Implement the Symbol class.
0014  */
0015 
0016 /**
0017  * @page symbol Symbol
0018  * The Symbol encapsulates the QPainterPath with an attribute @ref Symbol::filled() defining if the path is drawn filled
0019  * or not. If the path is drawn as an outline, the @ref Symbol::lineWidth() attribute is used to initialize the pen for
0020  * drawing the path. The end cap style and join style can be set which are added to the pen when drawing the path.
0021  */
0022 
0023 #include "Symbol.h"
0024 
0025 #include <QBrush>
0026 #include <QDataStream>
0027 #include <QPen>
0028 #include <QTransform>
0029 
0030 #include <KLocalizedString>
0031 
0032 #include "Exceptions.h"
0033 
0034 /**
0035  * Constructor
0036  *
0037  * The Symbol is initialized with filling enabled and a default pen width of 0.01 with a Qt::SquareCap end and a
0038  * Qt::MiterJoin join type. The pen width is scaled with the painter.
0039  */
0040 Symbol::Symbol()
0041     : m_filled(true)
0042     , m_lineWidth(0.01)
0043     , m_capStyle(Qt::SquareCap)
0044     , m_joinStyle(Qt::MiterJoin)
0045 {
0046 }
0047 
0048 /**
0049  * Get the QPainterPath for the symbol. The path also incorporates the path fill mode.
0050  *
0051  * @return a QPainterPath
0052  */
0053 QPainterPath Symbol::path() const
0054 {
0055     return m_paths.value(Stitch::Full);
0056 }
0057 
0058 /**
0059  * Get a version of the symbol based on the stitch type to be rendered.
0060  * The scaled versions are generated and cached within the symbol as required.
0061  *
0062  * @param type a Stitch::Type identifying the type of stitch.
0063  *
0064  * @return a scaled QPainterPath
0065  */
0066 QPainterPath Symbol::path(Stitch::Type type)
0067 {
0068     if (!m_paths.contains(type)) {
0069         double twoThirds = 2.0 / 3.0;
0070         double oneThird = 1.0 / 3.0;
0071         QTransform transform;
0072 
0073         switch (type) {
0074         case Stitch::Full:
0075             // nothing else to do
0076             break;
0077 
0078         case Stitch::TLQtr:
0079         case Stitch::TLSmallHalf:
0080         case Stitch::TLSmallFull:
0081             transform = QTransform::fromScale(0.5, 0.5);
0082             break;
0083 
0084         case Stitch::TRQtr:
0085         case Stitch::TRSmallHalf:
0086         case Stitch::TRSmallFull:
0087             transform = QTransform::fromScale(0.5, 0.5) * QTransform::fromTranslate(0.5, 0.0);
0088             break;
0089 
0090         case Stitch::BLQtr:
0091         case Stitch::BLSmallHalf:
0092         case Stitch::BLSmallFull:
0093             transform = QTransform::fromScale(0.5, 0.5) * QTransform::fromTranslate(0.0, 0.5);
0094             break;
0095 
0096         case Stitch::BRQtr:
0097         case Stitch::BRSmallHalf:
0098         case Stitch::BRSmallFull:
0099             transform = QTransform::fromScale(0.5, 0.5) * QTransform::fromTranslate(0.5, 0.5);
0100             break;
0101 
0102         case Stitch::TBHalf:
0103         case Stitch::BTHalf:
0104         case Stitch::FrenchKnot:
0105             transform = QTransform::fromScale(twoThirds, twoThirds) * QTransform::fromTranslate(oneThird / 2.0, oneThird / 2.0);
0106             break;
0107 
0108         case Stitch::TL3Qtr:
0109             transform = QTransform::fromScale(twoThirds, twoThirds);
0110             break;
0111 
0112         case Stitch::TR3Qtr:
0113             transform = QTransform::fromScale(twoThirds, twoThirds) * QTransform::fromTranslate(oneThird, 0.0);
0114             break;
0115 
0116         case Stitch::BL3Qtr:
0117             transform = QTransform::fromScale(twoThirds, twoThirds) * QTransform::fromTranslate(0.0, oneThird);
0118             break;
0119 
0120         case Stitch::BR3Qtr:
0121             transform = QTransform::fromScale(twoThirds, twoThirds) * QTransform::fromTranslate(oneThird, oneThird);
0122             break;
0123 
0124         case Stitch::Delete:
0125             break;
0126         }
0127 
0128         m_paths.insert(type, transform.map(m_paths.value(Stitch::Full)));
0129     }
0130 
0131     return m_paths.value(type);
0132 }
0133 
0134 /**
0135  * Get the path filled status.
0136  *
0137  * @return @c true if the path is to be drawn filled, @c false if unfilled
0138  */
0139 bool Symbol::filled() const
0140 {
0141     return m_filled;
0142 }
0143 
0144 /**
0145  * Get the outline path line width.
0146  *
0147  * @return a qreal representing the line width, this is scaled with the painter
0148  */
0149 qreal Symbol::lineWidth() const
0150 {
0151     return m_lineWidth;
0152 }
0153 
0154 /**
0155  * Get the pen cap style, see the QPen documentation for details on the styles.
0156  *
0157  * @return a Qt::PenCapStyle value
0158  */
0159 Qt::PenCapStyle Symbol::capStyle() const
0160 {
0161     return m_capStyle;
0162 }
0163 
0164 /**
0165  * Get the pen join style, see the QPen documentation for details on the styles.
0166  *
0167  * @return a Qt::PenJoinStyle value
0168  */
0169 Qt::PenJoinStyle Symbol::joinStyle() const
0170 {
0171     return m_joinStyle;
0172 }
0173 
0174 /**
0175  * Set the QPainterPath for the symbol.
0176  *
0177  * @param path a const reference to a QPainterPath
0178  */
0179 void Symbol::setPath(const QPainterPath &path)
0180 {
0181     m_paths.clear();
0182     m_paths.insert(Stitch::Full, path);
0183 }
0184 
0185 /**
0186  * Set the filled status of the path.
0187  *
0188  * @param filled @c true if the path is to be drawn filled, @c false if unfilled
0189  */
0190 void Symbol::setFilled(bool filled)
0191 {
0192     m_filled = filled;
0193 }
0194 
0195 /**
0196  * Set the line width for the outline paths.
0197  *
0198  * @param width the width of the pen
0199  */
0200 void Symbol::setLineWidth(qreal width)
0201 {
0202     m_lineWidth = width;
0203 }
0204 
0205 /**
0206  * Set the pen cap style, see the QPen documentation for details on the styles.
0207  *
0208  * @param capStyle a Qt::PenCapStyle value
0209  */
0210 void Symbol::setCapStyle(Qt::PenCapStyle capStyle)
0211 {
0212     m_capStyle = capStyle;
0213 }
0214 
0215 /**
0216  * Set the pen join style, see the QPen documentation for details on the styles.
0217  *
0218  * @param joinStyle a Qt::PenJoinStyle value
0219  */
0220 void Symbol::setJoinStyle(Qt::PenJoinStyle joinStyle)
0221 {
0222     m_joinStyle = joinStyle;
0223 }
0224 
0225 /**
0226  * Get a pen based on the parameters of the symbol.
0227  *
0228  * @return a black QPen with the symbols width and end styles
0229  */
0230 QPen Symbol::pen() const
0231 {
0232     QPen p;
0233 
0234     if (!m_filled) {
0235         p.setWidthF(m_lineWidth);
0236         p.setCapStyle(m_capStyle);
0237         p.setJoinStyle(m_joinStyle);
0238     } else {
0239         p = QPen(Qt::NoPen);
0240     }
0241 
0242     return p;
0243 }
0244 
0245 /**
0246  * Get a brush based on the parameters of the symbol.
0247  *
0248  * @return a black brush based on the filled state of the symbol
0249  */
0250 QBrush Symbol::brush() const
0251 {
0252     return QBrush(m_filled ? Qt::SolidPattern : Qt::NoBrush);
0253 }
0254 
0255 /**
0256  * Stream out a Symbol.
0257  *
0258  * @param stream a reference to the QDataStream to write to
0259  * @param symbol a const reference to the Symbol to stream
0260  *
0261  * @return a reference to the stream
0262  */
0263 QDataStream &operator<<(QDataStream &stream, const Symbol &symbol)
0264 {
0265     stream << symbol.version << symbol.m_paths.value(Stitch::Full) << symbol.m_filled << symbol.m_lineWidth << static_cast<qint32>(symbol.m_capStyle)
0266            << static_cast<qint32>(symbol.m_joinStyle);
0267 
0268     if (stream.status() != QDataStream::Ok) {
0269         throw FailedWriteFile(stream.status());
0270     }
0271 
0272     return stream;
0273 }
0274 
0275 /**
0276  * Stream in a Symbol.
0277  *
0278  * @param stream a reference to the QDataStream to read from
0279  * @param symbol a reference to the Symbol to stream
0280  *
0281  * @return a reference to the stream
0282  */
0283 QDataStream &operator>>(QDataStream &stream, Symbol &symbol)
0284 {
0285     qint32 version;
0286     qint32 capStyle;
0287     qint32 joinStyle;
0288     QPainterPath path;
0289     stream >> version;
0290 
0291     switch (version) {
0292     case 100:
0293         stream >> path >> symbol.m_filled >> symbol.m_lineWidth >> capStyle >> joinStyle;
0294         symbol.m_capStyle = static_cast<Qt::PenCapStyle>(capStyle);
0295         symbol.m_joinStyle = static_cast<Qt::PenJoinStyle>(joinStyle);
0296         symbol.m_paths.insert(Stitch::Full, path);
0297         break;
0298 
0299     default:
0300         throw InvalidFileVersion(QString(i18n("Symbol version %1", version)));
0301         break;
0302     }
0303 
0304     return stream;
0305 }