File indexing completed on 2024-05-12 15:56:41

0001 /* This file is part of the KDE project
0002  *
0003  * SPDX-FileCopyrightText: 2012 Thorsten Zachmann <zachmann@kde.org>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "KoHatchBackground.h"
0009 
0010 #include <KoShapeSavingContext.h>
0011 
0012 #include <KoXmlNS.h>
0013 #include <KoUnit.h>
0014 
0015 
0016 #include <FlakeDebug.h>
0017 
0018 #include <QColor>
0019 #include <QString>
0020 #include <QPainter>
0021 #include <QPainterPath>
0022 
0023 class KoHatchBackground::Private : public QSharedData
0024 {
0025 public:
0026     Private()
0027         : QSharedData()
0028         , angle(0.0)
0029         , distance(1.0)
0030         , style(KoHatchBackground::Single)
0031     {}
0032 
0033     QColor lineColor;
0034     int angle;
0035     qreal distance;
0036     KoHatchBackground::HatchStyle style;
0037     QString name;
0038 };
0039 
0040 KoHatchBackground::KoHatchBackground()
0041     : KoColorBackground()
0042     , d(new Private)
0043 {
0044 }
0045 
0046 KoHatchBackground::~KoHatchBackground()
0047 {
0048 }
0049 
0050 void KoHatchBackground::paint(QPainter &painter, const QPainterPath &fillPath) const
0051 {
0052     if (color().isValid()) {
0053         // paint background color if set by using the color background
0054         KoColorBackground::paint(painter, fillPath);
0055     }
0056 
0057     const QRectF targetRect = fillPath.boundingRect();
0058     painter.save();
0059     painter.setClipPath(fillPath);
0060     QPen pen(d->lineColor);
0061     // we set the pen width to 0.5 pt for the hatch. This is not defined in the spec.
0062     pen.setWidthF(0.5);
0063     painter.setPen(pen);
0064     QVector<QLineF> lines;
0065 
0066     // The different styles are handled by painting the lines multiple times with a different
0067     // angel offset as basically it just means we paint the lines also at a different angle.
0068     // This are the angle offsets we need to apply to the different lines of a style.
0069     // -90 is for single, 0 for the 2nd line in double and -45 for the 3th line in triple.
0070     const int angleOffset[] = {-90, 0, -45 };
0071     // The number of loops is defined by the style.
0072     int loops = (d->style == Single) ? 1 : (d->style == Double) ? 2 : 3;
0073 
0074     for (int i = 0; i < loops; ++i) {
0075         int angle = d->angle - angleOffset[i];
0076         qreal cosAngle = ::cos(angle/180.0*M_PI);
0077         // if cos is nearly 0 the lines are horizontal. Use a special case for that
0078         if (qAbs(cosAngle) > 0.00001) {
0079             qreal xDiff = tan(angle/180.0*M_PI) * targetRect.height();
0080             // calculate the distance we need to increase x when creating the lines so that the
0081             // distance between the lines is also correct for rotated lines.
0082             qreal xOffset = qAbs(d->distance / cosAngle);
0083 
0084             // if the lines go to the right we need to start more to the left. Get the correct start.
0085             qreal xStart = 0;
0086             while (-xDiff < xStart) {
0087                 xStart -= xOffset;
0088             }
0089 
0090             // if the lines go to the left we need to stop more at the right. Get the correct end offset
0091             qreal xEndOffset = 0;
0092             if (xDiff < 0) {
0093                 while (xDiff < -xEndOffset) {
0094                     xEndOffset += xOffset;
0095                 }
0096             }
0097             // create line objects.
0098             lines.reserve(lines.size() + int((targetRect.width() + xEndOffset - xStart) / xOffset) + 1);
0099             for (qreal x = xStart; x < targetRect.width() + xEndOffset; x += xOffset) {
0100                 lines.append(QLineF(x, 0, x + xDiff, targetRect.height()));
0101             }
0102         }
0103         else {
0104             // horizontal lines
0105             lines.reserve(lines.size() + int(targetRect.height()/d->distance) + 1);
0106             for (qreal y = 0; y < targetRect.height(); y += d->distance) {
0107                 lines.append(QLineF(0, y, targetRect.width(), y));
0108             }
0109         }
0110     }
0111 
0112     painter.drawLines(lines);
0113     painter.restore();
0114 }