Warning, file /office/calligra/libs/flake/KoHatchBackground.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* This file is part of the KDE project 0002 * 0003 * Copyright (C) 2012 Thorsten Zachmann <zachmann@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 #include "KoHatchBackground.h" 0022 #include "KoColorBackground_p.h" 0023 0024 #include <KoOdfLoadingContext.h> 0025 #include <KoStyleStack.h> 0026 #include <KoShapeSavingContext.h> 0027 #include <KoGenStyles.h> 0028 #include <KoGenStyle.h> 0029 #include <KoXmlNS.h> 0030 #include <KoUnit.h> 0031 0032 #include <FlakeDebug.h> 0033 0034 #include <QColor> 0035 #include <QString> 0036 #include <QPainter> 0037 #include <QPainterPath> 0038 0039 class KoHatchBackgroundPrivate : public KoColorBackgroundPrivate 0040 { 0041 public: 0042 KoHatchBackgroundPrivate() 0043 : angle(0.0) 0044 , distance(1.0) 0045 , style(KoHatchBackground::Single) 0046 {} 0047 0048 QColor lineColor; 0049 int angle; 0050 qreal distance; 0051 KoHatchBackground::HatchStyle style; 0052 QString name; 0053 }; 0054 0055 KoHatchBackground::KoHatchBackground() 0056 : KoColorBackground(*(new KoHatchBackgroundPrivate())) 0057 { 0058 } 0059 0060 void KoHatchBackground::paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &context, const QPainterPath &fillPath) const 0061 { 0062 Q_D(const KoHatchBackground); 0063 if (d->color.isValid()) { 0064 // paint background color if set by using the color background 0065 KoColorBackground::paint(painter, converter, context, fillPath); 0066 } 0067 0068 const QRectF targetRect = fillPath.boundingRect(); 0069 painter.save(); 0070 painter.setClipPath(fillPath); 0071 QPen pen(d->lineColor); 0072 // we set the pen width to 0.5 pt for the hatch. This is not defined in the spec. 0073 pen.setWidthF(0.5); 0074 painter.setPen(pen); 0075 QVector<QLineF> lines; 0076 0077 // The different styles are handled by painting the lines multiple times with a different 0078 // angel offset as basically it just means we paint the lines also at a different angle. 0079 // This are the angle offsets we need to apply to the different lines of a style. 0080 // -90 is for single, 0 for the 2nd line in double and -45 for the 3th line in triple. 0081 const int angleOffset[] = {-90, 0, -45 }; 0082 // The number of loops is defined by the style. 0083 int loops = (d->style == Single) ? 1 : (d->style == Double) ? 2 : 3; 0084 0085 for (int i = 0; i < loops; ++i) { 0086 int angle = d->angle - angleOffset[i]; 0087 qreal cosAngle = ::cos(angle/180.0*M_PI); 0088 // if cos is nearly 0 the lines are horizontal. Use a special case for that 0089 if (qAbs(cosAngle) > 0.00001) { 0090 qreal xDiff = tan(angle/180.0*M_PI) * targetRect.height(); 0091 // calculate the distance we need to increase x when creating the lines so that the 0092 // distance between the lines is also correct for rotated lines. 0093 qreal xOffset = qAbs(d->distance / cosAngle); 0094 0095 // if the lines go to the right we need to start more to the left. Get the correct start. 0096 qreal xStart = 0; 0097 while (-xDiff < xStart) { 0098 xStart -= xOffset; 0099 } 0100 0101 // if the lines go to the left we need to stop more at the right. Get the correct end offset 0102 qreal xEndOffset = 0; 0103 if (xDiff < 0) { 0104 while (xDiff < -xEndOffset) { 0105 xEndOffset += xOffset; 0106 } 0107 } 0108 // create line objects. 0109 lines.reserve(lines.size() + int((targetRect.width() + xEndOffset - xStart) / xOffset) + 1); 0110 for (qreal x = xStart; x < targetRect.width() + xEndOffset; x += xOffset) { 0111 lines.append(QLineF(x, 0, x + xDiff, targetRect.height())); 0112 } 0113 } 0114 else { 0115 // horizontal lines 0116 lines.reserve(lines.size() + int(targetRect.height()/d->distance) + 1); 0117 for (qreal y = 0; y < targetRect.height(); y += d->distance) { 0118 lines.append(QLineF(0, y, targetRect.width(), y)); 0119 } 0120 } 0121 } 0122 0123 painter.drawLines(lines); 0124 painter.restore(); 0125 } 0126 0127 void KoHatchBackground::fillStyle(KoGenStyle &style, KoShapeSavingContext &context) 0128 { 0129 Q_D(KoHatchBackground); 0130 0131 KoGenStyle::Type type = style.type(); 0132 KoGenStyle::PropertyType propertyType = (type == KoGenStyle::GraphicStyle || type == KoGenStyle::GraphicAutoStyle || 0133 type == KoGenStyle::DrawingPageStyle || type == KoGenStyle::DrawingPageAutoStyle ) 0134 ? KoGenStyle::DefaultType : KoGenStyle::GraphicType; 0135 0136 style.addProperty("draw:fill", "hatch", propertyType); 0137 style.addProperty("draw:fill-hatch-name", saveHatchStyle(context), propertyType); 0138 bool fillHatchSolid = d->color.isValid(); 0139 style.addProperty("draw:fill-hatch-solid", fillHatchSolid, propertyType); 0140 if (fillHatchSolid) { 0141 style.addProperty("draw:fill-color", d->color.name(), propertyType); 0142 } 0143 } 0144 0145 QString KoHatchBackground::saveHatchStyle(KoShapeSavingContext &context) const 0146 { 0147 Q_D(const KoHatchBackground); 0148 KoGenStyle hatchStyle(KoGenStyle::HatchStyle /*no family name*/); 0149 hatchStyle.addAttribute("draw:display-name", d->name); 0150 hatchStyle.addAttribute("draw:color", d->lineColor.name()); 0151 0152 hatchStyle.addAttributePt("draw:distance", d->distance); 0153 0154 hatchStyle.addAttribute("draw:rotation", QString("%1").arg(d->angle * 10)); 0155 0156 switch (d->style) { 0157 case Single: 0158 hatchStyle.addAttribute("draw:style", "single"); 0159 break; 0160 case Double: 0161 hatchStyle.addAttribute("draw:style", "double"); 0162 break; 0163 case Triple: 0164 hatchStyle.addAttribute("draw:style", "triple"); 0165 break; 0166 } 0167 0168 return context.mainStyles().insert(hatchStyle, "hatch"); 0169 } 0170 0171 bool KoHatchBackground::loadStyle(KoOdfLoadingContext &context, const QSizeF &shapeSize) 0172 { 0173 // <draw:hatch draw:name="hatchStyle3" draw:color="#000000" draw:display-name="#000000 Vertical" draw:distance="0.102cm" draw:rotation="900" draw:style="single"/> 0174 Q_D(KoHatchBackground); 0175 Q_UNUSED(shapeSize); 0176 0177 KoStyleStack &styleStack = context.styleStack(); 0178 QString fillStyle = styleStack.property(KoXmlNS::draw, "fill"); 0179 if (fillStyle == "hatch") { 0180 QString style = styleStack.property(KoXmlNS::draw, "fill-hatch-name"); 0181 debugFlake << " hatch style is :" << style; 0182 0183 KoXmlElement* draw = context.stylesReader().drawStyles("hatch").value(style); 0184 if (draw) { 0185 debugFlake << "Hatch style found for:" << style; 0186 0187 QString angle = draw->attributeNS(KoXmlNS::draw, "rotation", QString("0")); 0188 if (angle.at(angle.size()-1).isLetter()) { 0189 d->angle = KoUnit::parseAngle(angle); 0190 } 0191 else { 0192 // OO saves the angle value without unit and multiplied by a factor of 10 0193 d->angle = int(angle.toInt() / 10); 0194 } 0195 0196 debugFlake << "angle :" << d->angle; 0197 0198 d->name = draw->attributeNS(KoXmlNS::draw, "display-name"); 0199 0200 // use 2mm as default, just in case it is not given in a document so we show something sensible. 0201 d->distance = KoUnit::parseValue(draw->attributeNS(KoXmlNS::draw, "distance", "2mm")); 0202 0203 bool fillHatchSolid = styleStack.property(KoXmlNS::draw, "fill-hatch-solid") == QLatin1String("true"); 0204 if (fillHatchSolid) { 0205 QString fillColor = styleStack.property(KoXmlNS::draw, "fill-color"); 0206 if (!fillColor.isEmpty()) { 0207 d->color.setNamedColor(fillColor); 0208 } 0209 else { 0210 d->color =QColor(); 0211 } 0212 } 0213 else { 0214 d->color = QColor(); 0215 } 0216 d->lineColor.setNamedColor(draw->attributeNS(KoXmlNS::draw, "color", QString("#000000"))); 0217 0218 QString style = draw->attributeNS(KoXmlNS::draw, "style", QString()); 0219 if (style == "double") { 0220 d->style = Double; 0221 } 0222 else if (style == "triple") { 0223 d->style = Triple; 0224 } 0225 else { 0226 d->style = Single; 0227 } 0228 } 0229 0230 return true; 0231 } 0232 0233 return false; 0234 }