File indexing completed on 2024-06-09 04:20:48
0001 /* This file is part of the KDE project 0002 * 0003 * SPDX-FileCopyrightText: 2007 Jan Hambrecht <jaham@gmx.net> 0004 * SPDX-FileCopyrightText: 2009 Thomas Zander <zander@kde.org> 0005 * 0006 * SPDX-License-Identifier: LGPL-2.0-or-later 0007 */ 0008 0009 #include "KoShapePainter.h" 0010 0011 #include "KoCanvasBase.h" 0012 #include "KoSelectedShapesProxySimple.h" 0013 #include "KoShapeManager.h" 0014 #include "KoShape.h" 0015 #include "KoShapeStrokeModel.h" 0016 #include "KoShapeGroup.h" 0017 #include "KoShapeContainer.h" 0018 #include <KoViewConverter.h> 0019 #include <KoUnit.h> 0020 0021 #include <QPainter> 0022 #include <QImage> 0023 0024 class SimpleCanvas : public KoCanvasBase 0025 { 0026 public: 0027 SimpleCanvas() 0028 : KoCanvasBase(0), 0029 m_shapeManager(new KoShapeManager(this)), 0030 m_selectedShapesProxy(new KoSelectedShapesProxySimple(m_shapeManager.data())) 0031 { 0032 } 0033 0034 ~SimpleCanvas() override 0035 { 0036 } 0037 0038 void gridSize(QPointF *offset, QSizeF *spacing) const override 0039 { 0040 *offset = QPointF(); 0041 *spacing = QSizeF(); 0042 }; 0043 0044 bool snapToGrid() const override 0045 { 0046 return false; 0047 } 0048 0049 void addCommand(KUndo2Command *) override 0050 { 0051 } 0052 0053 KoShapeManager *shapeManager() const override 0054 { 0055 return m_shapeManager.data(); 0056 } 0057 0058 KoSelectedShapesProxy *selectedShapesProxy() const override 0059 { 0060 return m_selectedShapesProxy.data(); 0061 } 0062 0063 void updateCanvas(const QRectF&) override 0064 { 0065 } 0066 0067 KoToolProxy *toolProxy() const override 0068 { 0069 return 0; 0070 } 0071 0072 const KoViewConverter *viewConverter() const override 0073 { 0074 return 0; 0075 } 0076 0077 KoViewConverter *viewConverter() override 0078 { 0079 return 0; 0080 } 0081 0082 QWidget *canvasWidget() override 0083 { 0084 return 0; 0085 } 0086 0087 const QWidget *canvasWidget() const override 0088 { 0089 return 0; 0090 } 0091 0092 KoUnit unit() const override 0093 { 0094 return KoUnit(KoUnit::Point); 0095 } 0096 0097 void setCursor(const QCursor &) override {} 0098 0099 private: 0100 QScopedPointer<KoShapeManager> m_shapeManager; 0101 QScopedPointer<KoSelectedShapesProxySimple> m_selectedShapesProxy; 0102 }; 0103 0104 class Q_DECL_HIDDEN KoShapePainter::Private 0105 { 0106 public: 0107 Private() 0108 : canvas(new SimpleCanvas()) 0109 { 0110 } 0111 0112 ~Private() { delete canvas; } 0113 SimpleCanvas * canvas; 0114 }; 0115 0116 KoShapePainter::KoShapePainter() 0117 : d(new Private()) 0118 { 0119 } 0120 0121 KoShapePainter::~KoShapePainter() 0122 { 0123 delete d; 0124 } 0125 0126 void KoShapePainter::setShapes(const QList<KoShape*> &shapes) 0127 { 0128 d->canvas->shapeManager()->setShapes(shapes, KoShapeManager::AddWithoutRepaint); 0129 } 0130 0131 void KoShapePainter::paint(QPainter &painter) 0132 { 0133 foreach (KoShape *shape, d->canvas->shapeManager()->shapes()) { 0134 shape->waitUntilReady(false); 0135 } 0136 0137 d->canvas->shapeManager()->paint(painter); 0138 } 0139 0140 void KoShapePainter::paint(QPainter &painter, const QRect &painterRect, const QRectF &documentRect) 0141 { 0142 if (documentRect.width() == 0.0f || documentRect.height() == 0.0f) 0143 return; 0144 0145 KoViewConverter converter; 0146 // calculate the painter destination rectangle size in document coordinates 0147 QRectF paintBox = converter.viewToDocument(QRectF(QPointF(), painterRect.size())); 0148 0149 // compute the zoom factor based on the bounding rects in document coordinates 0150 // so that the content fits into the image 0151 qreal zoomW = paintBox.width() / documentRect.width(); 0152 qreal zoomH = paintBox.height() / documentRect.height(); 0153 qreal zoom = qMin(zoomW, zoomH); 0154 0155 // now set the zoom into the zoom handler used for painting the shape 0156 converter.setZoom(zoom); 0157 0158 painter.save(); 0159 0160 // initialize painter 0161 painter.setPen(QPen(Qt::NoPen)); 0162 painter.setBrush(Qt::NoBrush); 0163 painter.setRenderHint(QPainter::Antialiasing); 0164 painter.setClipRect(painterRect.adjusted(-1,-1,1,1)); 0165 0166 // convert document rectangle to view coordinates 0167 QRectF zoomedBound = converter.documentToView(documentRect); 0168 // calculate offset between painter rectangle and converted document rectangle 0169 QPointF offset = QRectF(painterRect).center() - zoomedBound.center(); 0170 // center content in painter rectangle 0171 painter.translate(offset.x(), offset.y()); 0172 painter.setTransform(converter.documentToView(), true); 0173 0174 // finally paint the shapes 0175 paint(painter); 0176 0177 painter.restore(); 0178 } 0179 0180 void KoShapePainter::paint(QImage &image) 0181 { 0182 if (image.isNull()) 0183 return; 0184 0185 QPainter painter(&image); 0186 0187 paint(painter, image.rect(), contentRect()); 0188 } 0189 0190 QRectF KoShapePainter::contentRect() const 0191 { 0192 QRectF bound; 0193 foreach (KoShape *shape, d->canvas->shapeManager()->shapes()) { 0194 if (!shape->isVisible()) 0195 continue; 0196 if (dynamic_cast<KoShapeGroup*>(shape)) 0197 continue; 0198 0199 QRectF shapeRect = shape->boundingRect(); 0200 0201 if (bound.isEmpty()) 0202 bound = shapeRect; 0203 else 0204 bound = bound.united(shapeRect); 0205 } 0206 return bound; 0207 }