File indexing completed on 2025-02-23 04:08:58

0001 /*
0002  * SPDX-FileCopyrightText: 2007, 2010 Adrian Page <adrian@pagenet.plus.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_canvas_widget_base.h"
0008 
0009 #include <QImage>
0010 #include <QPainter>
0011 #include <QTimer>
0012 #include <QMenu>
0013 
0014 #include <KoShapeManager.h>
0015 #include <KoToolManager.h>
0016 #include <KoViewConverter.h>
0017 #include <KoToolProxy.h>
0018 #include <KoCanvasController.h>
0019 #include <KoShape.h>
0020 #include <KoSelection.h>
0021 
0022 
0023 #include "kis_coordinates_converter.h"
0024 #include "kis_canvas_decoration.h"
0025 #include "kis_config.h"
0026 #include "kis_canvas2.h"
0027 #include "KisViewManager.h"
0028 #include "kis_selection_manager.h"
0029 #include "KisDocument.h"
0030 #include "kis_update_info.h"
0031 #include "KisQPainterStateSaver.h"
0032 
0033 
0034 struct KisCanvasWidgetBase::Private
0035 {
0036 public:
0037     Private(KisCanvas2 *newCanvas, KisCoordinatesConverter *newCoordinatesConverter)
0038         : canvas(newCanvas)
0039         , coordinatesConverter(newCoordinatesConverter)
0040         , viewConverter(newCanvas->viewConverter())
0041         , toolProxy(newCanvas->toolProxy())
0042         , ignorenextMouseEventExceptRightMiddleClick(0)
0043         , borderColor(Qt::gray)
0044     {}
0045 
0046     QList<KisCanvasDecorationSP> decorations;
0047     KisCanvas2 * canvas;
0048     KisCoordinatesConverter *coordinatesConverter;
0049     const KoViewConverter * viewConverter;
0050     KoToolProxy * toolProxy;
0051     QTimer blockMouseEvent;
0052 
0053     bool ignorenextMouseEventExceptRightMiddleClick; // HACK work around Qt bug not sending tablet right/dblclick https://bugreports.qt.io/browse/QTBUG-8598
0054     QColor borderColor;
0055 };
0056 
0057 KisCanvasWidgetBase::KisCanvasWidgetBase(KisCanvas2 * canvas, KisCoordinatesConverter *coordinatesConverter)
0058     : m_d(new Private(canvas, coordinatesConverter))
0059 {
0060     m_d->blockMouseEvent.setSingleShot(true);
0061 }
0062 
0063 KisCanvasWidgetBase::~KisCanvasWidgetBase()
0064 {
0065     /**
0066      * Clear all the attached decoration. Otherwise they might decide
0067      * to process some events or signals after the canvas has been
0068      * destroyed
0069      */
0070     //5qDeleteAll(m_d->decorations);
0071     m_d->decorations.clear();
0072 
0073     delete m_d;
0074 }
0075 
0076 void KisCanvasWidgetBase::drawDecorations(QPainter & gc, const QRect &updateWidgetRect) const
0077 {
0078     if (!m_d->canvas) {
0079         dbgFile<<"canvas doesn't exist, in canvas widget base!";
0080         return;
0081     }
0082     gc.save();
0083 
0084     // Setup the painter to take care of the offset; all that the
0085     // classes that do painting need to keep track of is resolution
0086     gc.setRenderHint(QPainter::Antialiasing);
0087     gc.setRenderHint(QPainter::TextAntialiasing);
0088 
0089     // This option does not do anything anymore with Qt4.6, so don't re-enable it since it seems to break display
0090     // https://lists.qt-project.org/pipermail/qt-interest-old/2009-December/017078.html
0091     // gc.setRenderHint(QPainter::Antialiasing);
0092 
0093     gc.setRenderHint(QPainter::SmoothPixmapTransform);
0094 
0095     {
0096         KisQPainterStateSaver paintShapesState(&gc);
0097         gc.setTransform(m_d->coordinatesConverter->documentToWidgetTransform());
0098 
0099         // Paint the shapes (other than the layers)
0100         m_d->canvas->globalShapeManager()->paint(gc);
0101 
0102     }
0103 
0104     // ask the decorations to paint themselves
0105     // decorations are painted in "widget" coordinate system
0106     Q_FOREACH (KisCanvasDecorationSP deco, m_d->decorations) {
0107         if (deco->visible()) {
0108             deco->paint(gc, m_d->coordinatesConverter->widgetToDocument(updateWidgetRect), m_d->coordinatesConverter,m_d->canvas);
0109         }
0110     }
0111 
0112     {
0113         KisQPainterStateSaver paintDecorationsState(&gc);
0114         gc.setTransform(m_d->coordinatesConverter->flakeToWidgetTransform());
0115 
0116         // - some tools do not restore gc, but that is not important here
0117         toolProxy()->paint(gc, *m_d->viewConverter);
0118     }
0119 
0120     gc.restore();
0121 }
0122 
0123 void KisCanvasWidgetBase::addDecoration(KisCanvasDecorationSP deco)
0124 {
0125     m_d->decorations.push_back(deco);
0126     std::stable_sort(m_d->decorations.begin(), m_d->decorations.end(), KisCanvasDecoration::comparePriority);
0127 }
0128 
0129 void KisCanvasWidgetBase::removeDecoration(const QString &id)
0130 {
0131     for (auto it = m_d->decorations.begin(); it != m_d->decorations.end(); ++it) {
0132         if ((*it)->id() == id) {
0133             it = m_d->decorations.erase(it);
0134             break;
0135         }
0136     }
0137 }
0138 
0139 KisCanvasDecorationSP KisCanvasWidgetBase::decoration(const QString& id) const
0140 {
0141     Q_FOREACH (KisCanvasDecorationSP deco, m_d->decorations) {
0142         if (deco->id() == id) {
0143             return deco;
0144         }
0145     }
0146     return 0;
0147 }
0148 
0149 void KisCanvasWidgetBase::setDecorations(const QList<KisCanvasDecorationSP > &decorations)
0150 {
0151     m_d->decorations=decorations;
0152     std::stable_sort(m_d->decorations.begin(), m_d->decorations.end(), KisCanvasDecoration::comparePriority);
0153 }
0154 
0155 QList<KisCanvasDecorationSP > KisCanvasWidgetBase::decorations() const
0156 {
0157     return m_d->decorations;
0158 }
0159 void KisCanvasWidgetBase::notifyDecorationsWindowMinimized(bool minimized)
0160 {
0161     Q_FOREACH (KisCanvasDecorationSP deco, m_d->decorations) {
0162         deco->notifyWindowMinimized(minimized);
0163     }
0164 }
0165 void KisCanvasWidgetBase::setWrapAroundViewingMode(bool value)
0166 {
0167     Q_UNUSED(value);
0168 }
0169 
0170 void KisCanvasWidgetBase::setWrapAroundViewingModeAxis(WrapAroundAxis value)
0171 {
0172     Q_UNUSED(value);
0173 }
0174 
0175 QImage KisCanvasWidgetBase::createCheckersImage(qint32 checkSize)
0176 {
0177     KisConfig cfg(true);
0178 
0179     if(checkSize < 0)
0180         checkSize = cfg.checkSize();
0181 
0182     QColor checkColor1 = cfg.checkersColor1();
0183     QColor checkColor2 = cfg.checkersColor2();
0184 
0185     QImage tile(checkSize * 2, checkSize * 2, QImage::Format_RGB32);
0186     QPainter pt(&tile);
0187     pt.fillRect(tile.rect(), checkColor2);
0188     pt.fillRect(0, 0, checkSize, checkSize, checkColor1);
0189     pt.fillRect(checkSize, checkSize, checkSize, checkSize, checkColor1);
0190     pt.end();
0191 
0192     return tile;
0193 }
0194 
0195 void KisCanvasWidgetBase::notifyConfigChanged()
0196 {
0197     KisConfig cfg(true);
0198     m_d->borderColor = cfg.canvasBorderColor();
0199 }
0200 
0201 QColor KisCanvasWidgetBase::borderColor() const
0202 {
0203     return m_d->borderColor;
0204 }
0205 
0206 KisCanvas2 *KisCanvasWidgetBase::canvas() const
0207 {
0208     return m_d->canvas;
0209 }
0210 
0211 KisCoordinatesConverter* KisCanvasWidgetBase::coordinatesConverter() const
0212 {
0213     return m_d->coordinatesConverter;
0214 }
0215 
0216 QVector<QRect> KisCanvasWidgetBase::updateCanvasProjection(const QVector<KisUpdateInfoSP> &infoObjects)
0217 {
0218     QVector<QRect> dirtyViewRects;
0219 
0220     Q_FOREACH (KisUpdateInfoSP info, infoObjects) {
0221         dirtyViewRects << this->updateCanvasProjection(info);
0222     }
0223 
0224     return dirtyViewRects;
0225 }
0226 
0227 KoToolProxy *KisCanvasWidgetBase::toolProxy() const
0228 {
0229     return m_d->toolProxy;
0230 }
0231 
0232 QVariant KisCanvasWidgetBase::processInputMethodQuery(Qt::InputMethodQuery query) const
0233 {
0234     return m_d->toolProxy->inputMethodQuery(query);
0235 }
0236 
0237 void KisCanvasWidgetBase::processInputMethodEvent(QInputMethodEvent *event)
0238 {
0239     m_d->toolProxy->inputMethodEvent(event);
0240 }
0241 
0242 void KisCanvasWidgetBase::processFocusInEvent(QFocusEvent *event)
0243 {
0244     m_d->toolProxy->focusInEvent(event);
0245 }
0246 
0247 void KisCanvasWidgetBase::processFocusOutEvent(QFocusEvent *event)
0248 {
0249     m_d->toolProxy->focusOutEvent(event);
0250 }