Krita Source Code Documentation
Loading...
Searching...
No Matches
KisView.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2014 Boudewijn Rempt <boud@valdyas.org>
3 * SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
8#include "KisView.h"
9
10#include "KisView_p.h"
11
12#include <KoDockFactoryBase.h>
13#include <KoDockRegistry.h>
14#include <KoDocumentInfo.h>
15#include <KoToolManager.h>
16
17#include <kis_icon.h>
18
19#include <kactioncollection.h>
20#include <klocalizedstring.h>
21#include <kis_debug.h>
22#include <kselectaction.h>
23#include <kconfiggroup.h>
24
25#include <QMessageBox>
26#include <QUrl>
27#include <QTemporaryFile>
28#include <QApplication>
29#include <QScreen>
30#include <QDragEnterEvent>
31#include <QDropEvent>
32#include <QList>
33#include <QPrintDialog>
34#include <QToolBar>
35#include <QStatusBar>
36#include <QMoveEvent>
37#include <QMdiSubWindow>
38#include <QFileInfo>
39#include <QScreen>
40
41#include <kis_image.h>
42#include <kis_node.h>
43
44#include <kis_group_layer.h>
45#include <kis_layer.h>
46#include <kis_mask.h>
47#include <kis_selection.h>
48
49#include "KisDocument.h"
51#include "KisMainWindow.h"
52#include "KisMimeDatabase.h"
53#include "KisPart.h"
57#include "KisViewManager.h"
59#include "kis_canvas2.h"
62#include "kis_clipboard.h"
63#include "kis_config.h"
64#include "kis_file_layer.h"
65#include "kis_fill_painter.h"
66#include "kis_filter_manager.h"
67#include "kis_image_manager.h"
68#include "kis_import_catcher.h"
69#include "kis_mimedata.h"
71#include "kis_node_manager.h"
72#include "kis_paint_layer.h"
78#include "kis_zoom_manager.h"
79#include "krita_utils.h"
86#include <kis_command_utils.h>
89#include "kformat.h"
90
91
92//static
94{
95 static int s_viewIFNumber = 0;
96 QString name; name.setNum(s_viewIFNumber++); name.prepend("view_");
97 return name;
98}
99
100bool KisView::s_firstView = true;
101
102class Q_DECL_HIDDEN KisView::Private
103{
104public:
106 KisDocument *document,
107 KisViewManager *viewManager)
108 : actionCollection(viewManager->actionCollection())
109 , viewConverter()
110 , canvasController(_q, viewManager->mainWindow(), viewManager->actionCollection())
111 , canvas(&viewConverter, viewManager->canvasResourceProvider()->resourceManager(), viewManager->mainWindow(), _q, document->shapeController())
112 , zoomManager(_q, &this->viewConverter, &this->canvasController)
113 , viewManager(viewManager)
114 , floatingMessageCompressor(100, KisSignalCompressor::POSTPONE)
115 , screenMigrationTracker(_q)
116 {
117 }
118
119 bool inOperation {false}; //in the middle of an operation (no screen refreshing)?
120
121 QPointer<KisDocument> document; // our KisDocument
122 QWidget *tempActiveWidget {nullptr};
123
124 KisKActionCollection* actionCollection {nullptr};
129 KisViewManager *viewManager {nullptr};
133 bool isCurrent {false};
134 bool showFloatingMessage {true};
137 QMdiSubWindow *subWindow {nullptr};
138
139 bool softProofing {false};
140 bool gamutCheck {false};
141
144
146
147 // Hmm sorry for polluting the private class with such a big inner class.
148 // At the beginning it was a little struct :)
149 class StatusBarItem : public boost::equality_comparable<StatusBarItem>
150 {
151 public:
152
153 StatusBarItem(QWidget * widget, int stretch, bool permanent)
154 : m_widget(widget),
155 m_stretch(stretch),
156 m_permanent(permanent),
157 m_connected(false),
158 m_hidden(false) {}
159
160 bool operator==(const StatusBarItem& rhs) {
161 return m_widget == rhs.m_widget;
162 }
163
164 QWidget * widget() const {
165 return m_widget;
166 }
167
168 void ensureItemShown(QStatusBar * sb) {
169 Q_ASSERT(m_widget);
170 if (!m_connected) {
171 if (m_permanent)
172 sb->addPermanentWidget(m_widget, m_stretch);
173 else
174 sb->addWidget(m_widget, m_stretch);
175
176 if(!m_hidden)
177 m_widget->show();
178
179 m_connected = true;
180 }
181 }
182 void ensureItemHidden(QStatusBar * sb) {
183 if (m_connected) {
184 m_hidden = m_widget->isHidden();
185 sb->removeWidget(m_widget);
186 m_widget->hide();
187 m_connected = false;
188 }
189 }
190
191 private:
192 QWidget * m_widget = 0;
195 bool m_connected = false;
196 bool m_hidden = false;
197
198 };
199
200};
201
202KisView::KisView(KisDocument *document, KisViewManager *viewManager, QWidget *parent)
203 : QWidget(parent)
204 , d(new Private(this, document, viewManager))
205{
206 Q_ASSERT(document);
207 setObjectName(newObjectName());
208
209 d->document = document;
210
211 setFocusPolicy(Qt::StrongFocus);
212
213 QStatusBar * sb = statusBar();
214 if (sb) { // No statusbar in e.g. konqueror
215 connect(d->document, SIGNAL(statusBarMessage(QString,int)),
216 this, SLOT(slotSavingStatusMessage(QString,int)));
217 connect(d->document, SIGNAL(clearStatusBarMessage()),
218 this, SLOT(slotClearStatusText()));
219 }
220
221 d->canvas.setup();
222
223 KisConfig cfg(false);
224
225 d->canvasController.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
226 d->canvasController.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
227 d->canvasController.setCanvas(&d->canvas);
228
229 d->zoomManager.setup(d->actionCollection);
230
231 setAcceptDrops(true);
232
233 connect(d->document, SIGNAL(sigLoadingFinished()), this, SLOT(slotLoadingFinished()));
234
235 d->referenceImagesDecoration = new KisReferenceImagesDecoration(this, document, /* viewReady = */ false);
236 d->canvas.addDecoration(d->referenceImagesDecoration);
237 d->referenceImagesDecoration->setVisible(true);
238
239 d->paintingAssistantsDecoration = new KisPaintingAssistantsDecoration(this);
240 d->canvas.addDecoration(d->paintingAssistantsDecoration);
241 d->paintingAssistantsDecoration->setVisible(true);
242
243 d->showFloatingMessage = cfg.showCanvasMessages();
245
246 connect(document, SIGNAL(sigReadWriteChanged(bool)), this, SLOT(slotUpdateDocumentTitle()));
247 connect(document, SIGNAL(sigRecoveredChanged(bool)), this, SLOT(slotUpdateDocumentTitle()));
248 connect(document, SIGNAL(sigPathChanged(QString)), this, SLOT(slotUpdateDocumentTitle()));
250 SIGNAL(sigUpdateMemoryStatistics()),
252 connect(document, SIGNAL(modified(bool)), this, SLOT(setWindowModified(bool)));
254 setWindowModified(document->isModified());
255}
256
258{
259 if (d->viewManager) {
260 if (d->viewManager->filterManager()->isStrokeRunning()) {
261 d->viewManager->filterManager()->cancelDialog();
262 }
263
264 d->viewManager->mainWindow()->notifyChildViewDestroyed(this);
265 }
266
268
274
275 KoToolManager::instance()->removeCanvasController(&d->canvasController);
276 d->canvasController.setCanvas(0);
277
279 delete d;
280}
281
283{
284 d->isCurrent = isCurrent;
285
286 if (!d->isCurrent && d->savedFloatingMessage) {
287 d->savedFloatingMessage->removeMessage();
288 }
289
290 KisInputManager *inputManager = globalInputManager();
291 if (d->isCurrent) {
292 inputManager->attachPriorityEventFilter(&d->canvasController);
293 } else {
294 inputManager->detachPriorityEventFilter(&d->canvasController);
295 }
296
302}
303
304bool KisView::isCurrent() const
305{
306 return d->isCurrent;
307}
308
310{
311 d->showFloatingMessage = show;
312}
313
314void KisView::showFloatingMessage(const QString &message, const QIcon& icon, int timeout, KisFloatingMessage::Priority priority, int alignment)
315{
316 if (!d->viewManager) return;
317
318 if(d->isCurrent && d->showFloatingMessage && d->viewManager->qtMainWindow()) {
319 if (d->savedFloatingMessage) {
320 d->savedFloatingMessage->tryOverrideMessage(message, icon, timeout, priority, alignment);
321 } else {
322 d->savedFloatingMessage = new KisFloatingMessage(message, this->canvasBase()->canvasWidget(), false, timeout, priority, alignment);
323 d->savedFloatingMessage->setShowOverParent(true);
324 d->savedFloatingMessage->setIcon(icon);
325
326 connect(&d->floatingMessageCompressor, SIGNAL(timeout()), d->savedFloatingMessage, SLOT(showMessage()));
327 d->floatingMessageCompressor.start();
328 }
329 }
330}
331
333{
334 return d->canvas.xAxisMirrored() || d->canvas.yAxisMirrored();
335}
336
338{
339 d->viewManager = view;
340
341 KoToolManager::instance()->addController(&d->canvasController);
342 KisShapeController* shapeController = dynamic_cast<KisShapeController*>(d->document->shapeController());
343 shapeController->setInitialShapeForCanvas(&d->canvas);
344
345 if (d->viewManager && d->viewManager->nodeManager()) {
346 d->viewManager->nodeManager()->nodesUpdated();
347 }
348
349 connect(image(), SIGNAL(sigSizeChanged(QPointF,QPointF)), this, SLOT(slotImageSizeChanged(QPointF,QPointF)));
350 connect(image(), SIGNAL(sigResolutionChanged(double,double)), this, SLOT(slotImageResolutionChanged()));
351
352 d->addNodeConnection.connectSync(image(), &KisImage::sigNodeAddedAsync,
354
355 // executed in a context of an image thread
356 connect(image(), SIGNAL(sigRemoveNodeAsync(KisNodeSP)),
358 Qt::DirectConnection);
359
360 d->removeNodeConnection.connectOutputSlot(this, &KisView::slotContinueRemoveNode);
361
362 d->viewManager->updateGUI();
363
364 KoToolManager::instance()->switchToolRequested("KritaShape/KisToolBrush");
365}
366
368{
369 return d->viewManager;
370}
371
372void KisView::slotContinueAddNode(KisNodeSP newActiveNode, KisNodeAdditionFlags flags)
373{
374 Q_UNUSED(flags)
375
376
384 if (!d->isCurrent &&
385 (!d->currentNode || !d->currentNode->parent())) {
386
387 d->currentNode = newActiveNode;
388 }
389}
390
391
393{
394 d->removeNodeConnection.start(KritaUtils::nearestNodeAfterRemoval(node));
395}
396
398{
399 if (!d->isCurrent) {
400 d->currentNode = newActiveNode;
401 }
402}
403
405{
406 return &d->zoomManager;
407}
408
410{
411 return &d->canvasController;
412}
413
415{
416 if (d->viewManager) {
417 return d->viewManager->canvasResourceProvider();
418 }
419 return 0;
420}
421
423{
424 return d->viewManager ? d->viewManager->inputManager() : 0;
425}
426
428{
429 return &d->canvas;
430}
431
433{
434 if (d->document) {
435 return d->document->image();
436 }
437 return 0;
438}
439
440
442{
443 return &d->viewConverter;
444}
445
446void KisView::dragEnterEvent(QDragEnterEvent *event)
447{
448 dbgUI << Q_FUNC_INFO
449 << "Formats: " << event->mimeData()->formats()
450 << "Urls: " << event->mimeData()->urls()
451 << "Has images: " << event->mimeData()->hasImage();
452
453 if (shouldAcceptDrag(event)) {
454 event->accept();
455 setFocus(); // activate view if it should accept the drop
456 } else {
457 event->ignore();
458 }
459}
460
461void KisView::dropEvent(QDropEvent *event)
462{
463 dbgUI << Q_FUNC_INFO;
464 dbgUI << "\t Formats: " << event->mimeData()->formats();
465 dbgUI << "\t Urls: " << event->mimeData()->urls();
466 dbgUI << "\t Has images: " << event->mimeData()->hasImage();
467
468 if (!shouldAcceptDrag(event)) {
469 return;
470 }
471
472 KisImageWSP kisimage = image();
473 Q_ASSERT(kisimage);
474
475 QPoint imgCursorPos = canvasBase()->coordinatesConverter()->widgetToImage(event->pos()).toPoint();
476 QRect imageBounds = kisimage->bounds();
477 boost::optional<QPoint> forcedCenter;
478
479 if (event->keyboardModifiers() & Qt::ShiftModifier && imageBounds.contains(imgCursorPos)) {
480 forcedCenter = imgCursorPos;
481 }
482
483 if (event->mimeData()->hasFormat("application/x-krita-node-internal-pointer")) {
484 KisShapeController *kritaShapeController =
485 dynamic_cast<KisShapeController*>(d->document->shapeController());
486
487 bool copyNode = true;
488 QList<KisNodeSP> nodes;
489
490 if (forcedCenter) {
491 nodes = KisMimeData::loadNodesFastAndRecenter(*forcedCenter, event->mimeData(), kisimage, kritaShapeController, copyNode);
492 } else {
493 nodes = KisMimeData::loadNodesFast(event->mimeData(), kisimage, kritaShapeController, copyNode);
494 }
495
496 Q_FOREACH (KisNodeSP node, nodes) {
497 if (node) {
499 if (!viewManager()->nodeManager()->activeLayer()) {
500 adapter.addNode(node, kisimage->rootLayer() , 0);
501 } else {
502 adapter.addNode(node,
503 viewManager()->nodeManager()->activeLayer()->parent(),
504 viewManager()->nodeManager()->activeLayer());
505 }
506 }
507 }
508 } else if (event->mimeData()->hasImage() || event->mimeData()->hasUrls()) {
509 const QMimeData *mData = event->mimeData();
510
511 // Opening a window on wayland causes the clipboard to be cleared, so we need to cache all the data we may need beforehand
512 QList<QUrl> urls = mData->urls();
513 const QImage qimage = KisClipboard::instance()->getImageWithFallback(mData, false);
514
515 KisCanvasDrop dlgAction;
516
517 const auto callPos = QCursor::pos();
518
519 const KisCanvasDrop::Action action = dlgAction.dropAs(*mData, callPos);
520
522 const QPair<bool, KisClipboard::PasteFormatBehaviour> source =
524
525 if (!source.first) {
526 dbgUI << "Paste event cancelled";
527 return;
528 }
529
531 const auto url = std::find_if(
532 urls.constBegin(),
533 urls.constEnd(),
534 [&](const QUrl &url) {
535 if (source.second
536 == KisClipboard::PASTE_FORMAT_DOWNLOAD) {
537 return !url.isLocalFile();
538 } else if (source.second
540 return url.isLocalFile();
541 } else {
542 return false;
543 }
544 });
545
546 if (url != urls.constEnd()) {
547 QScopedPointer<QTemporaryFile> tmp(new QTemporaryFile());
548 tmp->setAutoRemove(true);
549
550 const QUrl localUrl = [&]() -> QUrl {
551 if (!url->isLocalFile()) {
552 // download the file and substitute the url
553 KisRemoteFileFetcher fetcher;
554 tmp->setFileName(url->fileName());
555
556 if (!fetcher.fetchFile(*url, tmp.data())) {
557 warnUI << "Fetching" << *url << "failed";
558 return {};
559 }
560 return QUrl::fromLocalFile(tmp->fileName());
561 }
562 return *url;
563 }();
564
565 if (localUrl.isLocalFile()) {
566 this->mainWindow()
567 ->viewManager()
568 ->imageManager()
569 ->importImage(localUrl);
570 this->activateWindow();
571 return;
572 }
573 }
574 }
575
576 KisPaintDeviceSP clip = KisClipboard::instance()->clipFromBoardContentsWithData(qimage, urls, QRect(), true, -1, false, source);
577 if (clip) {
578 const auto pos = this->viewConverter()
579 ->imageToDocument(imgCursorPos)
580 .toPoint();
581
582 clip->moveTo(pos.x(), pos.y());
583
585 this->image());
586
587 KisPaintLayerSP layer = new KisPaintLayer(
588 this->image(),
589 this->image()->nextLayerName() + " " + i18n("(pasted)"),
591 clip);
593 this->mainWindow()->viewManager());
594 adapter.addNode(
595 layer,
596 this->mainWindow()->viewManager()->activeNode()->parent(),
597 this->mainWindow()->viewManager()->activeNode());
598 this->activateWindow();
599 return;
600 }
601 } else if (action == KisCanvasDrop::INSERT_AS_REFERENCE_IMAGE) {
602
603 KisPaintDeviceSP clip = KisClipboard::instance()-> clipFromBoardContentsWithData(qimage, urls, QRect(), true);
604 if (clip) {
606 this->image());
607
608 auto *reference =
610 *this->viewConverter(),
611 this);
612
613 if (reference) {
614 if (!urls.isEmpty()) {
615 const auto url = std::find_if(urls.constBegin(), urls.constEnd(), std::mem_fn(&QUrl::isLocalFile));
616 if (url != urls.constEnd()) {
617 reference->setFilename((*url).toLocalFile());
618 }
619 }
620 const auto pos = this->canvasBase()
622 ->widgetToImage(event->pos());
623 reference->setPosition(
624 (*this->viewConverter()).imageToDocument(pos));
625 this->canvasBase()
627 ->addReferenceImage(reference);
629 "ToolReferenceImages");
630 return;
631 }
632 }
633 } else if (action != KisCanvasDrop::NONE) {
634 // multiple URLs detected OR about to open a document
635
636 for (QUrl url : urls) { // do copy it
637 QScopedPointer<QTemporaryFile> tmp(new QTemporaryFile());
638 tmp->setAutoRemove(true);
639
640 if (!url.isLocalFile()) {
641 // download the file and substitute the url
642 KisRemoteFileFetcher fetcher;
643 tmp->setFileName(url.fileName());
644
645 if (!fetcher.fetchFile(url, tmp.data())) {
646 qWarning() << "Fetching" << url << "failed";
647 continue;
648 }
649 url = QUrl::fromLocalFile(tmp->fileName());
650 }
651
652 if (url.isLocalFile()) {
653 if (action == KisCanvasDrop::INSERT_MANY_LAYERS) {
654 this->mainWindow()
655 ->viewManager()
656 ->imageManager()
657 ->importImage(url);
658 this->activateWindow();
659 } else if (action == KisCanvasDrop::INSERT_MANY_FILE_LAYERS
660 || action
663 this->mainWindow()->viewManager());
664 QFileInfo fileInfo(url.toLocalFile());
665
666 QString type =
667 KisMimeDatabase::mimeTypeForFile(url.toLocalFile());
668 QStringList mimes =
671
672 if (!mimes.contains(type)) {
673 QString msg =
676 .errorMessage();
677 QMessageBox::warning(
678 this,
679 i18nc("@title:window", "Krita"),
680 i18n("Could not open %2.\nReason: %1.",
681 msg,
682 url.toDisplayString()));
683 continue;
684 }
685
686 KisFileLayer *fileLayer =
687 new KisFileLayer(this->image(),
688 "",
689 url.toLocalFile(),
691 "Bicubic",
692 fileInfo.fileName(),
694
695 KisLayerSP above =
696 this->mainWindow()->viewManager()->activeLayer();
697 KisNodeSP parent = above ? above->parent()
698 : this->mainWindow()
699 ->viewManager()
700 ->image()
701 ->root();
702
703 adapter.addNode(fileLayer, parent, above);
704 } else if (action == KisCanvasDrop::OPEN_IN_NEW_DOCUMENT
705 || action
707 if (this->mainWindow()) {
708 this->mainWindow()->openDocument(
709 url.toLocalFile(),
711 }
712 } else if (action
714 || action
715 == KisCanvasDrop::
716 INSERT_AS_REFERENCE_IMAGE) {
717 auto *reference =
718 KisReferenceImage::fromFile(url.toLocalFile(),
719 *this->viewConverter(),
720 this);
721
722 if (reference) {
723 const auto pos = this->canvasBase()
725 ->widgetToImage(event->pos());
726 reference->setPosition(
727 (*this->viewConverter()).imageToDocument(pos));
728 this->canvasBase()
730 ->addReferenceImage(reference);
731
733 "ToolReferenceImages");
734 }
735 }
736 }
737 }
738 }
739 } else if (event->mimeData()->hasColor() || event->mimeData()->hasFormat("krita/x-colorsetentry")) {
740 if (!image()) {
741 return;
742 }
743
744 // Cannot fill on non-painting layers (vector layer, clone layer, file layer, group layer)
745 if (d->viewManager->activeNode().isNull() ||
746 d->viewManager->activeNode()->inherits("KisShapeLayer") ||
747 d->viewManager->activeNode()->inherits("KisCloneLayer") ||
748 !d->viewManager->activeDevice()) {
749 showFloatingMessage(i18n("You cannot drag and drop colors on the selected layer type."), QIcon());
750 return;
751 }
752
753 // Cannot fill if the layer is not editable
754 if (!d->viewManager->activeNode()->isEditable()) {
755 QString message;
756 if (!d->viewManager->activeNode()->visible() && d->viewManager->activeNode()->userLocked()) {
757 message = i18n("Layer is locked and invisible.");
758 } else if (d->viewManager->activeNode()->userLocked()) {
759 message = i18n("Layer is locked.");
760 } else if(!d->viewManager->activeNode()->visible()) {
761 message = i18n("Layer is invisible.");
762 }
763 showFloatingMessage(message, KisIconUtils::loadIcon("object-locked"));
764 return;
765 }
766
767 // The cursor is outside the image
768 if (!image()->wrapAroundModePermitted() && !image()->bounds().contains(imgCursorPos)) {
769 return;
770 }
771
774 kundo2_i18n("Flood Fill Layer"), false, image().data()
775 );
776 strategy->setSupportsWrapAroundMode(true);
777 KisStrokeId fillStrokeId = image()->startStroke(strategy);
778 KIS_SAFE_ASSERT_RECOVER_RETURN(fillStrokeId);
779
780 QSharedPointer<QRect> dirtyRect = QSharedPointer<QRect>(new QRect);
781
782 KisResourcesSnapshotSP resources =
783 new KisResourcesSnapshot(image(), d->viewManager->activeNode(), d->viewManager->canvasResourceProvider()->resourceManager());
784
785 if (event->mimeData()->hasColor()) {
786 resources->setFGColorOverride(KoColor(event->mimeData()->colorData().value<QColor>(), image()->colorSpace()));
787 } else {
788 QByteArray byteData = event->mimeData()->data("krita/x-colorsetentry");
790 resources->setFGColorOverride(s.color());
791 }
792
793 // Use same options as the fill tool
794 KConfigGroup configGroup = KSharedConfig::openConfig()->group("KritaFill/KisToolFill");
795 QString fillMode = configGroup.readEntry<QString>("whatToFill", "");
796 if (fillMode.isEmpty()) {
797 if (configGroup.readEntry<bool>("fillSelection", false)) {
798 fillMode = "fillSelection";
799 } else {
800 fillMode = "fillContiguousRegion";
801 }
802 }
803 const bool useCustomBlendingOptions = configGroup.readEntry<bool>("useCustomBlendingOptions", false);
804 const qreal customOpacity =
805 qBound(0, configGroup.readEntry<int>("customOpacity", 100), 100) / 100.0;
806 QString customCompositeOp = configGroup.readEntry<QString>("customCompositeOp", COMPOSITE_OVER);
807 if (KoCompositeOpRegistry::instance().getKoID(customCompositeOp).id().isNull()) {
808 customCompositeOp = COMPOSITE_OVER;
809 }
810
811 if (event->keyboardModifiers() == Qt::ShiftModifier) {
812 if (fillMode == "fillSimilarRegions") {
813 fillMode = "fillSelection";
814 } else {
815 fillMode = "fillSimilarRegions";
816 }
817 } else if (event->keyboardModifiers() == Qt::AltModifier) {
818 if (fillMode == "fillContiguousRegion") {
819 fillMode = "fillSelection";
820 } else {
821 fillMode = "fillContiguousRegion";
822 }
823 }
824
825 if (fillMode == "fillSelection") {
826 FillProcessingVisitor *visitor = new FillProcessingVisitor(nullptr,
827 selection(),
828 resources);
829 visitor->setSeedPoint(imgCursorPos);
830 visitor->setSelectionOnly(true);
831 visitor->setUseCustomBlendingOptions(useCustomBlendingOptions);
832 if (useCustomBlendingOptions) {
833 visitor->setCustomOpacity(customOpacity);
834 visitor->setCustomCompositeOp(customCompositeOp);
835 }
836 visitor->setOutDirtyRect(dirtyRect);
837
838 image()->addJob(
839 fillStrokeId,
841 KUndo2CommandSP(new KisProcessingCommand(visitor, d->viewManager->activeNode())),
842 false,
845 )
846 );
847 } else {
848 const int threshold = configGroup.readEntry("thresholdAmount", 8);
849 const int opacitySpread = configGroup.readEntry("opacitySpread", 100);
850 const bool antiAlias = configGroup.readEntry("antiAlias", true);
851 const int grow = configGroup.readEntry("growSelection", 0);
852 const bool stopGrowingAtDarkestPixel = configGroup.readEntry<bool>("stopGrowingAtDarkestPixel", false);
853 const int feather = configGroup.readEntry("featherAmount", 0);
854 const int closeGap = configGroup.readEntry("closeGapAmount", 0);
855 QString sampleLayersMode = configGroup.readEntry("sampleLayersMode", "");
856 if (sampleLayersMode.isEmpty()) {
857 if (configGroup.readEntry("sampleMerged", false)) {
858 sampleLayersMode = "allLayers";
859 } else {
860 sampleLayersMode = "currentLayer";
861 }
862 }
863 QList<int> colorLabels;
864 {
865 const QStringList colorLabelsStr = configGroup.readEntry<QString>("colorLabels", "").split(',', Qt::SkipEmptyParts);
866
867 for (const QString &colorLabelStr : colorLabelsStr) {
868 bool ok;
869 const int colorLabel = colorLabelStr.toInt(&ok);
870 if (ok) {
871 colorLabels << colorLabel;
872 }
873 }
874 }
875
876 KisPaintDeviceSP referencePaintDevice = nullptr;
877 if (sampleLayersMode == "allLayers") {
878 referencePaintDevice = image()->projection();
879 } else if (sampleLayersMode == "currentLayer") {
880 referencePaintDevice = d->viewManager->activeNode()->paintDevice();
881 } else if (sampleLayersMode == "colorLabeledLayers") {
882 referencePaintDevice = KisMergeLabeledLayersCommand::createRefPaintDevice(image(), "Fill Tool Reference Result Paint Device");
883 image()->addJob(
884 fillStrokeId,
887 referencePaintDevice,
888 colorLabels,
890 false,
893 )
894 );
895 }
896
897 QSharedPointer<KoColor> referenceColor(new KoColor);
898 if (sampleLayersMode == "colorLabeledLayers") {
899 // We need to obtain the reference color from the reference paint
900 // device, but it is produced in a stroke, so we must get the color
901 // after the device is ready. So we get it in the stroke
902 image()->addJob(
903 fillStrokeId,
906 [referenceColor, referencePaintDevice, imgCursorPos]() -> KUndo2Command*
907 {
908 *referenceColor = referencePaintDevice->pixel(imgCursorPos);
909 return 0;
910 }
911 )),
912 false,
915 )
916 );
917 } else {
918 // Here the reference device is already ready, so we obtain the
919 // reference color directly
920 *referenceColor = referencePaintDevice->pixel(imgCursorPos);
921 }
922
923 if (fillMode == "fillContiguousRegion") {
924 const KisFillPainter::RegionFillingMode regionFillingMode =
925 configGroup.readEntry("contiguousFillMode", "") == "boundaryFill"
928 KoColor regionFillingBoundaryColor;
929 if (regionFillingMode == KisFillPainter::RegionFillingMode_BoundaryFill) {
930 const QString xmlColor = configGroup.readEntry("contiguousFillBoundaryColor", QString());
931 QDomDocument doc;
932 if (doc.setContent(xmlColor)) {
933 QDomElement e = doc.documentElement().firstChild().toElement();
934 QString channelDepthID = doc.documentElement().attribute("channeldepth", Integer16BitsColorDepthID.id());
935 bool ok;
936 if (e.hasAttribute("space") || e.tagName().toLower() == "srgb") {
937 regionFillingBoundaryColor = KoColor::fromXML(e, channelDepthID, &ok);
938 } else if (doc.documentElement().hasAttribute("space") || doc.documentElement().tagName().toLower() == "srgb"){
939 regionFillingBoundaryColor = KoColor::fromXML(doc.documentElement(), channelDepthID, &ok);
940 }
941 }
942 }
943 const bool useSelectionAsBoundary = configGroup.readEntry("useSelectionAsBoundary", false);
944 const bool blendingOptionsAreNoOp = useCustomBlendingOptions
945 ? (qFuzzyCompare(customOpacity, OPACITY_OPAQUE_F) &&
946 customCompositeOp == COMPOSITE_OVER)
947 : (qFuzzyCompare(resources->opacity(), OPACITY_OPAQUE_F) &&
948 resources->compositeOpId() == COMPOSITE_OVER);
949 const bool useFastMode = !resources->activeSelection() &&
950 blendingOptionsAreNoOp &&
951 opacitySpread == 100 &&
952 useSelectionAsBoundary == false &&
953 !antiAlias && grow == 0 && feather == 0 &&
954 closeGap == 0 &&
955 sampleLayersMode == "currentLayer";
956
957 FillProcessingVisitor *visitor = new FillProcessingVisitor(referencePaintDevice,
958 selection(),
959 resources);
960 visitor->setSeedPoint(imgCursorPos);
961 visitor->setUseFastMode(useFastMode);
962 visitor->setUseSelectionAsBoundary(useSelectionAsBoundary);
963 visitor->setFeather(feather);
964 visitor->setSizeMod(grow);
965 visitor->setStopGrowingAtDarkestPixel(stopGrowingAtDarkestPixel);
966 visitor->setRegionFillingMode(regionFillingMode);
967 if (regionFillingMode == KisFillPainter::RegionFillingMode_BoundaryFill) {
968 visitor->setRegionFillingBoundaryColor(regionFillingBoundaryColor);
969 }
970 visitor->setFillThreshold(threshold);
971 visitor->setOpacitySpread(opacitySpread);
972 visitor->setCloseGap(closeGap);
973 visitor->setAntiAlias(antiAlias);
974 visitor->setUseCustomBlendingOptions(useCustomBlendingOptions);
975 if (useCustomBlendingOptions) {
976 visitor->setCustomOpacity(customOpacity);
977 visitor->setCustomCompositeOp(customCompositeOp);
978 }
979 visitor->setOutDirtyRect(dirtyRect);
980
981 image()->addJob(
982 fillStrokeId,
984 KUndo2CommandSP(new KisProcessingCommand(visitor, d->viewManager->activeNode())),
985 false,
988 )
989 );
990 } else {
991 KisSelectionSP fillMask = new KisSelection;
993 progressHelper(new KisProcessingVisitor::ProgressHelper(currentNode()));
994
995 {
996 KisSelectionSP selection = this->selection();
997 KisFillPainter painter;
998 QRect bounds = image()->bounds();
999 if (selection) {
1000 bounds = bounds.intersected(selection->projection()->selectedRect());
1001 }
1002
1003 painter.setFillThreshold(threshold);
1004 painter.setOpacitySpread(opacitySpread);
1005 painter.setAntiAlias(antiAlias);
1006 painter.setSizemod(grow);
1007 painter.setStopGrowingAtDarkestPixel(stopGrowingAtDarkestPixel);
1008 painter.setFeather(feather);
1009
1012 fillMask->pixelSelection(), referenceColor, referencePaintDevice,
1013 bounds, selection ? selection->projection() : nullptr, progressHelper
1014 );
1015
1016 for (KisStrokeJobData *job : jobs) {
1017 image()->addJob(fillStrokeId, job);
1018 }
1019 }
1020
1021 {
1022 FillProcessingVisitor *visitor = new FillProcessingVisitor(nullptr,
1023 fillMask,
1024 resources);
1025
1026 visitor->setSeedPoint(imgCursorPos);
1027 visitor->setSelectionOnly(true);
1028 visitor->setProgressHelper(progressHelper);
1029 visitor->setOutDirtyRect(dirtyRect);
1030
1031 image()->addJob(
1032 fillStrokeId,
1034 KUndo2CommandSP(new KisProcessingCommand(visitor, currentNode())),
1035 false,
1038 )
1039 );
1040 }
1041 }
1042 }
1043
1044 image()->addJob(
1045 fillStrokeId,
1047 KUndo2CommandSP(new KisUpdateCommand(d->viewManager->activeNode(), dirtyRect, image().data())),
1048 false,
1051 )
1052 );
1053
1054 image()->endStroke(fillStrokeId);
1055 }
1056}
1057
1058void KisView::dragMoveEvent(QDragMoveEvent *event)
1059{
1060 dbgUI << Q_FUNC_INFO
1061 << "Formats: " << event->mimeData()->formats()
1062 << "Urls: " << event->mimeData()->urls()
1063 << "Has images: " << event->mimeData()->hasImage();
1064
1065 if (shouldAcceptDrag(event)) {
1066 event->accept();
1067 } else {
1068 event->ignore();
1069 }
1070}
1071
1073{
1074 return d->document;
1075}
1076
1078{
1079 KisMainWindow *window = mainWindow();
1080 QMdiSubWindow *subWindow = d->subWindow;
1081 delete this;
1082 return window->newView(document, subWindow);
1083}
1084
1086{
1087 return d->viewManager->mainWindow();
1088}
1089
1090void KisView::setSubWindow(QMdiSubWindow *subWindow)
1091{
1092 d->subWindow = subWindow;
1093}
1094
1095QStatusBar * KisView::statusBar() const
1096{
1097 KisMainWindow *mw = mainWindow();
1098 return mw ? mw->statusBar() : 0;
1099}
1100
1101void KisView::slotSavingStatusMessage(const QString &text, int timeout, bool isAutoSaving)
1102{
1103 QStatusBar *sb = statusBar();
1104 if (sb) {
1105 sb->showMessage(text, timeout);
1106 }
1107
1108 KisConfig cfg(true);
1109
1110 if (!sb || sb->isHidden() ||
1111 (!isAutoSaving && cfg.forceShowSaveMessages()) ||
1112 (cfg.forceShowAutosaveMessages() && isAutoSaving)) {
1113
1114 viewManager()->showFloatingMessage(text, QIcon());
1115 }
1116}
1117
1119{
1120 QStatusBar *sb = statusBar();
1121 if (sb) {
1122 sb->clearMessage();
1123 }
1124}
1125
1127{
1128 UnitActionGroup* unitActions = new UnitActionGroup(d->document, addPixelUnit, this);
1129 return unitActions->actions();
1130}
1131
1132void KisView::closeEvent(QCloseEvent *event)
1133{
1134 // Check whether we're the last view
1135 int viewCount = KisPart::instance()->viewCount(document());
1136 if (viewCount > 1) {
1137 // there are others still, so don't bother the user
1138 event->accept();
1139 return;
1140 }
1141
1142 if (queryClose()) {
1143 event->accept();
1144 return;
1145 }
1146
1147 event->ignore();
1148
1149}
1150
1152{
1153 if (!document())
1154 return true;
1155
1156 document()->waitForSavingToComplete();
1157
1158 if (document()->isModified()) {
1159 QString name;
1160 name = QFileInfo(document()->path()).fileName();
1161
1162 if (name.isEmpty())
1163 name = i18n("Untitled");
1164
1165 int res = QMessageBox::warning(this,
1166 i18nc("@title:window", "Krita"),
1167 i18n("<p>The document <b>'%1'</b> has been modified.</p><p>Do you want to save it?</p>", name),
1168 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes);
1169
1170 switch (res) {
1171 case QMessageBox::Yes : {
1172 bool isNative = (document()->mimeType() == document()->nativeFormatMimeType());
1173 if (!viewManager()->mainWindow()->saveDocument(document(), !isNative, false))
1174 return false;
1175 break;
1176 }
1177 case QMessageBox::No : {
1178 KisImageSP image = document()->image();
1181
1182 document()->removeAutoSaveFiles(document()->localFilePath(), document()->isRecovered());
1183 document()->setModified(false); // Now when queryClose() is called by closeEvent it won't do anything.
1184 break;
1185 }
1186 default : // case QMessageBox::Cancel :
1187 return false;
1188 }
1189 }
1190
1191 return true;
1192
1193}
1194
1196{
1197 d->canvas.slotScreenChanged(screen);
1198}
1199
1201{
1206 d->canvasController.updateScreenResolution(this);
1207
1208 if (d->canvas.resourceManager() && d->screenMigrationTracker.currentScreen()) {
1209 int penWidth = qRound(d->screenMigrationTracker.currentScreen()->devicePixelRatio());
1210 d->canvas.resourceManager()->setDecorationThickness(qMax(penWidth, 1));
1211 }
1212}
1213
1215{
1216 return d->screenMigrationTracker.currentScreen();
1217}
1218
1220{
1221 this->setPalette(pal);
1222 for (int i=0; i<this->children().size();i++) {
1223 QWidget *w = qobject_cast<QWidget*> ( this->children().at(i));
1224 if (w) {
1225 w->setPalette(pal);
1226 }
1227 }
1228 if (canvasBase()) {
1229 canvasBase()->canvasWidget()->setPalette(pal);
1230 }
1231 if (canvasController()) {
1232 canvasController()->setPalette(pal);
1233 }
1234}
1235
1237{
1238 QString title = d->document->caption();
1239
1240 if (!d->document->isReadWrite()) {
1241 title += " " + i18n("Write Protected");
1242 }
1243
1244 if (d->document->isRecovered()) {
1245 title += " " + i18n("Recovered");
1246 }
1247
1248 // show the file size for the document
1250
1251 if (fileSizeStats.imageSize) {
1252 title += QString(" (").append( KFormat().formatByteSize(qreal(fileSizeStats.imageSize))).append( ") ");
1253 }
1254
1255 title += "[*]";
1256
1257 this->setWindowTitle(title);
1258}
1259
1261{
1262 KisDocument *doc = document();
1263 if (doc) {
1264 doc->setPreActivatedNode(d->currentNode);
1265 }
1266}
1267
1269{
1270 config.setProperty("file", d->document->path());
1271 config.setProperty("window", mainWindow()->windowStateConfig().name());
1272
1273 if (d->subWindow) {
1274 config.setProperty("geometry", d->subWindow->saveGeometry().toBase64());
1275 }
1276
1277 const KoZoomState zoomState = d->canvasController.zoomState();
1278
1279 config.setProperty("zoomMode", zoomState.mode);
1280 config.setProperty("zoom", zoomState.zoom);
1281
1282 d->canvasController.saveCanvasState(config);
1283}
1284
1286{
1287 if (d->subWindow) {
1288 QByteArray geometry = QByteArray::fromBase64(config.getString("geometry", "").toLatin1());
1289 d->subWindow->restoreGeometry(QByteArray::fromBase64(geometry));
1290 }
1291
1292 qreal zoom = config.getFloat("zoom", 1.0f);
1293 int zoomMode = config.getInt("zoomMode", (int)KoZoomMode::ZOOM_PAGE);
1294 d->canvasController.setZoom((KoZoomMode::Mode)zoomMode, zoom);
1295 d->canvasController.restoreCanvasState(config);
1296}
1297
1299{
1300 d->currentNode = node;
1302
1304}
1305
1307{
1308 return d->currentNode;
1309}
1310
1312{
1313 KisNodeSP node;
1314 KisMaskSP mask = currentMask();
1315 if (mask) {
1316 node = mask->parent();
1317 }
1318 else {
1319 node = d->currentNode;
1320 }
1321 return qobject_cast<KisLayer*>(node.data());
1322}
1323
1325{
1326 return dynamic_cast<KisMask*>(d->currentNode.data());
1327}
1328
1330{
1331 KisLayerSP layer = currentLayer();
1332 if (layer)
1333 return layer->selection(); // falls through to the global
1334 // selection, or 0 in the end
1335 if (image()) {
1336 return image()->globalSelection();
1337 }
1338 return 0;
1339}
1340
1341void KisView::slotSoftProofing(bool softProofing)
1342{
1343 d->softProofing = softProofing;
1344 QString message;
1345 if (canvasBase()->image()->colorSpace()->colorDepthId().id().contains("F"))
1346 {
1347 message = i18n("Soft Proofing doesn't work in floating point.");
1348 viewManager()->showFloatingMessage(message,QIcon());
1349 return;
1350 }
1351 if (softProofing){
1352 message = i18n("Soft Proofing turned on.");
1353 } else {
1354 message = i18n("Soft Proofing turned off.");
1355 }
1356 viewManager()->showFloatingMessage(message,QIcon());
1358}
1359
1360void KisView::slotGamutCheck(bool gamutCheck)
1361{
1362 d->gamutCheck = gamutCheck;
1363 QString message;
1364 if (canvasBase()->image()->colorSpace()->colorDepthId().id().contains("F"))
1365 {
1366 message = i18n("Gamut Warnings don't work in floating point.");
1367 viewManager()->showFloatingMessage(message,QIcon());
1368 return;
1369 }
1370
1371 if (gamutCheck){
1372 message = i18n("Gamut Warnings turned on.");
1373 if (!d->softProofing){
1374 message += "\n "+i18n("But Soft Proofing is still off.");
1375 }
1376 } else {
1377 message = i18n("Gamut Warnings turned off.");
1378 }
1379 viewManager()->showFloatingMessage(message,QIcon());
1381}
1382
1384{
1385 return d->softProofing;
1386}
1387
1389{
1390 return d->gamutCheck;
1391}
1392
1394{
1395 if (!document()) return;
1396
1401
1402 if (image()->locked()) {
1403 // If this is the first view on the image, the image will have been locked
1404 // so unlock it.
1405 image()->blockSignals(false);
1406 image()->unlock();
1407 }
1408
1410
1411 connect(image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), this, SIGNAL(sigColorSpaceChanged(const KoColorSpace*)));
1412 connect(image(), SIGNAL(sigProfileChanged(const KoColorProfile*)), this, SIGNAL(sigProfileChanged(const KoColorProfile*)));
1413 connect(image(), SIGNAL(sigSizeChanged(QPointF,QPointF)), this, SIGNAL(sigSizeChanged(QPointF,QPointF)));
1414
1415 connect(&d->screenMigrationTracker, SIGNAL(sigScreenChanged(QScreen*)), this, SLOT(slotMigratedToScreen(QScreen*)));
1416 connect(&d->screenMigrationTracker, SIGNAL(sigScreenOrResolutionChanged(QScreen*)), this, SLOT(slotScreenOrResolutionChanged()));
1418}
1419
1421{
1422 d->canvasController.syncOnImageResolutionChange();
1423 d->zoomManager.syncOnImageResolutionChange();
1425}
1426
1427void KisView::slotImageSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint)
1428{
1429 d->canvasController.syncOnImageSizeChange(oldStillPoint, newStillPoint);
1431}
1432
1434{
1435 d->subWindow->close();
1436}
1437
1438bool KisView::shouldAcceptDrag(const QDropEvent *event) const
1439{
1440 const QMimeData *data = event->mimeData();
1441 if (data->hasFormat(QStringLiteral("application/x-krita-node-internal-pointer"))) {
1442 // Don't allow dragging layers onto their own canvas, that really only
1443 // gets triggered accidentally if you're a bit sloppy about selecting
1444 // or reordering layers and then you're left confused about the layer
1445 // duplicates that seem to show up at random. The user can override
1446 // this by explicitly holding down Ctrl if necessary. We always accept
1447 // the enter event so that this works properly, otherwise we don't get
1448 // any further drag events unless Ctrl was held to begin with.
1449 return event->type() == QEvent::DragEnter
1450 || event->keyboardModifiers().testFlag(Qt::ControlModifier)
1452 } else {
1453 return data->hasImage()
1454 || data->hasUrls()
1455 || data->hasFormat("krita/x-colorsetentry")
1456 || data->hasColor();
1457 }
1458}
KisMagneticGraph::vertex_descriptor source(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const qreal OPACITY_OPAQUE_F
const quint8 OPACITY_OPAQUE_U8
const QString COMPOSITE_OVER
void setOutDirtyRect(QSharedPointer< QRect > outDirtyRect)
void setStopGrowingAtDarkestPixel(bool stopGrowingAtDarkestPixel)
void setUseFastMode(bool useFastMode)
void setUseCustomBlendingOptions(bool useCustomBlendingOptions)
void setSeedPoint(const QPoint &seedPoint)
void setCustomCompositeOp(const QString &customCompositeOp)
void setProgressHelper(QSharedPointer< ProgressHelper > progressHelper)
void setOpacitySpread(int opacitySpread)
void setAntiAlias(bool antiAlias)
void setSelectionOnly(bool selectionOnly)
void setFillThreshold(int fillThreshold)
void setRegionFillingBoundaryColor(const KoColor &regionFillingBoundaryColor)
void setCustomOpacity(qreal customOpacity)
void setRegionFillingMode(KisFillPainter::RegionFillingMode regionFillingMode)
void setUseSelectionAsBoundary(bool useSelectionAsBoundary)
KisReferenceImagesDecorationSP referenceImagesDecoration() const
void slotScreenChanged(QScreen *screen)
void slotGamutCheck()
bool xAxisMirrored() const
Bools indicating canvasmirroring.
KisCoordinatesConverter * coordinatesConverter
void initializeImage()
void addDecoration(KisCanvasDecorationSP deco)
KisAbstractCanvasWidget * canvasWidget
void disconnectImage()
void slotSoftProofing()
bool yAxisMirrored() const
void slotTrySwitchShapeManager()
Action dropAs(const QMimeData &data, QPoint pos)
KisPaintDeviceSP clipFromBoardContentsWithData(QImage image, const QList< QUrl > urls, const QRect &imageBounds, bool showPopup, int overridePasteBehaviour=-1, bool useClipboardFallback=false, QPair< bool, PasteFormatBehaviour > source={false, PasteFormatBehaviour::PASTE_FORMAT_ASK}) const
QPair< bool, PasteFormatBehaviour > askUserForSourceWithData(QImage qimage, const QList< QUrl > urls, bool useClipboardFallback=false) const
static KisClipboard * instance()
QImage getImageWithFallback(const QMimeData *cbData, bool useClipboardFallback=false) const
bool forceShowSaveMessages(bool defaultValue=true) const
bool showCanvasMessages(bool defaultValue=false) const
bool forceShowAutosaveMessages(bool defaultValue=true) const
_Private::Traits< T >::Result widgetToImage(const T &obj) const
_Private::Traits< T >::Result imageToDocument(const T &obj) const
void setPreActivatedNode(KisNodeSP activatedNode)
The KisFileLayer class loads a particular file as a layer into the layer stack.
void setSizemod(int sizemod)
void setFillThreshold(int threshold)
void setFeather(int feather)
QVector< KisStrokeJobData * > createSimilarColorsSelectionJobs(KisPixelSelectionSP outSelection, const QSharedPointer< KoColor > referenceColor, KisPaintDeviceSP referenceDevice, const QRect &rect, KisPixelSelectionSP mask, QSharedPointer< KisProcessingVisitor::ProgressHelper > progressHelper=nullptr)
void setAntiAlias(bool antiAlias)
void setStopGrowingAtDarkestPixel(bool stopGrowingAtDarkestPixel)
void setOpacitySpread(int opacitySpread)
The KisFloatingMessage class shows the given message in a semi-transparent bubble that doesn't take f...
qint32 importImage(const QUrl &url, const QString &layerType="KisPaintLayer")
KisGroupLayerSP rootLayer() const
void unlock()
Definition kis_image.cc:805
void requestStrokeCancellation()
KisSelectionSP globalSelection() const
Definition kis_image.cc:695
QRect bounds() const override
void sigNodeAddedAsync(KisNodeSP node, KisNodeAdditionFlags flags)
static void adaptClipToImageColorSpace(KisPaintDeviceSP dev, KisImageSP image)
static QStringList supportedMimeTypes(Direction direction)
Central object to manage canvas input.
void detachPriorityEventFilter(QObject *filter)
detachPriorityEventFilter
void attachPriorityEventFilter(QObject *filter, int priority=0)
attachPriorityEventFilter
A container for a set of QAction objects.
Main window for Krita.
KisView * newView(QObject *document, QMdiSubWindow *subWindow=0)
bool openDocument(const QString &path, OpenFlags flags)
bool saveDocument(KisDocument *document, bool saveas, bool isExporting, bool isAdvancedExporting=false)
KisViewManager * viewManager
static KisPaintDeviceSP createRefPaintDevice(KisImageSP originalImage, QString name="Merge Labeled Layers Reference Paint Device")
@ GroupSelectionPolicy_SelectIfColorLabeled
Groups will be taken into account only if they have set an explicit color label. This ignores groups ...
static KisNodeList loadNodesFastAndRecenter(const QPoint &preferredCenter, const QMimeData *data, KisImageSP image, KisShapeController *shapeController, bool &copyNode)
static KisNodeList loadNodesFast(const QMimeData *data, KisImageSP image, KisShapeController *shapeController, bool &copyNode)
static bool isNodeMimeDataFromSameImage(const QMimeData *data, KisImageSP image)
static QString mimeTypeForFile(const QString &file, bool checkExistingFiles=true)
Find the mimetype for the given filename. The filename must include a suffix.
void addNode(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis, KisImageLayerAddCommand::Flags flags=KisImageLayerAddCommand::DoRedoUpdates|KisImageLayerAddCommand::DoUndoUpdates)
bool pixel(qint32 x, qint32 y, QColor *c) const
void moveTo(qint32 x, qint32 y)
static KisPart * instance()
Definition KisPart.cpp:131
void removeView(KisView *view)
Definition KisPart.cpp:320
int viewCount(KisDocument *doc) const
Definition KisPart.cpp:356
static KisReferenceImage * fromFile(const QString &filename, const KisCoordinatesConverter &converter, QWidget *parent)
static KisReferenceImage * fromPaintDevice(KisPaintDeviceSP src, const KisCoordinatesConverter &converter, QWidget *parent)
The KisReferenceImagesDecoration class draws the reference images on the canvas. The document stores ...
void addReferenceImage(KisReferenceImage *referenceImage)
The KisRemoteFileFetcher class can fetch a remote file and blocks until the file is downloaded.
bool fetchFile(const QUrl &remote, QIODevice *io)
fetch the image. Shows a progress dialog
The KisResourcesSnapshot class takes a snapshot of the various resources like colors and settings use...
void setFGColorOverride(const KoColor &color)
KisSelectionSP activeSelection() const
void setInitialShapeForCanvas(KisCanvas2 *canvas)
KoColor color() const
Definition KisSwatch.h:30
static KisSwatch fromByteArray(QByteArray &data, QString &groupName, int &originalRow, int &originalColumn)
Definition KisSwatch.cpp:57
KisMainWindow * mainWindow() const
KisImageManager * imageManager()
KisLayerSP activeLayer()
Convenience method to get at the active layer.
void blockUntilOperationsFinishedForced(KisImageSP image)
blockUntilOperationsFinished blocks the GUI of the application until execution of actions on image is...
KisSelectionManager * selectionManager()
KisImageWSP image() const
Return the image this view is displaying.
void showFloatingMessage(const QString &message, const QIcon &icon, int timeout=4500, KisFloatingMessage::Priority priority=KisFloatingMessage::Medium, int alignment=Qt::AlignCenter|Qt::TextWordWrap)
shows a floating message in the top right corner of the canvas
bool operator==(const StatusBarItem &rhs)
Definition KisView.cpp:160
StatusBarItem(QWidget *widget, int stretch, bool permanent)
Definition KisView.cpp:153
void ensureItemHidden(QStatusBar *sb)
Definition KisView.cpp:182
void ensureItemShown(QStatusBar *sb)
Definition KisView.cpp:168
QWidget * widget() const
Definition KisView.cpp:164
~KisView() override
Definition KisView.cpp:257
QScreen * currentScreen() const
Definition KisView.cpp:1214
KisView(KisDocument *document, KisViewManager *viewManager, QWidget *parent=0)
Definition KisView.cpp:202
KisCanvas2 * canvasBase() const
Definition KisView.cpp:427
void slotGamutCheck(bool gamutCheck)
slotGamutCheck set whether or not we're gamutchecking in this view. Will be setting the same in the v...
Definition KisView.cpp:1360
Private(KisView *_q, KisDocument *document, KisViewManager *viewManager)
Definition KisView.cpp:105
bool canvasIsMirrored() const
Definition KisView.cpp:332
void slotThemeChanged(QPalette pal)
Definition KisView.cpp:1219
static bool s_firstView
Definition KisView.h:266
QString newObjectName()
Definition KisView.cpp:93
void dropEvent(QDropEvent *event) override
Definition KisView.cpp:461
KisMainWindow * mainWindow() const
Definition KisView.cpp:1085
void syncLastActiveNodeToDocument()
Definition KisView.cpp:1260
void notifyCurrentStateChanged(bool isCurrent)
Definition KisView.cpp:282
bool gamutCheck
Definition KisView.cpp:140
void restoreViewState(const KisPropertiesConfiguration &config)
Definition KisView.cpp:1285
void slotClearStatusText()
Definition KisView.cpp:1118
void closeView()
Definition KisView.cpp:1433
KisInputManager * globalInputManager() const
Definition KisView.cpp:422
bool showFloatingMessage
Definition KisView.cpp:134
QList< QAction * > createChangeUnitActions(bool addPixelUnit=false)
create a list of actions that when activated will change the unit on the document.
Definition KisView.cpp:1126
KisCanvasController canvasController
Definition KisView.cpp:126
Private *const d
Definition KisView.h:264
QMdiSubWindow * subWindow
Definition KisView.cpp:137
void slotScreenOrResolutionChanged()
Definition KisView.cpp:1200
bool softProofing
Definition KisView.cpp:139
KisCoordinatesConverter viewConverter
Definition KisView.cpp:125
void setSubWindow(QMdiSubWindow *subWindow)
Definition KisView.cpp:1090
void sigColorSpaceChanged(const KoColorSpace *cs)
QStatusBar * statusBar() const
Definition KisView.cpp:1095
void dragMoveEvent(QDragMoveEvent *event) override
Definition KisView.cpp:1058
KisMaskSP currentMask() const
Definition KisView.cpp:1324
KisScreenMigrationTracker screenMigrationTracker
Definition KisView.cpp:145
void dragEnterEvent(QDragEnterEvent *event) override
Definition KisView.cpp:446
KisReferenceImagesDecorationSP referenceImagesDecoration
Definition KisView.cpp:132
KisViewManager * viewManager
Definition KisView.cpp:129
KisSignalCompressor floatingMessageCompressor
Definition KisView.cpp:136
KisImageWSP image() const
Definition KisView.cpp:432
void setShowFloatingMessage(bool show)
Definition KisView.cpp:309
void slotContinueRemoveNode(KisNodeSP newActiveNode)
Definition KisView.cpp:397
void slotSavingStatusMessage(const QString &text, int timeout, bool isAutoSaving=false)
Definition KisView.cpp:1101
KisView * replaceBy(KisDocument *document)
Definition KisView.cpp:1077
KisCanvasResourceProvider * resourceProvider() const
Definition KisView.cpp:414
void slotContinueAddNode(KisNodeSP newActiveNode, KisNodeAdditionFlags flags)
Definition KisView.cpp:372
void slotMigratedToScreen(QScreen *screen)
Definition KisView.cpp:1195
void closeEvent(QCloseEvent *event) override
Definition KisView.cpp:1132
QPointer< KisDocument > document
Definition KisView.cpp:121
void slotLoadingFinished()
Definition KisView.cpp:1393
void slotImageNodeRemoved(KisNodeSP node)
Definition KisView.cpp:392
void setViewManager(KisViewManager *view)
Definition KisView.cpp:337
bool shouldAcceptDrag(const QDropEvent *event) const
Definition KisView.cpp:1438
void saveViewState(KisPropertiesConfiguration &config) const
Definition KisView.cpp:1268
void slotUpdateDocumentTitle()
Definition KisView.cpp:1236
bool queryClose()
Definition KisView.cpp:1151
void slotSoftProofing(bool softProofing)
slotSoftProofing set whether or not we're softproofing in this view. Will be setting the same in the ...
Definition KisView.cpp:1341
KisNodeSP currentNode
Definition KisView.cpp:130
void slotImageResolutionChanged()
Definition KisView.cpp:1420
KisSelectionSP selection()
Definition KisView.cpp:1329
KisSynchronizedConnection< KisNodeSP > removeNodeConnection
Definition KisView.cpp:143
void slotImageSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint)
Definition KisView.cpp:1427
KisLayerSP currentLayer() const
Definition KisView.cpp:1311
void setCurrentNode(KisNodeSP node)
Definition KisView.cpp:1298
KisPaintingAssistantsDecorationSP paintingAssistantsDecoration
Definition KisView.cpp:131
QPointer< KisFloatingMessage > savedFloatingMessage
Definition KisView.cpp:135
KisSynchronizedConnection< KisNodeSP, KisNodeAdditionFlags > addNodeConnection
Definition KisView.cpp:142
bool isCurrent
Definition KisView.cpp:133
KisZoomManager zoomManager
Definition KisView.cpp:128
void sigProfileChanged(const KoColorProfile *profile)
KisCanvas2 canvas
Definition KisView.cpp:127
void sigSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint)
void updateImageBoundsSnapping()
QPointer< KoCanvasResourceProvider > resourceManager
static KoColor fromXML(const QDomElement &elt, const QString &channelDepthId)
Definition KoColor.cpp:350
static const KoCompositeOpRegistry & instance()
KoID getKoID(const QString &compositeOpID) const
QString id() const
Definition KoID.cpp:63
void switchToolRequested(const QString &id)
void removeCanvasController(KoCanvasController *controller)
void addController(KoCanvasController *controller)
static KoToolManager * instance()
Return the toolmanager singleton.
@ ZOOM_PAGE
zoom page
Definition KoZoomMode.h:25
KoZoomMode::Mode mode
Definition KoZoomState.h:24
static bool qFuzzyCompare(half p1, half p2)
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define bounds(x, a, b)
#define dbgUI
Definition kis_debug.h:52
#define warnUI
Definition kis_debug.h:94
QSharedPointer< KUndo2Command > KUndo2CommandSP
Definition kis_types.h:262
KUndo2MagicString kundo2_i18n(const char *text)
QList< KoSubpath * > split(const KoPathShape &path)
QIcon loadIcon(const QString &name)
KisNodeSP nearestNodeAfterRemoval(KisNodeSP node)
The LambdaCommand struct is a shorthand for creation of AggregateCommand commands using C++ lambda fe...
virtual KisSelectionSP selection() const
Definition kis_layer.cc:509
Statistics fetchMemoryStatistics(KisImageSP image) const
static KisMemoryStatisticsServer * instance()
KisNodeWSP parent
Definition kis_node.cpp:86
QString getString(const QString &name, const QString &def=QString()) const
virtual void setProperty(const QString &name, const QVariant &value)
int getInt(const QString &name, int def=0) const
float getFloat(const QString &name, float def=0.0) const
KisPixelSelectionSP projection() const
KisPixelSelectionSP pixelSelection
KisCanvas2 * canvas