File indexing completed on 2024-05-26 16:14:25

0001 /* This file is part of the KDE project
0002  *
0003  * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
0004  * Copyright (C) 2009 Thomas Zander <zander@kde.org>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  */
0021 
0022 #include "KoShapePainter.h"
0023 
0024 #include "KoCanvasBase.h"
0025 #include "KoShapeManager.h"
0026 #include "KoShapeManagerPaintingStrategy.h"
0027 #include "KoShape.h"
0028 #include "KoViewConverter.h"
0029 #include "KoShapeStrokeModel.h"
0030 #include "KoShapeGroup.h"
0031 #include "KoShapeContainer.h"
0032 
0033 #include <KoUnit.h>
0034 
0035 #include <QPainter>
0036 #include <QImage>
0037 
0038 class SimpleCanvas : public KoCanvasBase
0039 {
0040 public:
0041     SimpleCanvas()
0042         : KoCanvasBase(0), m_shapeManager(new KoShapeManager(this))
0043     {
0044     }
0045 
0046     ~SimpleCanvas() override
0047     {
0048         delete m_shapeManager;
0049     }
0050 
0051     void gridSize(qreal *horizontal, qreal *vertical) const override
0052     {
0053         if (horizontal)
0054             *horizontal = 0;
0055         if (vertical)
0056             *vertical = 0;
0057     };
0058 
0059     bool snapToGrid() const override
0060     {
0061         return false;
0062     }
0063 
0064     void addCommand(KUndo2Command *) override
0065     {
0066     }
0067 
0068     KoShapeManager *shapeManager() const override
0069     {
0070         return m_shapeManager;
0071     }
0072 
0073     void updateCanvas(const QRectF&) override
0074     {
0075     }
0076 
0077     KoToolProxy *toolProxy() const override
0078     {
0079         return 0;
0080     }
0081 
0082     KoViewConverter *viewConverter() const override
0083     {
0084         return 0;
0085     }
0086 
0087     QWidget *canvasWidget() override
0088     {
0089         return 0;
0090     }
0091 
0092     const QWidget *canvasWidget() const override
0093     {
0094         return 0;
0095     }
0096 
0097     KoUnit unit() const override
0098     {
0099         return KoUnit(KoUnit::Point);
0100     }
0101 
0102     void updateInputMethodInfo() override {}
0103 
0104     void setCursor(const QCursor &) override {}
0105 
0106 private:
0107     KoShapeManager *m_shapeManager;
0108 };
0109 
0110 class Q_DECL_HIDDEN KoShapePainter::Private
0111 {
0112 public:
0113     Private()
0114         : canvas(new SimpleCanvas())
0115     {
0116     }
0117 
0118     ~Private() { delete canvas; }
0119     SimpleCanvas * canvas;
0120 };
0121 
0122 KoShapePainter::KoShapePainter(KoShapeManagerPaintingStrategy *strategy)
0123     : d(new Private())
0124 {
0125     if (strategy) {
0126         strategy->setShapeManager(d->canvas->shapeManager());
0127         d->canvas->shapeManager()->setPaintingStrategy(strategy);
0128     }
0129 }
0130 
0131 KoShapePainter::~KoShapePainter()
0132 {
0133     delete d;
0134 }
0135 
0136 void KoShapePainter::setShapes(const QList<KoShape*> &shapes)
0137 {
0138     d->canvas->shapeManager()->setShapes(shapes, KoShapeManager::AddWithoutRepaint);
0139 }
0140 
0141 void KoShapePainter::paint(QPainter &painter, KoViewConverter &converter)
0142 {
0143     foreach (KoShape *shape, d->canvas->shapeManager()->shapes()) {
0144         shape->waitUntilReady(converter, false);
0145     }
0146 
0147     d->canvas->shapeManager()->paint(painter, converter, true);
0148 }
0149 
0150 void KoShapePainter::paint(QPainter &painter, const QRect &painterRect, const QRectF &documentRect)
0151 {
0152     if (documentRect.width() == 0.0f || documentRect.height() == 0.0f)
0153         return;
0154 
0155     KoViewConverter converter;
0156     // calculate the painter destination rectangle size in document coordinates
0157     QRectF paintBox = converter.viewToDocument(QRectF(QPointF(), painterRect.size()));
0158 
0159     // compute the zoom factor based on the bounding rects in document coordinates
0160     // so that the content fits into the image
0161     qreal zoomW = paintBox.width() / documentRect.width();
0162     qreal zoomH = paintBox.height() / documentRect.height();
0163     qreal zoom = qMin(zoomW, zoomH);
0164 
0165     // now set the zoom into the zoom handler used for painting the shape
0166     converter.setZoom(zoom);
0167 
0168     painter.save();
0169 
0170     // initialize painter
0171     painter.setPen(QPen(Qt::NoPen));
0172     painter.setBrush(Qt::NoBrush);
0173     painter.setRenderHint(QPainter::Antialiasing);
0174     painter.setClipRect(painterRect.adjusted(-1,-1,1,1));
0175 
0176     // convert document rectangle to view coordinates
0177     QRectF zoomedBound = converter.documentToView(documentRect);
0178     // calculate offset between painter rectangle and converted document rectangle
0179     QPointF offset = QRectF(painterRect).center() - zoomedBound.center();
0180     // center content in painter rectangle
0181     painter.translate(offset.x(), offset.y());
0182 
0183     // finally paint the shapes
0184     paint(painter, converter);
0185 
0186     painter.restore();
0187 }
0188 
0189 void KoShapePainter::paint(QImage &image)
0190 {
0191     if (image.isNull())
0192         return;
0193 
0194     QPainter painter(&image);
0195 
0196     paint(painter, image.rect(), contentRect());
0197 }
0198 
0199 QRectF KoShapePainter::contentRect() const
0200 {
0201     QRectF bound;
0202     foreach (KoShape *shape, d->canvas->shapeManager()->shapes()) {
0203         if (!shape->isVisible(true))
0204             continue;
0205         if (dynamic_cast<KoShapeGroup*>(shape))
0206             continue;
0207 
0208         QRectF shapeRect = shape->boundingRect();
0209 
0210         if (bound.isEmpty())
0211             bound = shapeRect;
0212         else
0213             bound = bound.united(shapeRect);
0214     }
0215     return bound;
0216 }