diff --git a/krita/plugins/extensions/dockers/lut/ocio_display_filter.h b/krita/plugins/extensions/dockers/lut/ocio_display_filter.h index af5c05caca..0717895090 100644 --- a/krita/plugins/extensions/dockers/lut/ocio_display_filter.h +++ b/krita/plugins/extensions/dockers/lut/ocio_display_filter.h @@ -1,97 +1,97 @@ /* * Copyright (c) 2012 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef OCIO_DISPLAY_FILTER_H #define OCIO_DISPLAY_FILTER_H +#include // for HAVE_OPENGL #include "kritalutdocker_export.h" #include #include #include #include -#include #include "kis_exposure_gamma_correction_interface.h" namespace OCIO = OCIO_NAMESPACE; enum OCIO_CHANNEL_SWIZZLE { LUMINANCE, RGBA, R, G, B, A }; class KRITALUTDOCKER_EXPORT OcioDisplayFilter : public KisDisplayFilter { Q_OBJECT public: explicit OcioDisplayFilter(KisExposureGammaCorrectionInterface *interface, QObject *parent = 0); ~OcioDisplayFilter(); void filter(quint8 *pixels, quint32 numPixels); void approximateInverseTransformation(quint8 *pixels, quint32 numPixels); void approximateForwardTransformation(quint8 *pixels, quint32 numPixels); bool useInternalColorManagement() const; bool lockCurrentColorVisualRepresentation() const; void setLockCurrentColorVisualRepresentation(bool value); KisExposureGammaCorrectionInterface *correctionInterface() const; #ifdef HAVE_OPENGL virtual QString program() const; GLuint lutTexture() const; #endif void updateProcessor(); OCIO::ConstConfigRcPtr config; const char *inputColorSpaceName; const char *displayDevice; const char *view; OCIO_CHANNEL_SWIZZLE swizzle; float exposure; float gamma; float blackPoint; float whitePoint; bool forceInternalColorManagement; private: OCIO::ConstProcessorRcPtr m_processor; OCIO::ConstProcessorRcPtr m_revereseApproximationProcessor; OCIO::ConstProcessorRcPtr m_forwardApproximationProcessor; KisExposureGammaCorrectionInterface *m_interface; bool m_lockCurrentColorVisualRepresentation; #ifdef HAVE_OPENGL QString m_program; GLuint m_lut3dTexID; QVector m_lut3d; QString m_lut3dcacheid; QString m_shadercacheid; #endif }; #endif // OCIO_DISPLAY_FILTER_H diff --git a/krita/ui/canvas/kis_display_filter.h b/krita/ui/canvas/kis_display_filter.h index 8971c62b97..69fe5d33e4 100644 --- a/krita/ui/canvas/kis_display_filter.h +++ b/krita/ui/canvas/kis_display_filter.h @@ -1,54 +1,55 @@ /* * Copyright (c) 2012 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_DISPLAY_FILTER_H #define KIS_DISPLAY_FILTER_H #include -#include +#include // for HAVE_OPENGL +#ifdef HAVE_OPENGL #include +#endif -#include #include class KisExposureGammaCorrectionInterface; /** * @brief The KisDisplayFilter class is the base class for filters that * are applied by the canvas to the projection before displaying. */ class KRITAUI_EXPORT KisDisplayFilter : public QObject { Q_OBJECT public: explicit KisDisplayFilter(QObject *parent = 0); #ifdef HAVE_OPENGL virtual QString program() const = 0; virtual GLuint lutTexture() const = 0; #endif virtual void filter(quint8 *pixels, quint32 numPixels) = 0; virtual void approximateInverseTransformation(quint8 *pixels, quint32 numPixels) = 0; virtual void approximateForwardTransformation(quint8 *pixels, quint32 numPixels) = 0; virtual bool useInternalColorManagement() const = 0; virtual KisExposureGammaCorrectionInterface *correctionInterface() const = 0; virtual bool lockCurrentColorVisualRepresentation() const = 0; }; #endif diff --git a/krita/ui/canvas/kis_mirror_axis.cpp b/krita/ui/canvas/kis_mirror_axis.cpp index 7e079ba82e..b8f699228c 100644 --- a/krita/ui/canvas/kis_mirror_axis.cpp +++ b/krita/ui/canvas/kis_mirror_axis.cpp @@ -1,339 +1,341 @@ /* * Copyright (c) 2014 Arjen Hiemstra * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "kis_mirror_axis.h" #include "KoConfig.h" #include #include #include #include +#ifdef HAVE_OPENGL #include #include +#endif #include #include "kis_canvas_resource_provider.h" #include "KisViewManager.h" #include "KisView.h" #include "kis_image.h" #include "canvas/kis_canvas_controller.h" #include "input/kis_input_manager.h" #include "kis_algebra_2d.h" class KisMirrorAxis::Private { public: Private(KisMirrorAxis* qq) : q(qq) , resourceProvider(0) , mirrorHorizontal(false) , mirrorVertical(false) , handleSize(32.f) , xActive(false) , yActive(false) , horizontalHandlePosition(64.f) , verticalHandlePosition(64.f) , sideMargin(10.f) , minHandlePosition(10.f + 32.f) , horizontalContainsCursor(false) , verticalContainsCursor(false) , horizontalAxis(QLineF()) , verticalAxis(QLineF()) { } void setAxisPosition(float x, float y); void recomputeVisibleAxes(QRect viewport); KisMirrorAxis* q; KisCanvasResourceProvider* resourceProvider; bool mirrorHorizontal; bool mirrorVertical; float handleSize; QPixmap horizontalHandleIcon; QPixmap verticalHandleIcon; QPixmap horizontalIcon; QPixmap verticalIcon; QPointF axisPosition; QRectF horizontalHandle; QRectF verticalHandle; bool xActive; bool yActive; float horizontalHandlePosition; float verticalHandlePosition; float sideMargin; float minHandlePosition; bool horizontalContainsCursor; bool verticalContainsCursor; QLineF horizontalAxis; QLineF verticalAxis; }; KisMirrorAxis::KisMirrorAxis(KisCanvasResourceProvider* provider, QPointerparent) : KisCanvasDecoration("mirror_axis", parent) , d(new Private(this)) { d->resourceProvider = provider; connect(d->resourceProvider, SIGNAL(mirrorModeChanged()), SLOT(mirrorModeChanged())); d->mirrorHorizontal = d->resourceProvider->mirrorHorizontal(); d->mirrorVertical = d->resourceProvider->mirrorVertical(); d->horizontalIcon = KisIconUtils::loadIcon("mirrorAxis-HorizontalMove").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->verticalIcon = KisIconUtils::loadIcon("mirrorAxis-VerticalMove").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->horizontalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->verticalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); setVisible(d->mirrorHorizontal || d->mirrorVertical); int imageWidth = parent->canvasBase()->image()->width(); int imageHeight = parent->canvasBase()->image()->height(); QPointF point(imageWidth / 2, imageHeight / 2); d->resourceProvider->resourceManager()->setResource(KisCanvasResourceProvider::MirrorAxesCenter, point); parent->installEventFilter(this); KisInputManager *inputManager = parent->canvasBase()->globalInputManager(); if (inputManager) { inputManager->attachPriorityEventFilter(this); } } KisMirrorAxis::~KisMirrorAxis() { delete d; } float KisMirrorAxis::handleSize() const { return d->handleSize; } void KisMirrorAxis::setHandleSize(float newSize) { if(d->handleSize != newSize) { d->handleSize = newSize; d->horizontalIcon = KisIconUtils::loadIcon("symmetry-horyzontal").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->verticalIcon = KisIconUtils::loadIcon("symmetry-vertical").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->horizontalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->verticalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->minHandlePosition = d->sideMargin + newSize; emit handleSizeChanged(); } } void KisMirrorAxis::drawDecoration(QPainter& gc, const QRectF& updateArea, const KisCoordinatesConverter* converter, KisCanvas2* canvas) { Q_UNUSED(updateArea); Q_UNUSED(converter); Q_UNUSED(canvas); gc.setPen(QPen(QColor(0, 0, 0, 128), 1)); gc.setBrush(Qt::white); gc.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); #if defined(HAVE_OPENGL) QOpenGLContext *ctx = QOpenGLContext::currentContext(); bool hasMultisample = ((gc.paintEngine()->type() == QPaintEngine::OpenGL2) && (ctx->hasExtension("GL_ARB_multisample"))); // QPainter cannot anti-alias the edges of circles etc. when using OpenGL // So instead, use native OpenGL anti-aliasing when available. if (hasMultisample) { gc.beginNativePainting(); ctx->functions()->glEnable(GL_MULTISAMPLE); gc.endNativePainting(); } #endif float halfHandleSize = d->handleSize / 2; d->recomputeVisibleAxes(gc.viewport()); if(d->mirrorHorizontal) { if (!d->horizontalAxis.isNull()) { // QPointF horizontalIndicatorCenter = d->horizontalAxis.unitVector().pointAt(15); // QRectF horizontalIndicator = QRectF(horizontalIndicatorCenter.x() - halfHandleSize, horizontalIndicatorCenter.y() - halfHandleSize, d->handleSize, d->handleSize); float horizontalHandlePosition = qBound(d->minHandlePosition, d->horizontalHandlePosition, d->horizontalAxis.length() - d->minHandlePosition); QPointF horizontalHandleCenter = d->horizontalAxis.unitVector().pointAt(horizontalHandlePosition); d->horizontalHandle = QRectF(horizontalHandleCenter.x() - halfHandleSize, horizontalHandleCenter.y() - halfHandleSize, d->handleSize, d->handleSize); gc.setPen(QPen(QColor(0, 0, 0, 64), 2, Qt::DashDotDotLine, Qt::RoundCap, Qt::RoundJoin)); gc.drawLine(d->horizontalAxis); // gc.drawEllipse(horizontalIndicator); // gc.drawPixmap(horizontalIndicator.adjusted(5, 5, -5, -5).toRect(), d->horizontalIcon); gc.setPen(QPen(QColor(0, 0, 0, 128), 2)); gc.drawEllipse(d->horizontalHandle); gc.drawPixmap(d->horizontalHandle.adjusted(5, 5, -5, -5).toRect(), d->horizontalIcon); } else { d->horizontalHandle = QRectF(); } } if(d->mirrorVertical) { if (!d->verticalAxis.isNull()) { gc.setPen(QPen(QColor(0, 0, 0, 64), 2, Qt::DashDotDotLine, Qt::RoundCap, Qt::RoundJoin)); gc.drawLine(d->verticalAxis); // QPointF verticalIndicatorCenter = d->verticalAxis.unitVector().pointAt(15); // QRectF verticalIndicator = QRectF(verticalIndicatorCenter.x() - halfHandleSize, verticalIndicatorCenter.y() - halfHandleSize, d->handleSize, d->handleSize); float verticalHandlePosition = qBound(d->minHandlePosition, d->verticalHandlePosition, d->verticalAxis.length() - d->minHandlePosition); QPointF verticalHandleCenter = d->verticalAxis.unitVector().pointAt(verticalHandlePosition); d->verticalHandle = QRectF(verticalHandleCenter.x() - halfHandleSize, verticalHandleCenter.y() - halfHandleSize, d->handleSize, d->handleSize); // gc.drawEllipse(verticalIndicator); // gc.drawPixmap(verticalIndicator.adjusted(5, 5, -5, -5).toRect(), d->verticalIcon); gc.setPen(QPen(QColor(0, 0, 0, 128), 2)); gc.drawEllipse(d->verticalHandle); gc.drawPixmap(d->verticalHandle.adjusted(5, 5, -5, -5).toRect(), d->verticalIcon); } else { d->verticalHandle = QRectF(); } } #if defined(HAVE_OPENGL) if (hasMultisample) { gc.beginNativePainting(); ctx->functions()->glDisable(GL_MULTISAMPLE); gc.endNativePainting(); } #endif } bool KisMirrorAxis::eventFilter(QObject* target, QEvent* event) { if(event->type() == QEvent::MouseButtonPress || event->type() == QEvent::TabletPress) { QMouseEvent* me = static_cast(event); if(d->mirrorHorizontal && d->horizontalHandle.contains(me->posF())) { d->xActive = true; QApplication::setOverrideCursor(Qt::ClosedHandCursor); event->accept(); return true; } if(d->mirrorVertical && d->verticalHandle.contains(me->posF())) { d->yActive = true; QApplication::setOverrideCursor(Qt::ClosedHandCursor); event->accept(); return true; } } if(event->type() == QEvent::MouseMove || event->type() == QEvent::TabletMove) { QMouseEvent* me = static_cast(event); if(d->xActive) { float axisX = view()->viewConverter()->widgetToImage(me->pos()).x(); d->setAxisPosition(axisX, d->axisPosition.y()); d->horizontalHandlePosition = KisAlgebra2D::dotProduct(me->pos() - d->horizontalAxis.p1(), d->horizontalAxis.unitVector().p2() - d->horizontalAxis.p1()); event->accept(); return true; } if(d->yActive) { float axisY = view()->viewConverter()->widgetToImage(me->pos()).y(); d->setAxisPosition(d->axisPosition.x(), axisY); d->verticalHandlePosition = KisAlgebra2D::dotProduct(me->pos() - d->verticalAxis.p1(), d->verticalAxis.unitVector().p2() - d->verticalAxis.p1()); event->accept(); return true; } if(d->mirrorHorizontal) { if(d->horizontalHandle.contains(me->posF())) { if(!d->horizontalContainsCursor) { QApplication::setOverrideCursor(Qt::OpenHandCursor); d->horizontalContainsCursor = true; } } else if(d->horizontalContainsCursor) { QApplication::restoreOverrideCursor(); d->horizontalContainsCursor = false; } } if(d->mirrorVertical) { if(d->verticalHandle.contains(me->posF())) { if(!d->verticalContainsCursor) { QApplication::setOverrideCursor(Qt::OpenHandCursor); d->verticalContainsCursor = true; } } else if(d->verticalContainsCursor) { QApplication::restoreOverrideCursor(); d->verticalContainsCursor = false; } } } if(event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::TabletRelease) { QApplication::restoreOverrideCursor(); if(d->xActive) { d->xActive = false; event->accept(); return true; } if(d->yActive) { d->yActive = false; event->accept(); return true; } } return QObject::eventFilter(target, event); } void KisMirrorAxis::mirrorModeChanged() { d->mirrorHorizontal = d->resourceProvider->mirrorHorizontal(); d->mirrorVertical = d->resourceProvider->mirrorVertical(); setVisible(d->mirrorHorizontal || d->mirrorVertical); } void KisMirrorAxis::Private::setAxisPosition(float x, float y) { QPointF newPosition = QPointF(x, y); resourceProvider->resourceManager()->setResource(KisCanvasResourceProvider::MirrorAxesCenter, newPosition); q->view()->canvasBase()->updateCanvas(); } void KisMirrorAxis::Private::recomputeVisibleAxes(QRect viewport) { KisCoordinatesConverter *converter = q->view()->viewConverter(); axisPosition = resourceProvider->resourceManager()->resource(KisCanvasResourceProvider::MirrorAxesCenter).toPointF(); QPointF samplePt1 = converter->imageToWidget(axisPosition); QPointF samplePt2 = converter->imageToWidget(QPointF(axisPosition.x(), axisPosition.y() - 100)); horizontalAxis = QLineF(samplePt1, samplePt2); if (!KisAlgebra2D::intersectLineRect(horizontalAxis, viewport)) horizontalAxis = QLineF(); samplePt2 = converter->imageToWidget(QPointF(axisPosition.x() - 100, axisPosition.y())); verticalAxis = QLineF(samplePt1, samplePt2); if (!KisAlgebra2D::intersectLineRect(verticalAxis, viewport)) verticalAxis = QLineF(); } diff --git a/krita/ui/canvas/kis_update_info.h b/krita/ui/canvas/kis_update_info.h index 483a2de676..27b322443c 100644 --- a/krita/ui/canvas/kis_update_info.h +++ b/krita/ui/canvas/kis_update_info.h @@ -1,143 +1,143 @@ /* * Copyright (c) 2010, Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_UPDATE_INFO_H_ #define KIS_UPDATE_INFO_H_ #include #include "kis_image_patch.h" #include "kis_shared.h" -#include "opengl/kis_opengl.h" #include "kritaui_export.h" +#include // for HAVE_OPENGL #include "kis_ui_types.h" class KRITAUI_EXPORT KisUpdateInfo : public KisShared { public: KisUpdateInfo(); virtual ~KisUpdateInfo(); virtual QRect dirtyViewportRect(); virtual QRect dirtyImageRect() const = 0; }; Q_DECLARE_METATYPE(KisUpdateInfoSP) #ifdef HAVE_OPENGL #include "opengl/kis_texture_tile_update_info.h" struct ConversionOptions { ConversionOptions() : m_needsConversion(false) {} ConversionOptions(const KoColorSpace *destinationColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) : m_needsConversion(true), m_destinationColorSpace(destinationColorSpace), m_renderingIntent(renderingIntent), m_conversionFlags(conversionFlags) { } bool m_needsConversion; const KoColorSpace *m_destinationColorSpace; KoColorConversionTransformation::Intent m_renderingIntent; KoColorConversionTransformation::ConversionFlags m_conversionFlags; }; class KisOpenGLUpdateInfo; typedef KisSharedPtr KisOpenGLUpdateInfoSP; class KisOpenGLUpdateInfo : public KisUpdateInfo { public: KisOpenGLUpdateInfo(ConversionOptions options); KisTextureTileUpdateInfoSPList tileList; QRect dirtyViewportRect(); QRect dirtyImageRect() const; void assignDirtyImageRect(const QRect &rect); bool needsConversion() const; void convertColorSpace(); private: QRect m_dirtyImageRect; ConversionOptions m_options; }; #endif /* HAVE_OPENGL */ class KisPPUpdateInfo : public KisUpdateInfo { public: enum TransferType { DIRECT, PATCH }; QRect dirtyViewportRect(); QRect dirtyImageRect() const; /** * The rect that was reported by KisImage as dirty */ QRect dirtyImageRectVar; /** * Rect of KisImage corresponding to @viewportRect. * It is cropped and aligned corresponding to the canvas. */ QRect imageRect; /** * Rect of canvas widget corresponding to @imageRect */ QRectF viewportRect; qreal scaleX; qreal scaleY; /** * Defines the way the source image is painted onto * prescaled QImage */ TransferType transfer; /** * Render hints for painting the direct painting/patch painting */ QPainter::RenderHints renderHints; /** * The number of additional pixels those should be added * to the patch */ qint32 borderWidth; /** * Used for temporary sorage of KisImage's data * by KisProjectionCache */ KisImagePatch patch; }; #endif /* KIS_UPDATE_INFO_H_ */ diff --git a/krita/ui/opengl/kis_opengl_image_textures.h b/krita/ui/opengl/kis_opengl_image_textures.h index f859f9e686..95c4d02314 100644 --- a/krita/ui/opengl/kis_opengl_image_textures.h +++ b/krita/ui/opengl/kis_opengl_image_textures.h @@ -1,214 +1,214 @@ /* * Copyright (c) 2005-2007 Adrian Page * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_OPENGL_IMAGE_TEXTURES_H_ #define KIS_OPENGL_IMAGE_TEXTURES_H_ -#include +#include // for HAVE_OPENGL #ifdef HAVE_OPENGL #include #include #include #include "kritaui_export.h" #include "kis_shared.h" #include "canvas/kis_update_info.h" #include "opengl/kis_texture_tile.h" class KisOpenGLImageTextures; class QOpenGLFunctions; typedef KisSharedPtr KisOpenGLImageTexturesSP; class KoColorProfile; /** * A set of OpenGL textures that contains the projection of a KisImage. */ class KRITAUI_EXPORT KisOpenGLImageTextures : public QObject, public KisShared { Q_OBJECT public: /** * Obtain a KisOpenGLImageTextures object for the given image. * @param image The image * @param monitorProfile The profile of the display device */ static KisOpenGLImageTexturesSP getImageTextures(KisImageWSP image, const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); /** * Default constructor. */ KisOpenGLImageTextures(); /** * Destructor. */ virtual ~KisOpenGLImageTextures(); /** * \return the image associated with the textures */ KisImageSP image() const; /** * Set the color profile of the display device. * @param profile The color profile of the display device */ void setMonitorProfile(const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); /** * Complete initialization can only happen once an OpenGL context has been created. * @param f Pointer to OpenGL functions. They must already be ininitialized. */ void initGL(QOpenGLFunctions *f); void setChannelFlags(const QBitArray &channelFlags); bool internalColorManagementActive() const; bool setInternalColorManagementActive(bool value); /** * The background checkers texture. */ static const int BACKGROUND_TEXTURE_CHECK_SIZE = 32; static const int BACKGROUND_TEXTURE_SIZE = BACKGROUND_TEXTURE_CHECK_SIZE * 2; /** * Generate a background texture from the given QImage. This is used for the checker * pattern on which the image is rendered. */ void generateCheckerTexture(const QImage & checkImage); GLuint checkerTexture(); void updateConfig(bool useBuffer, int NumMipmapLevels); public: inline QRect storedImageBounds() { return m_storedImageBounds; } inline int xToCol(int x) { return x / m_texturesInfo.effectiveWidth; } inline int yToRow(int y) { return y / m_texturesInfo.effectiveHeight; } inline KisTextureTile* getTextureTileCR(int col, int row) { if (m_initialized) { int tile = row * m_numCols + col; KIS_ASSERT_RECOVER_RETURN_VALUE(m_textureTiles.size() > tile, 0); return m_textureTiles[tile]; } return 0; } inline KisTextureTile* getTextureTile(int x, int y) { return getTextureTileCR(xToCol(x), yToRow(y)); } inline qreal texelSize() const { Q_ASSERT(m_texturesInfo.width == m_texturesInfo.height); return 1.0 / m_texturesInfo.width; } KisOpenGLUpdateInfoSP updateCache(const QRect& rect); KisOpenGLUpdateInfoSP updateCacheNoConversion(const QRect& rect); public Q_SLOTS: void recalculateCache(KisUpdateInfoSP info); void slotImageSizeChanged(qint32 w, qint32 h); protected: KisOpenGLImageTextures(KisImageWSP image, const KoColorProfile *monitorProfile, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags); void createImageTextureTiles(); void destroyImageTextureTiles(); static bool imageCanShareTextures(); private: QRect calculateTileRect(int col, int row) const; void getTextureSize(KisGLTexturesInfo *texturesInfo); void updateTextureFormat(); KisOpenGLUpdateInfoSP updateCacheImpl(const QRect& rect, bool convertColorSpace); private: KisImageWSP m_image; QRect m_storedImageBounds; const KoColorProfile *m_monitorProfile; KoColorConversionTransformation::Intent m_renderingIntent; KoColorConversionTransformation::ConversionFlags m_conversionFlags; /** * If the destination color space coincides with the one of the image, * then effectively, there is no conversion happens. That is used * for working with OCIO. */ const KoColorSpace* m_tilesDestinationColorSpace; /** * Shows whether the internal color management should be enabled or not. * Please note that if you disable color management, *but* your image color * space will not be supported (non-RGB), then it will be enabled anyway. * And this valiable will hold the real state of affairs! */ bool m_internalColorManagementActive; GLuint m_checkerTexture; KisGLTexturesInfo m_texturesInfo; int m_numCols; QVector m_textureTiles; QOpenGLFunctions *m_glFuncs; QBitArray m_channelFlags; bool m_allChannelsSelected; bool m_onlyOneChannelSelected; int m_selectedChannelIndex; bool m_useOcio; bool m_initialized; private: typedef QMap ImageTexturesMap; static ImageTexturesMap imageTexturesMap; }; #endif // HAVE_OPENGL #endif // KIS_OPENGL_IMAGE_TEXTURES_H_ diff --git a/krita/ui/opengl/kis_texture_tile.h b/krita/ui/opengl/kis_texture_tile.h index 9453dc7cc2..38ef350d1e 100644 --- a/krita/ui/opengl/kis_texture_tile.h +++ b/krita/ui/opengl/kis_texture_tile.h @@ -1,130 +1,130 @@ /* * Copyright (c) 2010 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_TEXTURE_TILE_H_ #define KIS_TEXTURE_TILE_H_ -#include +#include // for HAVE_OPENGL #ifdef HAVE_OPENGL class KisTextureTileUpdateInfo; #include #include #include #if !defined(QT_OPENGL_ES) #define USE_PIXEL_BUFFERS #include #endif struct KisGLTexturesInfo { // real width and height int width; int height; // width and height minus border padding? int effectiveWidth; int effectiveHeight; // size of the border padding int border; GLint internalFormat; GLint format; GLint type; }; inline QRect stretchRect(const QRect &rc, int delta) { return rc.adjusted(-delta, -delta, delta, delta); } class KisTextureTile { public: enum FilterMode { NearestFilterMode, // nearest BilinearFilterMode, // linear, no mipmap TrilinearFilterMode, // LINEAR_MIPMAP_LINEAR HighQualityFiltering // Mipmaps + custom shader }; KisTextureTile(const QRect &imageRect, const KisGLTexturesInfo *texturesInfo, const QByteArray &fillData, FilterMode mode, bool useBuffer, int numMipmapLevels, QOpenGLFunctions *f); ~KisTextureTile(); void setUseBuffer(bool useBuffer) { m_useBuffer = useBuffer; } void setNumMipmapLevels(int num) { m_numMipmapLevels = num; } void update(const KisTextureTileUpdateInfo &updateInfo); inline QRect tileRectInImagePixels() { return m_tileRectInImagePixels; } inline QRect textureRectInImagePixels() { return m_textureRectInImagePixels; } inline QRectF tileRectInTexturePixels() { return m_tileRectInTexturePixels; } void bindToActiveTexture(); int currentLodPlane() const; private: inline void setTextureParameters(); void setNeedsMipmapRegeneration(); void setCurrentLodPlane(int lod); GLuint m_textureId; #ifdef USE_PIXEL_BUFFERS void createTextureBuffer(const char*data, int size); QOpenGLBuffer *m_glBuffer; #endif QRect m_tileRectInImagePixels; QRectF m_tileRectInTexturePixels; QRect m_textureRectInImagePixels; FilterMode m_filter; const KisGLTexturesInfo *m_texturesInfo; bool m_needsMipmapRegeneration; int m_currentLodPlane; bool m_useBuffer; int m_numMipmapLevels; QOpenGLFunctions *f; Q_DISABLE_COPY(KisTextureTile) }; #endif /* HAVE_OPENGL */ #endif /* KIS_TEXTURE_TILE_H_ */ diff --git a/krita/ui/opengl/kis_texture_tile_update_info.h b/krita/ui/opengl/kis_texture_tile_update_info.h index 30cb3c4349..026b5b9485 100644 --- a/krita/ui/opengl/kis_texture_tile_update_info.h +++ b/krita/ui/opengl/kis_texture_tile_update_info.h @@ -1,304 +1,304 @@ /* * Copyright (c) 2010, Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_TEXTURE_TILE_UPDATE_INFO_H_ #define KIS_TEXTURE_TILE_UPDATE_INFO_H_ -#include "opengl/kis_opengl.h" +#include // for HAVE_OPENGL #ifdef HAVE_OPENGL #include #include #include #include #include "kis_image.h" #include "kis_paint_device.h" #include "kis_config.h" #include #include #include class KisTextureTileUpdateInfo; typedef QSharedPointer KisTextureTileUpdateInfoSP; typedef QVector KisTextureTileUpdateInfoSPList; class ConversionCache { public: class Buffer { public: Buffer () : m_size(0) {} inline void swap(Buffer &rhs) { m_data.swap(rhs.m_data); qSwap(m_size, rhs.m_size); } inline quint8* data() const { return m_data.data(); } inline void ensureNotSmaller(int size) { if (size > m_size) { try { m_data.reset(new quint8[size]); m_size = size; } catch (std::bad_alloc) { QMessageBox::critical(0, i18nc("@title:window", "Fatal Error"), i18n("Krita has run out of memory and has to close.")); qFatal("KisTextureTileUpdateInfo: Could not allocate enough memory"); } } } private: QScopedArrayPointer m_data; int m_size; }; public: inline void swap(Buffer &rhs) { m_cache.localData()->swap(rhs); } inline quint8* data() const { return m_cache.localData()->data(); } inline void ensureNotSmaller(int size) { if (!m_cache.hasLocalData()) { m_cache.setLocalData(new Buffer()); } m_cache.localData()->ensureNotSmaller(size); } private: QThreadStorage m_cache; }; class KisTextureTileUpdateInfo { public: KisTextureTileUpdateInfo() : m_patchPixelsLength(0) { } KisTextureTileUpdateInfo(qint32 col, qint32 row, QRect tileRect, QRect updateRect, QRect currentImageRect, int levelOfDetail) : m_patchPixelsLength(0) { m_tileCol = col; m_tileRow = row; m_tileRect = tileRect; m_originalTileRect = m_tileRect; m_patchRect = m_tileRect & updateRect; m_originalPatchRect = m_patchRect; m_currentImageRect = currentImageRect; m_patchLevelOfDetail = levelOfDetail; if (m_patchLevelOfDetail) { m_originalPatchRect = KisLodTransform::alignedRect(m_originalPatchRect, m_patchLevelOfDetail); m_patchRect = KisLodTransform::scaledRect(m_originalPatchRect, m_patchLevelOfDetail); m_tileRect = KisLodTransform::scaledRect(m_originalTileRect, m_patchLevelOfDetail); } } ~KisTextureTileUpdateInfo() { if (m_patchPixels.data()) { m_patchPixelsCache.swap(m_patchPixels); } } void retrieveData(KisImageWSP image, QBitArray m_channelFlags, bool onlyOneChannelSelected, int selectedChannelIndex) { m_patchColorSpace = image->projection()->colorSpace(); m_patchPixelsLength = m_patchColorSpace->pixelSize() * m_patchRect.width() * m_patchRect.height(); m_patchPixelsCache.ensureNotSmaller(m_patchPixelsLength); m_patchPixelsCache.swap(m_patchPixels); image->projection()->readBytes(m_patchPixels.data(), m_patchRect.x(), m_patchRect.y(), m_patchRect.width(), m_patchRect.height()); // XXX: if the paint colorspace is rgb, we should do the channel swizzling in // the display shader if (!m_channelFlags.isEmpty()) { m_conversionCache.ensureNotSmaller(m_patchPixelsLength); QList channelInfo = m_patchColorSpace->channels(); int channelSize = channelInfo[selectedChannelIndex]->size(); int pixelSize = m_patchColorSpace->pixelSize(); quint32 numPixels = m_patchRect.width() * m_patchRect.height(); KisConfig cfg; if (onlyOneChannelSelected && !cfg.showSingleChannelAsColor()) { int selectedChannelPos = channelInfo[selectedChannelIndex]->pos(); for (uint pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < m_patchColorSpace->channelCount(); ++channelIndex) { if (channelInfo[channelIndex]->channelType() == KoChannelInfo::COLOR) { memcpy(m_conversionCache.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), m_patchPixels.data() + (pixelIndex * pixelSize) + selectedChannelPos, channelSize); } else if (channelInfo[channelIndex]->channelType() == KoChannelInfo::ALPHA) { memcpy(m_conversionCache.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), m_patchPixels.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), channelSize); } } } } else { for (uint pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex) { for (uint channelIndex = 0; channelIndex < m_patchColorSpace->channelCount(); ++channelIndex) { if (m_channelFlags.testBit(channelIndex)) { memcpy(m_conversionCache.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), m_patchPixels.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), channelSize); } else { memset(m_conversionCache.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), 0, channelSize); } } } } m_conversionCache.swap(m_patchPixels); } } void convertTo(const KoColorSpace* dstCS, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) { if (dstCS == m_patchColorSpace && conversionFlags == KoColorConversionTransformation::Empty) return; if (m_patchRect.isValid()) { const qint32 numPixels = m_patchRect.width() * m_patchRect.height(); const quint32 conversionCacheLength = numPixels * dstCS->pixelSize(); m_conversionCache.ensureNotSmaller(conversionCacheLength); m_patchColorSpace->convertPixelsTo(m_patchPixels.data(), m_conversionCache.data(), dstCS, numPixels, renderingIntent, conversionFlags); m_patchColorSpace = dstCS; m_conversionCache.swap(m_patchPixels); m_patchPixelsLength = conversionCacheLength; } } inline quint8* data() const { return m_patchPixels.data(); } inline int patchLevelOfDetail() const { return m_patchLevelOfDetail; } inline QPoint realPatchOffset() const { return QPoint(m_patchRect.x() - m_tileRect.x(), m_patchRect.y() - m_tileRect.y()); } inline QSize realPatchSize() const { return m_patchRect.size(); } inline QSize realTileSize() const { return m_tileRect.size(); } inline bool isTopmost() const { return m_originalPatchRect.top() == m_currentImageRect.top(); } inline bool isLeftmost() const { return m_originalPatchRect.left() == m_currentImageRect.left(); } inline bool isRightmost() const { return m_originalPatchRect.right() == m_currentImageRect.right(); } inline bool isBottommost() const { return m_originalPatchRect.bottom() == m_currentImageRect.bottom(); } inline bool isEntireTileUpdated() const { return m_patchRect == m_tileRect; } inline qint32 tileCol() const { return m_tileCol; } inline qint32 tileRow() const { return m_tileRow; } inline quint32 pixelSize() const { return m_patchColorSpace->pixelSize(); } inline quint32 patchPixelsLength() const { return m_patchPixelsLength; } inline bool valid() const { return m_patchRect.isValid(); } private: Q_DISABLE_COPY(KisTextureTileUpdateInfo) private: qint32 m_tileCol; qint32 m_tileRow; QRect m_currentImageRect; QRect m_tileRect; QRect m_patchRect; const KoColorSpace* m_patchColorSpace; quint32 m_patchPixelsLength; QRect m_realPatchRect; QRect m_realPatchOffset; QRect m_realTileSize; int m_patchLevelOfDetail; QRect m_originalPatchRect; QRect m_originalTileRect; ConversionCache::Buffer m_patchPixels; static ConversionCache m_patchPixelsCache; static ConversionCache m_conversionCache; }; #endif /* HAVE_OPENGL */ #endif /* KIS_TEXTURE_TILE_UPDATE_INFO_H_ */ diff --git a/krita/ui/tool/kis_tool.cc b/krita/ui/tool/kis_tool.cc index 9ef7eb5196..9bc121d7ad 100644 --- a/krita/ui/tool/kis_tool.cc +++ b/krita/ui/tool/kis_tool.cc @@ -1,697 +1,699 @@ /* * Copyright (c) 2006, 2010 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool.h" -#include "opengl/kis_opengl.h" #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#ifdef HAVE_OPENGL #include "opengl/kis_opengl_canvas2.h" +#endif #include "kis_canvas_resource_provider.h" #include "canvas/kis_canvas2.h" #include "kis_coordinates_converter.h" #include "filter/kis_filter_configuration.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_cursor.h" #include #include #include "kis_resources_snapshot.h" #include #include "kis_action_registry.h" struct KisTool::Private { Private() : currentPattern(0), currentGradient(0), currentExposure(1.0), currentGenerator(0), optionWidget(0) { } QCursor cursor; // the cursor that should be shown on tool activation. // From the canvas resources KoPattern* currentPattern; KoAbstractGradient* currentGradient; KoColor currentFgColor; KoColor currentBgColor; float currentExposure; KisFilterConfiguration* currentGenerator; QWidget* optionWidget; }; KisTool::KisTool(KoCanvasBase * canvas, const QCursor & cursor) : KoToolBase(canvas) , d(new Private) { d->cursor = cursor; m_isActive = false; connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(resetCursorStyle())); connect(this, SIGNAL(isActiveChanged()), SLOT(resetCursorStyle())); KActionCollection *collection = this->canvas()->canvasController()->actionCollection(); if (!collection->action("toggle_fg_bg")) { QAction *toggleFgBg = KisActionRegistry::instance()->makeQAction("toggle_fg_bg", collection); collection->addAction("toggle_fg_bg", toggleFgBg); } if (!collection->action("reset_fg_bg")) { QAction *toggleFgBg = KisActionRegistry::instance()->makeQAction("reset_fg_bg", collection); collection->addAction("reset_fg_bg", toggleFgBg); } addAction("toggle_fg_bg", dynamic_cast(collection->action("toggle_fg_bg"))); addAction("reset_fg_bg", dynamic_cast(collection->action("reset_fg_bg"))); setMode(HOVER_MODE); } KisTool::~KisTool() { delete d; } void KisTool::activate(ToolActivation toolActivation, const QSet &shapes) { Q_UNUSED(toolActivation); Q_UNUSED(shapes); resetCursorStyle(); if (!canvas()) return; if (!canvas()->resourceManager()) return; d->currentFgColor = canvas()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value(); d->currentBgColor = canvas()->resourceManager()->resource(KoCanvasResourceManager::BackgroundColor).value(); if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentPattern)) { d->currentPattern = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPattern).value(); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentGradient)) { d->currentGradient = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentGradient).value(); } KisPaintOpPresetSP preset = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (preset && preset->settings()) { preset->settings()->activate(); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::HdrExposure)) { d->currentExposure = static_cast(canvas()->resourceManager()->resource(KisCanvasResourceProvider::HdrExposure).toDouble()); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentGeneratorConfiguration)) { d->currentGenerator = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentGeneratorConfiguration).value(); } connect(actions().value("toggle_fg_bg"), SIGNAL(triggered()), SLOT(slotToggleFgBg()), Qt::UniqueConnection); connect(actions().value("reset_fg_bg"), SIGNAL(triggered()), SLOT(slotResetFgBg()), Qt::UniqueConnection); connect(image(), SIGNAL(sigUndoDuringStrokeRequested()), SLOT(requestUndoDuringStroke()), Qt::UniqueConnection); connect(image(), SIGNAL(sigStrokeCancellationRequested()), SLOT(requestStrokeCancellation()), Qt::UniqueConnection); connect(image(), SIGNAL(sigStrokeEndRequested()), SLOT(requestStrokeEnd()), Qt::UniqueConnection); m_isActive = true; emit isActiveChanged(); } void KisTool::deactivate() { bool result = true; result &= disconnect(image().data(), SIGNAL(sigUndoDuringStrokeRequested()), this, 0); result &= disconnect(image().data(), SIGNAL(sigStrokeCancellationRequested()), this, 0); result &= disconnect(image().data(), SIGNAL(sigStrokeEndRequested()), this, 0); result &= disconnect(actions().value("toggle_fg_bg"), 0, this, 0); result &= disconnect(actions().value("reset_fg_bg"), 0, this, 0); if (!result) { warnKrita << "WARNING: KisTool::deactivate() failed to disconnect" << "some signal connections. Your actions might be executed twice!"; } m_isActive = false; emit isActiveChanged(); } void KisTool::requestUndoDuringStroke() { /** * Default implementation just cancells the stroke */ requestStrokeCancellation(); } void KisTool::requestStrokeCancellation() { } void KisTool::requestStrokeEnd() { } void KisTool::canvasResourceChanged(int key, const QVariant & v) { switch (key) { case(KoCanvasResourceManager::ForegroundColor): d->currentFgColor = v.value(); break; case(KoCanvasResourceManager::BackgroundColor): d->currentBgColor = v.value(); break; case(KisCanvasResourceProvider::CurrentPattern): d->currentPattern = static_cast(v.value()); break; case(KisCanvasResourceProvider::CurrentGradient): d->currentGradient = static_cast(v.value()); break; case(KisCanvasResourceProvider::HdrExposure): d->currentExposure = static_cast(v.toDouble()); break; case(KisCanvasResourceProvider::CurrentGeneratorConfiguration): d->currentGenerator = static_cast(v.value()); break; case(KisCanvasResourceProvider::CurrentPaintOpPreset): emit statusTextChanged(v.value()->name()); break; case(KisCanvasResourceProvider::CurrentKritaNode): resetCursorStyle(); break; default: break; // Do nothing }; } void KisTool::updateSettingsViews() { } QPointF KisTool::widgetCenterInWidgetPixels() { KisCanvas2 *kritaCanvas = dynamic_cast(canvas()); Q_ASSERT(kritaCanvas); const KisCoordinatesConverter *converter = kritaCanvas->coordinatesConverter(); return converter->flakeToWidget(converter->flakeCenterPoint()); } QPointF KisTool::convertDocumentToWidget(const QPointF& pt) { KisCanvas2 *kritaCanvas = dynamic_cast(canvas()); Q_ASSERT(kritaCanvas); return kritaCanvas->coordinatesConverter()->documentToWidget(pt); } QPointF KisTool::convertToPixelCoord(KoPointerEvent *e) { if (!image()) return e->point; return image()->documentToPixel(e->point); } QPointF KisTool::convertToPixelCoord(const QPointF& pt) { if (!image()) return pt; return image()->documentToPixel(pt); } QPoint KisTool::convertToIntPixelCoord(KoPointerEvent *e) { if (!image()) return e->point.toPoint(); return image()->documentToIntPixel(e->point); } QPointF KisTool::viewToPixel(const QPointF &viewCoord) const { if (!image()) return viewCoord; return image()->documentToPixel(canvas()->viewConverter()->viewToDocument(viewCoord)); } QRectF KisTool::convertToPt(const QRectF &rect) { if (!image()) return rect; QRectF r; //We add 1 in the following to the extreme coords because a pixel always has size r.setCoords(int(rect.left()) / image()->xRes(), int(rect.top()) / image()->yRes(), int(1 + rect.right()) / image()->xRes(), int(1 + rect.bottom()) / image()->yRes()); return r; } QPointF KisTool::pixelToView(const QPoint &pixelCoord) const { if (!image()) return pixelCoord; QPointF documentCoord = image()->pixelToDocument(pixelCoord); return canvas()->viewConverter()->documentToView(documentCoord); } QPointF KisTool::pixelToView(const QPointF &pixelCoord) const { if (!image()) return pixelCoord; QPointF documentCoord = image()->pixelToDocument(pixelCoord); return canvas()->viewConverter()->documentToView(documentCoord); } QRectF KisTool::pixelToView(const QRectF &pixelRect) const { if (!image()) return pixelRect; QPointF topLeft = pixelToView(pixelRect.topLeft()); QPointF bottomRight = pixelToView(pixelRect.bottomRight()); return QRectF(topLeft, bottomRight); } QPainterPath KisTool::pixelToView(const QPainterPath &pixelPolygon) const { QTransform matrix; qreal zoomX, zoomY; canvas()->viewConverter()->zoom(&zoomX, &zoomY); matrix.scale(zoomX/image()->xRes(), zoomY/ image()->yRes()); return matrix.map(pixelPolygon); } QPolygonF KisTool::pixelToView(const QPolygonF &pixelPath) const { QTransform matrix; qreal zoomX, zoomY; canvas()->viewConverter()->zoom(&zoomX, &zoomY); matrix.scale(zoomX/image()->xRes(), zoomY/ image()->yRes()); return matrix.map(pixelPath); } void KisTool::updateCanvasPixelRect(const QRectF &pixelRect) { canvas()->updateCanvas(convertToPt(pixelRect)); } void KisTool::updateCanvasViewRect(const QRectF &viewRect) { canvas()->updateCanvas(canvas()->viewConverter()->viewToDocument(viewRect)); } KisImageWSP KisTool::image() const { // For now, krita tools only work in krita, not for a krita shape. Krita shapes are for 2.1 KisCanvas2 * kisCanvas = dynamic_cast(canvas()); if (kisCanvas) { return kisCanvas->currentImage(); } return 0; } QCursor KisTool::cursor() const { return d->cursor; } void KisTool::notifyModified() const { if (image()) { image()->setModified(); } } KoPattern * KisTool::currentPattern() { return d->currentPattern; } KoAbstractGradient * KisTool::currentGradient() { return d->currentGradient; } KisPaintOpPresetSP KisTool::currentPaintOpPreset() { return canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); } KisNodeSP KisTool::currentNode() { KisNodeSP node = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value(); return node; } KoColor KisTool::currentFgColor() { return d->currentFgColor; } KoColor KisTool::currentBgColor() { return d->currentBgColor; } KisImageWSP KisTool::currentImage() { return image(); } KisFilterConfiguration * KisTool::currentGenerator() { return d->currentGenerator; } void KisTool::setMode(ToolMode mode) { m_mode = mode; } KisTool::ToolMode KisTool::mode() const { return m_mode; } KisTool::AlternateAction KisTool::actionToAlternateAction(ToolAction action) { KIS_ASSERT_RECOVER_RETURN_VALUE(action != Primary, Secondary); return (AlternateAction)action; } void KisTool::activatePrimaryAction() { resetCursorStyle(); } void KisTool::deactivatePrimaryAction() { resetCursorStyle(); } void KisTool::beginPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::beginPrimaryDoubleClickAction(KoPointerEvent *event) { beginPrimaryAction(event); } void KisTool::continuePrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::endPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } bool KisTool::primaryActionSupportsHiResEvents() const { return false; } void KisTool::activateAlternateAction(AlternateAction action) { Q_UNUSED(action); } void KisTool::deactivateAlternateAction(AlternateAction action) { Q_UNUSED(action); } void KisTool::beginAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::beginAlternateDoubleClickAction(KoPointerEvent *event, AlternateAction action) { beginAlternateAction(event, action); } void KisTool::continueAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::endAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::mouseDoubleClickEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseTripleClickEvent(KoPointerEvent *event) { mouseDoubleClickEvent(event); } void KisTool::mousePressEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseReleaseEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseMoveEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::deleteSelection() { KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image(), currentNode(), 0, this->canvas()->resourceManager()); KisSelectionSP selection = resources->activeSelection(); KisNodeSP node = resources->currentNode(); if(node && node->hasEditablePaintDevice()) { KisPaintDeviceSP device = node->paintDevice(); image()->barrierLock(); KisTransaction transaction(kundo2_i18n("Clear"), device); QRect dirtyRect; if (selection) { dirtyRect = selection->selectedRect(); device->clearSelection(selection); } else { dirtyRect = device->extent(); device->clear(); } transaction.commit(image()->undoAdapter()); device->setDirty(dirtyRect); image()->unlock(); } else { KoToolBase::deleteSelection(); } } void KisTool::setupPaintAction(KisRecordedPaintAction* action) { action->setPaintColor(currentFgColor()); action->setBackgroundColor(currentBgColor()); } QWidget* KisTool::createOptionWidget() { d->optionWidget = new QLabel(i18n("No options")); d->optionWidget->setObjectName("SpecialSpacer"); return d->optionWidget; } #define NEAR_VAL -1000.0 #define FAR_VAL 1000.0 #define PROGRAM_VERTEX_ATTRIBUTE 0 void KisTool::paintToolOutline(QPainter* painter, const QPainterPath &path) { #ifdef HAVE_OPENGL KisOpenGLCanvas2 *canvasWidget = dynamic_cast(canvas()->canvasWidget()); if (canvasWidget) { painter->beginNativePainting(); canvasWidget->paintToolOutline(path); painter->endNativePainting(); } else #endif // HAVE_OPENGL { painter->setCompositionMode(QPainter::RasterOp_SourceXorDestination); painter->setPen(QColor(128, 255, 128)); painter->drawPath(path); } } void KisTool::resetCursorStyle() { useCursor(d->cursor); } bool KisTool::overrideCursorIfNotEditable() { // override cursor for canvas iff this tool is active // and we can't paint on the active layer if (isActive()) { KisNodeSP node = currentNode(); if (node && !node->isEditable()) { canvas()->setCursor(Qt::ForbiddenCursor); return true; } } return false; } bool KisTool::isActive() const { return m_isActive; } void KisTool::slotToggleFgBg() { KoCanvasResourceManager* resourceManager = canvas()->resourceManager(); KoColor newFg = resourceManager->backgroundColor(); KoColor newBg = resourceManager->foregroundColor(); /** * NOTE: Some of color selectors do not differentiate foreground * and background colors, so if one wants them to end up * being set up to foreground color, it should be set the * last. */ resourceManager->setBackgroundColor(newBg); resourceManager->setForegroundColor(newFg); } void KisTool::slotResetFgBg() { KoCanvasResourceManager* resourceManager = canvas()->resourceManager(); // see a comment in slotToggleFgBg() resourceManager->setBackgroundColor(KoColor(Qt::white, KoColorSpaceRegistry::instance()->rgb8())); resourceManager->setForegroundColor(KoColor(Qt::black, KoColorSpaceRegistry::instance()->rgb8())); } void KisTool::setCurrentNodeLocked(bool locked) { if (currentNode()) { currentNode()->setSystemLocked(locked, false); } } bool KisTool::nodeEditable() { KisNodeSP node = currentNode(); if (!node) { return false; } if (!node->isEditable()) { KisCanvas2 * kiscanvas = static_cast(canvas()); QString message; if (!node->visible() && node->userLocked()) { message = i18n("Layer is locked and invisible."); } else if (node->userLocked()) { message = i18n("Layer is locked."); } else if(!node->visible()) { message = i18n("Layer is invisible."); } else { message = i18n("Group not editable."); } kiscanvas->viewManager()->showFloatingMessage(message, KisIconUtils::loadIcon("object-locked")); } return node->isEditable(); } bool KisTool::selectionEditable() { KisCanvas2 * kisCanvas = static_cast(canvas()); KisViewManager * view = kisCanvas->viewManager(); bool editable = view->selectionEditable(); if (!editable) { KisCanvas2 * kiscanvas = static_cast(canvas()); kiscanvas->viewManager()->showFloatingMessage(i18n("Local selection is locked."), KisIconUtils::loadIcon("object-locked")); } return editable; } void KisTool::listenToModifiers(bool listen) { Q_UNUSED(listen); } bool KisTool::listeningToModifiers() { return false; } diff --git a/libs/flake/KoCanvasControllerWidget.cpp b/libs/flake/KoCanvasControllerWidget.cpp index 968936eb58..64a82bd64f 100644 --- a/libs/flake/KoCanvasControllerWidget.cpp +++ b/libs/flake/KoCanvasControllerWidget.cpp @@ -1,624 +1,624 @@ /* This file is part of the KDE project * * Copyright (C) 2006, 2008-2009 Thomas Zander * Copyright (C) 2006 Peter Simonsson * Copyright (C) 2006, 2009 Thorsten Zachmann * Copyright (C) 2007-2010 Boudewijn Rempt * Copyright (C) 2007 C. Boemann * Copyright (C) 2006-2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoCanvasControllerWidget.h" #include "KoCanvasControllerWidget_p.h" #include "KoCanvasControllerWidgetViewport_p.h" #include "KoShape.h" #include "KoViewConverter.h" #include "KoCanvasBase.h" #include "KoCanvasObserverBase.h" #include "KoCanvasSupervisor.h" #include "KoToolManager_p.h" #include #include #include #include #include #include #include #include -#include +#include // for HAVE_OPENGL #ifdef HAVE_OPENGL #include #endif #include void KoCanvasControllerWidget::Private::setDocumentOffset() { // The margins scroll the canvas widget inside the viewport, not // the document. The documentOffset is meant to be the value that // the canvas must add to the update rect in its paint event, to // compensate. QPoint pt(q->horizontalScrollBar()->value(), q->verticalScrollBar()->value()); q->proxyObject->emitMoveDocumentOffset(pt); QWidget *canvasWidget = canvas->canvasWidget(); if (canvasWidget) { bool isCanvasOpenGL = false; QWidget *canvasWidget = canvas->canvasWidget(); if (canvasWidget) { #ifdef HAVE_OPENGL if (qobject_cast(canvasWidget) != 0) { isCanvasOpenGL = true; } #endif } if (!isCanvasOpenGL) { QPoint diff = q->documentOffset() - pt; if (q->canvasMode() == Spreadsheet && canvasWidget->layoutDirection() == Qt::RightToLeft) { canvasWidget->scroll(-diff.x(), diff.y()); } else { canvasWidget->scroll(diff.x(), diff.y()); } } } q->setDocumentOffset(pt); } void KoCanvasControllerWidget::Private::resetScrollBars() { // The scrollbar value always points at the top-left corner of the // bit of image we paint. int docH = q->documentSize().height() + q->margin(); int docW = q->documentSize().width() + q->margin(); int drawH = viewportWidget->height(); int drawW = viewportWidget->width(); QScrollBar *hScroll = q->horizontalScrollBar(); QScrollBar *vScroll = q->verticalScrollBar(); int horizontalReserve = vastScrollingFactor * drawW; int verticalReserve = vastScrollingFactor * drawH; int xMin = -horizontalReserve; int yMin = -verticalReserve; int xMax = docW - drawW + horizontalReserve; int yMax = docH - drawH + verticalReserve; hScroll->setRange(xMin, xMax); vScroll->setRange(yMin, yMax); int fontheight = QFontMetrics(q->font()).height(); vScroll->setPageStep(drawH); vScroll->setSingleStep(fontheight); hScroll->setPageStep(drawW); hScroll->setSingleStep(fontheight); } void KoCanvasControllerWidget::Private::emitPointerPositionChangedSignals(QEvent *event) { if (!canvas) return; if (!canvas->viewConverter()) return; QPoint pointerPos; QMouseEvent *mouseEvent = dynamic_cast(event); if (mouseEvent) { pointerPos = mouseEvent->pos(); } else { QTabletEvent *tabletEvent = dynamic_cast(event); if (tabletEvent) { pointerPos = tabletEvent->pos(); } } QPoint pixelPos = (pointerPos - canvas->documentOrigin()) + q->documentOffset(); QPointF documentPos = canvas->viewConverter()->viewToDocument(pixelPos); q->proxyObject->emitDocumentMousePositionChanged(documentPos); q->proxyObject->emitCanvasMousePositionChanged(pointerPos); } #include void KoCanvasControllerWidget::Private::activate() { QWidget *parent = q; while (parent->parentWidget()) { parent = parent->parentWidget(); } KoCanvasSupervisor *observerProvider = dynamic_cast(parent); if (!observerProvider) { return; } Q_FOREACH (KoCanvasObserverBase *docker, observerProvider->canvasObservers()) { KoCanvasObserverBase *observer = dynamic_cast(docker); if (observer) { observer->setObservedCanvas(q->canvas()); } } } void KoCanvasControllerWidget::Private::unsetCanvas() { QWidget *parent = q; while (parent->parentWidget()) { parent = parent->parentWidget(); } KoCanvasSupervisor *observerProvider = dynamic_cast(parent); if (!observerProvider) { return; } Q_FOREACH (KoCanvasObserverBase *docker, observerProvider->canvasObservers()) { KoCanvasObserverBase *observer = dynamic_cast(docker); if (observer && observer->observedCanvas() == q->canvas()) { observer->unsetObservedCanvas(); } } } //////////// KoCanvasControllerWidget::KoCanvasControllerWidget(KActionCollection * actionCollection, QWidget *parent) : QAbstractScrollArea(parent) , KoCanvasController(actionCollection) , d(new Private(this)) { // We need to set this as QDeclarativeView sets them a bit differnt from QAbstractScrollArea setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // And then our own Viewport d->viewportWidget = new Viewport(this); setViewport(d->viewportWidget); d->viewportWidget->setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus); setFrameStyle(0); //setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); setAutoFillBackground(false); /* Fixes: apps starting at zero zoom. Details: Since the document is set on the mainwindow before loading commences the inial show/layout can choose to set the document to be very small, even to be zero pixels tall. Setting a sane minimum size on the widget means we no loger get rounding errors in zooming and we no longer end up with zero-zoom. Note: KoPage apps should probably startup with a sane document size; for Krita that's impossible */ setMinimumSize(QSize(50, 50)); setMouseTracking(true); connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateCanvasOffsetX())); connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateCanvasOffsetY())); connect(d->viewportWidget, SIGNAL(sizeChanged()), this, SLOT(updateCanvasOffsetX())); connect(proxyObject, SIGNAL(moveDocumentOffset(const QPoint&)), d->viewportWidget, SLOT(documentOffsetMoved(const QPoint&))); } KoCanvasControllerWidget::~KoCanvasControllerWidget() { d->unsetCanvas(); delete d; } void KoCanvasControllerWidget::activate() { d->activate(); } void KoCanvasControllerWidget::scrollContentsBy(int dx, int dy) { Q_UNUSED(dx); Q_UNUSED(dy); d->setDocumentOffset(); } QSize KoCanvasControllerWidget::viewportSize() const { return viewport()->size(); } void KoCanvasControllerWidget::setDrawShadow(bool drawShadow) { d->viewportWidget->setDrawShadow(drawShadow); } void KoCanvasControllerWidget::resizeEvent(QResizeEvent *resizeEvent) { proxyObject->emitSizeChanged(resizeEvent->size()); // XXX: When resizing, keep the area we're looking at now in the // center of the resized view. d->resetScrollBars(); d->setDocumentOffset(); } void KoCanvasControllerWidget::setCanvas(KoCanvasBase *canvas) { Q_ASSERT(canvas); // param is not null if (d->canvas) { d->unsetCanvas(); proxyObject->emitCanvasRemoved(this); canvas->setCanvasController(0); d->canvas->canvasWidget()->removeEventFilter(this); } canvas->setCanvasController(this); d->canvas = canvas; changeCanvasWidget(canvas->canvasWidget()); proxyObject->emitCanvasSet(this); QTimer::singleShot(0, this, SLOT(activate())); setPreferredCenterFractionX(0); setPreferredCenterFractionY(0); } KoCanvasBase* KoCanvasControllerWidget::canvas() const { return d->canvas; } void KoCanvasControllerWidget::changeCanvasWidget(QWidget *widget) { if (d->viewportWidget->canvas()) { widget->setCursor(d->viewportWidget->canvas()->cursor()); d->viewportWidget->canvas()->removeEventFilter(this); } d->viewportWidget->setCanvas(widget); setFocusProxy(d->canvas->canvasWidget()); widget->installEventFilter(this); widget->setMouseTracking(true); } int KoCanvasControllerWidget::visibleHeight() const { if (d->canvas == 0) return 0; QWidget *canvasWidget = canvas()->canvasWidget(); int height1; if (canvasWidget == 0) height1 = viewport()->height(); else height1 = qMin(viewport()->height(), canvasWidget->height()); int height2 = height(); return qMin(height1, height2); } int KoCanvasControllerWidget::visibleWidth() const { if (d->canvas == 0) return 0; QWidget *canvasWidget = canvas()->canvasWidget(); int width1; if (canvasWidget == 0) width1 = viewport()->width(); else width1 = qMin(viewport()->width(), canvasWidget->width()); int width2 = width(); return qMin(width1, width2); } int KoCanvasControllerWidget::canvasOffsetX() const { int offset = -horizontalScrollBar()->value(); if (d->canvas) { offset += d->canvas->canvasWidget()->x() + frameWidth(); } return offset; } int KoCanvasControllerWidget::canvasOffsetY() const { int offset = -verticalScrollBar()->value(); if (d->canvas) { offset += d->canvas->canvasWidget()->y() + frameWidth(); } return offset; } void KoCanvasControllerWidget::updateCanvasOffsetX() { proxyObject->emitCanvasOffsetXChanged(canvasOffsetX()); if (d->ignoreScrollSignals) return; setPreferredCenterFractionX((horizontalScrollBar()->value() + viewport()->width() / 2.0) / documentSize().width()); } void KoCanvasControllerWidget::updateCanvasOffsetY() { proxyObject->emitCanvasOffsetYChanged(canvasOffsetY()); if (d->ignoreScrollSignals) return; setPreferredCenterFractionY((verticalScrollBar()->value() + verticalScrollBar()->pageStep() / 2.0) / documentSize().height()); } bool KoCanvasControllerWidget::eventFilter(QObject *watched, QEvent *event) { if (d->canvas && d->canvas->canvasWidget() && (watched == d->canvas->canvasWidget())) { if (event->type() == QEvent::MouseMove || event->type() == QEvent::TabletMove) { d->emitPointerPositionChangedSignals(event); } } return false; } void KoCanvasControllerWidget::ensureVisible(KoShape *shape) { Q_ASSERT(shape); ensureVisible(d->canvas->viewConverter()->documentToView(shape->boundingRect())); } void KoCanvasControllerWidget::ensureVisible(const QRectF &rect, bool smooth) { QRect currentVisible(-canvasOffsetX(), -canvasOffsetY(), visibleWidth(), visibleHeight()); QRect viewRect = rect.toRect(); viewRect.translate(d->canvas->documentOrigin()); if (!viewRect.isValid() || currentVisible.contains(viewRect)) return; // its visible. Nothing to do. // if we move, we move a little more so the amount of times we have to move is less. int jumpWidth = smooth ? 0 : currentVisible.width() / 5; int jumpHeight = smooth ? 0 : currentVisible.height() / 5; if (!smooth && viewRect.width() + jumpWidth > currentVisible.width()) jumpWidth = 0; if (!smooth && viewRect.height() + jumpHeight > currentVisible.height()) jumpHeight = 0; int horizontalMove = 0; if (currentVisible.width() <= viewRect.width()) // center view horizontalMove = viewRect.center().x() - currentVisible.center().x(); else if (currentVisible.x() > viewRect.x()) // move left horizontalMove = viewRect.x() - currentVisible.x() - jumpWidth; else if (currentVisible.right() < viewRect.right()) // move right horizontalMove = viewRect.right() - qMax(0, currentVisible.right() - jumpWidth); int verticalMove = 0; if (currentVisible.height() <= viewRect.height()) // center view verticalMove = viewRect.center().y() - currentVisible.center().y(); if (currentVisible.y() > viewRect.y()) // move up verticalMove = viewRect.y() - currentVisible.y() - jumpHeight; else if (currentVisible.bottom() < viewRect.bottom()) // move down verticalMove = viewRect.bottom() - qMax(0, currentVisible.bottom() - jumpHeight); pan(QPoint(horizontalMove, verticalMove)); } void KoCanvasControllerWidget::recenterPreferred() { const bool oldIgnoreScrollSignals = d->ignoreScrollSignals; d->ignoreScrollSignals = true; QPointF center = preferredCenter(); // convert into a viewport based point center.rx() += d->canvas->canvasWidget()->x() + frameWidth(); center.ry() += d->canvas->canvasWidget()->y() + frameWidth(); // scroll to a new center point QPointF topLeft = center - 0.5 * QPointF(viewport()->width(), viewport()->height()); setScrollBarValue(topLeft.toPoint()); d->ignoreScrollSignals = oldIgnoreScrollSignals; } void KoCanvasControllerWidget::zoomIn(const QPoint ¢er) { zoomBy(center, sqrt(2.0)); } void KoCanvasControllerWidget::zoomOut(const QPoint ¢er) { zoomBy(center, sqrt(0.5)); } void KoCanvasControllerWidget::zoomBy(const QPoint ¢er, qreal zoom) { setPreferredCenterFractionX(1.0 * center.x() / documentSize().width()); setPreferredCenterFractionY(1.0 * center.y() / documentSize().height()); const bool oldIgnoreScrollSignals = d->ignoreScrollSignals; d->ignoreScrollSignals = true; proxyObject->emitZoomRelative(zoom, preferredCenter()); d->ignoreScrollSignals = oldIgnoreScrollSignals; } void KoCanvasControllerWidget::zoomTo(const QRect &viewRect) { qreal scale; if (1.0 * viewport()->width() / viewRect.width() > 1.0 * viewport()->height() / viewRect.height()) scale = 1.0 * viewport()->height() / viewRect.height(); else scale = 1.0 * viewport()->width() / viewRect.width(); zoomBy(viewRect.center(), scale); } void KoCanvasControllerWidget::setToolOptionWidgets(const QList >&widgetMap) { emit toolOptionWidgetsChanged(widgetMap); } void KoCanvasControllerWidget::updateDocumentSize(const QSize &sz, bool recalculateCenter) { // Don't update if the document-size didn't changed to prevent infinite loops and unneeded updates. if (KoCanvasController::documentSize() == sz) return; if (!recalculateCenter) { // assume the distance from the top stays equal and recalculate the center. setPreferredCenterFractionX(documentSize().width() * preferredCenterFractionX() / sz.width()); setPreferredCenterFractionY(documentSize().height() * preferredCenterFractionY() / sz.height()); } const bool oldIgnoreScrollSignals = d->ignoreScrollSignals; d->ignoreScrollSignals = true; KoCanvasController::setDocumentSize(sz); d->viewportWidget->setDocumentSize(sz); d->resetScrollBars(); // Always emit the new offset. updateCanvasOffsetX(); updateCanvasOffsetY(); d->ignoreScrollSignals = oldIgnoreScrollSignals; } void KoCanvasControllerWidget::setZoomWithWheel(bool zoom) { d->zoomWithWheel = zoom; } void KoCanvasControllerWidget::setVastScrolling(qreal factor) { d->vastScrollingFactor = factor; } void KoCanvasControllerWidget::pan(const QPoint &distance) { QPoint sourcePoint = scrollBarValue(); setScrollBarValue(sourcePoint + distance); } void KoCanvasControllerWidget::setPreferredCenter(const QPointF &viewPoint) { setPreferredCenterFractionX(viewPoint.x() / documentSize().width()); setPreferredCenterFractionY(viewPoint.y() / documentSize().height()); recenterPreferred(); } QPointF KoCanvasControllerWidget::preferredCenter() const { QPointF center; center.setX(preferredCenterFractionX() * documentSize().width()); center.setY(preferredCenterFractionY() * documentSize().height()); return center; } void KoCanvasControllerWidget::paintEvent(QPaintEvent *event) { QPainter gc(viewport()); d->viewportWidget->handlePaintEvent(gc, event); } void KoCanvasControllerWidget::dragEnterEvent(QDragEnterEvent *event) { d->viewportWidget->handleDragEnterEvent(event); } void KoCanvasControllerWidget::dropEvent(QDropEvent *event) { d->viewportWidget->handleDropEvent(event); } void KoCanvasControllerWidget::dragMoveEvent(QDragMoveEvent *event) { d->viewportWidget->handleDragMoveEvent(event); } void KoCanvasControllerWidget::dragLeaveEvent(QDragLeaveEvent *event) { d->viewportWidget->handleDragLeaveEvent(event); } void KoCanvasControllerWidget::keyPressEvent(QKeyEvent *event) { KoToolManager::instance()->priv()->switchToolByShortcut(event); } void KoCanvasControllerWidget::wheelEvent(QWheelEvent *event) { if (d->zoomWithWheel != ((event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier)) { const qreal zoomCoeff = event->delta() > 0 ? sqrt(2.0) : sqrt(0.5); zoomRelativeToPoint(event->pos(), zoomCoeff); event->accept(); } else QAbstractScrollArea::wheelEvent(event); } void KoCanvasControllerWidget::zoomRelativeToPoint(const QPoint &widgetPoint, qreal zoomCoeff) { const QPoint offset = scrollBarValue(); const QPoint mousePos(widgetPoint + offset); const bool oldIgnoreScrollSignals = d->ignoreScrollSignals; d->ignoreScrollSignals = true; proxyObject->emitZoomRelative(zoomCoeff, mousePos); d->ignoreScrollSignals = oldIgnoreScrollSignals; } bool KoCanvasControllerWidget::focusNextPrevChild(bool) { // we always return false meaning the canvas takes keyboard focus, but never gives it away. return false; } void KoCanvasControllerWidget::setMargin(int margin) { KoCanvasController::setMargin(margin); Q_ASSERT(d->viewportWidget); d->viewportWidget->setMargin(margin); } QPoint KoCanvasControllerWidget::scrollBarValue() const { QScrollBar * hBar = horizontalScrollBar(); QScrollBar * vBar = verticalScrollBar(); return QPoint(hBar->value(), vBar->value()); } void KoCanvasControllerWidget::setScrollBarValue(const QPoint &value) { QScrollBar * hBar = horizontalScrollBar(); QScrollBar * vBar = verticalScrollBar(); hBar->setValue(value.x()); vBar->setValue(value.y()); } KoCanvasControllerWidget::Private *KoCanvasControllerWidget::priv() { return d; } //have to include this because of Q_PRIVATE_SLOT #include "moc_KoCanvasControllerWidget.cpp"