diff --git a/libs/ui/KisViewManager.cpp b/libs/ui/KisViewManager.cpp index 612646e18e..5767e4654d 100644 --- a/libs/ui/KisViewManager.cpp +++ b/libs/ui/KisViewManager.cpp @@ -1,1298 +1,1298 @@ /* * This file is part of KimageShop^WKrayon^WKrita * * Copyright (c) 1999 Matthias Elter * 1999 Michael Koch * 1999 Carsten Pfeiffer * 2002 Patrick Julien * 2003-2011 Boudewijn Rempt * 2004 Clarence Dang * 2011 José Luis Vergara * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "KisViewManager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "input/kis_input_manager.h" #include "canvas/kis_canvas2.h" #include "canvas/kis_canvas_controller.h" #include "canvas/kis_grid_manager.h" #include "dialogs/kis_dlg_blacklist_cleanup.h" #include "input/kis_input_profile_manager.h" #include "kis_action_manager.h" #include "kis_action.h" #include "kis_canvas_controls_manager.h" #include "kis_canvas_resource_provider.h" #include "kis_composite_progress_proxy.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_control_frame.h" #include "kis_coordinates_converter.h" #include "KisDocument.h" #include "kis_favorite_resource_manager.h" #include "kis_filter_manager.h" #include "kis_group_layer.h" #include #include "kis_image_manager.h" #include #include "kis_mainwindow_observer.h" #include "kis_mask_manager.h" #include "kis_mimedata.h" #include "kis_mirror_manager.h" #include "kis_node_commands_adapter.h" #include "kis_node.h" #include "kis_node_manager.h" #include "kis_painting_assistants_manager.h" #include #include "kis_paintop_box.h" #include #include "KisPart.h" #include "KisPrintJob.h" #include "kis_progress_widget.h" #include "kis_resource_server_provider.h" #include "kis_selection.h" #include "kis_selection_manager.h" #include "kis_shape_controller.h" #include "kis_shape_layer.h" #include #include "kis_statusbar.h" #include #include #include "kis_tooltip_manager.h" #include #include "KisView.h" #include "kis_zoom_manager.h" #include "widgets/kis_floating_message.h" #include "kis_signal_auto_connection.h" #include "kis_icon_utils.h" #include "kis_guides_manager.h" #include "kis_derived_resources.h" #include "dialogs/kis_delayed_save_dialog.h" class BlockingUserInputEventFilter : public QObject { bool eventFilter(QObject *watched, QEvent *event) override { Q_UNUSED(watched); if(dynamic_cast(event) || dynamic_cast(event) || dynamic_cast(event)) { return true; } else { return false; } } }; class KisViewManager::KisViewManagerPrivate { public: KisViewManagerPrivate(KisViewManager *_q, KActionCollection *_actionCollection, QWidget *_q_parent) : filterManager(_q) , createTemplate(0) , saveIncremental(0) , saveIncrementalBackup(0) , openResourcesDirectory(0) , rotateCanvasRight(0) , rotateCanvasLeft(0) , resetCanvasRotation(0) , wrapAroundAction(0) , levelOfDetailAction(0) , showRulersAction(0) , rulersTrackMouseAction(0) , zoomTo100pct(0) , zoomIn(0) , zoomOut(0) , selectionManager(_q) , statusBar(_q) , controlFrame(_q, _q_parent) , nodeManager(_q) , imageManager(_q) , gridManager(_q) , canvasControlsManager(_q) , paintingAssistantsManager(_q) , actionManager(_q, _actionCollection) , mainWindow(0) , showFloatingMessage(true) , currentImageView(0) , canvasResourceProvider(_q) , canvasResourceManager() , guiUpdateCompressor(30, KisSignalCompressor::POSTPONE, _q) , actionCollection(_actionCollection) , mirrorManager(_q) , inputManager(_q) , actionAuthor(0) { canvasResourceManager.addDerivedResourceConverter(toQShared(new KisCompositeOpResourceConverter)); canvasResourceManager.addDerivedResourceConverter(toQShared(new KisEffectiveCompositeOpResourceConverter)); canvasResourceManager.addDerivedResourceConverter(toQShared(new KisOpacityResourceConverter)); canvasResourceManager.addDerivedResourceConverter(toQShared(new KisFlowResourceConverter)); canvasResourceManager.addDerivedResourceConverter(toQShared(new KisSizeResourceConverter)); canvasResourceManager.addDerivedResourceConverter(toQShared(new KisLodAvailabilityResourceConverter)); canvasResourceManager.addDerivedResourceConverter(toQShared(new KisEraserModeResourceConverter)); canvasResourceManager.addResourceUpdateMediator(toQShared(new KisPresetUpdateMediator)); } public: KisFilterManager filterManager; KisAction *createTemplate; KisAction *createCopy; KisAction *saveIncremental; KisAction *saveIncrementalBackup; KisAction *openResourcesDirectory; KisAction *rotateCanvasRight; KisAction *rotateCanvasLeft; KisAction *resetCanvasRotation; KisAction *wrapAroundAction; KisAction *levelOfDetailAction; KisAction *showRulersAction; KisAction *rulersTrackMouseAction; KisAction *zoomTo100pct; KisAction *zoomIn; KisAction *zoomOut; KisAction *softProof; KisAction *gamutCheck; KisSelectionManager selectionManager; KisGuidesManager guidesManager; KisStatusBar statusBar; KisControlFrame controlFrame; KisNodeManager nodeManager; KisImageManager imageManager; KisGridManager gridManager; KisCanvasControlsManager canvasControlsManager; KisPaintingAssistantsManager paintingAssistantsManager; BlockingUserInputEventFilter blockingEventFilter; KisActionManager actionManager; QMainWindow* mainWindow; QPointer savedFloatingMessage; bool showFloatingMessage; QPointer currentImageView; KisCanvasResourceProvider canvasResourceProvider; KoCanvasResourceManager canvasResourceManager; KisSignalCompressor guiUpdateCompressor; KActionCollection *actionCollection; KisMirrorManager mirrorManager; KisInputManager inputManager; KisSignalAutoConnectionsStore viewConnections; KSelectAction *actionAuthor; // Select action for author profile. QByteArray canvasState; - bool blockUntillOperationsFinishedImpl(KisImageSP image, bool force); + bool blockUntilOperationsFinishedImpl(KisImageSP image, bool force); }; KisViewManager::KisViewManager(QWidget *parent, KActionCollection *_actionCollection) : d(new KisViewManagerPrivate(this, _actionCollection, parent)) { d->actionCollection = _actionCollection; d->mainWindow = dynamic_cast(parent); d->canvasResourceProvider.setResourceManager(&d->canvasResourceManager); connect(&d->guiUpdateCompressor, SIGNAL(timeout()), this, SLOT(guiUpdateTimeout())); createActions(); setupManagers(); // These initialization functions must wait until KisViewManager ctor is complete. d->statusBar.setup(); d->controlFrame.setup(parent); //Check to draw scrollbars after "Canvas only mode" toggle is created. this->showHideScrollbars(); QScopedPointer dummy(new KoDummyCanvasController(actionCollection())); KoToolManager::instance()->registerToolActions(actionCollection(), dummy.data()); QTimer::singleShot(0, this, SLOT(initializeStatusBarVisibility())); connect(KoToolManager::instance(), SIGNAL(inputDeviceChanged(KoInputDevice)), d->controlFrame.paintopBox(), SLOT(slotInputDeviceChanged(KoInputDevice))); connect(KoToolManager::instance(), SIGNAL(changedTool(KoCanvasController*,int)), d->controlFrame.paintopBox(), SLOT(slotToolChanged(KoCanvasController*,int))); connect(&d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), resourceProvider(), SLOT(slotNodeActivated(KisNodeSP))); connect(resourceProvider()->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), d->controlFrame.paintopBox(), SLOT(slotCanvasResourceChanged(int,QVariant))); connect(KisPart::instance(), SIGNAL(sigViewAdded(KisView*)), SLOT(slotViewAdded(KisView*))); connect(KisPart::instance(), SIGNAL(sigViewRemoved(KisView*)), SLOT(slotViewRemoved(KisView*))); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(slotUpdateAuthorProfileActions())); KisInputProfileManager::instance()->loadProfiles(); KisConfig cfg; d->showFloatingMessage = cfg.showCanvasMessages(); } KisViewManager::~KisViewManager() { KisConfig cfg; if (resourceProvider() && resourceProvider()->currentPreset()) { cfg.writeEntry("LastPreset", resourceProvider()->currentPreset()->name()); cfg.writeKoColor("LastForeGroundColor",resourceProvider()->fgColor()); cfg.writeKoColor("LastBackGroundColor",resourceProvider()->bgColor()); } cfg.writeEntry("baseLength", KoResourceItemChooserSync::instance()->baseLength()); delete d; } KActionCollection *KisViewManager::actionCollection() const { return d->actionCollection; } void KisViewManager::slotViewAdded(KisView *view) { d->inputManager.addTrackedCanvas(view->canvasBase()); if (viewCount() == 0) { d->statusBar.showAllStatusBarItems(); } } void KisViewManager::slotViewRemoved(KisView *view) { d->inputManager.removeTrackedCanvas(view->canvasBase()); if (viewCount() == 0) { d->statusBar.hideAllStatusBarItems(); } } void KisViewManager::setCurrentView(KisView *view) { bool first = true; if (d->currentImageView) { d->currentImageView->notifyCurrentStateChanged(false); d->currentImageView->canvasBase()->setCursor(QCursor(Qt::ArrowCursor)); first = false; KisDocument* doc = d->currentImageView->document(); if (doc) { doc->disconnect(this); } d->currentImageView->canvasController()->proxyObject->disconnect(&d->statusBar); d->viewConnections.clear(); } d->softProof->setChecked(view->softProofing()); d->gamutCheck->setChecked(view->gamutCheck()); QPointerimageView = qobject_cast(view); if (imageView) { // Wait for the async image to have loaded KisDocument* doc = view->document(); // connect(canvasController()->proxyObject, SIGNAL(documentMousePositionChanged(QPointF)), d->statusBar, SLOT(documentMousePositionChanged(QPointF))); d->currentImageView = imageView; // Restore the last used brush preset, color and background color. if (first) { KisConfig cfg; KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); QString lastPreset = cfg.readEntry("LastPreset", QString("Basic_tip_default")); KisPaintOpPresetSP preset = rserver->resourceByName(lastPreset); if (!preset) { preset = rserver->resourceByName("Basic_tip_default"); } if (!preset) { preset = rserver->resources().first(); } if (preset) { paintOpBox()->restoreResource(preset.data()); } const KoColorSpace *cs = KoColorSpaceRegistry::instance()->rgb8(); KoColor foreground(Qt::black, cs); d->canvasResourceProvider.setFGColor(cfg.readKoColor("LastForeGroundColor",foreground)); KoColor background(Qt::white, cs); d->canvasResourceProvider.setBGColor(cfg.readKoColor("LastBackGroundColor",background)); } KisCanvasController *canvasController = dynamic_cast(d->currentImageView->canvasController()); d->viewConnections.addUniqueConnection(&d->nodeManager, SIGNAL(sigNodeActivated(KisNodeSP)), doc->image(), SLOT(requestStrokeEndActiveNode())); d->viewConnections.addUniqueConnection(d->rotateCanvasRight, SIGNAL(triggered()), canvasController, SLOT(rotateCanvasRight15())); d->viewConnections.addUniqueConnection(d->rotateCanvasLeft, SIGNAL(triggered()),canvasController, SLOT(rotateCanvasLeft15())); d->viewConnections.addUniqueConnection(d->resetCanvasRotation, SIGNAL(triggered()),canvasController, SLOT(resetCanvasRotation())); d->viewConnections.addUniqueConnection(d->wrapAroundAction, SIGNAL(toggled(bool)), canvasController, SLOT(slotToggleWrapAroundMode(bool))); d->wrapAroundAction->setChecked(canvasController->wrapAroundMode()); d->viewConnections.addUniqueConnection(d->levelOfDetailAction, SIGNAL(toggled(bool)), canvasController, SLOT(slotToggleLevelOfDetailMode(bool))); d->levelOfDetailAction->setChecked(canvasController->levelOfDetailMode()); d->viewConnections.addUniqueConnection(d->currentImageView->image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), d->controlFrame.paintopBox(), SLOT(slotColorSpaceChanged(const KoColorSpace*))); d->viewConnections.addUniqueConnection(d->showRulersAction, SIGNAL(toggled(bool)), imageView->zoomManager(), SLOT(setShowRulers(bool))); d->viewConnections.addUniqueConnection(d->rulersTrackMouseAction, SIGNAL(toggled(bool)), imageView->zoomManager(), SLOT(setRulersTrackMouse(bool))); d->viewConnections.addUniqueConnection(d->zoomTo100pct, SIGNAL(triggered()), imageView->zoomManager(), SLOT(zoomTo100())); d->viewConnections.addUniqueConnection(d->zoomIn, SIGNAL(triggered()), imageView->zoomController()->zoomAction(), SLOT(zoomIn())); d->viewConnections.addUniqueConnection(d->zoomOut, SIGNAL(triggered()), imageView->zoomController()->zoomAction(), SLOT(zoomOut())); d->viewConnections.addUniqueConnection(d->softProof, SIGNAL(toggled(bool)), view, SLOT(slotSoftProofing(bool)) ); d->viewConnections.addUniqueConnection(d->gamutCheck, SIGNAL(toggled(bool)), view, SLOT(slotGamutCheck(bool)) ); imageView->zoomManager()->setShowRulers(d->showRulersAction->isChecked()); imageView->zoomManager()->setRulersTrackMouse(d->rulersTrackMouseAction->isChecked()); showHideScrollbars(); } d->filterManager.setView(imageView); d->selectionManager.setView(imageView); d->guidesManager.setView(imageView); d->nodeManager.setView(imageView); d->imageManager.setView(imageView); d->canvasControlsManager.setView(imageView); d->actionManager.setView(imageView); d->gridManager.setView(imageView); d->statusBar.setView(imageView); d->paintingAssistantsManager.setView(imageView); d->mirrorManager.setView(imageView); if (d->currentImageView) { d->currentImageView->notifyCurrentStateChanged(true); d->currentImageView->canvasController()->activate(); d->currentImageView->canvasController()->setFocus(); } d->actionManager.updateGUI(); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigSizeChanged(const QPointF&, const QPointF&)), resourceProvider(), SLOT(slotImageSizeChanged())); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigResolutionChanged(double,double)), resourceProvider(), SLOT(slotOnScreenResolutionChanged())); d->viewConnections.addUniqueConnection( image(), SIGNAL(sigNodeChanged(KisNodeSP)), this, SLOT(updateGUI())); d->viewConnections.addUniqueConnection( view->zoomManager()->zoomController(), SIGNAL(zoomChanged(KoZoomMode::Mode,qreal)), resourceProvider(), SLOT(slotOnScreenResolutionChanged())); resourceProvider()->slotImageSizeChanged(); resourceProvider()->slotOnScreenResolutionChanged(); Q_EMIT viewChanged(); } KoZoomController *KisViewManager::zoomController() const { if (d->currentImageView) { return d->currentImageView->zoomController(); } return 0; } KisImageWSP KisViewManager::image() const { if (document()) { return document()->image(); } return 0; } KisCanvasResourceProvider * KisViewManager::resourceProvider() { return &d->canvasResourceProvider; } KisCanvas2 * KisViewManager::canvasBase() const { if (d && d->currentImageView) { return d->currentImageView->canvasBase(); } return 0; } QWidget* KisViewManager::canvas() const { if (d && d->currentImageView && d->currentImageView->canvasBase()->canvasWidget()) { return d->currentImageView->canvasBase()->canvasWidget(); } return 0; } KisStatusBar * KisViewManager::statusBar() const { return &d->statusBar; } void KisViewManager::addStatusBarItem(QWidget *widget, int stretch, bool permanent) { d->statusBar.addStatusBarItem(widget, stretch, permanent); } void KisViewManager::removeStatusBarItem(QWidget *widget) { d->statusBar.removeStatusBarItem(widget); } KisPaintopBox* KisViewManager::paintOpBox() const { return d->controlFrame.paintopBox(); } KoProgressUpdater* KisViewManager::createProgressUpdater(KoProgressUpdater::Mode mode) { return new KisProgressUpdater(d->statusBar.progress(), document()->progressProxy(), mode); } KisSelectionManager * KisViewManager::selectionManager() { return &d->selectionManager; } KisNodeSP KisViewManager::activeNode() { return d->nodeManager.activeNode(); } KisLayerSP KisViewManager::activeLayer() { return d->nodeManager.activeLayer(); } KisPaintDeviceSP KisViewManager::activeDevice() { return d->nodeManager.activePaintDevice(); } KisZoomManager * KisViewManager::zoomManager() { if (d->currentImageView) { return d->currentImageView->zoomManager(); } return 0; } KisFilterManager * KisViewManager::filterManager() { return &d->filterManager; } KisImageManager * KisViewManager::imageManager() { return &d->imageManager; } KisInputManager* KisViewManager::inputManager() const { return &d->inputManager; } KisSelectionSP KisViewManager::selection() { if (d->currentImageView) { return d->currentImageView->selection(); } return 0; } bool KisViewManager::selectionEditable() { KisLayerSP layer = activeLayer(); if (layer) { KoProperties properties; QList masks = layer->childNodes(QStringList("KisSelectionMask"), properties); if (masks.size() == 1) { return masks[0]->isEditable(); } } // global selection is always editable return true; } KisUndoAdapter * KisViewManager::undoAdapter() { if (!document()) return 0; KisImageWSP image = document()->image(); Q_ASSERT(image); return image->undoAdapter(); } void KisViewManager::createActions() { KisConfig cfg; d->saveIncremental = actionManager()->createAction("save_incremental_version"); connect(d->saveIncremental, SIGNAL(triggered()), this, SLOT(slotSaveIncremental())); d->saveIncrementalBackup = actionManager()->createAction("save_incremental_backup"); connect(d->saveIncrementalBackup, SIGNAL(triggered()), this, SLOT(slotSaveIncrementalBackup())); connect(mainWindow(), SIGNAL(documentSaved()), this, SLOT(slotDocumentSaved())); d->saveIncremental->setEnabled(false); d->saveIncrementalBackup->setEnabled(false); KisAction *tabletDebugger = actionManager()->createAction("tablet_debugger"); connect(tabletDebugger, SIGNAL(triggered()), this, SLOT(toggleTabletLogger())); d->createTemplate = actionManager()->createAction("create_template"); connect(d->createTemplate, SIGNAL(triggered()), this, SLOT(slotCreateTemplate())); d->createCopy = actionManager()->createAction("create_copy"); connect(d->createCopy, SIGNAL(triggered()), this, SLOT(slotCreateCopy())); d->openResourcesDirectory = actionManager()->createAction("open_resources_directory"); connect(d->openResourcesDirectory, SIGNAL(triggered()), SLOT(openResourcesDirectory())); d->rotateCanvasRight = actionManager()->createAction("rotate_canvas_right"); d->rotateCanvasLeft = actionManager()->createAction("rotate_canvas_left"); d->resetCanvasRotation = actionManager()->createAction("reset_canvas_rotation"); d->wrapAroundAction = actionManager()->createAction("wrap_around_mode"); d->levelOfDetailAction = actionManager()->createAction("level_of_detail_mode"); d->softProof = actionManager()->createAction("softProof"); d->gamutCheck = actionManager()->createAction("gamutCheck"); KisAction *tAction = actionManager()->createAction("showStatusBar"); tAction->setChecked(cfg.showStatusBar()); connect(tAction, SIGNAL(toggled(bool)), this, SLOT(showStatusBar(bool))); tAction = actionManager()->createAction("view_show_canvas_only"); tAction->setChecked(false); connect(tAction, SIGNAL(toggled(bool)), this, SLOT(switchCanvasOnly(bool))); //Workaround, by default has the same shortcut as mirrorCanvas KisAction *a = dynamic_cast(actionCollection()->action("format_italic")); if (a) { a->setDefaultShortcut(QKeySequence()); } a = actionManager()->createAction("edit_blacklist_cleanup"); connect(a, SIGNAL(triggered()), this, SLOT(slotBlacklistCleanup())); d->showRulersAction = actionManager()->createAction("view_ruler"); d->showRulersAction->setChecked(cfg.showRulers()); connect(d->showRulersAction, SIGNAL(toggled(bool)), SLOT(slotSaveShowRulersState(bool))); d->rulersTrackMouseAction = actionManager()->createAction("rulers_track_mouse"); d->rulersTrackMouseAction->setChecked(cfg.rulersTrackMouse()); connect(d->rulersTrackMouseAction, SIGNAL(toggled(bool)), SLOT(slotSaveRulersTrackMouseState(bool))); d->zoomTo100pct = actionManager()->createAction("zoom_to_100pct"); d->zoomIn = actionManager()->createStandardAction(KStandardAction::ZoomIn, 0, ""); d->zoomOut = actionManager()->createStandardAction(KStandardAction::ZoomOut, 0, ""); d->actionAuthor = new KSelectAction(KisIconUtils::loadIcon("im-user"), i18n("Active Author Profile"), this); connect(d->actionAuthor, SIGNAL(triggered(const QString &)), this, SLOT(changeAuthorProfile(const QString &))); actionCollection()->addAction("settings_active_author", d->actionAuthor); slotUpdateAuthorProfileActions(); } void KisViewManager::setupManagers() { // Create the managers for filters, selections, layers etc. // XXX: When the currentlayer changes, call updateGUI on all // managers d->filterManager.setup(actionCollection(), actionManager()); d->selectionManager.setup(actionManager()); d->guidesManager.setup(actionManager()); d->nodeManager.setup(actionCollection(), actionManager()); d->imageManager.setup(actionManager()); d->gridManager.setup(actionManager()); d->paintingAssistantsManager.setup(actionManager()); d->canvasControlsManager.setup(actionManager()); d->mirrorManager.setup(actionCollection()); } void KisViewManager::updateGUI() { d->guiUpdateCompressor.start(); } void KisViewManager::slotBlacklistCleanup() { KisDlgBlacklistCleanup dialog; dialog.exec(); } KisNodeManager * KisViewManager::nodeManager() const { return &d->nodeManager; } KisActionManager* KisViewManager::actionManager() const { return &d->actionManager; } KisGridManager * KisViewManager::gridManager() const { return &d->gridManager; } KisGuidesManager * KisViewManager::guidesManager() const { return &d->guidesManager; } KisPaintingAssistantsManager* KisViewManager::paintingAssistantsManager() const { return &d->paintingAssistantsManager; } KisDocument *KisViewManager::document() const { if (d->currentImageView && d->currentImageView->document()) { return d->currentImageView->document(); } return 0; } int KisViewManager::viewCount() const { KisMainWindow *mw = qobject_cast(d->mainWindow); if (mw) { return mw->viewCount(); } return 0; } -bool KisViewManager::KisViewManagerPrivate::blockUntillOperationsFinishedImpl(KisImageSP image, bool force) +bool KisViewManager::KisViewManagerPrivate::blockUntilOperationsFinishedImpl(KisImageSP image, bool force) { const int busyWaitDelay = 1000; KisDelayedSaveDialog dialog(image, !force ? KisDelayedSaveDialog::GeneralDialog : KisDelayedSaveDialog::ForcedDialog, busyWaitDelay, mainWindow); dialog.blockIfImageIsBusy(); return dialog.result() == QDialog::Accepted; } -bool KisViewManager::blockUntillOperationsFinished(KisImageSP image) +bool KisViewManager::blockUntilOperationsFinished(KisImageSP image) { - return d->blockUntillOperationsFinishedImpl(image, false); + return d->blockUntilOperationsFinishedImpl(image, false); } void KisViewManager::blockUntillOperationsFinishedForced(KisImageSP image) { - d->blockUntillOperationsFinishedImpl(image, true); + d->blockUntilOperationsFinishedImpl(image, true); } void KisViewManager::slotCreateTemplate() { if (!document()) return; KisTemplateCreateDia::createTemplate( QStringLiteral("templates/"), ".kra", document(), mainWindow()); } void KisViewManager::slotCreateCopy() { if (!document()) return; KisDocument *doc = KisPart::instance()->createDocument(); QString name = document()->documentInfo()->aboutInfo("name"); if (name.isEmpty()) { name = document()->url().toLocalFile(); } name = i18n("%1 (Copy)", name); doc->documentInfo()->setAboutInfo("title", name); KisImageWSP image = document()->image(); KisImageSP newImage = new KisImage(doc->createUndoStore(), image->width(), image->height(), image->colorSpace(), name); newImage->setRootLayer(dynamic_cast(image->rootLayer()->clone().data())); doc->setCurrentImage(newImage); KisPart::instance()->addDocument(doc); KisMainWindow *mw = qobject_cast(d->mainWindow); mw->addViewAndNotifyLoadingCompleted(doc); } QMainWindow* KisViewManager::qtMainWindow() const { if (d->mainWindow) return d->mainWindow; //Fallback for when we have not yet set the main window. QMainWindow* w = qobject_cast(qApp->activeWindow()); if(w) return w; return mainWindow(); } void KisViewManager::setQtMainWindow(QMainWindow* newMainWindow) { d->mainWindow = newMainWindow; } void KisViewManager::slotDocumentSaved() { d->saveIncremental->setEnabled(true); d->saveIncrementalBackup->setEnabled(true); } void KisViewManager::slotSaveIncremental() { if (!document()) return; bool foundVersion; bool fileAlreadyExists; bool isBackup; QString version = "000"; QString newVersion; QString letter; QString fileName = document()->localFilePath(); // Find current version filenames // v v Regexp to find incremental versions in the filename, taking our backup scheme into account as well // Considering our incremental version and backup scheme, format is filename_001~001.ext QRegExp regex("_\\d{1,4}[.]|_\\d{1,4}[a-z][.]|_\\d{1,4}[~]|_\\d{1,4}[a-z][~]"); regex.indexIn(fileName); // Perform the search QStringList matches = regex.capturedTexts(); foundVersion = matches.at(0).isEmpty() ? false : true; // Ensure compatibility with Save Incremental Backup // If this regex is not kept separate, the entire algorithm needs modification; // It's simpler to just add this. QRegExp regexAux("_\\d{1,4}[~]|_\\d{1,4}[a-z][~]"); regexAux.indexIn(fileName); // Perform the search QStringList matchesAux = regexAux.capturedTexts(); isBackup = matchesAux.at(0).isEmpty() ? false : true; // If the filename has a version, prepare it for incrementation if (foundVersion) { version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches if (version.contains(QRegExp("[a-z]"))) { version.chop(1); // Trim "." letter = version.right(1); // Save letter version.chop(1); // Trim letter } else { version.chop(1); // Trim "." } version.remove(0, 1); // Trim "_" } else { // ...else, simply add a version to it so the next loop works QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension regex2.indexIn(fileName); QStringList matches2 = regex2.capturedTexts(); QString extensionPlusVersion = matches2.at(0); extensionPlusVersion.prepend(version); extensionPlusVersion.prepend("_"); fileName.replace(regex2, extensionPlusVersion); } // Prepare the base for new version filename int intVersion = version.toInt(0); ++intVersion; QString baseNewVersion = QString::number(intVersion); while (baseNewVersion.length() < version.length()) { baseNewVersion.prepend("0"); } // Check if the file exists under the new name and search until options are exhausted (test appending a to z) do { newVersion = baseNewVersion; newVersion.prepend("_"); if (!letter.isNull()) newVersion.append(letter); if (isBackup) { newVersion.append("~"); } else { newVersion.append("."); } fileName.replace(regex, newVersion); fileAlreadyExists = QFile(fileName).exists(); if (fileAlreadyExists) { if (!letter.isNull()) { char letterCh = letter.at(0).toLatin1(); ++letterCh; letter = QString(QChar(letterCh)); } else { letter = 'a'; } } } while (fileAlreadyExists && letter != "{"); // x, y, z, {... if (letter == "{") { QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental version"), i18n("Alternative names exhausted, try manually saving with a higher number")); return; } document()->setFileBatchMode(true); document()->saveAs(QUrl::fromUserInput(fileName)); document()->setFileBatchMode(false); if (mainWindow()) { mainWindow()->updateCaption(); } } void KisViewManager::slotSaveIncrementalBackup() { if (!document()) return; bool workingOnBackup; bool fileAlreadyExists; QString version = "000"; QString newVersion; QString letter; QString fileName = document()->localFilePath(); // First, discover if working on a backup file, or a normal file QRegExp regex("~\\d{1,4}[.]|~\\d{1,4}[a-z][.]"); regex.indexIn(fileName); // Perform the search QStringList matches = regex.capturedTexts(); workingOnBackup = matches.at(0).isEmpty() ? false : true; if (workingOnBackup) { // Try to save incremental version (of backup), use letter for alt versions version = matches.at(matches.count() - 1); // Look at the last index, we don't care about other matches if (version.contains(QRegExp("[a-z]"))) { version.chop(1); // Trim "." letter = version.right(1); // Save letter version.chop(1); // Trim letter } else { version.chop(1); // Trim "." } version.remove(0, 1); // Trim "~" // Prepare the base for new version filename int intVersion = version.toInt(0); ++intVersion; QString baseNewVersion = QString::number(intVersion); QString backupFileName = document()->localFilePath(); while (baseNewVersion.length() < version.length()) { baseNewVersion.prepend("0"); } // Check if the file exists under the new name and search until options are exhausted (test appending a to z) do { newVersion = baseNewVersion; newVersion.prepend("~"); if (!letter.isNull()) newVersion.append(letter); newVersion.append("."); backupFileName.replace(regex, newVersion); fileAlreadyExists = QFile(backupFileName).exists(); if (fileAlreadyExists) { if (!letter.isNull()) { char letterCh = letter.at(0).toLatin1(); ++letterCh; letter = QString(QChar(letterCh)); } else { letter = 'a'; } } } while (fileAlreadyExists && letter != "{"); // x, y, z, {... if (letter == "{") { QMessageBox::critical(mainWindow(), i18nc("@title:window", "Couldn't save incremental backup"), i18n("Alternative names exhausted, try manually saving with a higher number")); return; } QFile::copy(fileName, backupFileName); document()->saveAs(QUrl::fromUserInput(fileName)); if (mainWindow()) mainWindow()->updateCaption(); } else { // if NOT working on a backup... // Navigate directory searching for latest backup version, ignore letters const quint8 HARDCODED_DIGIT_COUNT = 3; QString baseNewVersion = "000"; QString backupFileName = document()->localFilePath(); QRegExp regex2("[.][a-z]{2,4}$"); // Heuristic to find file extension regex2.indexIn(backupFileName); QStringList matches2 = regex2.capturedTexts(); QString extensionPlusVersion = matches2.at(0); extensionPlusVersion.prepend(baseNewVersion); extensionPlusVersion.prepend("~"); backupFileName.replace(regex2, extensionPlusVersion); // Save version with 1 number higher than the highest version found ignoring letters do { newVersion = baseNewVersion; newVersion.prepend("~"); newVersion.append("."); backupFileName.replace(regex, newVersion); fileAlreadyExists = QFile(backupFileName).exists(); if (fileAlreadyExists) { // Prepare the base for new version filename, increment by 1 int intVersion = baseNewVersion.toInt(0); ++intVersion; baseNewVersion = QString::number(intVersion); while (baseNewVersion.length() < HARDCODED_DIGIT_COUNT) { baseNewVersion.prepend("0"); } } } while (fileAlreadyExists); // Save both as backup and on current file for interapplication workflow document()->setFileBatchMode(true); QFile::copy(fileName, backupFileName); document()->saveAs(QUrl::fromUserInput(fileName)); document()->setFileBatchMode(false); if (mainWindow()) mainWindow()->updateCaption(); } } void KisViewManager::disableControls() { // prevents possible crashes, if somebody changes the paintop during dragging by using the mousewheel // this is for Bug 250944 // the solution blocks all wheel, mouse and key event, while dragging with the freehand tool // see KisToolFreehand::initPaint() and endPaint() d->controlFrame.paintopBox()->installEventFilter(&d->blockingEventFilter); Q_FOREACH (QObject* child, d->controlFrame.paintopBox()->children()) { child->installEventFilter(&d->blockingEventFilter); } } void KisViewManager::enableControls() { d->controlFrame.paintopBox()->removeEventFilter(&d->blockingEventFilter); Q_FOREACH (QObject* child, d->controlFrame.paintopBox()->children()) { child->removeEventFilter(&d->blockingEventFilter); } } void KisViewManager::showStatusBar(bool toggled) { KisMainWindow *mw = mainWindow(); if(mw && mw->statusBar()) { mw->statusBar()->setVisible(toggled); KisConfig cfg; cfg.setShowStatusBar(toggled); } } void KisViewManager::switchCanvasOnly(bool toggled) { KisConfig cfg; KisMainWindow* main = mainWindow(); if(!main) { dbgUI << "Unable to switch to canvas-only mode, main window not found"; return; } if (toggled) { d->canvasState = qtMainWindow()->saveState(); } if (cfg.hideStatusbarFullscreen()) { if (main->statusBar()) { if (!toggled) { if (main->statusBar()->dynamicPropertyNames().contains("wasvisible")) { if (main->statusBar()->property("wasvisible").toBool()) { main->statusBar()->setVisible(true); } } } else { main->statusBar()->setProperty("wasvisible", main->statusBar()->isVisible()); main->statusBar()->setVisible(false); } } } if (cfg.hideDockersFullscreen()) { KisAction* action = qobject_cast(main->actionCollection()->action("view_toggledockers")); if (action) { action->setCheckable(true); if (toggled) { if (action->isChecked()) { cfg.setShowDockers(action->isChecked()); action->setChecked(false); } else { cfg.setShowDockers(false); } } else { action->setChecked(cfg.showDockers()); } } } if (cfg.hideTitlebarFullscreen() && !cfg.fullscreenMode()) { if(toggled) { main->setWindowState( main->windowState() | Qt::WindowFullScreen); } else { main->setWindowState( main->windowState() & ~Qt::WindowFullScreen); } } if (cfg.hideMenuFullscreen()) { if (!toggled) { if (main->menuBar()->dynamicPropertyNames().contains("wasvisible")) { if (main->menuBar()->property("wasvisible").toBool()) { main->menuBar()->setVisible(true); } } } else { main->menuBar()->setProperty("wasvisible", main->menuBar()->isVisible()); main->menuBar()->setVisible(false); } } if (cfg.hideToolbarFullscreen()) { QList toolBars = main->findChildren(); Q_FOREACH (QToolBar* toolbar, toolBars) { if (!toggled) { if (toolbar->dynamicPropertyNames().contains("wasvisible")) { if (toolbar->property("wasvisible").toBool()) { toolbar->setVisible(true); } } } else { toolbar->setProperty("wasvisible", toolbar->isVisible()); toolbar->setVisible(false); } } } showHideScrollbars(); if (toggled) { // show a fading heads-up display about the shortcut to go back showFloatingMessage(i18n("Going into Canvas-Only mode.\nPress %1 to go back.", actionCollection()->action("view_show_canvas_only")->shortcut().toString()), QIcon()); } else { main->restoreState(d->canvasState); } } void KisViewManager::toggleTabletLogger() { d->inputManager.toggleTabletLogger(); } void KisViewManager::openResourcesDirectory() { QString dir = KoResourcePaths::locateLocal("data", ""); QDesktopServices::openUrl(QUrl::fromLocalFile(dir)); } void KisViewManager::updateIcons() { if (mainWindow()) { QList dockers = mainWindow()->dockWidgets(); Q_FOREACH (QDockWidget* dock, dockers) { dbgKrita << "name " << dock->objectName(); KoDockWidgetTitleBar* titlebar = dynamic_cast(dock->titleBarWidget()); if (titlebar) { titlebar->updateIcons(); } QObjectList objects; objects.append(dock); while (!objects.isEmpty()) { QObject* object = objects.takeFirst(); objects.append(object->children()); KisIconUtils::updateIconCommon(object); } } } } void KisViewManager::initializeStatusBarVisibility() { KisConfig cfg; d->mainWindow->statusBar()->setVisible(cfg.showStatusBar()); } void KisViewManager::guiUpdateTimeout() { d->nodeManager.updateGUI(); d->selectionManager.updateGUI(); d->filterManager.updateGUI(); if (zoomManager()) { zoomManager()->updateGUI(); } d->gridManager.updateGUI(); d->actionManager.updateGUI(); } void KisViewManager::showFloatingMessage(const QString &message, const QIcon& icon, int timeout, KisFloatingMessage::Priority priority, int alignment) { if (!d->currentImageView) return; d->currentImageView->showFloatingMessageImpl(message, icon, timeout, priority, alignment); emit floatingMessageRequested(message, icon.name()); } KisMainWindow *KisViewManager::mainWindow() const { return qobject_cast(d->mainWindow); } void KisViewManager::showHideScrollbars() { if (!d->currentImageView) return; if (!d->currentImageView->canvasController()) return; KisConfig cfg; bool toggled = actionCollection()->action("view_show_canvas_only")->isChecked(); if ( (toggled && cfg.hideScrollbarsFullscreen()) || (!toggled && cfg.hideScrollbars()) ) { d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); } else { d->currentImageView->canvasController()->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); d->currentImageView->canvasController()->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); } } void KisViewManager::slotSaveShowRulersState(bool value) { KisConfig cfg; cfg.setShowRulers(value); } void KisViewManager::slotSaveRulersTrackMouseState(bool value) { KisConfig cfg; cfg.setRulersTrackMouse(value); } void KisViewManager::setShowFloatingMessage(bool show) { d->showFloatingMessage = show; } void KisViewManager::changeAuthorProfile(const QString &profileName) { KConfigGroup appAuthorGroup(KoGlobal::calligraConfig(), "Author"); if (profileName.isEmpty()) { appAuthorGroup.writeEntry("active-profile", ""); } else if (profileName == i18nc("choice for author profile", "Anonymous")) { appAuthorGroup.writeEntry("active-profile", "anonymous"); } else { appAuthorGroup.writeEntry("active-profile", profileName); } appAuthorGroup.sync(); Q_FOREACH (KisDocument *doc, KisPart::instance()->documents()) { doc->documentInfo()->updateParameters(); } } void KisViewManager::slotUpdateAuthorProfileActions() { Q_ASSERT(d->actionAuthor); if (!d->actionAuthor) { return; } d->actionAuthor->clear(); d->actionAuthor->addAction(i18n("Default Author Profile")); d->actionAuthor->addAction(i18nc("choice for author profile", "Anonymous")); KConfigGroup authorGroup(KoGlobal::calligraConfig(), "Author"); QStringList profiles = authorGroup.readEntry("profile-names", QStringList()); Q_FOREACH (const QString &profile , profiles) { d->actionAuthor->addAction(profile); } KConfigGroup appAuthorGroup(KoGlobal::calligraConfig(), "Author"); QString profileName = appAuthorGroup.readEntry("active-profile", ""); if (profileName == "anonymous") { d->actionAuthor->setCurrentItem(1); } else if (profiles.contains(profileName)) { d->actionAuthor->setCurrentAction(profileName); } else { d->actionAuthor->setCurrentItem(0); } } diff --git a/libs/ui/KisViewManager.h b/libs/ui/KisViewManager.h index e7d9356867..a9ec5c67e1 100644 --- a/libs/ui/KisViewManager.h +++ b/libs/ui/KisViewManager.h @@ -1,269 +1,269 @@ /* * Copyright (c) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KIS_GUI_CLIENT_H #define KIS_GUI_CLIENT_H #include #include #include #include #include #include #include #include #include "kis_floating_message.h" class QPoint; class KisView; class KisCanvas2; class KisCanvasResourceProvider; class KisDocument; class KisFilterManager; class KisGridManager; class KisGuidesManager; class KisImageManager; class KisNodeManager; class KisPaintingAssistantsManager; class KisPaintopBox; class KisSelectionManager; class KisStatusBar; class KisUndoAdapter; class KisZoomManager; class KisPaintopBox; class KisActionManager; class KisInputManager; /** * Krita view class * * Following the broad model-view-controller idea this class shows you one view on the document. * There can be multiple views of the same document each in with independent settings for viewMode and zoom etc. */ class KRITAUI_EXPORT KisViewManager : public QObject { Q_OBJECT public: /** * Construct a new view on the krita document. * @param document the document we show. * @param parent a parent widget we show ourselves in. */ KisViewManager(QWidget *parent, KActionCollection *actionCollection); virtual ~KisViewManager(); /** * Retrieves the entire action collection. */ virtual KActionCollection* actionCollection() const; public: // Krita specific interfaces void setCurrentView(KisView *view); /// Return the image this view is displaying KisImageWSP image() const; KoZoomController *zoomController() const; /// The resource provider contains all per-view settings, such as /// current color, current paint op etc. KisCanvasResourceProvider * resourceProvider(); /// Return the canvasbase class KisCanvas2 * canvasBase() const; /// Return the actual widget that is displaying the current image QWidget* canvas() const; /// Return the wrapper class around the statusbar KisStatusBar * statusBar() const; /** * This adds a widget to the statusbar for this view. * If you use this method instead of using statusBar() directly, * KisView will take care of removing the items when the view GUI is deactivated * and readding them when it is reactivated. * The parameters are the same as QStatusBar::addWidget(). */ void addStatusBarItem(QWidget * widget, int stretch = 0, bool permanent = false); /** * Remove a widget from the statusbar for this view. */ void removeStatusBarItem(QWidget * widget); KisPaintopBox* paintOpBox() const; /// create a new progress updater KoProgressUpdater *createProgressUpdater(KoProgressUpdater::Mode mode = KoProgressUpdater::Threaded); /// The selection manager handles everything action related to /// selections. KisSelectionManager *selectionManager(); /// The node manager handles everything about nodes KisNodeManager *nodeManager() const; KisActionManager *actionManager() const; /** * Convenience method to get at the active node, which may be * a layer or a mask or a selection */ KisNodeSP activeNode(); /// Convenience method to get at the active layer KisLayerSP activeLayer(); /// Convenience method to get at the active paint device KisPaintDeviceSP activeDevice(); /// The filtermanager handles everything action-related to filters KisFilterManager *filterManager(); /// The image manager handles everything action-related to the /// current image KisImageManager *imageManager(); /// Filters events and sends them to canvas actions KisInputManager *inputManager() const; /// Convenience method to get at the active selection (the /// selection of the current layer, or, if that does not exist, /// the global selection. KisSelectionSP selection(); /// Checks if the current global or local selection is editable bool selectionEditable(); /// The undo adapter is used to add commands to the undo stack KisUndoAdapter *undoAdapter(); KisDocument *document() const; int viewCount() const; /** * @brief blockUntillOperationsFinished blocks the GUI of the application until execution * of actions on \p image is finished * @param image the image which we should wait for * @return true if the image has finished execution of the actions, false if * the user cancelled operation */ - bool blockUntillOperationsFinished(KisImageSP image); + bool blockUntilOperationsFinished(KisImageSP image); /** * @brief blockUntillOperationsFinished blocks the GUI of the application until execution * of actions on \p image is finished. Does *not* provide a "Cancel" button. So the * user is forced to wait. * @param image the image which we should wait for */ void blockUntillOperationsFinishedForced(KisImageSP image); public: KisGridManager * gridManager() const; KisGuidesManager * guidesManager() const; KisPaintingAssistantsManager* paintingAssistantsManager() const; /// disable and enable toolbar controls. used for disabling them during painting. void enableControls(); void disableControls(); /// shows a floating message in the top right corner of the canvas void showFloatingMessage(const QString &message, const QIcon& icon, int timeout = 4500, KisFloatingMessage::Priority priority = KisFloatingMessage::Medium, int alignment = Qt::AlignCenter | Qt::TextWordWrap); /// @return the KoMaindow this view is in, or 0 KisMainWindow *mainWindow() const; /// The QMainWindow associated with this view. This is most likely going to be shell(), but /// when running as Gemini or Sketch, this will be set to the applications' own QMainWindow. /// This can be checked by qobject_casting to KisMainWindow to check the difference. QMainWindow* qtMainWindow() const; /// The mainWindow function will return the shell() value, unless this function is called /// with a non-null value. To make it return shell() again, simply pass null to this function. void setQtMainWindow(QMainWindow* newMainWindow); public Q_SLOTS: void switchCanvasOnly(bool toggled); void setShowFloatingMessage(bool show); void showHideScrollbars(); /// Visit all managers to update gui elements, e.g. enable / disable actions. /// This is heavy-duty call, so it uses a compressor. void updateGUI(); /// Update the style of all the icons void updateIcons(); void slotViewAdded(KisView *view); void slotViewRemoved(KisView *view); Q_SIGNALS: void floatingMessageRequested(const QString &message, const QString &iconName); /** * @brief viewChanged * sent out when the view has changed. */ void viewChanged(); private Q_SLOTS: void slotBlacklistCleanup(); void slotCreateTemplate(); void slotCreateCopy(); void slotDocumentSaved(); void slotSaveIncremental(); void slotSaveIncrementalBackup(); void showStatusBar(bool toggled); void toggleTabletLogger(); void openResourcesDirectory(); void initializeStatusBarVisibility(); void guiUpdateTimeout(); void changeAuthorProfile(const QString &profileName); void slotUpdateAuthorProfileActions(); void slotSaveShowRulersState(bool value); void slotSaveRulersTrackMouseState(bool value); private: void createActions(); void setupManagers(); /// The zoommanager handles everything action-related to zooming KisZoomManager * zoomManager(); private: class KisViewManagerPrivate; KisViewManagerPrivate * const d; }; #endif diff --git a/libs/ui/actions/kis_selection_action_factories.cpp b/libs/ui/actions/kis_selection_action_factories.cpp index 8daab7667f..d0123a689a 100644 --- a/libs/ui/actions/kis_selection_action_factories.cpp +++ b/libs/ui/actions/kis_selection_action_factories.cpp @@ -1,643 +1,643 @@ /* * Copyright (c) 2012 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_selection_action_factories.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisViewManager.h" #include "kis_canvas_resource_provider.h" #include "kis_clipboard.h" #include "kis_pixel_selection.h" #include "kis_paint_layer.h" #include "kis_image.h" #include "kis_image_barrier_locker.h" #include "kis_fill_painter.h" #include "kis_transaction.h" #include "kis_iterator_ng.h" #include "kis_processing_applicator.h" #include "kis_group_layer.h" #include "commands/kis_selection_commands.h" #include "commands/kis_image_layer_add_command.h" #include "kis_tool_proxy.h" #include "kis_canvas2.h" #include "kis_canvas_controller.h" #include "kis_selection_manager.h" #include "kis_transaction_based_command.h" #include "kis_selection_filters.h" #include "kis_shape_selection.h" #include "KisPart.h" #include "kis_shape_layer.h" #include #include "kis_import_catcher.h" #include #include #include "kis_canvas_resource_provider.h" #include "kis_figure_painting_tool_helper.h" namespace ActionHelper { void copyFromDevice(KisViewManager *view, KisPaintDeviceSP device, bool makeSharpClip = false) { KisImageWSP image = view->image(); if (!image) return; KisSelectionSP selection = view->selection(); QRect rc = (selection) ? selection->selectedExactRect() : image->bounds(); KisPaintDeviceSP clip = new KisPaintDevice(device->colorSpace()); Q_CHECK_PTR(clip); const KoColorSpace *cs = clip->colorSpace(); // TODO if the source is linked... copy from all linked layers?!? // Copy image data KisPainter::copyAreaOptimized(QPoint(), device, clip, rc); if (selection) { // Apply selection mask. KisPaintDeviceSP selectionProjection = selection->projection(); KisHLineIteratorSP layerIt = clip->createHLineIteratorNG(0, 0, rc.width()); KisHLineConstIteratorSP selectionIt = selectionProjection->createHLineIteratorNG(rc.x(), rc.y(), rc.width()); const KoColorSpace *selCs = selection->projection()->colorSpace(); for (qint32 y = 0; y < rc.height(); y++) { for (qint32 x = 0; x < rc.width(); x++) { /** * Sharp method is an exact reverse of COMPOSITE_OVER * so if you cover the cut/copied piece over its source * you get an exactly the same image without any seams */ if (makeSharpClip) { qreal dstAlpha = cs->opacityF(layerIt->rawData()); qreal sel = selCs->opacityF(selectionIt->oldRawData()); qreal newAlpha = sel * dstAlpha / (1.0 - dstAlpha + sel * dstAlpha); float mask = newAlpha / dstAlpha; cs->applyAlphaNormedFloatMask(layerIt->rawData(), &mask, 1); } else { cs->applyAlphaU8Mask(layerIt->rawData(), selectionIt->oldRawData(), 1); } layerIt->nextPixel(); selectionIt->nextPixel(); } layerIt->nextRow(); selectionIt->nextRow(); } } KisClipboard::instance()->setClip(clip, rc.topLeft()); } } void KisSelectAllActionFactory::run(KisViewManager *view) { KisImageWSP image = view->image(); if (!image) return; KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Select All")); if (!image->globalSelection()) { ap->applyCommand(new KisSetEmptyGlobalSelectionCommand(image), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); } struct SelectAll : public KisTransactionBasedCommand { SelectAll(KisImageSP image) : m_image(image) {} KisImageSP m_image; KUndo2Command* paint() override { KisSelectionSP selection = m_image->globalSelection(); KisSelectionTransaction transaction(selection->pixelSelection()); selection->pixelSelection()->select(m_image->bounds()); return transaction.endAndTake(); } }; ap->applyCommand(new SelectAll(image), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); endAction(ap, KisOperationConfiguration(id()).toXML()); } void KisDeselectActionFactory::run(KisViewManager *view) { KisImageWSP image = view->image(); if (!image) return; KUndo2Command *cmd = new KisDeselectGlobalSelectionCommand(image); KisProcessingApplicator *ap = beginAction(view, cmd->text()); ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); endAction(ap, KisOperationConfiguration(id()).toXML()); } void KisReselectActionFactory::run(KisViewManager *view) { KisImageWSP image = view->image(); if (!image) return; KUndo2Command *cmd = new KisReselectGlobalSelectionCommand(image); KisProcessingApplicator *ap = beginAction(view, cmd->text()); ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); endAction(ap, KisOperationConfiguration(id()).toXML()); } void KisFillActionFactory::run(const QString &fillSource, KisViewManager *view) { KisNodeSP node = view->activeNode(); if (!node || !node->hasEditablePaintDevice()) return; KisSelectionSP selection = view->selection(); QRect selectedRect = selection ? selection->selectedRect() : view->image()->bounds(); Q_UNUSED(selectedRect); KisPaintDeviceSP filled = node->paintDevice()->createCompositionSourceDevice(); Q_UNUSED(filled); bool usePattern = false; bool useBgColor = false; if (fillSource.contains("pattern")) { usePattern = true; } else if (fillSource.contains("bg")) { useBgColor = true; } KisProcessingApplicator applicator(view->image(), node, KisProcessingApplicator::NONE, KisImageSignalVector() << ModifiedSignal, kundo2_i18n("Flood Fill Layer")); KisResourcesSnapshotSP resources = new KisResourcesSnapshot(view->image(), node, view->resourceProvider()->resourceManager()); if (!fillSource.contains("opacity")) { resources->setOpacity(1.0); } KisProcessingVisitorSP visitor = new FillProcessingVisitor(QPoint(0, 0), // start position selection, resources, false, // fast mode usePattern, true, // fill only selection, 0, // feathering radius 0, // sizemod 80, // threshold, false, // unmerged useBgColor); applicator.applyVisitor(visitor, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); applicator.end(); } void KisClearActionFactory::run(KisViewManager *view) { // XXX: "Add saving of XML data for Clear action" view->canvasBase()->toolProxy()->deleteSelection(); } void KisImageResizeToSelectionActionFactory::run(KisViewManager *view) { // XXX: "Add saving of XML data for Image Resize To Selection action" KisSelectionSP selection = view->selection(); if (!selection) return; view->image()->cropImage(selection->selectedExactRect()); } void KisCutCopyActionFactory::run(bool willCut, bool makeSharpClip, KisViewManager *view) { KisImageSP image = view->image(); if (!image) return; bool haveShapesSelected = view->selectionManager()->haveShapesSelected(); if (haveShapesSelected) { // XXX: "Add saving of XML data for Cut/Copy of shapes" KisImageBarrierLocker locker(image); if (willCut) { view->canvasBase()->toolProxy()->cut(); } else { view->canvasBase()->toolProxy()->copy(); } } else { KisNodeSP node = view->activeNode(); if (!node) return; KisSelectionSP selection = view->selection(); if (selection.isNull()) return; { KisImageBarrierLocker locker(image); KisPaintDeviceSP dev = node->paintDevice(); if (!dev) { dev = node->projection(); } if (!dev) { view->showFloatingMessage( i18nc("floating message when cannot copy from a node", "Cannot copy pixels from this type of layer "), QIcon(), 3000, KisFloatingMessage::Medium); return; } if (dev->exactBounds().isEmpty()) { view->showFloatingMessage( i18nc("floating message when copying empty selection", "Selection is empty: no pixels were copied "), QIcon(), 3000, KisFloatingMessage::Medium); return; } ActionHelper::copyFromDevice(view, dev, makeSharpClip); } if (willCut) { KUndo2Command *command = 0; if (willCut && node->hasEditablePaintDevice()) { struct ClearSelection : public KisTransactionBasedCommand { ClearSelection(KisNodeSP node, KisSelectionSP sel) : m_node(node), m_sel(sel) {} KisNodeSP m_node; KisSelectionSP m_sel; KUndo2Command* paint() override { KisSelectionSP cutSelection = m_sel; // Shrinking the cutting area was previously used // for getting seamless cut-paste. Now we use makeSharpClip // instead. // QRect originalRect = cutSelection->selectedExactRect(); // static const int preciseSelectionThreshold = 16; // // if (originalRect.width() > preciseSelectionThreshold || // originalRect.height() > preciseSelectionThreshold) { // cutSelection = new KisSelection(*m_sel); // delete cutSelection->flatten(); // // KisSelectionFilter* filter = new KisShrinkSelectionFilter(1, 1, false); // // QRect processingRect = filter->changeRect(originalRect); // filter->process(cutSelection->pixelSelection(), processingRect); // } KisTransaction transaction(m_node->paintDevice()); m_node->paintDevice()->clearSelection(cutSelection); m_node->setDirty(cutSelection->selectedRect()); return transaction.endAndTake(); } }; command = new ClearSelection(node, selection); } KUndo2MagicString actionName = willCut ? kundo2_i18n("Cut") : kundo2_i18n("Copy"); KisProcessingApplicator *ap = beginAction(view, actionName); if (command) { ap->applyCommand(command, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::NORMAL); } KisOperationConfiguration config(id()); config.setProperty("will-cut", willCut); endAction(ap, config.toXML()); } } } void KisCopyMergedActionFactory::run(KisViewManager *view) { KisImageWSP image = view->image(); if (!image) return; - if (!view->blockUntillOperationsFinished(image)) return; + if (!view->blockUntilOperationsFinished(image)) return; image->barrierLock(); KisPaintDeviceSP dev = image->root()->projection(); ActionHelper::copyFromDevice(view, dev); image->unlock(); KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Copy Merged")); endAction(ap, KisOperationConfiguration(id()).toXML()); } void KisPasteActionFactory::run(KisViewManager *view) { KisImageWSP image = view->image(); if (!image) return; KisPaintDeviceSP clip = KisClipboard::instance()->clip(image->bounds(), true); if (clip) { KisImportCatcher::adaptClipToImageColorSpace(clip, image); KisPaintLayer *newLayer = new KisPaintLayer(image.data(), image->nextLayerName() + i18n("(pasted)"), OPACITY_OPAQUE_U8, clip); KisNodeSP aboveNode = view->activeLayer(); KisNodeSP parentNode = aboveNode ? aboveNode->parent() : image->root(); KUndo2Command *cmd = new KisImageLayerAddCommand(image, newLayer, parentNode, aboveNode); KisProcessingApplicator *ap = beginAction(view, cmd->text()); ap->applyCommand(cmd, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::NORMAL); endAction(ap, KisOperationConfiguration(id()).toXML()); } else { // XXX: "Add saving of XML data for Paste of shapes" view->canvasBase()->toolProxy()->paste(); } } void KisPasteNewActionFactory::run(KisViewManager *viewManager) { Q_UNUSED(viewManager); KisPaintDeviceSP clip = KisClipboard::instance()->clip(QRect(), true); if (!clip) return; QRect rect = clip->exactBounds(); if (rect.isEmpty()) return; KisDocument *doc = KisPart::instance()->createDocument(); KisImageSP image = new KisImage(doc->createUndoStore(), rect.width(), rect.height(), clip->colorSpace(), i18n("Pasted")); KisPaintLayerSP layer = new KisPaintLayer(image.data(), image->nextLayerName() + i18n("(pasted)"), OPACITY_OPAQUE_U8, clip->colorSpace()); KisPainter::copyAreaOptimized(QPoint(), clip, layer->paintDevice(), rect); image->addNode(layer.data(), image->rootLayer()); doc->setCurrentImage(image); KisPart::instance()->addDocument(doc); KisMainWindow *win = viewManager->mainWindow(); win->addViewAndNotifyLoadingCompleted(doc); } void KisInvertSelectionOperaton::runFromXML(KisViewManager* view, const KisOperationConfiguration& config) { KisSelectionFilter* filter = new KisInvertSelectionFilter(); runFilter(filter, view, config); } void KisSelectionToVectorActionFactory::run(KisViewManager *view) { KisSelectionSP selection = view->selection(); if (selection->hasShapeSelection() || !selection->outlineCacheValid()) { return; } QPainterPath selectionOutline = selection->outlineCache(); QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform(); KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(selectionOutline)); shape->setShapeId(KoPathShapeId); /** * Mark a shape that it belongs to a shape selection */ if(!shape->userData()) { shape->setUserData(new KisShapeSelectionMarker); } KisProcessingApplicator *ap = beginAction(view, kundo2_i18n("Convert to Vector Selection")); ap->applyCommand(view->canvasBase()->shapeController()->addShape(shape), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); endAction(ap, KisOperationConfiguration(id()).toXML()); } class KisShapeSelectionPaste : public KoOdfPaste { public: KisShapeSelectionPaste(KisViewManager* view) : m_view(view) { } ~KisShapeSelectionPaste() override { } bool process(const KoXmlElement & body, KoOdfReadStore & odfStore) override { KoOdfLoadingContext loadingContext(odfStore.styles(), odfStore.store()); KoShapeLoadingContext context(loadingContext, m_view->canvasBase()->shapeController()->resourceManager()); KoXmlElement child; QList shapes; forEachElement(child, body) { KoShape * shape = KoShapeRegistry::instance()->createShapeFromOdf(child, context); if (shape) { shapes.append(shape); } } if (!shapes.isEmpty()) { KisSelectionToolHelper helper(m_view->canvasBase(), kundo2_i18n("Convert shapes to vector selection")); helper.addSelectionShapes(shapes); } return true; } private: KisViewManager* m_view; }; void KisShapesToVectorSelectionActionFactory::run(KisViewManager* view) { QList shapes = view->canvasBase()->shapeManager()->selection()->selectedShapes(); KoShapeOdfSaveHelper saveHelper(shapes); KoDrag drag; drag.setOdf(KoOdf::mimeType(KoOdf::Text), saveHelper); QMimeData* mimeData = drag.mimeData(); Q_ASSERT(mimeData->hasFormat(KoOdf::mimeType(KoOdf::Text))); KisShapeSelectionPaste paste(view); paste.paste(KoOdf::Text, mimeData); } void KisSelectionToShapeActionFactory::run(KisViewManager *view) { KisSelectionSP selection = view->selection(); if (!selection->outlineCacheValid()) { return; } QPainterPath selectionOutline = selection->outlineCache(); QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform(); KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(selectionOutline)); shape->setShapeId(KoPathShapeId); KoColor fgColor = view->canvasBase()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value(); KoShapeStroke* border = new KoShapeStroke(1.0, fgColor.toQColor()); shape->setStroke(border); view->document()->shapeController()->addShape(shape); } void KisStrokeSelectionActionFactory::run(KisViewManager *view, StrokeSelectionOptions params) { KisImageWSP image = view->image(); if (!image) { return; } KisSelectionSP selection = view->selection(); if (!selection) { return; } int size = params.lineSize; KisPixelSelectionSP pixelSelection = selection->projection(); if (!pixelSelection->outlineCacheValid()) { pixelSelection->recalculateOutlineCache(); } QPainterPath outline = pixelSelection->outlineCache(); QColor color = params.color.toQColor(); KisNodeSP currentNode = view->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value(); if (!currentNode->inherits("KisShapeLayer") && currentNode->childCount() == 0) { KoCanvasResourceManager * rManager = view->resourceProvider()->resourceManager(); KisPainter::StrokeStyle strokeStyle = KisPainter::StrokeStyleBrush; KisPainter::FillStyle fillStyle = params.fillStyle(); KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polyline"), image, currentNode, rManager , strokeStyle, fillStyle); helper.setFGColorOverride(params.color); helper.setSelectionOverride(0); QPen pen(Qt::red, size); pen.setJoinStyle(Qt::RoundJoin); if (fillStyle != KisPainter::FillStyleNone) { helper.paintPainterPathQPenFill(outline, pen, params.fillColor); } else { helper.paintPainterPathQPen(outline, pen, params.fillColor); } } else { QTransform transform = view->canvasBase()->coordinatesConverter()->imageToDocumentTransform(); KoShape *shape = KoPathShape::createShapeFromPainterPath(transform.map(outline)); shape->setShapeId(KoPathShapeId); KoShapeStroke* border = new KoShapeStroke(size, color); shape->setStroke(border); view->document()->shapeController()->addShape(shape); } image->setModified(); } void KisStrokeBrushSelectionActionFactory::run(KisViewManager *view, StrokeSelectionOptions params) { KisImageWSP image = view->image(); if (!image) { return; } KisSelectionSP selection = view->selection(); if (!selection) { return; } KisPixelSelectionSP pixelSelection = selection->projection(); if (!pixelSelection->outlineCacheValid()) { pixelSelection->recalculateOutlineCache(); } KisNodeSP currentNode = view->resourceProvider()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value(); if (!currentNode->inherits("KisShapeLayer") && currentNode->childCount() == 0) { KoCanvasResourceManager * rManager = view->resourceProvider()->resourceManager(); QPainterPath outline = pixelSelection->outlineCache(); KisPainter::StrokeStyle strokeStyle = KisPainter::StrokeStyleBrush; KisPainter::FillStyle fillStyle = KisPainter::FillStyleNone; KoColor color = params.color; KisFigurePaintingToolHelper helper(kundo2_i18n("Draw Polyline"), image, currentNode, rManager , strokeStyle, fillStyle); helper.setFGColorOverride(color); helper.setSelectionOverride(0); helper.paintPainterPath(outline); image->setModified(); } } diff --git a/libs/ui/kis_filter_manager.cc b/libs/ui/kis_filter_manager.cc index 13e2fc6d51..5f19104b76 100644 --- a/libs/ui/kis_filter_manager.cc +++ b/libs/ui/kis_filter_manager.cc @@ -1,350 +1,350 @@ /* * Copyright (c) 2007 Boudewijn Rempt * Copyright (c) 2007 Cyrille Berger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_filter_manager.h" #include #include #include #include #include #include #include // krita/image #include #include #include #include // krita/ui #include "KisViewManager.h" #include "kis_canvas2.h" #include #include "kis_action.h" #include "kis_action_manager.h" #include "kis_canvas_resource_provider.h" #include "dialogs/kis_dlg_filter.h" #include "strokes/kis_filter_stroke_strategy.h" #include "krita_utils.h" struct KisFilterManager::Private { Private() : reapplyAction(0) , actionCollection(0) , actionManager(0) , view(0) { } KisAction* reapplyAction; QHash filterActionMenus; QHash filters2Action; KActionCollection *actionCollection; KisActionManager *actionManager; KisViewManager *view; KisFilterConfigurationSP lastConfiguration; KisFilterConfigurationSP currentlyAppliedConfiguration; KisStrokeId currentStrokeId; QRect initialApplyRect; QSignalMapper actionsMapper; QPointer filterDialog; }; KisFilterManager::KisFilterManager(KisViewManager * view) : d(new Private) { d->view = view; } KisFilterManager::~KisFilterManager() { delete d; } void KisFilterManager::setView(QPointerimageView) { Q_UNUSED(imageView); } void KisFilterManager::setup(KActionCollection * ac, KisActionManager *actionManager) { d->actionCollection = ac; d->actionManager = actionManager; // Setup reapply action d->reapplyAction = d->actionManager->createAction("filter_apply_again"); d->reapplyAction->setEnabled(false); connect(d->reapplyAction, SIGNAL(triggered()), SLOT(reapplyLastFilter())); connect(&d->actionsMapper, SIGNAL(mapped(const QString&)), SLOT(showFilterDialog(const QString&))); // Setup list of filters QStringList keys = KisFilterRegistry::instance()->keys(); keys.sort(); Q_FOREACH (const QString &filterName, keys) { insertFilter(filterName); } connect(KisFilterRegistry::instance(), SIGNAL(filterAdded(QString)), SLOT(insertFilter(const QString &))); } void KisFilterManager::insertFilter(const QString & filterName) { Q_ASSERT(d->actionCollection); KisFilterSP filter = KisFilterRegistry::instance()->value(filterName); Q_ASSERT(filter); if (d->filters2Action.contains(filter.data())) { warnKrita << "Filter" << filterName << " has already been inserted"; return; } KoID category = filter->menuCategory(); KActionMenu* actionMenu = d->filterActionMenus[ category.id()]; if (!actionMenu) { actionMenu = new KActionMenu(category.name(), this); d->actionCollection->addAction(category.id(), actionMenu); d->filterActionMenus[category.id()] = actionMenu; } KisAction *action = new KisAction(filter->menuEntry(), this); action->setDefaultShortcut(filter->shortcut()); action->setActivationFlags(KisAction::ACTIVE_DEVICE); d->actionManager->addAction(QString("krita_filter_%1").arg(filterName), action); d->filters2Action[filter.data()] = action; actionMenu->addAction(action); d->actionsMapper.setMapping(action, filterName); connect(action, SIGNAL(triggered()), &d->actionsMapper, SLOT(map())); } void KisFilterManager::updateGUI() { if (!d->view) return; bool enable = false; KisNodeSP activeNode = d->view->activeNode(); enable = activeNode && activeNode->hasEditablePaintDevice(); d->reapplyAction->setEnabled(enable); for (QHash::iterator it = d->filters2Action.begin(); it != d->filters2Action.end(); ++it) { bool localEnable = enable; it.value()->setEnabled(localEnable); } } void KisFilterManager::reapplyLastFilter() { if (!d->lastConfiguration) return; apply(d->lastConfiguration); finish(); } void KisFilterManager::showFilterDialog(const QString &filterId) { if (d->filterDialog && d->filterDialog->isVisible()) { KisFilterSP filter = KisFilterRegistry::instance()->value(filterId); d->filterDialog->setFilter(filter); return; } connect(d->view->image(), SIGNAL(sigStrokeCancellationRequested()), SLOT(slotStrokeCancelRequested()), Qt::UniqueConnection); connect(d->view->image(), SIGNAL(sigStrokeEndRequested()), SLOT(slotStrokeEndRequested()), Qt::UniqueConnection); /** * The UI should show only after every running stroke is finished, * so a virtual barrier is added here. */ - if (!d->view->blockUntillOperationsFinished(d->view->image())) { + if (!d->view->blockUntilOperationsFinished(d->view->image())) { return; } Q_ASSERT(d->view); Q_ASSERT(d->view->activeNode()); KisPaintDeviceSP dev = d->view->activeNode()->paintDevice(); if (!dev) { warnKrita << "KisFilterManager::showFilterDialog(): Filtering was requested for illegal active layer!" << d->view->activeNode(); return; } KisFilterSP filter = KisFilterRegistry::instance()->value(filterId); if (dev->colorSpace()->willDegrade(filter->colorSpaceIndependence())) { // Warning bells! if (filter->colorSpaceIndependence() == TO_LAB16) { if (QMessageBox::warning(d->view->mainWindow(), i18nc("@title:window", "Krita"), i18n("The %1 filter will convert your %2 data to 16-bit L*a*b* and vice versa. ", filter->name(), dev->colorSpace()->name()), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) != QMessageBox::Ok) return; } else if (filter->colorSpaceIndependence() == TO_RGBA16) { if (QMessageBox::warning(d->view->mainWindow(), i18nc("@title:window", "Krita"), i18n("The %1 filter will convert your %2 data to 16-bit RGBA and vice versa. ", filter->name() , dev->colorSpace()->name()), QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok) != QMessageBox::Ok) return; } } if (filter->showConfigurationWidget()) { if (!d->filterDialog) { d->filterDialog = new KisDlgFilter(d->view , d->view->activeNode(), this, d->view->mainWindow()); d->filterDialog->setAttribute(Qt::WA_DeleteOnClose); } d->filterDialog->setFilter(filter); d->filterDialog->setVisible(true); } else { apply(KisFilterConfigurationSP(filter->defaultConfiguration())); finish(); } } void KisFilterManager::apply(KisFilterConfigurationSP filterConfig) { KisFilterSP filter = KisFilterRegistry::instance()->value(filterConfig->name()); KisImageWSP image = d->view->image(); if (d->currentStrokeId) { image->addJob(d->currentStrokeId, new KisFilterStrokeStrategy::CancelSilentlyMarker); image->cancelStroke(d->currentStrokeId); d->currentStrokeId.clear(); } else { image->waitForDone(); d->initialApplyRect = d->view->activeNode()->exactBounds(); } QRect applyRect = d->initialApplyRect; KisPaintDeviceSP paintDevice = d->view->activeNode()->paintDevice(); if (paintDevice && filter->needsTransparentPixels(filterConfig.data(), paintDevice->colorSpace())) { applyRect |= image->bounds(); } KoCanvasResourceManager *resourceManager = d->view->resourceProvider()->resourceManager(); KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image, d->view->activeNode(), resourceManager); d->currentStrokeId = image->startStroke(new KisFilterStrokeStrategy(filter, KisFilterConfigurationSP(filterConfig), resources)); QRect processRect = filter->changedRect(applyRect, filterConfig.data(), 0); processRect &= image->bounds(); if (filter->supportsThreading()) { QSize size = KritaUtils::optimalPatchSize(); QVector rects = KritaUtils::splitRectIntoPatches(processRect, size); Q_FOREACH (const QRect &rc, rects) { image->addJob(d->currentStrokeId, new KisFilterStrokeStrategy::Data(rc, true)); } } else { image->addJob(d->currentStrokeId, new KisFilterStrokeStrategy::Data(processRect, false)); } d->currentlyAppliedConfiguration = filterConfig; } void KisFilterManager::finish() { Q_ASSERT(d->currentStrokeId); d->view->image()->endStroke(d->currentStrokeId); KisFilterSP filter = KisFilterRegistry::instance()->value(d->currentlyAppliedConfiguration->name()); if (filter->bookmarkManager()) { filter->bookmarkManager()->save(KisBookmarkedConfigurationManager::ConfigLastUsed, d->currentlyAppliedConfiguration.data()); } d->lastConfiguration = d->currentlyAppliedConfiguration; d->reapplyAction->setEnabled(true); d->reapplyAction->setText(i18n("Apply Filter Again: %1", filter->name())); d->currentStrokeId.clear(); d->currentlyAppliedConfiguration.clear(); } void KisFilterManager::cancel() { Q_ASSERT(d->currentStrokeId); d->view->image()->cancelStroke(d->currentStrokeId); d->currentStrokeId.clear(); d->currentlyAppliedConfiguration.clear(); } bool KisFilterManager::isStrokeRunning() const { return d->currentStrokeId; } void KisFilterManager::slotStrokeEndRequested() { if (d->currentStrokeId && d->filterDialog) { d->filterDialog->accept(); } } void KisFilterManager::slotStrokeCancelRequested() { if (d->currentStrokeId && d->filterDialog) { d->filterDialog->reject(); } } diff --git a/libs/ui/kis_layer_manager.cc b/libs/ui/kis_layer_manager.cc index 8398bdb375..fdfdcf06a0 100644 --- a/libs/ui/kis_layer_manager.cc +++ b/libs/ui/kis_layer_manager.cc @@ -1,845 +1,845 @@ /* * Copyright (C) 2006 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_layer_manager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisImportExportManager.h" #include "kis_config.h" #include "kis_cursor.h" #include "dialogs/kis_dlg_adj_layer_props.h" #include "dialogs/kis_dlg_adjustment_layer.h" #include "dialogs/kis_dlg_layer_properties.h" #include "dialogs/kis_dlg_generator_layer.h" #include "dialogs/kis_dlg_file_layer.h" #include "dialogs/kis_dlg_layer_style.h" #include "KisDocument.h" #include "kis_filter_manager.h" #include "kis_node_visitor.h" #include "kis_paint_layer.h" #include "commands/kis_image_commands.h" #include "commands/kis_layer_command.h" #include "commands/kis_node_commands.h" #include "kis_canvas_resource_provider.h" #include "kis_selection_manager.h" #include "kis_statusbar.h" #include "KisViewManager.h" #include "kis_zoom_manager.h" #include "canvas/kis_canvas2.h" #include "widgets/kis_meta_data_merge_strategy_chooser_widget.h" #include "widgets/kis_wdg_generator.h" #include "kis_progress_widget.h" #include "kis_node_commands_adapter.h" #include "kis_node_manager.h" #include "kis_action.h" #include "kis_action_manager.h" #include "KisPart.h" #include "kis_raster_keyframe_channel.h" #include "kis_signal_compressor_with_param.h" #include "kis_abstract_projection_plane.h" #include "commands_new/kis_set_layer_style_command.h" #include "kis_post_execution_undo_adapter.h" #include "kis_selection_mask.h" #include "kis_layer_utils.h" #include "lazybrush/kis_colorize_mask.h" #include "KisSaveGroupVisitor.h" KisLayerManager::KisLayerManager(KisViewManager * view) : m_view(view) , m_imageView(0) , m_imageFlatten(0) , m_imageMergeLayer(0) , m_groupLayersSave(0) , m_imageResizeToLayer(0) , m_flattenLayer(0) , m_rasterizeLayer(0) , m_commandsAdapter(new KisNodeCommandsAdapter(m_view)) , m_layerStyle(0) { } KisLayerManager::~KisLayerManager() { delete m_commandsAdapter; } void KisLayerManager::setView(QPointerview) { m_imageView = view; } KisLayerSP KisLayerManager::activeLayer() { if (m_imageView) { return m_imageView->currentLayer(); } return 0; } KisPaintDeviceSP KisLayerManager::activeDevice() { if (activeLayer()) { return activeLayer()->paintDevice(); } return 0; } void KisLayerManager::activateLayer(KisLayerSP layer) { if (m_imageView) { emit sigLayerActivated(layer); layersUpdated(); if (layer) { m_view->resourceProvider()->slotNodeActivated(layer.data()); } } } void KisLayerManager::setup(KisActionManager* actionManager) { m_imageFlatten = actionManager->createAction("flatten_image"); connect(m_imageFlatten, SIGNAL(triggered()), this, SLOT(flattenImage())); m_imageMergeLayer = actionManager->createAction("merge_layer"); connect(m_imageMergeLayer, SIGNAL(triggered()), this, SLOT(mergeLayer())); m_flattenLayer = actionManager->createAction("flatten_layer"); connect(m_flattenLayer, SIGNAL(triggered()), this, SLOT(flattenLayer())); m_rasterizeLayer = actionManager->createAction("rasterize_layer"); connect(m_rasterizeLayer, SIGNAL(triggered()), this, SLOT(rasterizeLayer())); m_groupLayersSave = actionManager->createAction("save_groups_as_images"); connect(m_groupLayersSave, SIGNAL(triggered()), this, SLOT(saveGroupLayers())); m_convertGroupAnimated = actionManager->createAction("convert_group_to_animated"); connect(m_convertGroupAnimated, SIGNAL(triggered()), this, SLOT(convertGroupToAnimated())); m_imageResizeToLayer = actionManager->createAction("resizeimagetolayer"); connect(m_imageResizeToLayer, SIGNAL(triggered()), this, SLOT(imageResizeToActiveLayer())); KisAction *action = actionManager->createAction("trim_to_image"); connect(action, SIGNAL(triggered()), this, SLOT(trimToImage())); m_layerStyle = actionManager->createAction("layer_style"); connect(m_layerStyle, SIGNAL(triggered()), this, SLOT(layerStyle())); } void KisLayerManager::updateGUI() { KisImageWSP image = m_view->image(); KisLayerSP layer; qint32 nlayers = 0; if (image) { layer = activeLayer(); nlayers = image->nlayers(); } // XXX these should be named layer instead of image m_imageFlatten->setEnabled(nlayers > 1); m_imageMergeLayer->setEnabled(nlayers > 1 && layer && layer->prevSibling()); m_flattenLayer->setEnabled(nlayers > 1 && layer && layer->firstChild()); if (m_view->statusBar()) m_view->statusBar()->setProfile(image); } void KisLayerManager::imageResizeToActiveLayer() { KisLayerSP layer; KisImageWSP image = m_view->image(); if (image && (layer = activeLayer())) { QRect cropRect = layer->projection()->nonDefaultPixelArea(); if (!cropRect.isEmpty()) { image->cropImage(cropRect); } else { m_view->showFloatingMessage( i18nc("floating message in layer manager", "Layer is empty "), QIcon(), 2000, KisFloatingMessage::Low); } } } void KisLayerManager::trimToImage() { KisImageWSP image = m_view->image(); if (image) { image->cropImage(image->bounds()); } } void KisLayerManager::layerProperties() { if (!m_view) return; if (!m_view->document()) return; KisLayerSP layer = activeLayer(); QList selectedNodes = m_view->nodeManager()->selectedNodes(); const bool multipleLayersSelected = selectedNodes.size() > 1; if (!layer) return; KisAdjustmentLayerSP alayer = KisAdjustmentLayerSP(dynamic_cast(layer.data())); KisGeneratorLayerSP glayer = KisGeneratorLayerSP(dynamic_cast(layer.data())); if (alayer && !multipleLayersSelected) { KisPaintDeviceSP dev = alayer->projection(); KisDlgAdjLayerProps dlg(alayer, alayer.data(), dev, m_view, alayer->filter().data(), alayer->name(), i18n("Filter Layer Properties"), m_view->mainWindow(), "dlgadjlayerprops"); dlg.resize(dlg.minimumSizeHint()); KisFilterConfigurationSP configBefore(alayer->filter()); KIS_ASSERT_RECOVER_RETURN(configBefore); QString xmlBefore = configBefore->toXML(); if (dlg.exec() == QDialog::Accepted) { alayer->setName(dlg.layerName()); KisFilterConfigurationSP configAfter(dlg.filterConfiguration()); Q_ASSERT(configAfter); QString xmlAfter = configAfter->toXML(); if(xmlBefore != xmlAfter) { KisChangeFilterCmd *cmd = new KisChangeFilterCmd(alayer, configBefore->name(), xmlBefore, configAfter->name(), xmlAfter, false); // FIXME: check whether is needed cmd->redo(); m_view->undoAdapter()->addCommand(cmd); m_view->document()->setModified(true); } } else { KisFilterConfigurationSP configAfter(dlg.filterConfiguration()); Q_ASSERT(configAfter); QString xmlAfter = configAfter->toXML(); if(xmlBefore != xmlAfter) { alayer->setFilter(KisFilterRegistry::instance()->cloneConfiguration(configBefore.data())); alayer->setDirty(); } } } else if (glayer && !multipleLayersSelected) { KisDlgGeneratorLayer dlg(glayer->name(), m_view, m_view->mainWindow()); dlg.setCaption(i18n("Fill Layer Properties")); KisFilterConfigurationSP configBefore(glayer->filter()); Q_ASSERT(configBefore); QString xmlBefore = configBefore->toXML(); dlg.setConfiguration(configBefore.data()); dlg.resize(dlg.minimumSizeHint()); if (dlg.exec() == QDialog::Accepted) { glayer->setName(dlg.layerName()); KisFilterConfigurationSP configAfter(dlg.configuration()); Q_ASSERT(configAfter); QString xmlAfter = configAfter->toXML(); if(xmlBefore != xmlAfter) { KisChangeFilterCmd *cmd = new KisChangeFilterCmd(glayer, configBefore->name(), xmlBefore, configAfter->name(), xmlAfter, true); // FIXME: check whether is needed cmd->redo(); m_view->undoAdapter()->addCommand(cmd); m_view->document()->setModified(true); } } } else { // If layer == normal painting layer, vector layer, or group layer QList selectedNodes = m_view->nodeManager()->selectedNodes(); KisDlgLayerProperties *dialog = new KisDlgLayerProperties(selectedNodes, m_view); dialog->resize(dialog->minimumSizeHint()); dialog->setAttribute(Qt::WA_DeleteOnClose); Qt::WindowFlags flags = dialog->windowFlags(); dialog->setWindowFlags(flags | Qt::WindowStaysOnTopHint | Qt::Dialog); dialog->show(); } } void KisLayerManager::convertNodeToPaintLayer(KisNodeSP source) { KisImageWSP image = m_view->image(); if (!image) return; KisLayer *srcLayer = qobject_cast(source.data()); if (srcLayer && (srcLayer->inherits("KisGroupLayer") || srcLayer->layerStyle() || srcLayer->childCount() > 0)) { image->flattenLayer(srcLayer); return; } KisPaintDeviceSP srcDevice = source->paintDevice() ? source->projection() : source->original(); bool putBehind = false; QString newCompositeOp = source->compositeOpId(); KisColorizeMask *colorizeMask = dynamic_cast(source.data()); if (colorizeMask) { srcDevice = colorizeMask->coloringProjection(); putBehind = colorizeMask->compositeOpId() == COMPOSITE_BEHIND; if (putBehind) { newCompositeOp = COMPOSITE_OVER; } } if (!srcDevice) return; KisPaintDeviceSP clone; if (*srcDevice->colorSpace() != *srcDevice->compositionSourceColorSpace()) { clone = new KisPaintDevice(srcDevice->compositionSourceColorSpace()); QRect rc(srcDevice->extent()); KisPainter::copyAreaOptimized(rc.topLeft(), srcDevice, clone, rc); } else { clone = new KisPaintDevice(*srcDevice); } KisLayerSP layer = new KisPaintLayer(image, source->name(), source->opacity(), clone); layer->setCompositeOpId(newCompositeOp); KisNodeSP parent = source->parent(); KisNodeSP above = source; while (parent && !parent->allowAsChild(layer)) { above = above->parent(); parent = above ? above->parent() : 0; } if (putBehind && above == source->parent()) { above = above->prevSibling(); } m_commandsAdapter->beginMacro(kundo2_i18n("Convert to a Paint Layer")); m_commandsAdapter->addNode(layer, parent, above); m_commandsAdapter->removeNode(source); m_commandsAdapter->endMacro(); } void KisLayerManager::convertGroupToAnimated() { KisGroupLayerSP group = dynamic_cast(activeLayer().data()); if (group.isNull()) return; KisPaintLayerSP animatedLayer = new KisPaintLayer(m_view->image(), group->name(), OPACITY_OPAQUE_U8); animatedLayer->enableAnimation(); KisRasterKeyframeChannel *contentChannel = dynamic_cast( animatedLayer->getKeyframeChannel(KisKeyframeChannel::Content.id(), true)); KIS_ASSERT_RECOVER_RETURN(contentChannel); KisNodeSP child = group->firstChild(); int time = 0; while (child) { contentChannel->importFrame(time, child->projection(), NULL); time++; child = child->nextSibling(); } m_commandsAdapter->beginMacro(kundo2_i18n("Convert to an animated layer")); m_commandsAdapter->addNode(animatedLayer, group->parent(), group); m_commandsAdapter->removeNode(group); m_commandsAdapter->endMacro(); } void KisLayerManager::adjustLayerPosition(KisNodeSP node, KisNodeSP activeNode, KisNodeSP &parent, KisNodeSP &above) { Q_ASSERT(activeNode); parent = activeNode; above = parent->lastChild(); while (parent && (!parent->allowAsChild(node) || parent->userLocked())) { above = parent; parent = parent->parent(); } if (!parent) { warnKrita << "KisLayerManager::adjustLayerPosition:" << "No node accepted newly created node"; parent = m_view->image()->root(); above = parent->lastChild(); } } void KisLayerManager::addLayerCommon(KisNodeSP activeNode, KisLayerSP layer, bool updateImage) { KisNodeSP parent; KisNodeSP above; adjustLayerPosition(layer, activeNode, parent, above); KisGroupLayer *group = dynamic_cast(parent.data()); const bool parentForceUpdate = group && !group->projectionIsValid(); updateImage |= parentForceUpdate; m_commandsAdapter->addNode(layer, parent, above, updateImage, updateImage); } KisLayerSP KisLayerManager::addLayer(KisNodeSP activeNode) { KisLayerSP layer = KisLayerUtils::constructDefaultLayer(m_view->image()); addLayerCommon(activeNode, layer, false); return layer; } void KisLayerManager::addGroupLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); addLayerCommon(activeNode, new KisGroupLayer(image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8), false); } void KisLayerManager::addCloneLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); addLayerCommon(activeNode, new KisCloneLayer(activeLayer(), image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8)); } void KisLayerManager::addShapeLayer(KisNodeSP activeNode) { if (!m_view) return; if (!m_view->document()) return; KisImageWSP image = m_view->image(); KisShapeLayerSP layer = new KisShapeLayer(m_view->document()->shapeController(), image.data(), image->nextLayerName(), OPACITY_OPAQUE_U8); addLayerCommon(activeNode, layer, false); } void KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); KisSelectionSP selection = m_view->selection(); KisAdjustmentLayerSP adjl = addAdjustmentLayer(activeNode, QString(), 0, selection); image->refreshGraph(); KisPaintDeviceSP previewDevice = new KisPaintDevice(*adjl->original()); KisDlgAdjustmentLayer dlg(adjl, adjl.data(), previewDevice, image->nextLayerName(), i18n("New Filter Layer"), m_view); dlg.resize(dlg.minimumSizeHint()); // ensure that the device may be free'd by the dialog // when it is not needed anymore previewDevice = 0; if (dlg.exec() != QDialog::Accepted || adjl->filter().isNull()) { // XXX: add messagebox warning if there's no filter set! m_commandsAdapter->undoLastCommand(); } else { adjl->setName(dlg.layerName()); } } KisAdjustmentLayerSP KisLayerManager::addAdjustmentLayer(KisNodeSP activeNode, const QString & name, KisFilterConfigurationSP filter, KisSelectionSP selection) { KisImageWSP image = m_view->image(); KisAdjustmentLayerSP layer = new KisAdjustmentLayer(image, name, filter, selection); addLayerCommon(activeNode, layer); return layer; } void KisLayerManager::addGeneratorLayer(KisNodeSP activeNode) { KisImageWSP image = m_view->image(); KisDlgGeneratorLayer dlg(image->nextLayerName(), m_view, m_view->mainWindow()); dlg.resize(dlg.minimumSizeHint()); if (dlg.exec() == QDialog::Accepted) { KisSelectionSP selection = m_view->selection(); KisFilterConfigurationSP generator = dlg.configuration(); QString name = dlg.layerName(); addLayerCommon(activeNode, new KisGeneratorLayer(image, name, generator, selection)); } } void KisLayerManager::rotateLayer(double radians) { if (!m_view->image()) return; KisLayerSP layer = activeLayer(); if (!layer) return; - if (!m_view->blockUntillOperationsFinished(m_view->image())) return; + if (!m_view->blockUntilOperationsFinished(m_view->image())) return; m_view->image()->rotateNode(layer, radians); } void KisLayerManager::shearLayer(double angleX, double angleY) { if (!m_view->image()) return; KisLayerSP layer = activeLayer(); if (!layer) return; - if (!m_view->blockUntillOperationsFinished(m_view->image())) return; + if (!m_view->blockUntilOperationsFinished(m_view->image())) return; m_view->image()->shearNode(layer, angleX, angleY); } void KisLayerManager::flattenImage() { KisImageSP image = m_view->image(); - if (!m_view->blockUntillOperationsFinished(image)) return; + if (!m_view->blockUntilOperationsFinished(image)) return; if (image) { bool doIt = true; if (image->nHiddenLayers() > 0) { int answer = QMessageBox::warning(m_view->mainWindow(), i18nc("@title:window", "Flatten Image"), i18n("The image contains hidden layers that will be lost. Do you want to flatten the image?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (answer != QMessageBox::Yes) { doIt = false; } } if (doIt) { image->flatten(); } } } inline bool isSelectionMask(KisNodeSP node) { return dynamic_cast(node.data()); } bool tryMergeSelectionMasks(KisNodeSP currentNode, KisImageSP image) { bool result = false; KisNodeSP prevNode = currentNode->prevSibling(); if (isSelectionMask(currentNode) && prevNode && isSelectionMask(prevNode)) { QList mergedNodes; mergedNodes.append(currentNode); mergedNodes.append(prevNode); image->mergeMultipleLayers(mergedNodes, currentNode); result = true; } return result; } void KisLayerManager::mergeLayer() { KisImageSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; - if (!m_view->blockUntillOperationsFinished(image)) return; + if (!m_view->blockUntilOperationsFinished(image)) return; QList selectedNodes = m_view->nodeManager()->selectedNodes(); if (selectedNodes.size() > 1) { image->mergeMultipleLayers(selectedNodes, m_view->activeNode()); } else if (!tryMergeSelectionMasks(m_view->activeNode(), image)) { if (!layer->prevSibling()) return; KisLayer *prevLayer = qobject_cast(layer->prevSibling().data()); if (!prevLayer) return; if (layer->metaData()->isEmpty() && prevLayer->metaData()->isEmpty()) { image->mergeDown(layer, KisMetaData::MergeStrategyRegistry::instance()->get("Drop")); } else { const KisMetaData::MergeStrategy* strategy = KisMetaDataMergeStrategyChooserWidget::showDialog(m_view->mainWindow()); if (!strategy) return; image->mergeDown(layer, strategy); } } m_view->updateGUI(); } void KisLayerManager::flattenLayer() { KisImageSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; - if (!m_view->blockUntillOperationsFinished(image)) return; + if (!m_view->blockUntilOperationsFinished(image)) return; image->flattenLayer(layer); m_view->updateGUI(); } void KisLayerManager::rasterizeLayer() { KisImageSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; - if (!m_view->blockUntillOperationsFinished(image)) return; + if (!m_view->blockUntilOperationsFinished(image)) return; KisPaintLayerSP paintLayer = new KisPaintLayer(image, layer->name(), layer->opacity()); KisPainter gc(paintLayer->paintDevice()); QRect rc = layer->projection()->exactBounds(); gc.bitBlt(rc.topLeft(), layer->projection(), rc); m_commandsAdapter->beginMacro(kundo2_i18n("Rasterize Layer")); m_commandsAdapter->addNode(paintLayer.data(), layer->parent().data(), layer.data()); int childCount = layer->childCount(); for (int i = 0; i < childCount; i++) { m_commandsAdapter->moveNode(layer->firstChild(), paintLayer, paintLayer->lastChild()); } m_commandsAdapter->removeNode(layer); m_commandsAdapter->endMacro(); updateGUI(); } void KisLayerManager::layersUpdated() { KisLayerSP layer = activeLayer(); if (!layer) return; m_view->updateGUI(); } void KisLayerManager::saveGroupLayers() { QStringList listMimeFilter = KisImportExportManager::mimeFilter(KisImportExportManager::Export); KoDialog dlg; QWidget *page = new QWidget(&dlg); dlg.setMainWidget(page); QBoxLayout *layout = new QVBoxLayout(page); KisFileNameRequester *urlRequester = new KisFileNameRequester(page); urlRequester->setMode(KoFileDialog::SaveFile); if (m_view->document()->url().isLocalFile()) { urlRequester->setStartDir(QFileInfo(m_view->document()->url().toLocalFile()).absolutePath()); } urlRequester->setMimeTypeFilters(listMimeFilter); urlRequester->setFileName(m_view->document()->url().toLocalFile()); layout->addWidget(urlRequester); QCheckBox *chkInvisible = new QCheckBox(i18n("Convert Invisible Groups"), page); chkInvisible->setChecked(false); layout->addWidget(chkInvisible); QCheckBox *chkDepth = new QCheckBox(i18n("Export Only Toplevel Groups"), page); chkDepth->setChecked(true); layout->addWidget(chkDepth); if (!dlg.exec()) return; QString path = urlRequester->fileName(); if (path.isEmpty()) return; QFileInfo f(path); QString mimeType= KisMimeDatabase::mimeTypeForFile(f.fileName()); if (mimeType.isEmpty()) { mimeType = "image/png"; } QString extension = KisMimeDatabase::suffixesForMimeType(mimeType).first(); QString basename = f.baseName(); KisImageSP image = m_view->image(); if (!image) return; KisSaveGroupVisitor v(image, chkInvisible->isChecked(), chkDepth->isChecked(), f.absolutePath(), basename, extension, mimeType); image->rootLayer()->accept(v); } bool KisLayerManager::activeLayerHasSelection() { return (activeLayer()->selection() != 0); } void KisLayerManager::addFileLayer(KisNodeSP activeNode) { QString basePath; QUrl url = m_view->document()->url(); if (url.isLocalFile()) { basePath = QFileInfo(url.toLocalFile()).absolutePath(); } KisImageWSP image = m_view->image(); KisDlgFileLayer dlg(basePath, image->nextLayerName(), m_view->mainWindow()); dlg.resize(dlg.minimumSizeHint()); if (dlg.exec() == QDialog::Accepted) { QString name = dlg.layerName(); QString fileName = dlg.fileName(); if(fileName.isEmpty()){ QMessageBox::critical(m_view->mainWindow(), i18nc("@title:window", "Krita"), i18n("No file name specified")); return; } KisFileLayer::ScalingMethod scalingMethod = dlg.scaleToImageResolution(); addLayerCommon(activeNode, new KisFileLayer(image, basePath, fileName, scalingMethod, name, OPACITY_OPAQUE_U8)); } } void updateLayerStyles(KisLayerSP layer, KisDlgLayerStyle *dlg) { KisSetLayerStyleCommand::updateLayerStyle(layer, dlg->style()->clone()); } void KisLayerManager::layerStyle() { KisImageWSP image = m_view->image(); if (!image) return; KisLayerSP layer = activeLayer(); if (!layer) return; - if (!m_view->blockUntillOperationsFinished(image)) return; + if (!m_view->blockUntilOperationsFinished(image)) return; KisPSDLayerStyleSP oldStyle; if (layer->layerStyle()) { oldStyle = layer->layerStyle()->clone(); } else { oldStyle = toQShared(new KisPSDLayerStyle()); } KisDlgLayerStyle dlg(oldStyle->clone(), m_view->resourceProvider()); std::function updateCall(std::bind(updateLayerStyles, layer, &dlg)); SignalToFunctionProxy proxy(updateCall); connect(&dlg, SIGNAL(configChanged()), &proxy, SLOT(start())); if (dlg.exec() == QDialog::Accepted) { KisPSDLayerStyleSP newStyle = dlg.style(); KUndo2CommandSP command = toQShared( new KisSetLayerStyleCommand(layer, oldStyle, newStyle)); image->postExecutionUndoAdapter()->addCommand(command); } } diff --git a/libs/ui/tool/kis_tool.cc b/libs/ui/tool/kis_tool.cc index 5eb901ff1d..29409c7f23 100644 --- a/libs/ui/tool/kis_tool.cc +++ b/libs/ui/tool/kis_tool.cc @@ -1,698 +1,698 @@ /* * Copyright (c) 2006, 2010 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_tool.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_node_manager.h" #include #include #include #include #include #include #include #include #include #include #include #include "opengl/kis_opengl_canvas2.h" #include "kis_canvas_resource_provider.h" #include "canvas/kis_canvas2.h" #include "kis_coordinates_converter.h" #include "filter/kis_filter_configuration.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_cursor.h" #include #include #include "kis_resources_snapshot.h" #include #include "kis_action_registry.h" #include "kis_tool_utils.h" struct Q_DECL_HIDDEN KisTool::Private { QCursor cursor; // the cursor that should be shown on tool activation. // From the canvas resources KoPattern* currentPattern{0}; KoAbstractGradient* currentGradient{0}; KoColor currentFgColor; KoColor currentBgColor; float currentExposure{1.0}; KisFilterConfigurationSP currentGenerator; QWidget* optionWidget{0}; ToolMode m_mode{HOVER_MODE}; bool m_isActive{false}; }; KisTool::KisTool(KoCanvasBase * canvas, const QCursor & cursor) : KoToolBase(canvas) , d(new Private) { d->cursor = cursor; connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), SLOT(resetCursorStyle())); connect(this, SIGNAL(isActiveChanged()), SLOT(resetCursorStyle())); KActionCollection *collection = this->canvas()->canvasController()->actionCollection(); if (!collection->action("toggle_fg_bg")) { QAction *toggleFgBg = KisActionRegistry::instance()->makeQAction("toggle_fg_bg", collection); collection->addAction("toggle_fg_bg", toggleFgBg); } if (!collection->action("reset_fg_bg")) { QAction *toggleFgBg = KisActionRegistry::instance()->makeQAction("reset_fg_bg", collection); collection->addAction("reset_fg_bg", toggleFgBg); } addAction("toggle_fg_bg", dynamic_cast(collection->action("toggle_fg_bg"))); addAction("reset_fg_bg", dynamic_cast(collection->action("reset_fg_bg"))); } KisTool::~KisTool() { delete d; } void KisTool::activate(ToolActivation toolActivation, const QSet &shapes) { Q_UNUSED(toolActivation); Q_UNUSED(shapes); resetCursorStyle(); if (!canvas()) return; if (!canvas()->resourceManager()) return; d->currentFgColor = canvas()->resourceManager()->resource(KoCanvasResourceManager::ForegroundColor).value(); d->currentBgColor = canvas()->resourceManager()->resource(KoCanvasResourceManager::BackgroundColor).value(); if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentPattern)) { d->currentPattern = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPattern).value(); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentGradient)) { d->currentGradient = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentGradient).value(); } KisPaintOpPresetSP preset = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if (preset && preset->settings()) { preset->settings()->activate(); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::HdrExposure)) { d->currentExposure = static_cast(canvas()->resourceManager()->resource(KisCanvasResourceProvider::HdrExposure).toDouble()); } if (canvas()->resourceManager()->hasResource(KisCanvasResourceProvider::CurrentGeneratorConfiguration)) { d->currentGenerator = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentGeneratorConfiguration).value(); } connect(actions().value("toggle_fg_bg"), SIGNAL(triggered()), SLOT(slotToggleFgBg()), Qt::UniqueConnection); connect(actions().value("reset_fg_bg"), SIGNAL(triggered()), SLOT(slotResetFgBg()), Qt::UniqueConnection); connect(image(), SIGNAL(sigUndoDuringStrokeRequested()), SLOT(requestUndoDuringStroke()), Qt::UniqueConnection); connect(image(), SIGNAL(sigStrokeCancellationRequested()), SLOT(requestStrokeCancellation()), Qt::UniqueConnection); connect(image(), SIGNAL(sigStrokeEndRequested()), SLOT(requestStrokeEnd()), Qt::UniqueConnection); d->m_isActive = true; emit isActiveChanged(); } void KisTool::deactivate() { bool result = true; result &= disconnect(image().data(), SIGNAL(sigUndoDuringStrokeRequested()), this, 0); result &= disconnect(image().data(), SIGNAL(sigStrokeCancellationRequested()), this, 0); result &= disconnect(image().data(), SIGNAL(sigStrokeEndRequested()), this, 0); result &= disconnect(actions().value("toggle_fg_bg"), 0, this, 0); result &= disconnect(actions().value("reset_fg_bg"), 0, this, 0); if (!result) { warnKrita << "WARNING: KisTool::deactivate() failed to disconnect" << "some signal connections. Your actions might be executed twice!"; } d->m_isActive = false; emit isActiveChanged(); } void KisTool::requestUndoDuringStroke() { /** * Default implementation just cancells the stroke */ requestStrokeCancellation(); } void KisTool::requestStrokeCancellation() { } void KisTool::requestStrokeEnd() { } void KisTool::canvasResourceChanged(int key, const QVariant & v) { switch (key) { case(KoCanvasResourceManager::ForegroundColor): d->currentFgColor = v.value(); break; case(KoCanvasResourceManager::BackgroundColor): d->currentBgColor = v.value(); break; case(KisCanvasResourceProvider::CurrentPattern): d->currentPattern = static_cast(v.value()); break; case(KisCanvasResourceProvider::CurrentGradient): d->currentGradient = static_cast(v.value()); break; case(KisCanvasResourceProvider::HdrExposure): d->currentExposure = static_cast(v.toDouble()); break; case(KisCanvasResourceProvider::CurrentGeneratorConfiguration): d->currentGenerator = static_cast(v.value()); break; case(KisCanvasResourceProvider::CurrentPaintOpPreset): emit statusTextChanged(v.value()->name()); break; case(KisCanvasResourceProvider::CurrentKritaNode): resetCursorStyle(); break; default: break; // Do nothing }; } void KisTool::updateSettingsViews() { } QPointF KisTool::widgetCenterInWidgetPixels() { KisCanvas2 *kritaCanvas = dynamic_cast(canvas()); Q_ASSERT(kritaCanvas); const KisCoordinatesConverter *converter = kritaCanvas->coordinatesConverter(); return converter->flakeToWidget(converter->flakeCenterPoint()); } QPointF KisTool::convertDocumentToWidget(const QPointF& pt) { KisCanvas2 *kritaCanvas = dynamic_cast(canvas()); Q_ASSERT(kritaCanvas); return kritaCanvas->coordinatesConverter()->documentToWidget(pt); } QPointF KisTool::convertToPixelCoord(KoPointerEvent *e) { if (!image()) return e->point; return image()->documentToPixel(e->point); } QPointF KisTool::convertToPixelCoord(const QPointF& pt) { if (!image()) return pt; return image()->documentToPixel(pt); } QPointF KisTool::convertToPixelCoordAndSnap(KoPointerEvent *e, const QPointF &offset, bool useModifiers) { if (!image()) return e->point; KoSnapGuide *snapGuide = canvas()->snapGuide(); QPointF pos = snapGuide->snap(e->point, offset, useModifiers ? e->modifiers() : Qt::NoModifier); return image()->documentToPixel(pos); } QPointF KisTool::convertToPixelCoordAndSnap(const QPointF& pt, const QPointF &offset) { if (!image()) return pt; KoSnapGuide *snapGuide = canvas()->snapGuide(); QPointF pos = snapGuide->snap(pt, offset, Qt::NoModifier); return image()->documentToPixel(pos); } QPoint KisTool::convertToIntPixelCoord(KoPointerEvent *e) { if (!image()) return e->point.toPoint(); return image()->documentToIntPixel(e->point); } QPointF KisTool::viewToPixel(const QPointF &viewCoord) const { if (!image()) return viewCoord; return image()->documentToPixel(canvas()->viewConverter()->viewToDocument(viewCoord)); } QRectF KisTool::convertToPt(const QRectF &rect) { if (!image()) return rect; QRectF r; //We add 1 in the following to the extreme coords because a pixel always has size r.setCoords(int(rect.left()) / image()->xRes(), int(rect.top()) / image()->yRes(), int(1 + rect.right()) / image()->xRes(), int(1 + rect.bottom()) / image()->yRes()); return r; } QPointF KisTool::pixelToView(const QPoint &pixelCoord) const { if (!image()) return pixelCoord; QPointF documentCoord = image()->pixelToDocument(pixelCoord); return canvas()->viewConverter()->documentToView(documentCoord); } QPointF KisTool::pixelToView(const QPointF &pixelCoord) const { if (!image()) return pixelCoord; QPointF documentCoord = image()->pixelToDocument(pixelCoord); return canvas()->viewConverter()->documentToView(documentCoord); } QRectF KisTool::pixelToView(const QRectF &pixelRect) const { if (!image()) return pixelRect; QPointF topLeft = pixelToView(pixelRect.topLeft()); QPointF bottomRight = pixelToView(pixelRect.bottomRight()); return QRectF(topLeft, bottomRight); } QPainterPath KisTool::pixelToView(const QPainterPath &pixelPolygon) const { QTransform matrix; qreal zoomX, zoomY; canvas()->viewConverter()->zoom(&zoomX, &zoomY); matrix.scale(zoomX/image()->xRes(), zoomY/ image()->yRes()); return matrix.map(pixelPolygon); } QPolygonF KisTool::pixelToView(const QPolygonF &pixelPath) const { QTransform matrix; qreal zoomX, zoomY; canvas()->viewConverter()->zoom(&zoomX, &zoomY); matrix.scale(zoomX/image()->xRes(), zoomY/ image()->yRes()); return matrix.map(pixelPath); } void KisTool::updateCanvasPixelRect(const QRectF &pixelRect) { canvas()->updateCanvas(convertToPt(pixelRect)); } void KisTool::updateCanvasViewRect(const QRectF &viewRect) { canvas()->updateCanvas(canvas()->viewConverter()->viewToDocument(viewRect)); } KisImageWSP KisTool::image() const { // For now, krita tools only work in krita, not for a krita shape. Krita shapes are for 2.1 KisCanvas2 * kisCanvas = dynamic_cast(canvas()); if (kisCanvas) { return kisCanvas->currentImage(); } return 0; } QCursor KisTool::cursor() const { return d->cursor; } void KisTool::notifyModified() const { if (image()) { image()->setModified(); } } KoPattern * KisTool::currentPattern() { return d->currentPattern; } KoAbstractGradient * KisTool::currentGradient() { return d->currentGradient; } KisPaintOpPresetSP KisTool::currentPaintOpPreset() { return canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); } KisNodeSP KisTool::currentNode() const { KisNodeSP node = canvas()->resourceManager()->resource(KisCanvasResourceProvider::CurrentKritaNode).value(); return node; } KisNodeList KisTool::selectedNodes() const { KisCanvas2 * kiscanvas = static_cast(canvas()); KisViewManager* viewManager = kiscanvas->viewManager(); return viewManager->nodeManager()->selectedNodes(); } KoColor KisTool::currentFgColor() { return d->currentFgColor; } KoColor KisTool::currentBgColor() { return d->currentBgColor; } KisImageWSP KisTool::currentImage() { return image(); } KisFilterConfigurationSP KisTool::currentGenerator() { return d->currentGenerator; } void KisTool::setMode(ToolMode mode) { d->m_mode = mode; } KisTool::ToolMode KisTool::mode() const { return d->m_mode; } KisTool::AlternateAction KisTool::actionToAlternateAction(ToolAction action) { KIS_ASSERT_RECOVER_RETURN_VALUE(action != Primary, Secondary); return (AlternateAction)action; } void KisTool::activatePrimaryAction() { resetCursorStyle(); } void KisTool::deactivatePrimaryAction() { resetCursorStyle(); } void KisTool::beginPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::beginPrimaryDoubleClickAction(KoPointerEvent *event) { beginPrimaryAction(event); } void KisTool::continuePrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::endPrimaryAction(KoPointerEvent *event) { Q_UNUSED(event); } bool KisTool::primaryActionSupportsHiResEvents() const { return false; } void KisTool::activateAlternateAction(AlternateAction action) { Q_UNUSED(action); } void KisTool::deactivateAlternateAction(AlternateAction action) { Q_UNUSED(action); } void KisTool::beginAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::beginAlternateDoubleClickAction(KoPointerEvent *event, AlternateAction action) { beginAlternateAction(event, action); } void KisTool::continueAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::endAlternateAction(KoPointerEvent *event, AlternateAction action) { Q_UNUSED(event); Q_UNUSED(action); } void KisTool::mouseDoubleClickEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseTripleClickEvent(KoPointerEvent *event) { mouseDoubleClickEvent(event); } void KisTool::mousePressEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseReleaseEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::mouseMoveEvent(KoPointerEvent *event) { Q_UNUSED(event); } void KisTool::deleteSelection() { KisResourcesSnapshotSP resources = new KisResourcesSnapshot(image(), currentNode(), this->canvas()->resourceManager()); KisCanvas2 * kiscanvas = static_cast(canvas()); KisViewManager* viewManager = kiscanvas->viewManager(); - viewManager->blockUntillOperationsFinished(image()); + viewManager->blockUntilOperationsFinished(image()); if (!KisToolUtils::clearImage(image(), resources->currentNode(), resources->activeSelection())) { KoToolBase::deleteSelection(); } } void KisTool::setupPaintAction(KisRecordedPaintAction* action) { action->setPaintColor(currentFgColor()); action->setBackgroundColor(currentBgColor()); } QWidget* KisTool::createOptionWidget() { d->optionWidget = new QLabel(i18n("No options")); d->optionWidget->setObjectName("SpecialSpacer"); return d->optionWidget; } #define NEAR_VAL -1000.0 #define FAR_VAL 1000.0 #define PROGRAM_VERTEX_ATTRIBUTE 0 void KisTool::paintToolOutline(QPainter* painter, const QPainterPath &path) { KisOpenGLCanvas2 *canvasWidget = dynamic_cast(canvas()->canvasWidget()); if (canvasWidget) { painter->beginNativePainting(); canvasWidget->paintToolOutline(path); painter->endNativePainting(); } else { painter->setCompositionMode(QPainter::RasterOp_SourceXorDestination); painter->setPen(QColor(128, 255, 128)); painter->drawPath(path); } } void KisTool::resetCursorStyle() { useCursor(d->cursor); } bool KisTool::overrideCursorIfNotEditable() { // override cursor for canvas iff this tool is active // and we can't paint on the active layer if (isActive()) { KisNodeSP node = currentNode(); if (node && !node->isEditable()) { canvas()->setCursor(Qt::ForbiddenCursor); return true; } } return false; } bool KisTool::isActive() const { return d->m_isActive; } void KisTool::slotToggleFgBg() { KoCanvasResourceManager* resourceManager = canvas()->resourceManager(); KoColor newFg = resourceManager->backgroundColor(); KoColor newBg = resourceManager->foregroundColor(); /** * NOTE: Some of color selectors do not differentiate foreground * and background colors, so if one wants them to end up * being set up to foreground color, it should be set the * last. */ resourceManager->setBackgroundColor(newBg); resourceManager->setForegroundColor(newFg); } void KisTool::slotResetFgBg() { KoCanvasResourceManager* resourceManager = canvas()->resourceManager(); // see a comment in slotToggleFgBg() resourceManager->setBackgroundColor(KoColor(Qt::white, KoColorSpaceRegistry::instance()->rgb8())); resourceManager->setForegroundColor(KoColor(Qt::black, KoColorSpaceRegistry::instance()->rgb8())); } void KisTool::setCurrentNodeLocked(bool locked) { if (currentNode()) { currentNode()->setSystemLocked(locked, false); } } bool KisTool::nodeEditable() { KisNodeSP node = currentNode(); if (!node) { return false; } bool nodeEditable = node->isEditable(); if (!nodeEditable) { KisCanvas2 * kiscanvas = static_cast(canvas()); QString message; if (!node->visible() && node->userLocked()) { message = i18n("Layer is locked and invisible."); } else if (node->userLocked()) { message = i18n("Layer is locked."); } else if(!node->visible()) { message = i18n("Layer is invisible."); } else { message = i18n("Group not editable."); } kiscanvas->viewManager()->showFloatingMessage(message, KisIconUtils::loadIcon("object-locked")); } return nodeEditable; } bool KisTool::selectionEditable() { KisCanvas2 * kisCanvas = static_cast(canvas()); KisViewManager * view = kisCanvas->viewManager(); bool editable = view->selectionEditable(); if (!editable) { KisCanvas2 * kiscanvas = static_cast(canvas()); kiscanvas->viewManager()->showFloatingMessage(i18n("Local selection is locked."), KisIconUtils::loadIcon("object-locked")); } return editable; } void KisTool::listenToModifiers(bool listen) { Q_UNUSED(listen); } bool KisTool::listeningToModifiers() { return false; } diff --git a/plugins/extensions/clonesarray/dlg_clonesarray.cpp b/plugins/extensions/clonesarray/dlg_clonesarray.cpp index fc5c34e789..76e3703b83 100644 --- a/plugins/extensions/clonesarray/dlg_clonesarray.cpp +++ b/plugins/extensions/clonesarray/dlg_clonesarray.cpp @@ -1,257 +1,257 @@ /* * Copyright (c) 2013 Dmitry Kazakov * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dlg_clonesarray.h" #include #include #include #include #include #include #include #include #include #include DlgClonesArray::DlgClonesArray(KisViewManager *view, QWidget *parent) : KoDialog(parent), m_view(view), m_applicator(0), m_baseLayer(m_view->activeLayer()) { Q_ASSERT(m_baseLayer); setCaption(i18n("Create Clones Array")); setButtons(Ok | Apply | Cancel); setDefaultButton(Ok); setObjectName("clones_array_dialog"); m_page = new WdgClonesArray(this); Q_CHECK_PTR(m_page); m_page->setObjectName("clones_array"); setMainWidget(m_page); resize(m_page->sizeHint()); connect(this, SIGNAL(okClicked()), SLOT(okClicked())); connect(this, SIGNAL(applyClicked()), SLOT(applyClicked())); connect(this, SIGNAL(cancelClicked()), SLOT(cancelClicked())); connect(m_page->columnXOffset, SIGNAL(valueChanged(int)), SLOT(syncOrthogonalToAngular())); connect(m_page->columnYOffset, SIGNAL(valueChanged(int)), SLOT(syncOrthogonalToAngular())); connect(m_page->rowXOffset, SIGNAL(valueChanged(int)), SLOT(syncOrthogonalToAngular())); connect(m_page->rowYOffset, SIGNAL(valueChanged(int)), SLOT(syncOrthogonalToAngular())); connect(m_page->columnDistance, SIGNAL(valueChanged(double)), SLOT(syncAngularToOrthogonal())); connect(m_page->columnAngle, SIGNAL(valueChanged(double)), SLOT(syncAngularToOrthogonal())); connect(m_page->rowDistance, SIGNAL(valueChanged(double)), SLOT(syncAngularToOrthogonal())); connect(m_page->rowAngle, SIGNAL(valueChanged(double)), SLOT(syncAngularToOrthogonal())); connect(m_page->numNegativeColumns, SIGNAL(valueChanged(int)), SLOT(setDirty())); connect(m_page->numPositiveColumns, SIGNAL(valueChanged(int)), SLOT(setDirty())); connect(m_page->numNegativeRows, SIGNAL(valueChanged(int)), SLOT(setDirty())); connect(m_page->numPositiveRows, SIGNAL(valueChanged(int)), SLOT(setDirty())); connect(m_page->numNegativeColumns, SIGNAL(valueChanged(int)), SLOT(updateCheckboxAvailability())); connect(m_page->numPositiveColumns, SIGNAL(valueChanged(int)), SLOT(updateCheckboxAvailability())); connect(m_page->numNegativeRows, SIGNAL(valueChanged(int)), SLOT(updateCheckboxAvailability())); connect(m_page->numPositiveRows, SIGNAL(valueChanged(int)), SLOT(updateCheckboxAvailability())); connect(m_page->columnPreference, SIGNAL(stateChanged(int)), SLOT(setDirty())); initializeValues(); updateCheckboxAvailability(); } DlgClonesArray::~DlgClonesArray() { delete m_page; } void DlgClonesArray::initializeValues() { if (m_baseLayer && m_baseLayer->original()) { QRect bounds = m_baseLayer->original()->exactBounds(); m_page->columnXOffset->setValue(bounds.width()); m_page->rowYOffset->setValue(bounds.height()); } } void DlgClonesArray::setDirty() { m_isDirty = true; enableButtonApply(m_isDirty); } void DlgClonesArray::setClean() { m_isDirty = false; enableButtonApply(m_isDirty); } void DlgClonesArray::updateCheckboxAvailability() { m_page->columnPreference->setEnabled( m_page->numNegativeColumns->value() > 0 || m_page->numNegativeRows->value() > 0); } void DlgClonesArray::syncOrthogonalToAngular() { setAngularSignalsEnabled(false); int x, y; x = m_page->columnXOffset->value(); y = m_page->columnYOffset->value(); m_page->columnDistance->setValue((float)sqrt(pow2(x) + pow2(y))); m_page->columnAngle->setValue(kisRadiansToDegrees(atan2((double) y, (double) x))); x = m_page->rowXOffset->value(); y = m_page->rowYOffset->value(); m_page->rowDistance->setValue((float)sqrt(pow2(x) + pow2(y))); m_page->rowAngle->setValue(kisRadiansToDegrees(atan2((double) y, (double) x))); setAngularSignalsEnabled(true); setDirty(); } void DlgClonesArray::syncAngularToOrthogonal() { setOrthogonalSignalsEnabled(false); qreal a, d; d = m_page->columnDistance->value(); a = kisDegreesToRadians(m_page->columnAngle->value()); m_page->columnXOffset->setValue(qRound(d * cos(a))); m_page->columnYOffset->setValue(qRound(d * sin(a))); d = m_page->rowDistance->value(); a = kisDegreesToRadians(m_page->rowAngle->value()); m_page->rowXOffset->setValue(qRound(d * cos(a))); m_page->rowYOffset->setValue(qRound(d * sin(a))); setOrthogonalSignalsEnabled(true); setDirty(); } void DlgClonesArray::setOrthogonalSignalsEnabled(bool value) { m_page->columnXOffset->blockSignals(!value); m_page->columnYOffset->blockSignals(!value); m_page->rowXOffset->blockSignals(!value); m_page->rowYOffset->blockSignals(!value); } void DlgClonesArray::setAngularSignalsEnabled(bool value) { m_page->columnDistance->blockSignals(!value); m_page->columnAngle->blockSignals(!value); m_page->rowDistance->blockSignals(!value); m_page->rowAngle->blockSignals(!value); } void DlgClonesArray::okClicked() { if (!m_applicator || m_isDirty) { reapplyClones(); } Q_ASSERT(m_applicator); m_applicator->end(); delete m_applicator; m_applicator = 0; } void DlgClonesArray::applyClicked() { reapplyClones(); } void DlgClonesArray::cancelClicked() { if (m_applicator) { m_applicator->cancel(); delete m_applicator; m_applicator = 0; } } void DlgClonesArray::reapplyClones() { cancelClicked(); KisImageSP image = m_view->image(); - if (!m_view->blockUntillOperationsFinished(image)) return; + if (!m_view->blockUntilOperationsFinished(image)) return; m_applicator = new KisProcessingApplicator(image, 0, KisProcessingApplicator::NONE, KisImageSignalVector() << ModifiedSignal); int columnXOffset = m_page->columnXOffset->value(); int columnYOffset = m_page->columnYOffset->value(); int rowXOffset = m_page->rowXOffset->value(); int rowYOffset = m_page->rowYOffset->value(); bool rowPreference = !m_page->columnPreference->isChecked(); int startColumn = -m_page->numNegativeColumns->value(); int startRow = -m_page->numNegativeRows->value(); int endColumn = m_page->numPositiveColumns->value() - 1; int endRow = m_page->numPositiveRows->value() - 1; QString positiveGroupName = QString(i18n("+ Array of %1")).arg(m_baseLayer->name()); KisGroupLayerSP positiveGroupLayer = new KisGroupLayer(image, positiveGroupName, OPACITY_OPAQUE_U8); m_applicator->applyCommand(new KisImageLayerAddCommand(image, positiveGroupLayer, m_baseLayer->parent(), m_baseLayer, false, true), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); KisGroupLayerSP negativeGroupLayer; if (startRow < 0 || startColumn < 0) { QString negativeGroupName = QString(i18n("- Array of %1")).arg(m_baseLayer->name()); negativeGroupLayer = new KisGroupLayer(image, negativeGroupName, OPACITY_OPAQUE_U8); m_applicator->applyCommand(new KisImageLayerAddCommand(image, negativeGroupLayer, m_baseLayer->parent(), m_baseLayer->prevSibling(), false, true), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); } for (int row = endRow; row >= startRow; row--) { for (int col = endColumn; col >= startColumn; col--) { if (!col && !row) continue; bool choosePositiveGroup = rowPreference ? row > 0 || (row == 0 && col > 0) : col > 0 || (col == 0 && row > 0); KisNodeSP parent = choosePositiveGroup ? positiveGroupLayer : negativeGroupLayer; QString cloneName = QString("Clone %1, %2").arg(col).arg(row); KisCloneLayerSP clone = new KisCloneLayer(m_baseLayer, image, cloneName, OPACITY_OPAQUE_U8); clone->setX(-row * rowXOffset + col * columnXOffset); clone->setY(-row * rowYOffset + col * columnYOffset); m_applicator->applyCommand(new KisImageLayerAddCommand(image, clone, parent, 0, true, false), KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); } } setClean(); } diff --git a/plugins/extensions/waveletdecompose/waveletdecompose.cpp b/plugins/extensions/waveletdecompose/waveletdecompose.cpp index fc77093107..b8587afa08 100644 --- a/plugins/extensions/waveletdecompose/waveletdecompose.cpp +++ b/plugins/extensions/waveletdecompose/waveletdecompose.cpp @@ -1,161 +1,161 @@ /* * Copyright (C) 2016 Miroslav Talasek * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "waveletdecompose.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dlg_waveletdecompose.h" #include "kis_node_manager.h" #include "kis_node_commands_adapter.h" #include "kis_undo_adapter.h" #include #include K_PLUGIN_FACTORY_WITH_JSON(WaveletDecomposeFactory, "kritawaveletdecompose.json", registerPlugin();) WaveletDecompose::WaveletDecompose(QObject *parent, const QVariantList &) : KisViewPlugin(parent) { KisAction *action = createAction("waveletdecompose"); connect(action, SIGNAL(triggered()), this, SLOT(slotWaveletDecompose())); } WaveletDecompose::~WaveletDecompose() { } void WaveletDecompose::slotWaveletDecompose() { DlgWaveletDecompose dlg(m_view->mainWindow(), "WaveletDecompose"); if (dlg.exec() == QDialog::Accepted) { QApplication::setOverrideCursor(Qt::WaitCursor); KoProgressUpdater* pu = m_view->createProgressUpdater(KoProgressUpdater::Unthreaded); pu->start(100, i18n("Wavelet Decompose")); QPointer updater = pu->startSubtask(); updater->setProgress(0); KisImageSP image = m_view->image(); if (!image) return; - if (!m_view->blockUntillOperationsFinished(image)) return; + if (!m_view->blockUntilOperationsFinished(image)) return; image->barrierLock(); KisPaintDeviceSP projection = new KisPaintDevice(*(image->projection()), false, 0); if (!projection) return; const KoColorSpace *cs = projection->colorSpace(); const KoCompositeOp* op = cs->compositeOp(COMPOSITE_GRAIN_EXTRACT); int scales = dlg.scales(); QList results; const QBitArray flags(0); QRect rc = image->bounds(); KisPaintDeviceSP original = projection; //main loop for(int level = 0; level < scales; ++level){ //copy original KisPaintDeviceSP blur = new KisPaintDevice(*original, false, 0); //blur it KisWaveletKernel::applyWavelet(blur, rc, 1 << level, 1 << level, flags, 0); //do grain extract blur from original KisPainter painter(original); painter.setCompositeOp(op); painter.bitBlt(0, 0, blur, 0, 0, rc.width(), rc.height()); painter.end(); //original is new scale and blur is new original results << original; original = blur; updater->setProgress((level * 100) / scales); } //add new layers KisUndoAdapter *undo = image->undoAdapter(); undo->beginMacro(kundo2_i18n("Wavelet decompose")); KisNodeCommandsAdapter adapter(m_view); KisGroupLayerSP baseGroup = image->rootLayer(); //add layer goup KisGroupLayerSP grp = new KisGroupLayer(image, i18n("Wavelet decompose"), OPACITY_OPAQUE_U8); adapter.addNode(grp, baseGroup, baseGroup->lastChild()); baseGroup = grp; //add scales int i = 1; const KoCompositeOp* op2 = cs->compositeOp(COMPOSITE_GRAIN_MERGE); Q_FOREACH (const KisPaintDeviceSP &l, results) { KisPaintLayerSP paintLayer = new KisPaintLayer(image, QStringLiteral("Scale %1").arg(i), OPACITY_OPAQUE_U8, l); adapter.addNode(paintLayer, baseGroup, 0); adapter.setCompositeOp(paintLayer, op2); ++i; } //add residual KisPaintLayerSP paintLayer = new KisPaintLayer(image, "Residual", OPACITY_OPAQUE_U8, original); adapter.addNode(paintLayer, baseGroup, 0); undo->endMacro(); updater->setProgress(100); image->unlock(); image->setModified(); } QApplication::restoreOverrideCursor(); } #include "waveletdecompose.moc"