krita/ui

kis_canvas2.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002  *
00003  * Copyright (C) Boudewijn Rempt <boud@valdyas.org>, (C) 2006
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA..
00018  */
00019 
00020 #include "kis_canvas2.h"
00021 
00022 #include <QWidget>
00023 #include <QTime>
00024 #include <QLabel>
00025 #include <QMouseEvent>
00026 
00027 #include <kis_debug.h>
00028 
00029 #include "KoUnit.h"
00030 #include "KoZoomHandler.h"
00031 #include "KoViewConverter.h"
00032 #include "KoShapeManager.h"
00033 #include "colorprofiles/KoIccColorProfile.h"
00034 #include "KoColorSpaceRegistry.h"
00035 #include "KoCanvasController.h"
00036 #include "KoDocument.h"
00037 #include "KoZoomAction.h"
00038 #include "KoToolProxy.h"
00039 #include "KoSelection.h"
00040 
00041 #include "kis_prescaled_projection.h"
00042 #include "kis_image.h"
00043 #include "kis_doc2.h"
00044 #include "flake/kis_shape_layer.h"
00045 #include "kis_canvas_resource_provider.h"
00046 #include "kis_view2.h"
00047 #include "kis_config.h"
00048 #include "kis_config_notifier.h"
00049 #include "kis_abstract_canvas_widget.h"
00050 #include "kis_qpainter_canvas.h"
00051 #include "kis_group_layer.h"
00052 #include "flake/kis_shape_controller.h"
00053 #include "kis_layer_manager.h"
00054 #include "kis_selection.h"
00055 #include "kis_selection_component.h"
00056 #include "flake/kis_shape_selection.h"
00057 
00058 #include "opengl/kis_opengl_canvas2.h"
00059 #include "opengl/kis_opengl_image_textures.h"
00060 #ifdef HAVE_OPENGL
00061 #include <QGLFormat>
00062 #endif
00063 #include "kis_projection_cache.h"
00064 
00065 class KisCanvas2::KisCanvas2Private
00066 {
00067 
00068 public:
00069 
00070     KisCanvas2Private(KoCanvasBase * parent, KoViewConverter * viewConverter, KisView2 * view)
00071             : viewConverter(viewConverter)
00072             , view(view)
00073             , canvasWidget(0)
00074             , shapeManager(new KoShapeManager(parent))
00075             , monitorProfile(0)
00076             , currentCanvasIsOpenGL(false)
00077             , currentCanvasUsesOpenGLShaders(false)
00078             , toolProxy(new KoToolProxy(parent)) {
00079     }
00080 
00081     ~KisCanvas2Private() {
00082         delete shapeManager;
00083         delete toolProxy;
00084     }
00085 
00086     KoViewConverter * viewConverter;
00087     KisView2 * view;
00088     KisAbstractCanvasWidget * canvasWidget;
00089     KoShapeManager * shapeManager;
00090     KoColorProfile * monitorProfile;
00091     bool currentCanvasIsOpenGL;
00092     bool currentCanvasUsesOpenGLShaders;
00093     KoToolProxy * toolProxy;
00094     QPoint documentOffset;
00095     KoShapeControllerBase * sc;
00096 #ifdef HAVE_OPENGL
00097     KisOpenGLImageTexturesSP openGLImageTextures;
00098 #endif
00099     KisPrescaledProjectionSP prescaledProjection;
00100 };
00101 
00102 KisCanvas2::KisCanvas2(KoViewConverter * viewConverter, KisView2 * view, KoShapeControllerBase * sc)
00103         : KoCanvasBase(sc)
00104         , m_d(new KisCanvas2Private(this, viewConverter, view))
00105 {
00106     createCanvas();
00107     connect(view->canvasController(), SIGNAL(moveDocumentOffset(const QPoint&)), SLOT(documentOffsetMoved(const QPoint&)));
00108     connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
00109     connect(this, SIGNAL(canvasDestroyed(QWidget *)), m_d->view, SLOT(slotCanvasDestroyed(QWidget *)));
00110 }
00111 
00112 KisCanvas2::~KisCanvas2()
00113 {
00114     delete m_d;
00115 }
00116 
00117 void KisCanvas2::setCanvasWidget(QWidget * widget)
00118 {
00119     KisAbstractCanvasWidget * tmp = dynamic_cast<KisAbstractCanvasWidget*>(widget);
00120     Q_ASSERT_X(tmp, "setCanvasWidget", "Cannot cast the widget to a KisAbstractCanvasWidget");
00121     emit canvasDestroyed(widget);
00122     m_d->canvasWidget = tmp;
00123     widget->setAutoFillBackground(false);
00124     widget->setAttribute(Qt::WA_OpaquePaintEvent);
00125     widget->setMouseTracking(true);
00126     widget->setAcceptDrops(true);
00127     KoCanvasController *controller = canvasController();
00128     if (controller) {
00129         Q_ASSERT(controller->canvas() == this);
00130         // Avoids jumping and redrawing when changing zoom means the image fits in the area completely
00131         controller->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
00132         controller->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
00133 
00134         controller->changeCanvasWidget(widget);
00135     }
00136 }
00137 
00138 void KisCanvas2::gridSize(qreal *horizontal, qreal *vertical) const
00139 {
00140     Q_ASSERT(horizontal);
00141     Q_ASSERT(vertical);
00142     *horizontal = m_d->view->document()->gridData().gridX();
00143     *vertical = m_d->view->document()->gridData().gridY();
00144 }
00145 
00146 bool KisCanvas2::snapToGrid() const
00147 {
00148     return m_d->view->document()->gridData().snapToGrid();
00149 }
00150 
00151 void KisCanvas2::addCommand(QUndoCommand *command)
00152 {
00153     m_d->view->koDocument()->addCommand(command);
00154 }
00155 
00156 void KisCanvas2::startMacro(const QString &title)
00157 {
00158     m_d->view->koDocument()->beginMacro(title);
00159 }
00160 
00161 void KisCanvas2::stopMacro()
00162 {
00163     m_d->view->koDocument()->endMacro();
00164 }
00165 
00166 KoShapeManager* KisCanvas2::shapeManager() const
00167 {
00168     if (!m_d->view) return m_d->shapeManager;
00169     if (!m_d->view->layerManager()) return m_d->shapeManager;
00170 
00171     KisLayerSP activeLayer = m_d->view->layerManager()->activeLayer();
00172     if (activeLayer) {
00173         KisShapeLayer * shapeLayer = dynamic_cast<KisShapeLayer*>(activeLayer.data());
00174         if (shapeLayer) {
00175             return shapeLayer->shapeManager();
00176         }
00177         if (activeLayer->selection() && activeLayer->selection()->hasShapeSelection()) {
00178             KoShapeManager* m = static_cast<KisShapeSelection*>(activeLayer->selection()->shapeSelection())->shapeManager();
00179             return m;
00180 
00181         }
00182     }
00183     return m_d->shapeManager;
00184 }
00185 
00186 KoShapeManager * KisCanvas2::globalShapeManager() const
00187 {
00188     return m_d->shapeManager;
00189 }
00190 
00191 void KisCanvas2::updateCanvas(const QRectF& rc)
00192 {
00193     // updateCanvas is called from tools, never from the projection
00194     // updates, so no need to prescale!
00195     QRect vRect = viewRectFromDoc(rc);
00196     if (!vRect.isEmpty()) {
00197         m_d->canvasWidget->widget()->update(vRect);
00198     }
00199 }
00200 
00201 void KisCanvas2::updateInputMethodInfo()
00202 {
00203     // TODO call (the protected) QWidget::updateMicroFocus() on the proper canvas widget...
00204 }
00205 
00206 const KoViewConverter* KisCanvas2::viewConverter() const
00207 {
00208     return m_d->viewConverter;
00209 }
00210 
00211 QWidget* KisCanvas2::canvasWidget()
00212 {
00213     return m_d->canvasWidget->widget();
00214 }
00215 
00216 const QWidget* KisCanvas2::canvasWidget() const
00217 {
00218     return m_d->canvasWidget->widget();
00219 }
00220 
00221 
00222 KoUnit KisCanvas2::unit() const
00223 {
00224     return KoUnit(KoUnit::Pixel);
00225 }
00226 
00227 KoToolProxy * KisCanvas2::toolProxy() const
00228 {
00229     return m_d->toolProxy;
00230 }
00231 
00232 void KisCanvas2::createQPainterCanvas()
00233 {
00234 #ifdef HAVE_OPENGL
00235     m_d->openGLImageTextures = 0;
00236 #endif
00237     m_d->currentCanvasIsOpenGL = false;
00238 
00239     KisQPainterCanvas * canvasWidget = new KisQPainterCanvas(this, m_d->view);
00240     m_d->prescaledProjection = new KisPrescaledProjection();
00241     m_d->prescaledProjection->setViewConverter(m_d->viewConverter);
00242     m_d->prescaledProjection->setMonitorProfile(monitorProfile());
00243     canvasWidget->setPrescaledProjection(m_d->prescaledProjection);
00244 
00245     connect(canvasWidget, SIGNAL(documentOriginChanged(const QPoint&)), this, SLOT(updateRulers()));
00246 
00247     setCanvasWidget(canvasWidget);
00248 }
00249 
00250 void KisCanvas2::createOpenGLCanvas()
00251 {
00252 #ifdef HAVE_OPENGL
00253     if (QGLFormat::hasOpenGL()) {
00254         // XXX: The image isn't done loading here!
00255         m_d->openGLImageTextures = KisOpenGLImageTextures::getImageTextures(m_d->view->image(), m_d->monitorProfile);
00256         KisOpenGLCanvas2 * canvasWidget = new KisOpenGLCanvas2(this, m_d->view, m_d->openGLImageTextures);
00257         setCanvasWidget(canvasWidget);
00258         m_d->currentCanvasIsOpenGL = true;
00259         m_d->currentCanvasUsesOpenGLShaders = m_d->openGLImageTextures->usingHDRExposureProgram();
00260 
00261         connect(canvasWidget, SIGNAL(documentOriginChanged(const QPoint&)), this, SLOT(updateRulers()));
00262 
00263     } else {
00264         warnKrita << "Tried to create OpenGL widget when system doesn't have OpenGL\n";
00265         createQPainterCanvas();
00266     }
00267 #endif
00268 }
00269 
00270 void KisCanvas2::createCanvas()
00271 {
00272     KisConfig cfg;
00273     slotSetDisplayProfile(KoColorSpaceRegistry::instance()->profileByName(cfg.monitorProfile()));
00274 
00275     if (cfg.useOpenGL()) {
00276 #ifdef HAVE_OPENGL
00277         createOpenGLCanvas();
00278 #else
00279         warnKrita << "OpenGL requested while its not available, starting qpainter canvas";
00280         createQPainterCanvas();
00281 #endif
00282     } else {
00283         createQPainterCanvas();
00284 
00285     }
00286 
00287 }
00288 
00289 KisView2* KisCanvas2::view()
00290 {
00291     return m_d->view;
00292 }
00293 
00294 
00295 QRect KisCanvas2::viewRectFromDoc(const QRectF & rc)
00296 {
00297     QRect viewRect = m_d->viewConverter->documentToView(rc).toAlignedRect();
00298     viewRect = viewRect.translated(-m_d->documentOffset);
00299     // comment out this line if zou want to see the preview outside of the canvas
00300     // viewRect = viewRect.intersected(QRect(0, 0, m_d->canvasWidget->widget()->width(), m_d->canvasWidget->widget()->height()));
00301     viewRect.translate(documentOrigin());
00302     return viewRect;
00303 }
00304 
00305 
00306 void KisCanvas2::updateCanvasProjection(const QRect & rc)
00307 {
00308     if (m_d->prescaledProjection) {
00309         QRect vRect = m_d->prescaledProjection->updateCanvasProjection(rc);
00310         if (!vRect.isEmpty()) {
00311             vRect.translate(m_d->canvasWidget->documentOrigin());
00312             m_d->canvasWidget->widget()->update(vRect);
00313             //m_d->canvasWidget->widget()->update();
00314         }
00315     }
00316 }
00317 
00318 
00319 void KisCanvas2::updateCanvas()
00320 {
00321     m_d->canvasWidget->widget()->update();
00322 }
00323 
00324 
00325 KisImageWSP KisCanvas2::image()
00326 {
00327     return m_d->view->image();
00328 
00329 }
00330 
00331 KoColorProfile *  KisCanvas2::monitorProfile()
00332 {
00333     return m_d->monitorProfile;
00334 }
00335 
00336 KisImageWSP KisCanvas2::currentImage()
00337 {
00338     return m_d->view->image();
00339 }
00340 
00341 void KisCanvas2::setImageSize(qint32 w, qint32 h)
00342 {
00343     if (m_d->prescaledProjection)
00344         m_d->prescaledProjection->setImageSize(w, h);
00345 }
00346 
00347 void KisCanvas2::connectCurrentImage()
00348 {
00349 #ifdef HAVE_OPENGL
00350     if (m_d->openGLImageTextures) {
00351         connect(m_d->openGLImageTextures, SIGNAL(sigImageUpdated(const QRect &)), SLOT(updateCanvas()));
00352         connect(m_d->openGLImageTextures, SIGNAL(sigSizeChanged(qint32, qint32)), SLOT(setImageSize(qint32, qint32)));
00353     } else {
00354 #endif
00355         connect(m_d->view->image(), SIGNAL(sigImageUpdated(const QRect &)), SLOT(updateCanvasProjection(const QRect &)));
00356         connect(m_d->view->image(), SIGNAL(sigSizeChanged(qint32, qint32)), SLOT(setImageSize(qint32, qint32)));
00357 
00358         if (m_d->prescaledProjection) {
00359             m_d->prescaledProjection->setImage(m_d->view->image());
00360         }
00361 
00362 #ifdef HAVE_OPENGL
00363     }
00364 #endif
00365     emit imageChanged(m_d->view->image());
00366 }
00367 
00368 void KisCanvas2::disconnectCurrentImage()
00369 {
00370 #ifdef HAVE_OPENGL
00371     if (m_d->openGLImageTextures) {
00372         m_d->openGLImageTextures->disconnect(this);
00373     }
00374 #endif
00375     m_d->view->image()->disconnect(this);
00376 }
00377 
00378 void KisCanvas2::resetCanvas()
00379 {
00380     KisConfig cfg;
00381 #if HAVE_OPENGL
00382 
00383     if ((cfg.useOpenGL() != m_d->currentCanvasIsOpenGL) ||
00384             (m_d->currentCanvasIsOpenGL && (cfg.useOpenGLShaders() != m_d->currentCanvasUsesOpenGLShaders))) {
00385 
00386         disconnectCurrentImage();
00387         createCanvas();
00388         connectCurrentImage();
00389     }
00390 
00391     if (cfg.useOpenGL()) {
00392         m_d->openGLImageTextures->setMonitorProfile(monitorProfile());
00393     } else {
00394         if (image()) {
00395             updateCanvasProjection(image()->bounds());
00396         }
00397     }
00398 #endif
00399     m_d->canvasWidget->widget()->update();
00400 }
00401 
00402 void KisCanvas2::documentOffsetMoved(const QPoint &documentOffset)
00403 {
00404     m_d->documentOffset = documentOffset;
00405     m_d->canvasWidget->documentOffsetMoved(documentOffset);
00406 }
00407 
00408 void KisCanvas2::preScale()
00409 {
00410     if (!m_d->currentCanvasIsOpenGL && m_d->prescaledProjection)
00411         m_d->prescaledProjection->preScale();
00412 }
00413 
00414 bool KisCanvas2::usingHDRExposureProgram()
00415 {
00416 #ifdef HAVE_OPENGL
00417     if (m_d->currentCanvasIsOpenGL) {
00418         if (m_d->openGLImageTextures->usingHDRExposureProgram()) {
00419             return true;
00420         }
00421     }
00422 #endif
00423     return false;
00424 }
00425 
00426 void KisCanvas2::slotConfigChanged()
00427 {
00428     resetCanvas();
00429 }
00430 
00431 void KisCanvas2::slotSetDisplayProfile(const KoColorProfile * profile)
00432 {
00433     m_d->monitorProfile = const_cast<KoColorProfile*>(profile);
00434 }
00435 
00436 void KisCanvas2::addDecoration(KisCanvasDecoration* deco)
00437 {
00438     m_d->canvasWidget->addDecoration(deco);
00439 }
00440 
00441 KisCanvasDecoration* KisCanvas2::decoration(const QString& id)
00442 {
00443     return m_d->canvasWidget->decoration(id);
00444 }
00445 
00446 
00447 QPoint KisCanvas2::documentOrigin() const
00448 {
00449     return m_d->canvasWidget->documentOrigin();
00450 }
00451 
00452 
00453 void KisCanvas2::adjustOrigin()
00454 {
00455     m_d->canvasWidget->adjustOrigin();
00456 }
00457 
00458 
00459 void KisCanvas2::updateRulers()
00460 {
00461     emit documentOriginChanged();
00462 }
00463 
00464 
00465 QPoint KisCanvas2::documentOffset() const
00466 {
00467     return m_d->documentOffset;
00468 }
00469 
00470 
00471 #include "kis_canvas2.moc"