kis_canvas2.cpp 27.9 KB
Newer Older
1
/* This file is part of the KDE project
2
 *
Halla Rempt's avatar
Halla Rempt committed
3
 * Copyright (C) 2006, 2010 Boudewijn Rempt <boud@valdyas.org>
4
 * Copyright (C) Lukáš Tvrdý <lukast.dev@gmail.com>, (C) 2010
5
 * Copyright (C) 2011 Silvio Heinrich <plassy@web.de>
6
 *
7 8 9 10
 *  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.
11
 *
12 13 14 15
 *  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.
16
 *
17 18 19
 *  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..
20
 */
Halla Rempt's avatar
Halla Rempt committed
21

22
#include "kis_canvas2.h"
23

24
#include <QApplication>
25
#include <QWidget>
26
#include <QVBoxLayout>
27
#include <QTime>
28
#include <QLabel>
29
#include <QMouseEvent>
30
#include <QDesktopWidget>
31

32
#include <kis_debug.h>
33

34 35 36
#include <KoUnit.h>
#include <KoShapeManager.h>
#include <KoColorProfile.h>
37
#include <KoCanvasControllerWidget.h>
38
#include <KisDocument.h>
39
#include <KoSelection.h>
40
#include <KoShapeController.h>
41

42
#include <kis_lod_transform.h>
43
#include "kis_tool_proxy.h"
44
#include "kis_coordinates_converter.h"
45
#include "kis_prescaled_projection.h"
46
#include "kis_image.h"
47
#include "kis_image_barrier_locker.h"
48
#include "KisDocument.h"
Halla Rempt's avatar
Halla Rempt committed
49
#include "flake/kis_shape_layer.h"
Halla Rempt's avatar
Halla Rempt committed
50
#include "kis_canvas_resource_provider.h"
51
#include "KisViewManager.h"
52
#include "kis_config.h"
53
#include "kis_config_notifier.h"
Halla Rempt's avatar
Halla Rempt committed
54
#include "kis_abstract_canvas_widget.h"
55
#include "kis_qpainter_canvas.h"
Halla Rempt's avatar
Halla Rempt committed
56
#include "kis_group_layer.h"
Halla Rempt's avatar
Halla Rempt committed
57
#include "flake/kis_shape_controller.h"
58
#include "kis_node_manager.h"
59
#include "kis_selection.h"
60
#include "kis_selection_component.h"
Halla Rempt's avatar
Halla Rempt committed
61
#include "flake/kis_shape_selection.h"
62
#include "kis_image_config.h"
63
#include "kis_infinity_manager.h"
64
#include "kis_signal_compressor.h"
65
#include "kis_display_color_converter.h"
66
#include "kis_exposure_gamma_correction_interface.h"
67 68
#include "KisView.h"
#include "kis_canvas_controller.h"
69
#include "kis_grid_config.h"
70

71 72
#include "kis_animation_player.h"
#include "kis_animation_frame_cache.h"
73
#include "opengl/kis_opengl_canvas2.h"
Halla Rempt's avatar
Halla Rempt committed
74
#include "opengl/kis_opengl.h"
75
#include "kis_fps_decoration.h"
Halla Rempt's avatar
Halla Rempt committed
76

77 78 79
#include "KoColorConversionTransformation.h"
#include "KisProofingConfiguration.h"

80
#include <kis_favorite_resource_manager.h>
81
#include <kis_popup_palette.h>
82

83
#include "input/kis_input_manager.h"
84
#include "kis_painting_assistants_decoration.h"
85

86 87
#include "kis_canvas_updates_compressor.h"

88
class Q_DECL_HIDDEN KisCanvas2::KisCanvas2Private
Halla Rempt's avatar
Halla Rempt committed
89
{
90

91 92
public:

93
    KisCanvas2Private(KoCanvasBase *parent, KisCoordinatesConverter* coordConverter, QPointer<KisView> view, KoCanvasResourceManager* resourceManager)
94
        : coordinatesConverter(coordConverter)
95
        , view(view)
96 97 98
        , shapeManager(parent)
        , toolProxy(parent)
        , displayColorConverter(resourceManager, view)
99
    {
Halla Rempt's avatar
Halla Rempt committed
100
    }
101

102
    KisCoordinatesConverter *coordinatesConverter;
103
    QPointer<KisView>view;
104 105
    KisAbstractCanvasWidget *canvasWidget = 0;
    KoShapeManager shapeManager;
106
    bool currentCanvasIsOpenGL;
107
    int openGLFilterMode;
108
    KisToolProxy toolProxy;
109
    KisPrescaledProjectionSP prescaledProjection;
110
    bool vastScrolling;
111

112
    KisSignalCompressor updateSignalCompressor;
113 114
    QRect savedUpdateRect;

115
    QBitArray channelFlags;
116 117 118
    KisProofingConfiguration *proofingConfig = 0;
    bool softProofing = false;
    bool gamutCheck = false;
119

120 121
    KisPopupPalette *popupPalette = 0;
    KisDisplayColorConverter displayColorConverter;
122 123

    KisCanvasUpdatesCompressor projectionUpdatesCompressor;
Jouni Pentikäinen's avatar
Jouni Pentikäinen committed
124
    KisAnimationPlayer *animationPlayer;
125
    KisAnimationFrameCacheSP frameCache;
126
    bool lodAllowedInCanvas;
127
    bool bootstrapLodBlocked;
128 129

    bool effectiveLodAllowedInCanvas() {
130
        return lodAllowedInCanvas && !bootstrapLodBlocked;
131
    }
132 133
};

134
KisCanvas2::KisCanvas2(KisCoordinatesConverter *coordConverter, KoCanvasResourceManager *resourceManager, KisView *view, KoShapeBasedDocumentBase *sc)
135
    : KoCanvasBase(sc, resourceManager)
136
    , m_d(new KisCanvas2Private(this, coordConverter, view, resourceManager))
137
{
138 139 140 141 142
    /**
     * While loading LoD should be blocked. Only when GUI has finished
     * loading and zoom level settled down, LoD is given a green
     * light.
     */
143
    m_d->bootstrapLodBlocked = true;
144 145 146 147 148
    connect(view->mainWindow(), SIGNAL(guiLoadingFinished()), SLOT(bootstrapFinished()));

    m_d->updateSignalCompressor.setDelay(10);
    m_d->updateSignalCompressor.setMode(KisSignalCompressor::FIRST_ACTIVE);

149

150 151
}

152
void KisCanvas2::setup()
153
{
154
    // a bit of duplication from slotConfigChanged()
Dmitry Kazakov's avatar
Dmitry Kazakov committed
155
    KisConfig cfg;
156
    m_d->vastScrolling = cfg.vastScrolling();
157
    m_d->lodAllowedInCanvas = cfg.levelOfDetailEnabled();
158

Dmitry Kazakov's avatar
Dmitry Kazakov committed
159
    createCanvas(cfg.useOpenGL());
160

161
    setLodAllowedInCanvas(m_d->lodAllowedInCanvas);
162
    m_d->animationPlayer = new KisAnimationPlayer(this);
163
    connect(m_d->view->canvasController()->proxyObject, SIGNAL(moveDocumentOffset(QPoint)), SLOT(documentOffsetMoved(QPoint)));
Halla Rempt's avatar
Halla Rempt committed
164
    connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotConfigChanged()));
165

166
    /**
167
     * We switch the shape manager every time vector layer or
168 169 170 171
     * shape selection is activated. Flake does not expect this
     * and connects all the signals of the global shape manager
     * to the clients in the constructor. To workaround this we
     * forward the signals of local shape managers stored in the
172
     * vector layers to the signals of global shape manager. So the
173 174 175 176 177 178 179 180
     * sequence of signal deliveries is the following:
     *
     * shapeLayer.m_d.canvas.m_shapeManager.selection() ->
     * shapeLayer ->
     * shapeController ->
     * globalShapeManager.selection()
     */

181
    KisShapeController *kritaShapeController = static_cast<KisShapeController*>(shapeController()->documentBase());
182
    connect(kritaShapeController, SIGNAL(selectionChanged()),
183
            this, SLOT(slotSelectionChanged()));
184 185
    connect(kritaShapeController, SIGNAL(selectionContentChanged()),
            globalShapeManager(), SIGNAL(selectionContentChanged()));
Halla Rempt's avatar
Halla Rempt committed
186 187
    connect(kritaShapeController, SIGNAL(currentLayerChanged(const KoShapeLayer*)),
            globalShapeManager()->selection(), SIGNAL(currentLayerChanged(const KoShapeLayer*)));
188

189
    connect(&m_d->updateSignalCompressor, SIGNAL(timeout()), SLOT(slotDoCanvasUpdate()));
190 191
}

192 193
KisCanvas2::~KisCanvas2()
{
194 195 196
    if (m_d->animationPlayer->isPlaying()) {
        m_d->animationPlayer->forcedStopOnExit();
    }
197 198 199
    delete m_d;
}

200
void KisCanvas2::setCanvasWidget(QWidget * widget)
201
{
202
    KisAbstractCanvasWidget *tmp = dynamic_cast<KisAbstractCanvasWidget*>(widget);
Halla Rempt's avatar
Halla Rempt committed
203
    Q_ASSERT_X(tmp, "setCanvasWidget", "Cannot cast the widget to a KisAbstractCanvasWidget");
204 205
    if (m_d->popupPalette) {
        m_d->popupPalette->setParent(widget);
206
    }
207

208 209
    if(m_d->canvasWidget != 0)
    {
210
        tmp->setDecorations(m_d->canvasWidget->decorations());
211 212 213 214 215 216

        // Redundant check for the constructor case, see below
        if(viewManager() != 0)
            viewManager()->inputManager()->removeTrackedCanvas(this);
    }

217
    m_d->canvasWidget = tmp;
218

219 220 221 222 223
    // Either tmp was null or we are being called by KisCanvas2 constructor that is called by KisView
    // constructor, so the view manager still doesn't exists.
    if(m_d->canvasWidget != 0 && viewManager() != 0)
        viewManager()->inputManager()->addTrackedCanvas(this);

224 225
    if (!m_d->canvasWidget->decoration(INFINITY_DECORATION_ID)) {
        KisInfinityManager *manager = new KisInfinityManager(m_d->view, this);
226
        manager->setVisible(true);
227 228 229
        m_d->canvasWidget->addDecoration(manager);
    }

Halla Rempt's avatar
Halla Rempt committed
230 231 232 233
    widget->setAutoFillBackground(false);
    widget->setAttribute(Qt::WA_OpaquePaintEvent);
    widget->setMouseTracking(true);
    widget->setAcceptDrops(true);
234

235
    KoCanvasControllerWidget *controller = dynamic_cast<KoCanvasControllerWidget*>(canvasController());
236 237 238 239
    if (controller) {
        Q_ASSERT(controller->canvas() == this);
        controller->changeCanvasWidget(widget);
    }
240 241
}

242
bool KisCanvas2::canvasIsOpenGL() const
243 244 245 246
{
    return m_d->currentCanvasIsOpenGL;
}

247 248 249 250 251
KisOpenGL::FilterMode KisCanvas2::openGLFilterMode() const
{
    return KisOpenGL::FilterMode(m_d->openGLFilterMode);
}

252
void KisCanvas2::gridSize(QPointF *offset, QSizeF *spacing) const
253
{
Sven Langkamp's avatar
Sven Langkamp committed
254
    QTransform transform = coordinatesConverter()->imageToDocumentTransform();
255

256 257 258 259 260 261 262 263
    const QPoint intSpacing = m_d->view->document()->gridConfig().spacing();
    const QPoint intOffset = m_d->view->document()->gridConfig().offset();

    QPointF size = transform.map(QPointF(intSpacing));
    spacing->rwidth() = size.x();
    spacing->rheight() = size.y();

    *offset = transform.map(QPointF(intOffset));
264 265
}

266
bool KisCanvas2::snapToGrid() const
267
{
268
    return m_d->view->document()->gridConfig().snapToGrid();
269 270
}

271 272
qreal KisCanvas2::rotationAngle() const
{
273
    return m_d->coordinatesConverter->rotationAngle();
274 275
}

276 277 278 279 280 281 282 283 284 285
bool KisCanvas2::xAxisMirrored() const
{
    return m_d->coordinatesConverter->xAxisMirrored();
}

bool KisCanvas2::yAxisMirrored() const
{
    return m_d->coordinatesConverter->yAxisMirrored();
}

286 287
void KisCanvas2::channelSelectionChanged()
{
288 289 290 291
    KisImageWSP image = this->image();
    m_d->channelFlags = image->rootLayer()->channelFlags();

    image->barrierLock();
292
    m_d->canvasWidget->channelSelectionChanged(m_d->channelFlags);
293 294 295 296
    startUpdateInPatches(image->bounds());

    image->unlock();

297 298
}

Alexander Potashev's avatar
Alexander Potashev committed
299
void KisCanvas2::addCommand(KUndo2Command *command)
300
{
301
    // This method exists to support flake-related operations
302
    m_d->view->document()->addCommand(command);
303 304
}

305
KoShapeManager* KisCanvas2::shapeManager() const
306
{
307 308
    if (!viewManager()) return globalShapeManager();
    if (!viewManager()->nodeManager()) return globalShapeManager();
309

310
    KisLayerSP activeLayer = viewManager()->nodeManager()->activeLayer();
311
    if (activeLayer && activeLayer->isEditable()) {
Halla Rempt's avatar
Halla Rempt committed
312
        KisShapeLayer * shapeLayer = dynamic_cast<KisShapeLayer*>(activeLayer.data());
313
        if (shapeLayer) {
314
            return shapeLayer->shapeManager();
315
        }
316 317 318 319 320 321
        KisSelectionSP selection = activeLayer->selection();
        if (selection && !selection.isNull()) {
            if (selection->hasShapeSelection()) {
                KoShapeManager* m = dynamic_cast<KisShapeSelection*>(selection->shapeSelection())->shapeManager();
                return m;
            }
322 323

        }
324
    }
325
    return globalShapeManager();
326 327
}

328 329
KoShapeManager * KisCanvas2::globalShapeManager() const
{
330
    return &m_d->shapeManager;
331 332
}

Halla Rempt's avatar
Halla Rempt committed
333 334
void KisCanvas2::updateInputMethodInfo()
{
335 336 337
    // TODO call (the protected) QWidget::updateMicroFocus() on the proper canvas widget...
}

338 339 340 341 342
const KisCoordinatesConverter* KisCanvas2::coordinatesConverter() const
{
    return m_d->coordinatesConverter;
}

343
KoViewConverter* KisCanvas2::viewConverter() const
344
{
345
    return m_d->coordinatesConverter;
346
}
Halla Rempt's avatar
Halla Rempt committed
347

348 349 350 351 352
KisInputManager* KisCanvas2::globalInputManager() const
{
    return m_d->view->globalInputManager();
}

353 354 355 356
QWidget* KisCanvas2::canvasWidget()
{
    return m_d->canvasWidget->widget();
}
357 358 359 360 361

const QWidget* KisCanvas2::canvasWidget() const
{
    return m_d->canvasWidget->widget();
}
362 363 364 365


KoUnit KisCanvas2::unit() const
{
366 367 368 369 370
    KoUnit unit(KoUnit::Pixel);

    KisImageWSP image = m_d->view->image();
    if (image) {
        if (!qFuzzyCompare(image->xRes(), image->yRes())) {
Halla Rempt's avatar
Halla Rempt committed
371
            warnKrita << "WARNING: resolution of the image is anisotropic"
372 373 374 375 376 377 378 379 380
                       << ppVar(image->xRes())
                       << ppVar(image->yRes());
        }

        const qreal resolution = image->xRes();
        unit.setFactor(resolution);
    }

    return unit;
381
}
382

Halla Rempt's avatar
Halla Rempt committed
383 384
KoToolProxy * KisCanvas2::toolProxy() const
{
385
    return &m_d->toolProxy;
386
}
387

388 389 390
void KisCanvas2::createQPainterCanvas()
{
    m_d->currentCanvasIsOpenGL = false;
391

392
    KisQPainterCanvas * canvasWidget = new KisQPainterCanvas(this, m_d->coordinatesConverter, m_d->view);
393
    m_d->prescaledProjection = new KisPrescaledProjection();
394
    m_d->prescaledProjection->setCoordinatesConverter(m_d->coordinatesConverter);
395 396 397 398
    m_d->prescaledProjection->setMonitorProfile(m_d->displayColorConverter.monitorProfile(),
                                                m_d->displayColorConverter.renderingIntent(),
                                                m_d->displayColorConverter.conversionFlags());
    m_d->prescaledProjection->setDisplayFilter(m_d->displayColorConverter.displayFilter());
Halla Rempt's avatar
Halla Rempt committed
399 400
    canvasWidget->setPrescaledProjection(m_d->prescaledProjection);
    setCanvasWidget(canvasWidget);
401
}
Halla Rempt's avatar
Halla Rempt committed
402

403 404
void KisCanvas2::createOpenGLCanvas()
{
405
    KisConfig cfg;
406
    m_d->openGLFilterMode = cfg.openGLFilteringMode();
Dmitry Kazakov's avatar
Dmitry Kazakov committed
407
    m_d->currentCanvasIsOpenGL = true;
408

409
    KisOpenGLCanvas2 *canvasWidget = new KisOpenGLCanvas2(this, m_d->coordinatesConverter, 0, m_d->view->image(), &m_d->displayColorConverter);
410
    m_d->frameCache = KisAnimationFrameCache::getFrameCache(canvasWidget->openGLImageTextures());
411

412
    setCanvasWidget(canvasWidget);
413 414 415 416

    if (canvasWidget->needsFpsDebugging() && !decoration(KisFpsDecoration::idTag)) {
        addDecoration(new KisFpsDecoration(imageView()));
    }
417
}
418

Dmitry Kazakov's avatar
Dmitry Kazakov committed
419
void KisCanvas2::createCanvas(bool useOpenGL)
420
{
Dmitry Kazakov's avatar
Dmitry Kazakov committed
421
    // deinitialize previous canvas structures
422 423 424
    m_d->prescaledProjection = 0;
    m_d->frameCache = 0;

425 426 427
    KisConfig cfg;
    QDesktopWidget dw;
    const KoColorProfile *profile = cfg.displayProfile(dw.screenNumber(imageView()));
428
    m_d->displayColorConverter.setMonitorProfile(profile);
429

Dmitry Kazakov's avatar
Dmitry Kazakov committed
430
    if (useOpenGL) {
431 432 433 434 435 436 437 438 439
        if (KisOpenGL::hasOpenGL()) {
            createOpenGLCanvas();
            if (cfg.canvasState() == "OPENGL_FAILED") {
                // Creating the opengl canvas failed, fall back
                warnKrita << "OpenGL Canvas initialization returned OPENGL_FAILED. Falling back to QPainter.";
                createQPainterCanvas();
            }
        } else {
            warnKrita << "Tried to create OpenGL widget when system doesn't have OpenGL\n";
Dmitry Kazakov's avatar
Dmitry Kazakov committed
440 441
            createQPainterCanvas();
        }
442
    }
443
    else {
444
        createQPainterCanvas();
445
    }
446

447 448
    if (m_d->popupPalette) {
        m_d->popupPalette->setParent(m_d->canvasWidget->widget());
449 450
    }

451 452
}

453
void KisCanvas2::initializeImage()
454
{
455
    KisImageWSP image = m_d->view->image();
456

457
    m_d->coordinatesConverter->setImage(image);
458

459
    connect(image, SIGNAL(sigImageUpdated(QRect)), SLOT(startUpdateCanvasProjection(QRect)), Qt::DirectConnection);
460
    connect(this, SIGNAL(sigCanvasCacheUpdated()), SLOT(updateCanvasProjection()));
461
    connect(image, SIGNAL(sigProofingConfigChanged()), SLOT(slotChangeProofingConfig()));
462 463
    connect(image, SIGNAL(sigSizeChanged(const QPointF&, const QPointF&)), SLOT(startResizingImage()), Qt::DirectConnection);
    connect(this, SIGNAL(sigContinueResizeImage(qint32,qint32)), SLOT(finishResizingImage(qint32,qint32)));
464

465 466 467 468 469 470 471 472 473 474 475 476
    connectCurrentCanvas();
}

void KisCanvas2::connectCurrentCanvas()
{
    KisImageWSP image = m_d->view->image();

    if (!m_d->currentCanvasIsOpenGL) {
        Q_ASSERT(m_d->prescaledProjection);
        m_d->prescaledProjection->setImage(image);
    }

477
    startResizingImage();
478 479

    emit imageChanged(image);
480
    setLodAllowedInCanvas(m_d->lodAllowedInCanvas);
481 482
}

483
void KisCanvas2::resetCanvas(bool useOpenGL)
484
{
485 486 487 488 489
    // we cannot reset the canvas before it's created, but this method might be called,
    // for instance when setting the monitor profile.
    if (!m_d->canvasWidget) {
        return;
    }
Halla Rempt's avatar
Halla Rempt committed
490
    KisConfig cfg;
491 492
    bool needReset = (m_d->currentCanvasIsOpenGL != useOpenGL) ||
        (m_d->currentCanvasIsOpenGL &&
493
         m_d->openGLFilterMode != cfg.openGLFilteringMode());
494

495
    if (needReset) {
Dmitry Kazakov's avatar
Dmitry Kazakov committed
496
        createCanvas(useOpenGL);
497
        connectCurrentCanvas();
498
        notifyZoomChanged();
499
    }
500
    updateCanvasWidgetImpl();
501 502
}

503
void KisCanvas2::startUpdateInPatches(const QRect &imageRect)
504 505
{
    if (m_d->currentCanvasIsOpenGL) {
506
        startUpdateCanvasProjection(imageRect);
507
    } else {
508 509 510
        KisImageConfig imageConfig;
        int patchWidth = imageConfig.updatePatchWidth();
        int patchHeight = imageConfig.updatePatchHeight();
511

512 513
        for (int y = 0; y < imageRect.height(); y += patchHeight) {
            for (int x = 0; x < imageRect.width(); x += patchWidth) {
514
                QRect patchRect(x, y, patchWidth, patchHeight);
515 516 517 518 519 520
                startUpdateCanvasProjection(patchRect);
            }
        }
    }
}

521
void KisCanvas2::setDisplayFilter(KisDisplayFilter *displayFilter)
522
{
523
    m_d->displayColorConverter.setDisplayFilter(displayFilter);
524
    KisImageWSP image = this->image();
525

526
    image->barrierLock();
527

528
    m_d->canvasWidget->setDisplayFilter(displayFilter);
529

530
    image->unlock();
531 532
}

533 534
KisDisplayFilter *KisCanvas2::displayFilter() const
{
535
    return m_d->displayColorConverter.displayFilter();
536 537
}

538
KisDisplayColorConverter* KisCanvas2::displayColorConverter() const
539
{
540
    return &m_d->displayColorConverter;
541 542
}

543 544
KisExposureGammaCorrectionInterface* KisCanvas2::exposureGammaCorrectionInterface() const
{
545
    KisDisplayFilter *displayFilter =
546
        m_d->displayColorConverter.displayFilter();
547 548 549 550 551 552

    return displayFilter ?
        displayFilter->correctionInterface() :
        KisDumbExposureGammaCorrectionInterface::instance();
}

553 554 555 556 557 558 559 560 561 562 563
void KisCanvas2::setProofingOptions(bool softProof, bool gamutCheck)
{
    m_d->proofingConfig = this->image()->proofingConfiguration();
    if (!m_d->proofingConfig) {
        qDebug()<<"Canvas: No proofing config found, generating one.";
        m_d->proofingConfig = new KisProofingConfiguration();
    }
    KoColorConversionTransformation::ConversionFlags conversionFlags = m_d->proofingConfig->conversionFlags;

    if (softProof) {
        conversionFlags |= KoColorConversionTransformation::SoftProofing;
564 565
    } else {
        conversionFlags = conversionFlags &  ~KoColorConversionTransformation::SoftProofing;
566 567 568
    }
    if (gamutCheck) {
        conversionFlags |= KoColorConversionTransformation::GamutCheck;
569 570
    } else {
        conversionFlags = conversionFlags & ~KoColorConversionTransformation::GamutCheck;
571 572 573
    }
    m_d->proofingConfig->conversionFlags = conversionFlags;

574 575 576
    qDebug()<<"setting softproofing in canvas: "<<softProof <<", "<<gamutCheck;
    qDebug()<<conversionFlags.testFlag(KoColorConversionTransformation::SoftProofing);
    qDebug()<<conversionFlags.testFlag(KoColorConversionTransformation::GamutCheck);
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592
    startUpdateInPatches(this->image()->bounds());

}

void KisCanvas2::slotSoftProofing(bool softProofing)
{
    m_d->softProofing = softProofing;
    setProofingOptions(m_d->softProofing, m_d->gamutCheck);
}

void KisCanvas2::slotGamutCheck(bool gamutCheck)
{
    m_d->gamutCheck = gamutCheck;
    setProofingOptions(m_d->softProofing, m_d->gamutCheck);
}

593 594 595 596 597
void KisCanvas2::slotChangeProofingConfig()
{
    setProofingOptions(m_d->softProofing, m_d->gamutCheck);
}

598 599 600 601 602 603 604 605 606
KisProofingConfiguration *KisCanvas2::proofingConfiguration() const
{
    if (!m_d->proofingConfig) {
        qDebug()<<"No proofing config found, generating one";
        m_d->proofingConfig = new KisProofingConfiguration();
    }
    return m_d->proofingConfig;
}

607
void KisCanvas2::startResizingImage()
608
{
609 610 611 612
    KisImageWSP image = this->image();
    qint32 w = image->width();
    qint32 h = image->height();

613 614 615 616 617 618
    emit sigContinueResizeImage(w, h);

    QRect imageBounds(0, 0, w, h);
    startUpdateInPatches(imageBounds);
}

Halla Rempt's avatar
Halla Rempt committed
619
void KisCanvas2::finishResizingImage(qint32 w, qint32 h)
620
{
621
    m_d->canvasWidget->finishResizingImage(w, h);
622 623
}

624
void KisCanvas2::startUpdateCanvasProjection(const QRect & rc)
625
{
626
    KisUpdateInfoSP info = m_d->canvasWidget->startUpdateCanvasProjection(rc, m_d->channelFlags);
627 628
    if (m_d->projectionUpdatesCompressor.putUpdateInfo(info)) {
        emit sigCanvasCacheUpdated();
629
    }
630 631
}

632
void KisCanvas2::updateCanvasProjection()
633
{
634 635 636 637
    while (KisUpdateInfoSP info = m_d->projectionUpdatesCompressor.takeUpdateInfo()) {
        QRect vRect = m_d->canvasWidget->updateCanvasProjection(info);
        if (!vRect.isEmpty()) {
            updateCanvasWidgetImpl(m_d->coordinatesConverter->viewportToWidget(vRect).toAlignedRect());
638
        }
639
    }
640

641 642 643
    // TODO: Implement info->dirtyViewportRect() for KisOpenGLCanvas2 to avoid updating whole canvas
    if (m_d->currentCanvasIsOpenGL) {
        updateCanvasWidgetImpl();
Dmitry Kazakov's avatar
Dmitry Kazakov committed
644 645 646
    }
}

647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
void KisCanvas2::slotDoCanvasUpdate()
{
    if (m_d->canvasWidget->isBusy()) {
        // just restarting the timer
        updateCanvasWidgetImpl(m_d->savedUpdateRect);
        return;
    }

    if (m_d->savedUpdateRect.isEmpty()) {
        m_d->canvasWidget->widget()->update();
        emit updateCanvasRequested(m_d->canvasWidget->widget()->rect());
    } else {
        emit updateCanvasRequested(m_d->savedUpdateRect);
        m_d->canvasWidget->widget()->update(m_d->savedUpdateRect);
    }

    m_d->savedUpdateRect = QRect();
}

void KisCanvas2::updateCanvasWidgetImpl(const QRect &rc)
{
668
    if (!m_d->updateSignalCompressor.isActive() ||
669 670 671
        !m_d->savedUpdateRect.isEmpty()) {
        m_d->savedUpdateRect |= rc;
    }
672
    m_d->updateSignalCompressor.start();
673 674
}

675 676
void KisCanvas2::updateCanvas()
{
677
    updateCanvasWidgetImpl();
678 679 680 681 682
}

void KisCanvas2::updateCanvas(const QRectF& documentRect)
{
    if (m_d->currentCanvasIsOpenGL && m_d->canvasWidget->decorations().size() > 0) {
683
        updateCanvasWidgetImpl();
684 685 686 687 688 689 690
    }
    else {
        // updateCanvas is called from tools, never from the projection
        // updates, so no need to prescale!
        QRect widgetRect = m_d->coordinatesConverter->documentToWidget(documentRect).toAlignedRect();
        widgetRect.adjust(-2, -2, 2, 2);
        if (!widgetRect.isEmpty()) {
691
            updateCanvasWidgetImpl(widgetRect);
692 693 694 695
        }
    }
}

696 697 698 699 700 701
void KisCanvas2::disconnectCanvasObserver(QObject *object)
{
    KoCanvasBase::disconnectCanvasObserver(object);
    m_d->view->disconnect(object);
}

702 703 704 705 706 707
void KisCanvas2::notifyZoomChanged()
{
    if (!m_d->currentCanvasIsOpenGL) {
        Q_ASSERT(m_d->prescaledProjection);
        m_d->prescaledProjection->notifyZoomChanged();
    }
708

709
    notifyLevelOfDetailChange();
710
    updateCanvas(); // update the canvas, because that isn't done when zooming using KoZoomAction
711 712
}

713 714
void KisCanvas2::notifyLevelOfDetailChange()
{
715
    if (!m_d->effectiveLodAllowedInCanvas()) return;
716 717 718 719 720 721 722 723 724 725 726 727

    KisImageSP image = this->image();

    const qreal effectiveZoom = m_d->coordinatesConverter->effectiveZoom();

    KisConfig cfg;
    const int maxLod = cfg.numMipmapLevels();

    int lod = KisLodTransform::scaleToLod(effectiveZoom, maxLod);
    image->setDesiredLevelOfDetail(lod);
}

728 729
void KisCanvas2::preScale()
{
Dmitry Kazakov's avatar
Dmitry Kazakov committed
730 731
    if (!m_d->currentCanvasIsOpenGL) {
        Q_ASSERT(m_d->prescaledProjection);
732
        m_d->prescaledProjection->preScale();
Dmitry Kazakov's avatar
Dmitry Kazakov committed
733 734 735
    }
}

736
const KoColorProfile *  KisCanvas2::monitorProfile()
Dmitry Kazakov's avatar
Dmitry Kazakov committed
737
{
738
    return m_d->displayColorConverter.monitorProfile();
Dmitry Kazakov's avatar
Dmitry Kazakov committed
739 740
}

741 742 743 744 745 746 747 748 749
KisViewManager* KisCanvas2::viewManager() const
{
    if (m_d->view) {
        return m_d->view->viewManager();
    }
    return 0;
}

QPointer<KisView>KisCanvas2::imageView() const
Dmitry Kazakov's avatar
Dmitry Kazakov committed
750 751 752 753
{
    return m_d->view;
}

754
KisImageWSP KisCanvas2::image() const
Dmitry Kazakov's avatar
Dmitry Kazakov committed
755 756 757 758 759
{
    return m_d->view->image();

}

760
KisImageWSP KisCanvas2::currentImage() const
Dmitry Kazakov's avatar
Dmitry Kazakov committed
761 762 763 764 765 766
{
    return m_d->view->image();
}

void KisCanvas2::documentOffsetMoved(const QPoint &documentOffset)
{
767
    QPointF offsetBefore = m_d->coordinatesConverter->imageRectInViewportPixels().topLeft();
768
    m_d->coordinatesConverter->setDocumentOffset(documentOffset);
769
    QPointF offsetAfter = m_d->coordinatesConverter->imageRectInViewportPixels().topLeft();
770 771

    QPointF moveOffset = offsetAfter - offsetBefore;
772 773 774 775

    if (!m_d->currentCanvasIsOpenGL)
        m_d->prescaledProjection->viewportMoved(moveOffset);

776 777
    emit documentOffsetUpdateFinished();

778
    updateCanvas();
779 780
}

781 782
void KisCanvas2::slotConfigChanged()
{
783
    KisConfig cfg;
784
    m_d->vastScrolling = cfg.vastScrolling();
785

Halla Rempt's avatar
Halla Rempt committed
786
    resetCanvas(cfg.useOpenGL());
787
    slotSetDisplayProfile(cfg.displayProfile(QApplication::desktop()->screenNumber(this->canvasWidget())));
788

789 790
}

791 792 793 794 795 796 797
void KisCanvas2::refetchDataFromImage()
{
    KisImageSP image = this->image();
    KisImageBarrierLocker l(image);
    startUpdateInPatches(image->bounds());
}