File indexing completed on 2024-05-05 04:35:18

0001 /* This file is part of the TikZKit project.
0002  *
0003  * Copyright (C) 2013 Dominik Haumann <dhaumann@kde.org>
0004  *
0005  * This library is free software; you can redistribute it and/or modify
0006  * it under the terms of the GNU Library General Public License as published
0007  * by the Free Software Foundation, either version 2 of the License, or
0008  * (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
0013  * GNU 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, see
0017  * <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "Painter.h"
0021 
0022 #include <tikz/core/Style.h>
0023 #include <tikz/core/tikz.h>
0024 
0025 #include <QPainter>
0026 #include <QPainterPath>
0027 #include <QDebug>
0028 
0029 namespace tikz {
0030 namespace ui {
0031 
0032 class PainterPrivate
0033 {
0034     public:
0035         QPainter* painter;
0036         tikz::core::Style* style;
0037 };
0038 
0039 Painter::Painter(QPainter * painter, tikz::core::Style * style)
0040     : d(new PainterPrivate())
0041 {
0042     d->painter = painter;
0043     d->style = style;
0044 }
0045 
0046 Painter::~Painter()
0047 {
0048     delete d;
0049 }
0050 
0051 /**
0052  * This functions returns a dash pattern for the respective pen style.
0053  * The generated dash pattern follows the dash patterns defined by PGF/TikZ,
0054  * see file generic/pgf/frontendlayer/tikz/tikz.code.tex fur further details.
0055  *
0056  * If @p style has a tikz::PenStyle::SolidLine as pen style, an empty vector is returned.
0057  */
0058 static QVector<qreal> penStyle(qreal lineWidth, tikz::PenStyle style)
0059 {
0060     //
0061     // NOTE: all calculations have the unit 'pt'
0062     //
0063     QVector<qreal> pattern;
0064     switch (style) {
0065         case tikz::PenStyle::SolidLine: break; // leave empty
0066         case tikz::PenStyle::DottedLine: pattern << lineWidth*lineWidth << 2; break;
0067         case tikz::PenStyle::DenselyDottedLine: pattern << lineWidth*lineWidth << 1; break;
0068         case tikz::PenStyle::LooselyDottedLine: pattern << lineWidth*lineWidth << 4; break;
0069         case tikz::PenStyle::DashedLine: pattern << 3 << 3; break;
0070         case tikz::PenStyle::DenselyDashedLine: pattern << 3 << 2; break;
0071         case tikz::PenStyle::LooselyDashedLine: pattern << 3 << 6; break;
0072         case tikz::PenStyle::DashDottedLine: pattern << 3 << 2 << lineWidth << 2; break;
0073         case tikz::PenStyle::DenselyDashDottedLine: pattern << 3 << 1 << lineWidth*lineWidth << 1; break;
0074         case tikz::PenStyle::LooselyDashDottedLine: pattern << 3 << 4 << lineWidth*lineWidth << 4; break;
0075         case tikz::PenStyle::DashDotDottedLine: pattern << 3 << 2 << lineWidth*lineWidth << 2 << lineWidth*lineWidth << 2; break;
0076         case tikz::PenStyle::DenselyDashDotDottedLine: pattern << 3 << 1 << lineWidth*lineWidth << 1 << lineWidth*lineWidth << 1; break;
0077         case tikz::PenStyle::LooselyDashDotDottedLine: pattern << 3 << 4 << lineWidth*lineWidth << 4 << lineWidth*lineWidth << 4; break;
0078         default: break;
0079     }
0080 
0081     for (int i = 0; i < pattern.size(); ++i) {
0082         pattern[i] /= lineWidth;
0083     }
0084     return pattern;
0085 }
0086 
0087 QPen Painter::pen() const
0088 {
0089     // invalid color -> NoPen
0090     QColor c = d->style->penColor();
0091     if (!c.isValid()) {
0092         return Qt::NoPen;
0093     }
0094 
0095     // construct valid pen
0096     QPen pen(c);
0097     pen.setWidthF(d->style->penWidth().toPoint());
0098     pen.setCapStyle(Qt::FlatCap);
0099     pen.setJoinStyle(Qt::MiterJoin);
0100 //    setMiterLimit
0101     return pen;
0102 }
0103 
0104 void Painter::drawPath(const QPainterPath & path)
0105 {
0106     QPen p = pen();
0107 
0108     p.setWidthF(d->style->penWidth().toPoint());
0109     QVector<qreal> pattern = tikz::ui::penStyle(d->style->penWidth().toPoint(), d->style->penStyle());
0110     if (d->style->penStyle() != tikz::PenStyle::SolidLine) {
0111         p.setDashPattern(pattern);
0112     }
0113 
0114     // first pass: draw line
0115     d->painter->setPen(p);
0116     d->painter->setBrush(Qt::NoBrush);
0117     d->painter->setOpacity(d->style->penOpacity());
0118     d->painter->drawPath(path);
0119 
0120     // second pass: draw inner line
0121     if (d->style->doubleLine() && d->style->innerLineWidth().toPoint() > 0) {
0122         if (d->style->penStyle() != tikz::PenStyle::SolidLine) {
0123             // scale by different line widths to match distances
0124             for (int i = 0; i < pattern.size(); ++i) {
0125                 pattern[i] *= d->style->penWidth().toPoint() / d->style->innerLineWidth().toPoint();
0126             }
0127             p.setDashPattern(pattern);
0128         }
0129 
0130         p.setWidthF(d->style->innerLineWidth().toPoint());
0131         p.setColor(d->style->innerLineColor());
0132         d->painter->setPen(p);
0133         d->painter->drawPath(path);
0134     }
0135 }
0136 
0137 void Painter::fillPath(const QPainterPath & path)
0138 {
0139     // shortcut: only paint if required
0140     if (d->style->fillColor().alpha() == 0 || d->style->fillOpacity() == 0.0) {
0141         return;
0142     }
0143 
0144     QPen p = pen();
0145     p.setColor(Qt::transparent);
0146     p.setWidthF(d->style->penWidth().toPoint());
0147 
0148     const QBrush brush(d->style->fillColor());
0149 
0150     d->painter->setPen(p);
0151     d->painter->setBrush(brush);
0152     d->painter->setOpacity(d->style->fillOpacity());
0153     d->painter->fillPath(path, brush);
0154 }
0155 
0156 }
0157 }
0158 
0159 // kate: indent-width 4; replace-tabs on;