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 }