diff --git a/krita/data/templates/animation/.directory b/krita/data/templates/animation/.directory index 548f3e2cbe..e97c8024d7 100644 --- a/krita/data/templates/animation/.directory +++ b/krita/data/templates/animation/.directory @@ -1,11 +1,15 @@ [Desktop Entry] Name=Animation Templates Name[ca]=Plantilles d'animació +Name[ca@valencia]=Plantilles d'animació +Name[cs]=Šablony animací: Name[en_GB]=Animation Templates Name[it]=Modelli di animazioni Name[nl]=Animatiesjablonen Name[pl]=Szablony animacji Name[pt]=Modelos de Animações +Name[pt_BR]=Modelos de animação +Name[sv]=Animeringsmallar Name[uk]=Шаблони анімацій Name[x-test]=xxAnimation Templatesxx X-KDE-DefaultTab=true diff --git a/krita/data/templates/animation/Anim-Jp-EN.desktop b/krita/data/templates/animation/Anim-Jp-EN.desktop index 5734b9c4e3..46f2baa38f 100644 --- a/krita/data/templates/animation/Anim-Jp-EN.desktop +++ b/krita/data/templates/animation/Anim-Jp-EN.desktop @@ -1,22 +1,23 @@ [Desktop Entry] Type=Link URL=.source/Anim-Jp-EN.kra Icon=template_animation Name=Animation-Japanese-En Name[ca]=Animació-Japonès-EN Name[ca@valencia]=Animació-Japonés-EN Name[de]=Animation-Japanisch-En Name[en_GB]=Animation-Japanese-En Name[es]=Animación-Japonés-En Name[et]=Animation-Japanese-En Name[it]=Animazione-Giapponese-EN Name[ja]=日本式アニメ(英語版) Name[nl]=Animatie-Japans-En Name[pl]=Animacja-Japońska-En Name[pt]=Animação-Japonês-EN +Name[pt_BR]=Animation-Japanese-En Name[ru]=Анимация-японская-англ Name[sk]=Animation-Japanese-En Name[sv]=Animering-japanska-en Name[uk]=Японська анімація (англійською) Name[x-test]=xxAnimation-Japanese-Enxx Name[zh_CN]=日本动画 (英式) diff --git a/krita/data/templates/animation/Anim-Jp-JP.desktop b/krita/data/templates/animation/Anim-Jp-JP.desktop index 4a773fea09..166deb207f 100644 --- a/krita/data/templates/animation/Anim-Jp-JP.desktop +++ b/krita/data/templates/animation/Anim-Jp-JP.desktop @@ -1,22 +1,23 @@ [Desktop Entry] Type=Link URL=.source/Anim-Jp-JP.kra Icon=template_animation Name=Animation-Japanese-JP Name[ca]=Animació-Japonès-JP Name[ca@valencia]=Animació-Japonés-JP Name[de]=Animation-Japanisch-JP Name[en_GB]=Animation-Japanese-JP Name[es]=Animación-Japonés-JP Name[et]=Animation-Japanese-JP Name[it]=Animazione-Giapponese-JP Name[ja]=日本式アニメ(日本語版) Name[nl]=Animatie-Japans-JP Name[pl]=Animacja-Japońska-JP Name[pt]=Animação-Japonês-JP +Name[pt_BR]=Animation-Japanese-JP Name[ru]=Анимация-японская-японск Name[sk]=Animation-Japanese-JP Name[sv]=Animering-japanska-jp Name[uk]=Японська анімація (японською) Name[x-test]=xxAnimation-Japanese-JPxx Name[zh_CN]=日本动画 (日式) diff --git a/krita/main.cc b/krita/main.cc index 44785e451e..6882c1ff8e 100644 --- a/krita/main.cc +++ b/krita/main.cc @@ -1,262 +1,266 @@ /* * Copyright (c) 1999 Matthias Elter * Copyright (c) 2002 Patrick Julien * Copyright (c) 2015 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "data/splash/splash_screen.xpm" #include "data/splash/splash_holidays.xpm" #include "KisDocument.h" #include "kis_splash_screen.h" #include "KisPart.h" #include "KisApplicationArguments.h" #include #if defined Q_OS_WIN #include #include #include #elif defined HAVE_X11 - #include - #include +#include +#include #endif #if defined HAVE_KCRASH #include #elif defined USE_DRMINGW namespace { void tryInitDrMingw() { wchar_t path[MAX_PATH]; QString pathStr = QCoreApplication::applicationDirPath().replace(L'/', L'\\') + QStringLiteral("\\exchndl.dll"); if (pathStr.size() > MAX_PATH - 1) { return; } int pathLen = pathStr.toWCharArray(path); path[pathLen] = L'\0'; // toWCharArray doesn't add NULL terminator HMODULE hMod = LoadLibraryW(path); if (!hMod) { return; } // No need to call ExcHndlInit since the crash handler is installed on DllMain auto myExcHndlSetLogFileNameA = reinterpret_cast(GetProcAddress(hMod, "ExcHndlSetLogFileNameA")); if (!myExcHndlSetLogFileNameA) { return; } // Set the log file path to %LocalAppData%\kritacrash.log QString logFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation).replace(L'/', L'\\') + QStringLiteral("\\kritacrash.log"); myExcHndlSetLogFileNameA(logFile.toLocal8Bit()); } } // namespace #endif extern "C" int main(int argc, char **argv) { // The global initialization of the random generator qsrand(time(0)); bool runningInKDE = !qgetenv("KDE_FULL_SESSION").isEmpty(); #if defined HAVE_X11 qputenv("QT_QPA_PLATFORM", "xcb"); #endif /** * Disable debug output by default. (krita.input enables tablet debugging.) * Debug logs can be controlled by an environment variable QT_LOGGING_RULES. * * As an example, to get full debug output, run the following: * export QT_LOGGING_RULES="krita*=true"; krita * * See: http://doc.qt.io/qt-5/qloggingcategory.html */ QLoggingCategory::setFilterRules("krita*.debug=false\n" "krita*.warning=true\n" "krita.tabletlog=true"); // A per-user unique string, without /, because QLocalServer cannot use names with a / in it QString key = "Krita3" + QDesktopServices::storageLocation(QDesktopServices::HomeLocation).replace("/", "_"); key = key.replace(":", "_").replace("\\","_"); QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts, true); KisOpenGL::setDefaultFormat(); QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings, true); QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true); + const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); #if QT_VERSION >= 0x050600 + QSettings kritarc(configPath + QStringLiteral("/kritarc"), QSettings::IniFormat); + if (kritarc.value("EnableHiDPI", false).toBool()) { + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + } if (!qgetenv("KRITA_HIDPI").isEmpty()) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); } #endif KLocalizedString::setApplicationDomain("krita"); // first create the application so we can create a pixmap KisApplication app(key, argc, argv); #ifdef Q_OS_LINUX qputenv("XDG_DATA_DIRS", QFile::encodeName(KoResourcePaths::getApplicationRoot() + "share") + ":" + qgetenv("XDG_DATA_DIRS")); #else qputenv("XDG_DATA_DIRS", QFile::encodeName(KoResourcePaths::getApplicationRoot() + "share")); #endif qDebug() << "Setting XDG_DATA_DIRS" << qgetenv("XDG_DATA_DIRS"); qDebug() << "Available translations" << KLocalizedString::availableApplicationTranslations(); qDebug() << "Available domain translations" << KLocalizedString::availableDomainTranslations("krita"); // Now that the paths are set, set the language. First check the override from the langage // selection dialog. - const QString configPath = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation); QSettings languageoverride(configPath + QStringLiteral("/klanguageoverridesrc"), QSettings::IniFormat); languageoverride.beginGroup(QStringLiteral("Language")); QString language = languageoverride.value(qAppName(), "").toString(); qDebug() << "Override language:" << language; if (!language.isEmpty()) { KLocalizedString::setLanguages(language.split(":")); // And override Qt's locale, too qputenv("LANG", language.split(":").first().toUtf8()); QLocale locale(language.split(":").first()); QLocale::setDefault(locale); qDebug() << "Qt ui languages" << locale.uiLanguages(); } else { // And if there isn't one, check the one set by the system. // XXX: This doesn't work, for some !@#$% reason. QLocale locale = QLocale::system(); if (locale.bcp47Name() != QStringLiteral("en")) { qputenv("LANG", locale.bcp47Name().toLatin1()); KLocalizedString::setLanguages(QStringList() << locale.bcp47Name()); } } #ifdef Q_OS_WIN QDir appdir(KoResourcePaths::getApplicationRoot()); QString path = qgetenv("PATH"); qputenv("PATH", QFile::encodeName(appdir.absolutePath() + "/bin" + ";" + appdir.absolutePath() + "/lib" + ";" + appdir.absolutePath() + "/Frameworks" + ";" + appdir.absolutePath() + ";" + path)); qDebug() << "PATH" << qgetenv("PATH"); #endif if (qApp->applicationDirPath().contains(KRITA_BUILD_DIR)) { qFatal("FATAL: You're trying to run krita from the build location. You can only run Krita from the installation location."); } #if defined HAVE_KCRASH KCrash::initialize(); #elif defined USE_DRMINGW tryInitDrMingw(); #endif // If we should clear the config, it has to be done as soon as possible after // KisApplication has been created. Otherwise the config file may have been read // and stored in a KConfig object we have no control over. app.askClearConfig(); KisApplicationArguments args(app); if (app.isRunning()) { // only pass arguments to main instance if they are not for batch processing // any batch processing would be done in this separate instance const bool batchRun = (args.print() || args.exportAs() || args.exportAsPdf()); if (!batchRun) { QByteArray ba = args.serialize(); if (app.sendMessage(ba)) { return 0; } } } if (!runningInKDE) { // Icons in menus are ugly and distracting app.setAttribute(Qt::AA_DontShowIconsInMenus); } #if defined HAVE_X11 app.installNativeEventFilter(KisXi2EventFilter::instance()); #endif // then create the pixmap from an xpm: we cannot get the // location of our datadir before we've started our components, // so use an xpm. QDate currentDate = QDate::currentDate(); QWidget *splash = 0; if (currentDate > QDate(currentDate.year(), 12, 4) || currentDate < QDate(currentDate.year(), 1, 9)) { - splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_holidays_xpm)); + splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_holidays_xpm)); } else { splash = new KisSplashScreen(app.applicationVersion(), QPixmap(splash_screen_xpm)); } app.setSplashScreen(splash); #if defined Q_OS_WIN KisTabletSupportWin::init(); // app.installNativeEventFilter(new KisTabletSupportWin()); #endif if (!app.start(args)) { return 1; } #if QT_VERSION >= 0x050700 app.setAttribute(Qt::AA_CompressHighFrequencyEvents, false); #endif // Set up remote arguments. QObject::connect(&app, SIGNAL(messageReceived(QByteArray,QObject*)), &app, SLOT(remoteArguments(QByteArray,QObject*))); QObject::connect(&app, SIGNAL(fileOpenRequest(QString)), &app, SLOT(fileOpenRequested(QString))); int state = app.exec(); return state; } diff --git a/libs/flake/CMakeLists.txt b/libs/flake/CMakeLists.txt index e9a3bbde8a..437b4c0c62 100644 --- a/libs/flake/CMakeLists.txt +++ b/libs/flake/CMakeLists.txt @@ -1,225 +1,226 @@ project(kritaflake) include_directories( ${CMAKE_SOURCE_DIR}/libs/flake/commands ${CMAKE_SOURCE_DIR}/libs/flake/tools ${CMAKE_SOURCE_DIR}/libs/flake/svg ${CMAKE_BINARY_DIR}/libs/flake ) add_subdirectory(styles) add_subdirectory(tests) set(kritaflake_SRCS KoGradientHelper.cpp KoFlake.cpp KoCanvasBase.cpp KoResourceManager_p.cpp KoDerivedResourceConverter.cpp KoResourceUpdateMediator.cpp KoCanvasResourceManager.cpp KoDocumentResourceManager.cpp KoCanvasObserverBase.cpp KoCanvasSupervisor.cpp KoDockFactoryBase.cpp KoDockRegistry.cpp KoDataCenterBase.cpp KoInsets.cpp KoPathShape.cpp KoPathPoint.cpp KoPathSegment.cpp KoSelection.cpp KoShape.cpp KoShapeAnchor.cpp KoShapeBasedDocumentBase.cpp KoShapeApplicationData.cpp KoShapeContainer.cpp KoShapeContainerModel.cpp KoShapeContainerDefaultModel.cpp KoShapeGroup.cpp KoShapeManagerPaintingStrategy.cpp KoShapeManager.cpp KoShapePaintingContext.cpp KoFrameShape.cpp KoUnavailShape.cpp KoMarkerData.cpp KoMarker.cpp KoMarkerCollection.cpp KoMarkerSharedLoadingData.cpp KoToolBase.cpp KoCanvasController.cpp KoCanvasControllerWidget.cpp KoCanvasControllerWidgetViewport_p.cpp KoShapeRegistry.cpp KoDeferredShapeFactoryBase.cpp KoToolFactoryBase.cpp KoPathShapeFactory.cpp KoShapeFactoryBase.cpp KoShapeUserData.cpp KoParameterShape.cpp KoPointerEvent.cpp KoShapeController.cpp KoToolSelection.cpp KoShapeLayer.cpp KoPostscriptPaintDevice.cpp KoInputDevice.cpp KoToolManager_p.cpp KoToolManager.cpp KoToolRegistry.cpp KoToolProxy.cpp KoShapeSavingContext.cpp KoShapeLoadingContext.cpp KoLoadingShapeUpdater.cpp KoPathShapeLoader.cpp KoShapeStrokeModel.cpp KoShapeStroke.cpp KoShapeBackground.cpp KoColorBackground.cpp KoGradientBackground.cpp KoOdfGradientBackground.cpp KoHatchBackground.cpp KoPatternBackground.cpp KoShapeConfigWidgetBase.cpp KoDrag.cpp KoDragOdfSaveHelper.cpp KoShapeOdfSaveHelper.cpp KoShapePaste.cpp KoConnectionPoint.cpp KoConnectionShape.cpp KoConnectionShapeLoadingUpdater.cpp KoConnectionShapeFactory.cpp KoConnectionShapeConfigWidget.cpp KoSnapGuide.cpp KoSnapProxy.cpp KoSnapStrategy.cpp KoSnapData.cpp KoShapeShadow.cpp KoSharedLoadingData.cpp KoSharedSavingData.cpp KoViewConverter.cpp KoInputDeviceHandler.cpp KoInputDeviceHandlerEvent.cpp KoInputDeviceHandlerRegistry.cpp KoImageData.cpp KoImageData_p.cpp KoImageCollection.cpp KoOdfWorkaround.cpp KoFilterEffect.cpp KoFilterEffectStack.cpp KoFilterEffectFactoryBase.cpp KoFilterEffectRegistry.cpp KoFilterEffectConfigWidgetBase.cpp KoFilterEffectRenderContext.cpp KoFilterEffectLoadingContext.cpp KoTextShapeDataBase.cpp KoTosContainer.cpp KoTosContainerModel.cpp KoClipPath.cpp KoCurveFit.cpp commands/KoShapeGroupCommand.cpp commands/KoShapeAlignCommand.cpp commands/KoShapeBackgroundCommand.cpp commands/KoShapeCreateCommand.cpp commands/KoShapeDeleteCommand.cpp commands/KoShapeDistributeCommand.cpp commands/KoShapeLockCommand.cpp commands/KoShapeMoveCommand.cpp commands/KoShapeShearCommand.cpp commands/KoShapeSizeCommand.cpp commands/KoShapeStrokeCommand.cpp commands/KoShapeUngroupCommand.cpp commands/KoShapeReorderCommand.cpp commands/KoShapeKeepAspectRatioCommand.cpp commands/KoPathBaseCommand.cpp commands/KoPathPointMoveCommand.cpp commands/KoPathControlPointMoveCommand.cpp commands/KoPathPointTypeCommand.cpp commands/KoPathPointRemoveCommand.cpp commands/KoPathPointInsertCommand.cpp commands/KoPathSegmentBreakCommand.cpp commands/KoPathBreakAtPointCommand.cpp commands/KoPathSegmentTypeCommand.cpp commands/KoPathCombineCommand.cpp commands/KoSubpathRemoveCommand.cpp commands/KoSubpathJoinCommand.cpp commands/KoParameterHandleMoveCommand.cpp commands/KoParameterToPathCommand.cpp commands/KoShapeTransformCommand.cpp commands/KoPathFillRuleCommand.cpp commands/KoConnectionShapeTypeCommand.cpp commands/KoShapeShadowCommand.cpp commands/KoPathReverseCommand.cpp commands/KoShapeRenameCommand.cpp commands/KoShapeRunAroundCommand.cpp commands/KoPathPointMergeCommand.cpp commands/KoShapeTransparencyCommand.cpp commands/KoShapeClipCommand.cpp commands/KoShapeUnclipCommand.cpp commands/KoPathShapeMarkerCommand.cpp commands/KoShapeConnectionChangeCommand.cpp tools/KoCreateShapeStrategy.cpp tools/KoPathToolFactory.cpp tools/KoPathTool.cpp tools/KoPathToolSelection.cpp tools/KoPathToolHandle.cpp tools/PathToolOptionWidget.cpp tools/KoPathPointRubberSelectStrategy.cpp tools/KoPathPointMoveStrategy.cpp tools/KoPathConnectionPointStrategy.cpp tools/KoPathControlPointMoveStrategy.cpp tools/KoParameterChangeStrategy.cpp tools/KoZoomTool.cpp tools/KoZoomToolFactory.cpp tools/KoZoomToolWidget.cpp tools/KoZoomStrategy.cpp tools/KoPanTool.cpp tools/KoPanToolFactory.cpp tools/KoInteractionTool.cpp tools/KoInteractionStrategy.cpp tools/KoCreateShapesTool.cpp tools/KoCreateShapesToolFactory.cpp tools/KoShapeRubberSelectStrategy.cpp tools/KoPathSegmentChangeStrategy.cpp svg/KoShapePainter.cpp svg/SvgUtil.cpp svg/SvgGraphicContext.cpp svg/SvgSavingContext.cpp svg/SvgWriter.cpp svg/SvgStyleWriter.cpp svg/SvgShape.cpp svg/SvgParser.cpp svg/SvgStyleParser.cpp svg/SvgGradientHelper.cpp svg/SvgPatternHelper.cpp svg/SvgFilterHelper.cpp svg/SvgCssHelper.cpp svg/SvgClipPathHelper.cpp svg/SvgLoadingContext.cpp svg/SvgShapeFactory.cpp FlakeDebug.cpp + tests/MockShapes.cpp ) ki18n_wrap_ui(kritaflake_SRCS tools/PathToolOptionWidgetBase.ui KoConnectionShapeConfigWidget.ui tools/KoZoomToolWidget.ui ) add_library(kritaflake SHARED ${kritaflake_SRCS}) generate_export_header(kritaflake BASE_NAME kritaflake) target_include_directories(kritaflake PUBLIC $ $ $ ) target_link_libraries(kritaflake kritapigment kritawidgetutils kritaodf kritaundo2 KF5::WidgetsAddons Qt5::Svg) set_target_properties(kritaflake PROPERTIES VERSION ${GENERIC_KRITA_LIB_VERSION} SOVERSION ${GENERIC_KRITA_LIB_SOVERSION} ) install(TARGETS kritaflake ${INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/libs/flake/KoCanvasBase.cpp b/libs/flake/KoCanvasBase.cpp index 4624eaf1f7..01d3f85940 100644 --- a/libs/flake/KoCanvasBase.cpp +++ b/libs/flake/KoCanvasBase.cpp @@ -1,122 +1,129 @@ /* This file is part of the KDE project Copyright (C) 2006 Thorsten Zachmann 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 +#include +#include #include "KoCanvasBase.h" #include "KoCanvasResourceManager.h" #include "KoShapeController.h" #include "KoCanvasController.h" #include "KoViewConverter.h" #include "KoSnapGuide.h" #include "KoShapeManager.h" #include "KoToolProxy.h" #include "KoSelection.h" class Q_DECL_HIDDEN KoCanvasBase::Private { public: - Private() : shapeController(0), + Private() + : shapeController(0), resourceManager(0), isResourceManagerShared(false), controller(0), snapGuide(0) { } ~Private() { delete shapeController; if (!isResourceManagerShared) { delete resourceManager; } delete snapGuide; } - KoShapeController *shapeController; - KoCanvasResourceManager *resourceManager; + QPointer shapeController; + QPointer resourceManager; bool isResourceManagerShared; KoCanvasController *controller; KoSnapGuide *snapGuide; }; KoCanvasBase::KoCanvasBase(KoShapeBasedDocumentBase *shapeBasedDocument, KoCanvasResourceManager *sharedResourceManager) : d(new Private()) { d->resourceManager = sharedResourceManager ? sharedResourceManager : new KoCanvasResourceManager(); d->isResourceManagerShared = sharedResourceManager; d->shapeController = new KoShapeController(this, shapeBasedDocument); d->snapGuide = new KoSnapGuide(this); } KoCanvasBase::~KoCanvasBase() { + d->shapeController->reset(); delete d; } QPointF KoCanvasBase::viewToDocument(const QPointF &viewPoint) const { return viewConverter()->viewToDocument(viewPoint - documentOrigin()); } KoShapeController *KoCanvasBase::shapeController() const { - return d->shapeController; + if (d->shapeController) + return d->shapeController; + else + return 0; } void KoCanvasBase::disconnectCanvasObserver(QObject *object) { if (shapeManager()) shapeManager()->selection()->disconnect(object); if (resourceManager()) resourceManager()->disconnect(object); if (shapeManager()) shapeManager()->disconnect(object); if (toolProxy()) toolProxy()->disconnect(object); } KoCanvasResourceManager *KoCanvasBase::resourceManager() const { return d->resourceManager; } void KoCanvasBase::ensureVisible(const QRectF &rect) { if (d->controller && d->controller->canvas()) d->controller->ensureVisible( d->controller->canvas()->viewConverter()->documentToView(rect)); } void KoCanvasBase::setCanvasController(KoCanvasController *controller) { d->controller = controller; } KoCanvasController *KoCanvasBase::canvasController() const { return d->controller; } void KoCanvasBase::clipToDocument(const KoShape *, QPointF &) const { } KoSnapGuide * KoCanvasBase::snapGuide() const { return d->snapGuide; } diff --git a/libs/flake/KoCanvasBase.h b/libs/flake/KoCanvasBase.h index 880cb54452..d8fad1ed95 100644 --- a/libs/flake/KoCanvasBase.h +++ b/libs/flake/KoCanvasBase.h @@ -1,240 +1,241 @@ /* This file is part of the KDE project Copyright (C) 2006, 2010 Boudewijn Rempt Copyright (C) 2006, 2010 Thomas Zander Copyright (C) 2006 Thorsten Zachmann 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. */ #ifndef KOCANVASBASE_H #define KOCANVASBASE_H #include #include "kritaflake_export.h" class KUndo2Command; class KoUnit; class KoCanvasResourceManager; class KoShapeManager; class KoToolProxy; class KoViewConverter; class KoShapeController; class KoShapeBasedDocumentBase; class KoCanvasController; class KoShape; class KoSnapGuide; class QWidget; class QCursor; -class QObject; class QPointF; class QRectF; class QSizeF; +#include + /** * KoCanvasBase is the interface actual application canvas classes * should implement. Flake tools know about the canvas, so they can * do things like scroll, redraw, set a cursor etc. */ -class KRITAFLAKE_EXPORT KoCanvasBase +class KRITAFLAKE_EXPORT KoCanvasBase : public QObject { - + Q_OBJECT public: /** * The constructor. * @param shapeBasedDocument the implementation of the shapeController that the * application provides to allow shapes to be added in multiple views. */ explicit KoCanvasBase(KoShapeBasedDocumentBase *shapeBasedDocument, KoCanvasResourceManager *sharedResourceManager = 0); virtual ~KoCanvasBase(); public: /** * @return true if opengl can be used directly on the canvas */ virtual bool canvasIsOpenGL() const { return false; } /** * retrieve the grid size setting. * The grid spacing will be provided in pt. * @param horizontal a pointer to a qreal that will be filled with the horizontal grid-spacing * @param vertical a pointer to a qreal that will be filled with the vertical grid-spacing */ virtual void gridSize(QPointF *offset, QSizeF *spacing) const = 0; /** * return if snap to grid is enabled. * @return if snap to grid is enabled. */ virtual bool snapToGrid() const = 0; /** * set the specified cursor on this canvas * * @param cursor the new cursor * @return the old cursor */ virtual void setCursor(const QCursor &cursor) = 0; /** * Adds a command to the history. Call this for each @p command you create. * This will also execute the command. * This means, most of the application's code will look like * MyCommand * cmd = new MyCommand( parameters ); * canvas.addCommand( cmd ); * * Note that the command history takes ownership of the command, it will delete * it when the undo limit is reached, or when deleting the command history itself. * @param command the command to add */ virtual void addCommand(KUndo2Command *command) = 0; /** * return the current shapeManager * @return the current shapeManager */ virtual KoShapeManager *shapeManager() const = 0; /** * Tell the canvas to repaint the specified rectangle. The coordinates * are document coordinates, not view coordinates. */ virtual void updateCanvas(const QRectF &rc) = 0; /** * Return the proxy to the active tool (determining which tool * is really, really active is hard when tablets are involved, * so leave that to others. */ virtual KoToolProxy *toolProxy() const = 0; /** * Return the viewConverter for this view. * @return the viewConverter for this view. */ virtual KoViewConverter *viewConverter() const = 0; /** * Convert a coordinate in pixels to pt. * @param viewPoint the point in the coordinate system of the widget, or window. */ virtual QPointF viewToDocument(const QPointF &viewPoint) const; /** * Return the widget that will be added to the scrollArea. */ virtual QWidget *canvasWidget() = 0; /** * Return the widget that will be added to the scrollArea. */ virtual const QWidget *canvasWidget() const = 0; /** * Return the unit of the current document for initialization of the widgets created * by the flake framework. * @see KoDocument::unit() */ virtual KoUnit unit() const = 0; /** * Called when the user tries to move the argument shape to allow the application to limit the * users movement to stay within the document bounds. * An implementation can alter the parameter move to make sure that if the distance moved * is applied to the shape it will not become unreachable for the user. * The default implementation does not restrict movement. * @param shape the shape that will be moved soon. * @param move the distance the caller intends to move the shape. */ virtual void clipToDocument(const KoShape *shape, QPointF &move) const; /** * Return the position of the document origin inside the canvas widget, in pixels. * By default the origin of the canvas widget and the position of the * document origin are coincident, thus an empty point is returned. */ virtual QPoint documentOrigin() const { return QPoint(0, 0); } /** * This method should somehow call QWidget::updateMicroFocus() on the canvas widget. */ virtual void updateInputMethodInfo() = 0; /** * disconnect the given QObject completely and utterly from any and all * connections it has to any QObject owned by the canvas. Do this in * the setCanvas of every KoCanvasObserver. */ virtual void disconnectCanvasObserver(QObject *object); /** * Return a pointer to the resource manager associated with this * canvas. The resource manager contains per-canvas settings such * as current foreground and background color. * If instead of per-canvas resources you need per-document resources * you can by going via the shapeController instead; * @code * canvasBase->shapeController()->resourceManager(); * @endcode * @see KoShapeController::resourceManager() */ KoCanvasResourceManager *resourceManager() const; /** * Return the shape controller for this canvas. * A shape controller is used to create or delete shapes and show the relevant dialogs to the user. */ KoShapeController *shapeController() const; /** * Return the canvas controller for this canvas. */ KoCanvasController *canvasController() const; /** * @brief Scrolls the content of the canvas so that the given rect is visible. * * The rect is to be specified in document coordinates. * * @param rect the rectangle to make visible */ virtual void ensureVisible(const QRectF &rect); /** * Returns the snap guide of the canvas */ KoSnapGuide *snapGuide() const; /// called by KoCanvasController to set the controller that handles this canvas. void setCanvasController(KoCanvasController *controller); private: // we need a KoShapeBasedDocumentBase so that it can work KoCanvasBase(); class Private; Private * const d; }; #endif // KOCANVASBASE_H diff --git a/libs/flake/KoCanvasControllerWidget.cpp b/libs/flake/KoCanvasControllerWidget.cpp index b94cd533e2..d2164b01f8 100644 --- a/libs/flake/KoCanvasControllerWidget.cpp +++ b/libs/flake/KoCanvasControllerWidget.cpp @@ -1,593 +1,598 @@ /* This file is part of the KDE project * * Copyright (C) 2006, 2008-2009 Thomas Zander * Copyright (C) 2006 Peter Simonsson * Copyright (C) 2006, 2009 Thorsten Zachmann * Copyright (C) 2007-2010 Boudewijn Rempt * Copyright (C) 2007 C. Boemann * Copyright (C) 2006-2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoCanvasControllerWidget.h" #include "KoCanvasControllerWidget_p.h" #include "KoCanvasControllerWidgetViewport_p.h" #include "KoShape.h" #include "KoViewConverter.h" #include "KoCanvasBase.h" #include "KoCanvasObserverBase.h" #include "KoCanvasSupervisor.h" #include "KoToolManager_p.h" #include #include #include #include #include #include #include #include #include #include void KoCanvasControllerWidget::Private::setDocumentOffset() { // The margins scroll the canvas widget inside the viewport, not // the document. The documentOffset is meant to be the value that // the canvas must add to the update rect in its paint event, to // compensate. QPoint pt(q->horizontalScrollBar()->value(), q->verticalScrollBar()->value()); q->proxyObject->emitMoveDocumentOffset(pt); QWidget *canvasWidget = canvas->canvasWidget(); if (canvasWidget) { // If it isn't an OpenGL canvas if (qobject_cast(canvasWidget) == 0) { QPoint diff = q->documentOffset() - pt; if (q->canvasMode() == Spreadsheet && canvasWidget->layoutDirection() == Qt::RightToLeft) { canvasWidget->scroll(-diff.x(), diff.y()); } else { canvasWidget->scroll(diff.x(), diff.y()); } } } q->setDocumentOffset(pt); } void KoCanvasControllerWidget::Private::resetScrollBars() { // The scrollbar value always points at the top-left corner of the // bit of image we paint. int docH = q->documentSize().height() + q->margin(); int docW = q->documentSize().width() + q->margin(); int drawH = viewportWidget->height(); int drawW = viewportWidget->width(); QScrollBar *hScroll = q->horizontalScrollBar(); QScrollBar *vScroll = q->verticalScrollBar(); int horizontalReserve = vastScrollingFactor * drawW; int verticalReserve = vastScrollingFactor * drawH; int xMin = -horizontalReserve; int yMin = -verticalReserve; int xMax = docW - drawW + horizontalReserve; int yMax = docH - drawH + verticalReserve; hScroll->setRange(xMin, xMax); vScroll->setRange(yMin, yMax); int fontheight = QFontMetrics(q->font()).height(); vScroll->setPageStep(drawH); vScroll->setSingleStep(fontheight); hScroll->setPageStep(drawW); hScroll->setSingleStep(fontheight); } void KoCanvasControllerWidget::Private::emitPointerPositionChangedSignals(QEvent *event) { if (!canvas) return; if (!canvas->viewConverter()) return; QPoint pointerPos; QMouseEvent *mouseEvent = dynamic_cast(event); if (mouseEvent) { pointerPos = mouseEvent->pos(); } else { QTabletEvent *tabletEvent = dynamic_cast(event); if (tabletEvent) { pointerPos = tabletEvent->pos(); } } QPoint pixelPos = (pointerPos - canvas->documentOrigin()) + q->documentOffset(); QPointF documentPos = canvas->viewConverter()->viewToDocument(pixelPos); q->proxyObject->emitDocumentMousePositionChanged(documentPos); q->proxyObject->emitCanvasMousePositionChanged(pointerPos); } #include void KoCanvasControllerWidget::Private::activate() { QWidget *parent = q; while (parent->parentWidget()) { parent = parent->parentWidget(); } KoCanvasSupervisor *observerProvider = dynamic_cast(parent); if (!observerProvider) { return; } + + KoCanvasBase *canvas = q->canvas(); Q_FOREACH (KoCanvasObserverBase *docker, observerProvider->canvasObservers()) { KoCanvasObserverBase *observer = dynamic_cast(docker); if (observer) { - observer->setObservedCanvas(q->canvas()); + observer->setObservedCanvas(canvas); } } } -void KoCanvasControllerWidget::Private::unsetCanvas() +void KoCanvasControllerWidget::Private::unsetCanvas(KoCanvasBase *canvas) { QWidget *parent = q; while (parent->parentWidget()) { parent = parent->parentWidget(); } KoCanvasSupervisor *observerProvider = dynamic_cast(parent); if (!observerProvider) { return; } Q_FOREACH (KoCanvasObserverBase *docker, observerProvider->canvasObservers()) { KoCanvasObserverBase *observer = dynamic_cast(docker); - if (observer && observer->observedCanvas() == q->canvas()) { - observer->unsetObservedCanvas(); + if (observer) { + if (!canvas || observer->observedCanvas() == q->canvas()) { + observer->unsetObservedCanvas(); + } } } } //////////// KoCanvasControllerWidget::KoCanvasControllerWidget(KActionCollection * actionCollection, QWidget *parent) : QAbstractScrollArea(parent) , KoCanvasController(actionCollection) , d(new Private(this)) { // We need to set this as QDeclarativeView sets them a bit differnt from QAbstractScrollArea setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // And then our own Viewport d->viewportWidget = new Viewport(this); setViewport(d->viewportWidget); d->viewportWidget->setFocusPolicy(Qt::NoFocus); setFocusPolicy(Qt::NoFocus); setFrameStyle(0); //setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); setAutoFillBackground(false); /* Fixes: apps starting at zero zoom. Details: Since the document is set on the mainwindow before loading commences the inial show/layout can choose to set the document to be very small, even to be zero pixels tall. Setting a sane minimum size on the widget means we no loger get rounding errors in zooming and we no longer end up with zero-zoom. Note: KoPage apps should probably startup with a sane document size; for Krita that's impossible */ setMinimumSize(QSize(50, 50)); setMouseTracking(true); connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateCanvasOffsetX())); connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(updateCanvasOffsetY())); connect(d->viewportWidget, SIGNAL(sizeChanged()), this, SLOT(updateCanvasOffsetX())); connect(proxyObject, SIGNAL(moveDocumentOffset(const QPoint&)), d->viewportWidget, SLOT(documentOffsetMoved(const QPoint&))); } KoCanvasControllerWidget::~KoCanvasControllerWidget() { - d->unsetCanvas(); + d->unsetCanvas(0); delete d; } void KoCanvasControllerWidget::activate() { d->activate(); } void KoCanvasControllerWidget::scrollContentsBy(int dx, int dy) { Q_UNUSED(dx); Q_UNUSED(dy); d->setDocumentOffset(); } QSize KoCanvasControllerWidget::viewportSize() const { return viewport()->size(); } void KoCanvasControllerWidget::setDrawShadow(bool drawShadow) { d->viewportWidget->setDrawShadow(drawShadow); } void KoCanvasControllerWidget::resizeEvent(QResizeEvent *resizeEvent) { proxyObject->emitSizeChanged(resizeEvent->size()); // XXX: When resizing, keep the area we're looking at now in the // center of the resized view. d->resetScrollBars(); d->setDocumentOffset(); } void KoCanvasControllerWidget::setCanvas(KoCanvasBase *canvas) { Q_ASSERT(canvas); // param is not null if (d->canvas) { - d->unsetCanvas(); + d->unsetCanvas(canvas); proxyObject->emitCanvasRemoved(this); canvas->setCanvasController(0); d->canvas->canvasWidget()->removeEventFilter(this); } canvas->setCanvasController(this); d->canvas = canvas; changeCanvasWidget(canvas->canvasWidget()); proxyObject->emitCanvasSet(this); QTimer::singleShot(0, this, SLOT(activate())); setPreferredCenterFractionX(0); setPreferredCenterFractionY(0); } KoCanvasBase* KoCanvasControllerWidget::canvas() const { + if (d->canvas.isNull()) return 0; return d->canvas; } void KoCanvasControllerWidget::changeCanvasWidget(QWidget *widget) { if (d->viewportWidget->canvas()) { widget->setCursor(d->viewportWidget->canvas()->cursor()); d->viewportWidget->canvas()->removeEventFilter(this); } d->viewportWidget->setCanvas(widget); setFocusProxy(d->canvas->canvasWidget()); } int KoCanvasControllerWidget::visibleHeight() const { if (d->canvas == 0) return 0; QWidget *canvasWidget = canvas()->canvasWidget(); int height1; if (canvasWidget == 0) height1 = viewport()->height(); else height1 = qMin(viewport()->height(), canvasWidget->height()); int height2 = height(); return qMin(height1, height2); } int KoCanvasControllerWidget::visibleWidth() const { if (d->canvas == 0) return 0; QWidget *canvasWidget = canvas()->canvasWidget(); int width1; if (canvasWidget == 0) width1 = viewport()->width(); else width1 = qMin(viewport()->width(), canvasWidget->width()); int width2 = width(); return qMin(width1, width2); } int KoCanvasControllerWidget::canvasOffsetX() const { int offset = -horizontalScrollBar()->value(); if (d->canvas) { offset += d->canvas->canvasWidget()->x() + frameWidth(); } return offset; } int KoCanvasControllerWidget::canvasOffsetY() const { int offset = -verticalScrollBar()->value(); if (d->canvas) { offset += d->canvas->canvasWidget()->y() + frameWidth(); } return offset; } void KoCanvasControllerWidget::updateCanvasOffsetX() { proxyObject->emitCanvasOffsetXChanged(canvasOffsetX()); if (d->ignoreScrollSignals) return; setPreferredCenterFractionX((horizontalScrollBar()->value() + viewport()->width() / 2.0) / documentSize().width()); } void KoCanvasControllerWidget::updateCanvasOffsetY() { proxyObject->emitCanvasOffsetYChanged(canvasOffsetY()); if (d->ignoreScrollSignals) return; setPreferredCenterFractionY((verticalScrollBar()->value() + verticalScrollBar()->pageStep() / 2.0) / documentSize().height()); } void KoCanvasControllerWidget::ensureVisible(KoShape *shape) { Q_ASSERT(shape); ensureVisible(d->canvas->viewConverter()->documentToView(shape->boundingRect())); } void KoCanvasControllerWidget::ensureVisible(const QRectF &rect, bool smooth) { QRect currentVisible(-canvasOffsetX(), -canvasOffsetY(), visibleWidth(), visibleHeight()); QRect viewRect = rect.toRect(); viewRect.translate(d->canvas->documentOrigin()); if (!viewRect.isValid() || currentVisible.contains(viewRect)) return; // its visible. Nothing to do. // if we move, we move a little more so the amount of times we have to move is less. int jumpWidth = smooth ? 0 : currentVisible.width() / 5; int jumpHeight = smooth ? 0 : currentVisible.height() / 5; if (!smooth && viewRect.width() + jumpWidth > currentVisible.width()) jumpWidth = 0; if (!smooth && viewRect.height() + jumpHeight > currentVisible.height()) jumpHeight = 0; int horizontalMove = 0; if (currentVisible.width() <= viewRect.width()) // center view horizontalMove = viewRect.center().x() - currentVisible.center().x(); else if (currentVisible.x() > viewRect.x()) // move left horizontalMove = viewRect.x() - currentVisible.x() - jumpWidth; else if (currentVisible.right() < viewRect.right()) // move right horizontalMove = viewRect.right() - qMax(0, currentVisible.right() - jumpWidth); int verticalMove = 0; if (currentVisible.height() <= viewRect.height()) // center view verticalMove = viewRect.center().y() - currentVisible.center().y(); if (currentVisible.y() > viewRect.y()) // move up verticalMove = viewRect.y() - currentVisible.y() - jumpHeight; else if (currentVisible.bottom() < viewRect.bottom()) // move down verticalMove = viewRect.bottom() - qMax(0, currentVisible.bottom() - jumpHeight); pan(QPoint(horizontalMove, verticalMove)); } void KoCanvasControllerWidget::recenterPreferred() { const bool oldIgnoreScrollSignals = d->ignoreScrollSignals; d->ignoreScrollSignals = true; QPointF center = preferredCenter(); // convert into a viewport based point center.rx() += d->canvas->canvasWidget()->x() + frameWidth(); center.ry() += d->canvas->canvasWidget()->y() + frameWidth(); // scroll to a new center point QPointF topLeft = center - 0.5 * QPointF(viewport()->width(), viewport()->height()); setScrollBarValue(topLeft.toPoint()); d->ignoreScrollSignals = oldIgnoreScrollSignals; } void KoCanvasControllerWidget::zoomIn(const QPoint ¢er) { zoomBy(center, sqrt(2.0)); } void KoCanvasControllerWidget::zoomOut(const QPoint ¢er) { zoomBy(center, sqrt(0.5)); } void KoCanvasControllerWidget::zoomBy(const QPoint ¢er, qreal zoom) { setPreferredCenterFractionX(1.0 * center.x() / documentSize().width()); setPreferredCenterFractionY(1.0 * center.y() / documentSize().height()); const bool oldIgnoreScrollSignals = d->ignoreScrollSignals; d->ignoreScrollSignals = true; proxyObject->emitZoomRelative(zoom, preferredCenter()); d->ignoreScrollSignals = oldIgnoreScrollSignals; } void KoCanvasControllerWidget::zoomTo(const QRect &viewRect) { qreal scale; if (1.0 * viewport()->width() / viewRect.width() > 1.0 * viewport()->height() / viewRect.height()) scale = 1.0 * viewport()->height() / viewRect.height(); else scale = 1.0 * viewport()->width() / viewRect.width(); zoomBy(viewRect.center(), scale); } void KoCanvasControllerWidget::updateDocumentSize(const QSize &sz, bool recalculateCenter) { // Don't update if the document-size didn't changed to prevent infinite loops and unneeded updates. if (KoCanvasController::documentSize() == sz) return; if (!recalculateCenter) { // assume the distance from the top stays equal and recalculate the center. setPreferredCenterFractionX(documentSize().width() * preferredCenterFractionX() / sz.width()); setPreferredCenterFractionY(documentSize().height() * preferredCenterFractionY() / sz.height()); } const bool oldIgnoreScrollSignals = d->ignoreScrollSignals; d->ignoreScrollSignals = true; KoCanvasController::setDocumentSize(sz); d->viewportWidget->setDocumentSize(sz); d->resetScrollBars(); // Always emit the new offset. updateCanvasOffsetX(); updateCanvasOffsetY(); d->ignoreScrollSignals = oldIgnoreScrollSignals; } void KoCanvasControllerWidget::setZoomWithWheel(bool zoom) { d->zoomWithWheel = zoom; } void KoCanvasControllerWidget::setVastScrolling(qreal factor) { d->vastScrollingFactor = factor; } void KoCanvasControllerWidget::pan(const QPoint &distance) { QPoint sourcePoint = scrollBarValue(); setScrollBarValue(sourcePoint + distance); } void KoCanvasControllerWidget::setPreferredCenter(const QPointF &viewPoint) { setPreferredCenterFractionX(viewPoint.x() / documentSize().width()); setPreferredCenterFractionY(viewPoint.y() / documentSize().height()); recenterPreferred(); } QPointF KoCanvasControllerWidget::preferredCenter() const { QPointF center; center.setX(preferredCenterFractionX() * documentSize().width()); center.setY(preferredCenterFractionY() * documentSize().height()); return center; } void KoCanvasControllerWidget::paintEvent(QPaintEvent *event) { QPainter gc(viewport()); d->viewportWidget->handlePaintEvent(gc, event); } void KoCanvasControllerWidget::dragEnterEvent(QDragEnterEvent *event) { d->viewportWidget->handleDragEnterEvent(event); } void KoCanvasControllerWidget::dropEvent(QDropEvent *event) { d->viewportWidget->handleDropEvent(event); } void KoCanvasControllerWidget::dragMoveEvent(QDragMoveEvent *event) { d->viewportWidget->handleDragMoveEvent(event); } void KoCanvasControllerWidget::dragLeaveEvent(QDragLeaveEvent *event) { d->viewportWidget->handleDragLeaveEvent(event); } void KoCanvasControllerWidget::keyPressEvent(QKeyEvent *event) { KoToolManager::instance()->priv()->switchToolByShortcut(event); } void KoCanvasControllerWidget::wheelEvent(QWheelEvent *event) { if (d->zoomWithWheel != ((event->modifiers() & Qt::ControlModifier) == Qt::ControlModifier)) { const qreal zoomCoeff = event->delta() > 0 ? sqrt(2.0) : sqrt(0.5); zoomRelativeToPoint(event->pos(), zoomCoeff); event->accept(); } else QAbstractScrollArea::wheelEvent(event); } void KoCanvasControllerWidget::zoomRelativeToPoint(const QPoint &widgetPoint, qreal zoomCoeff) { const QPoint offset = scrollBarValue(); const QPoint mousePos(widgetPoint + offset); const bool oldIgnoreScrollSignals = d->ignoreScrollSignals; d->ignoreScrollSignals = true; proxyObject->emitZoomRelative(zoomCoeff, mousePos); d->ignoreScrollSignals = oldIgnoreScrollSignals; } bool KoCanvasControllerWidget::focusNextPrevChild(bool) { // we always return false meaning the canvas takes keyboard focus, but never gives it away. return false; } void KoCanvasControllerWidget::setMargin(int margin) { KoCanvasController::setMargin(margin); Q_ASSERT(d->viewportWidget); d->viewportWidget->setMargin(margin); } QPoint KoCanvasControllerWidget::scrollBarValue() const { QScrollBar * hBar = horizontalScrollBar(); QScrollBar * vBar = verticalScrollBar(); return QPoint(hBar->value(), vBar->value()); } void KoCanvasControllerWidget::setScrollBarValue(const QPoint &value) { QScrollBar * hBar = horizontalScrollBar(); QScrollBar * vBar = verticalScrollBar(); hBar->setValue(value.x()); vBar->setValue(value.y()); } KoCanvasControllerWidget::Private *KoCanvasControllerWidget::priv() { return d; } //have to include this because of Q_PRIVATE_SLOT #include "moc_KoCanvasControllerWidget.cpp" diff --git a/libs/flake/KoCanvasControllerWidget_p.h b/libs/flake/KoCanvasControllerWidget_p.h index 5529f0b588..b715738c98 100644 --- a/libs/flake/KoCanvasControllerWidget_p.h +++ b/libs/flake/KoCanvasControllerWidget_p.h @@ -1,68 +1,68 @@ /* This file is part of the KDE project * * Copyright (C) 2006, 2008-2009 Thomas Zander * Copyright (C) 2006 Peter Simonsson * Copyright (C) 2006, 2009 Thorsten Zachmann * Copyright (C) 2007-2010 Boudewijn Rempt * Copyright (C) 2007 C. Boemann * Copyright (C) 2006-2008 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef KoCanvasControllerWidget_p_h #define KoCanvasControllerWidget_p_h #include #include class KoCanvasControllerWidget; class Viewport; class KoCanvasBase; class Q_DECL_HIDDEN KoCanvasControllerWidget::Private { public: Private(KoCanvasControllerWidget *qq) : q(qq) , canvas(0) , ignoreScrollSignals(false) , zoomWithWheel(false) , vastScrollingFactor(0) { } /** * Gets called by the tool manager if this canvas controller is the current active canvas controller. */ void setDocumentOffset(); void resetScrollBars(); void emitPointerPositionChangedSignals(QEvent *event); void activate(); - void unsetCanvas(); + void unsetCanvas(KoCanvasBase *canvas); KoCanvasControllerWidget *q; - KoCanvasBase *canvas; + QPointer canvas; Viewport *viewportWidget; bool ignoreScrollSignals; bool zoomWithWheel; qreal vastScrollingFactor; }; #endif diff --git a/libs/flake/KoCanvasObserverBase.cpp b/libs/flake/KoCanvasObserverBase.cpp index b3e9a192fd..c56538b7bc 100644 --- a/libs/flake/KoCanvasObserverBase.cpp +++ b/libs/flake/KoCanvasObserverBase.cpp @@ -1,60 +1,62 @@ /* This file is part of the KDE project * Copyright (C) 2007 Thomas Zander * * 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 "KoCanvasObserverBase.h" +#include +#include class KoCanvasObserverBasePrivate { public: KoCanvasObserverBasePrivate() : canvas(0) {} ~KoCanvasObserverBasePrivate() {} - KoCanvasBase* canvas; + QPointer canvas; }; KoCanvasObserverBase::KoCanvasObserverBase() : d(new KoCanvasObserverBasePrivate) { } KoCanvasObserverBase::~KoCanvasObserverBase() { delete d; } void KoCanvasObserverBase::setObservedCanvas(KoCanvasBase* canvas) { d->canvas = canvas; setCanvas(canvas); } void KoCanvasObserverBase::unsetObservedCanvas() { d->canvas = 0; unsetCanvas(); } KoCanvasBase* KoCanvasObserverBase::observedCanvas() const { return d->canvas; } diff --git a/libs/flake/KoCanvasResourceManager.cpp b/libs/flake/KoCanvasResourceManager.cpp index 45f2189de4..79b3a93279 100644 --- a/libs/flake/KoCanvasResourceManager.cpp +++ b/libs/flake/KoCanvasResourceManager.cpp @@ -1,197 +1,197 @@ /* Copyright (c) 2006 Boudewijn Rempt (boud@valdyas.org) Copyright (C) 2007, 2010 Thomas Zander Copyright (c) 2008 Carlos Licea Copyright (c) 2011 Jan Hambrecht This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "KoCanvasResourceManager.h" #include #include #include "KoShape.h" #include "KoShapeStroke.h" #include "KoResourceManager_p.h" #include class Q_DECL_HIDDEN KoCanvasResourceManager::Private { public: KoResourceManager manager; }; KoCanvasResourceManager::KoCanvasResourceManager(QObject *parent) - : QObject(parent), - d(new Private()) + : QObject(parent) + , d(new Private()) { const KoColorSpace* cs = KoColorSpaceRegistry::instance()->rgb8(); setForegroundColor(KoColor(Qt::black, cs)); setBackgroundColor(KoColor(Qt::white, cs)); setResource(ApplicationSpeciality, NoSpecial); connect(&d->manager, &KoResourceManager::resourceChanged, this, &KoCanvasResourceManager::canvasResourceChanged); } KoCanvasResourceManager::~KoCanvasResourceManager() { delete d; } void KoCanvasResourceManager::setResource(int key, const QVariant &value) { d->manager.setResource(key, value); } QVariant KoCanvasResourceManager::resource(int key) const { return d->manager.resource(key); } void KoCanvasResourceManager::setResource(int key, const KoColor &color) { QVariant v; v.setValue(color); setResource(key, v); } void KoCanvasResourceManager::setResource(int key, KoShape *shape) { QVariant v; v.setValue(shape); setResource(key, v); } void KoCanvasResourceManager::setResource(int key, const KoUnit &unit) { QVariant v; v.setValue(unit); setResource(key, v); } KoColor KoCanvasResourceManager::koColorResource(int key) const { return d->manager.koColorResource(key); } void KoCanvasResourceManager::setForegroundColor(const KoColor &color) { setResource(ForegroundColor, color); } KoColor KoCanvasResourceManager::foregroundColor() const { return koColorResource(ForegroundColor); } void KoCanvasResourceManager::setBackgroundColor(const KoColor &color) { setResource(BackgroundColor, color); } KoColor KoCanvasResourceManager::backgroundColor() const { return koColorResource(BackgroundColor); } KoShape *KoCanvasResourceManager::koShapeResource(int key) const { return d->manager.koShapeResource(key); } KoUnit KoCanvasResourceManager::unitResource(int key) const { return resource(key).value(); } void KoCanvasResourceManager::setActiveStroke(const KoShapeStroke &stroke) { QVariant v; v.setValue(stroke); setResource(ActiveStroke, v); } KoShapeStroke KoCanvasResourceManager::activeStroke() const { if (!d->manager.hasResource(ActiveStroke)) { KoShapeStroke empty; return empty; } return resource(ActiveStroke).value(); } bool KoCanvasResourceManager::boolResource(int key) const { return d->manager.boolResource(key); } int KoCanvasResourceManager::intResource(int key) const { return d->manager.intResource(key); } QString KoCanvasResourceManager::stringResource(int key) const { return d->manager.stringResource(key); } QSizeF KoCanvasResourceManager::sizeResource(int key) const { return d->manager.sizeResource(key); } bool KoCanvasResourceManager::hasResource(int key) const { return d->manager.hasResource(key); } void KoCanvasResourceManager::clearResource(int key) { d->manager.clearResource(key); } void KoCanvasResourceManager::addDerivedResourceConverter(KoDerivedResourceConverterSP converter) { d->manager.addDerivedResourceConverter(converter); } bool KoCanvasResourceManager::hasDerivedResourceConverter(int key) { return d->manager.hasDerivedResourceConverter(key); } void KoCanvasResourceManager::removeDerivedResourceConverter(int key) { d->manager.removeDerivedResourceConverter(key); } void KoCanvasResourceManager::addResourceUpdateMediator(KoResourceUpdateMediatorSP mediator) { d->manager.addResourceUpdateMediator(mediator); } bool KoCanvasResourceManager::hasResourceUpdateMediator(int key) { return d->manager.hasResourceUpdateMediator(key); } void KoCanvasResourceManager::removeResourceUpdateMediator(int key) { d->manager.removeResourceUpdateMediator(key); } diff --git a/libs/flake/KoShapeBasedDocumentBase.cpp b/libs/flake/KoShapeBasedDocumentBase.cpp index fc13c9e9c0..6883607383 100644 --- a/libs/flake/KoShapeBasedDocumentBase.cpp +++ b/libs/flake/KoShapeBasedDocumentBase.cpp @@ -1,82 +1,84 @@ /* This file is part of the KDE project Copyright (C) 2006, 2010 Thomas Zander Copyright (C) 2011 Jan Hambrecht This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ +#include + #include "KoShapeBasedDocumentBase.h" #include "KoDocumentResourceManager.h" #include "KoShapeRegistry.h" #include "KoShapeFactoryBase.h" #include #include #include class KoShapeBasedDocumentBasePrivate { public: KoShapeBasedDocumentBasePrivate() : resourceManager(new KoDocumentResourceManager()) { KoShapeRegistry *registry = KoShapeRegistry::instance(); foreach (const QString &id, registry->keys()) { KoShapeFactoryBase *shapeFactory = registry->value(id); shapeFactory->newDocumentResourceManager(resourceManager); } // read persistent application wide resources KSharedConfigPtr config = KSharedConfig::openConfig(); if (config->hasGroup("Misc")) { KConfigGroup miscGroup = config->group("Misc"); const qreal pasteOffset = miscGroup.readEntry("CopyOffset", 10.0); resourceManager->setPasteOffset(pasteOffset); const bool pasteAtCursor = miscGroup.readEntry("PasteAtCursor", true); resourceManager->enablePasteAtCursor(pasteAtCursor); const uint grabSensitivity = miscGroup.readEntry("GrabSensitivity", 3); resourceManager->setGrabSensitivity(grabSensitivity); const uint handleRadius = miscGroup.readEntry("HandleRadius", 3); resourceManager->setHandleRadius(handleRadius); } } ~KoShapeBasedDocumentBasePrivate() { delete resourceManager; } - KoDocumentResourceManager *resourceManager; + QPointer resourceManager; }; KoShapeBasedDocumentBase::KoShapeBasedDocumentBase() : d(new KoShapeBasedDocumentBasePrivate()) { } KoShapeBasedDocumentBase::~KoShapeBasedDocumentBase() { delete d; } void KoShapeBasedDocumentBase::shapesRemoved(const QList & /*shapes*/, KUndo2Command * /*command*/) { } KoDocumentResourceManager *KoShapeBasedDocumentBase::resourceManager() const { return d->resourceManager; } diff --git a/libs/flake/KoShapeController.cpp b/libs/flake/KoShapeController.cpp index 7d4559247a..840cabd945 100644 --- a/libs/flake/KoShapeController.cpp +++ b/libs/flake/KoShapeController.cpp @@ -1,185 +1,191 @@ /* This file is part of the KDE project * * Copyright (C) 2006-2007, 2010 Thomas Zander * Copyright (C) 2006-2008 Thorsten Zachmann * Copyright (C) 2011 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "KoShapeController.h" #include "KoShapeBasedDocumentBase.h" #include "KoShapeRegistry.h" #include "KoDocumentResourceManager.h" #include "KoShapeManager.h" #include "KoShapeLayer.h" #include "KoSelection.h" #include "commands/KoShapeCreateCommand.h" #include "commands/KoShapeDeleteCommand.h" #include "commands/KoShapeConnectionChangeCommand.h" #include "KoCanvasBase.h" #include "KoShapeConfigWidgetBase.h" #include "KoShapeFactoryBase.h" #include "KoShape.h" #include "KoConnectionShape.h" #include #include #include #include class KoShapeController::Private { public: Private() : canvas(0), shapeBasedDocument(0) { } KoCanvasBase *canvas; KoShapeBasedDocumentBase *shapeBasedDocument; KUndo2Command* addShape(KoShape *shape, bool showDialog, KUndo2Command *parent) { if (canvas) { if (showDialog) { KoShapeFactoryBase *factory = KoShapeRegistry::instance()->value(shape->shapeId()); Q_ASSERT(factory); int z = 0; Q_FOREACH (KoShape *sh, canvas->shapeManager()->shapes()) z = qMax(z, sh->zIndex()); shape->setZIndex(z + 1); // show config dialog. KPageDialog *dialog = new KPageDialog(canvas->canvasWidget()); dialog->setWindowTitle(i18n("%1 Options", factory->name())); int pageCount = 0; QList widgets; Q_FOREACH (KoShapeConfigWidgetBase* panel, factory->createShapeOptionPanels()) { if (! panel->showOnShapeCreate()) continue; panel->open(shape); panel->connect(panel, SIGNAL(accept()), dialog, SLOT(accept())); widgets.append(panel); panel->setResourceManager(canvas->resourceManager()); panel->setUnit(canvas->unit()); QString title = panel->windowTitle().isEmpty() ? panel->objectName() : panel->windowTitle(); dialog->addPage(panel, title); pageCount ++; } if (pageCount > 0) { if (pageCount > 1) dialog->setFaceType(KPageDialog::Tabbed); if (dialog->exec() != KPageDialog::Accepted) { delete dialog; return 0; } Q_FOREACH (KoShapeConfigWidgetBase *widget, widgets) widget->save(); } delete dialog; } // set the active layer as parent if there is not yet a parent. if (!shape->parent()) { shape->setParent(canvas->shapeManager()->selection()->activeLayer()); } } return new KoShapeCreateCommand(shapeBasedDocument, shape, parent); } void handleAttachedConnections(KoShape *shape, KUndo2Command *parentCmd) { foreach (KoShape *dependee, shape->dependees()) { KoConnectionShape *connection = dynamic_cast(dependee); if (connection) { if (shape == connection->firstShape()) { new KoShapeConnectionChangeCommand(connection, KoConnectionShape::StartHandle, shape, connection->firstConnectionId(), 0, -1, parentCmd); } else if (shape == connection->secondShape()) { new KoShapeConnectionChangeCommand(connection, KoConnectionShape::EndHandle, shape, connection->secondConnectionId(), 0, -1, parentCmd); } } } } }; KoShapeController::KoShapeController(KoCanvasBase *canvas, KoShapeBasedDocumentBase *shapeBasedDocument) : d(new Private()) { d->canvas = canvas; d->shapeBasedDocument = shapeBasedDocument; if (shapeBasedDocument) { shapeBasedDocument->resourceManager()->setShapeController(this); } } KoShapeController::~KoShapeController() { delete d; } +void KoShapeController::reset() +{ + d->canvas = 0; + d->shapeBasedDocument = 0; +} + KUndo2Command* KoShapeController::addShape(KoShape *shape, KUndo2Command *parent) { return d->addShape(shape, true, parent); } KUndo2Command* KoShapeController::addShapeDirect(KoShape *shape, KUndo2Command *parent) { return d->addShape(shape, false, parent); } KUndo2Command* KoShapeController::removeShape(KoShape *shape, KUndo2Command *parent) { KUndo2Command *cmd = new KoShapeDeleteCommand(d->shapeBasedDocument, shape, parent); QList shapes; shapes.append(shape); d->shapeBasedDocument->shapesRemoved(shapes, cmd); // detach shape from any attached connection shapes d->handleAttachedConnections(shape, cmd); return cmd; } KUndo2Command* KoShapeController::removeShapes(const QList &shapes, KUndo2Command *parent) { KUndo2Command *cmd = new KoShapeDeleteCommand(d->shapeBasedDocument, shapes, parent); d->shapeBasedDocument->shapesRemoved(shapes, cmd); foreach (KoShape *shape, shapes) { d->handleAttachedConnections(shape, cmd); } return cmd; } void KoShapeController::setShapeControllerBase(KoShapeBasedDocumentBase *shapeBasedDocument) { d->shapeBasedDocument = shapeBasedDocument; } KoDocumentResourceManager *KoShapeController::resourceManager() const { if (!d->shapeBasedDocument) return 0; return d->shapeBasedDocument->resourceManager(); } KoShapeBasedDocumentBase *KoShapeController::documentBase() const { return d->shapeBasedDocument; } diff --git a/libs/flake/KoShapeController.h b/libs/flake/KoShapeController.h index 42f7d45068..793fa9ffd0 100644 --- a/libs/flake/KoShapeController.h +++ b/libs/flake/KoShapeController.h @@ -1,135 +1,143 @@ /* This file is part of the KDE project * * Copyright (C) 2006-2007, 2010 Thomas Zander * Copyright (C) 2006-2008 Thorsten Zachmann * * 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. */ #ifndef KOSHAPECONTROLLER_H #define KOSHAPECONTROLLER_H #include "kritaflake_export.h" +#include #include #include class KoCanvasBase; class KoShape; class KoShapeBasedDocumentBase; class KUndo2Command; class KoDocumentResourceManager; /** * Class used by tools to maintain the list of shapes. * All applications have some sort of list of all shapes that belong to the document. * The applications implement the KoShapeBasedDocumentBase interface (all pure virtuals) * to add and remove shapes from the document. To ensure that an application can expect * a certain protocol to be adhered to when adding/removing shapes, all tools use the API * from this class for maintaining the list of shapes in the document. So no tool gets * to access the application directly. */ -class KRITAFLAKE_EXPORT KoShapeController +class KRITAFLAKE_EXPORT KoShapeController : public QObject { + Q_OBJECT + public: /** * Create a new Controller; typically not called by applications, only * by the KonCanvasBase constructor. * @param canvas the canvas this controller works for. The canvas can be 0 * @param shapeBasedDocument the application provided shapeBasedDocument that we can call. */ KoShapeController(KoCanvasBase *canvas, KoShapeBasedDocumentBase *shapeBasedDocument); /// destructor ~KoShapeController(); + /** + * @brief reset sets the canvas and shapebased document to 0. + */ + void reset(); + /** * @brief Add a shape to the document. * If the shape has no parent, the active layer will become its parent. * * @param shape to add to the document * @param parent the parent command if the resulting command is a compound undo command. * * @return command which will insert the shape into the document or 0 if the * insertion was cancelled. The command is not yet executed. */ KUndo2Command* addShape(KoShape *shape, KUndo2Command *parent = 0); /** * @brief Add a shape to the document, skipping any dialogs or other user interaction. * * @param shape to add to the document * @param parent the parent command if the resulting command is a compound undo command. * * @return command which will insert the shape into the document. The command is not yet executed. */ KUndo2Command* addShapeDirect(KoShape *shape, KUndo2Command *parent = 0); /** * @brief Remove a shape from the document. * * @param shape to remove from the document * @param parent the parent command if the resulting command is a compound undo command. * * @return command which will remove the shape from the document. * The command is not yet executed. */ KUndo2Command* removeShape(KoShape *shape, KUndo2Command *parent = 0); /** * Remove a shape from the document. * * @param shapes the set of shapes to remove from the document * @param parent the parent command if the resulting command is a compound undo command. * * @return command which will remove the shape from the document. * The command is not yet executed. */ KUndo2Command* removeShapes(const QList &shapes, KUndo2Command *parent = 0); /** * @brief Set the KoShapeBasedDocumentBase used to add/remove shapes. * * NOTE: only Sheets uses this method. Do not use it in your application. Sheets * has to also call: * KoToolManager::instance()->updateShapeControllerBase(shapeBasedDocument, canvas->canvasController()); * * @param shapeBasedDocument the new shapeBasedDocument. */ void setShapeControllerBase(KoShapeBasedDocumentBase *shapeBasedDocument); /** * Return a pointer to the resource manager associated with the * shape-set (typically a document). The resource manager contains * document wide resources * such as variable managers, the image * collection and others. */ KoDocumentResourceManager *resourceManager() const; /** * @brief Returns the KoShapeBasedDocumentBase used to add/remove shapes. * * @return the KoShapeBasedDocumentBase */ KoShapeBasedDocumentBase *documentBase() const; private: class Private; Private * const d; }; Q_DECLARE_METATYPE(KoShapeController *) #endif diff --git a/libs/flake/tests/MockShapes.cpp b/libs/flake/tests/MockShapes.cpp new file mode 100644 index 0000000000..cac2024943 --- /dev/null +++ b/libs/flake/tests/MockShapes.cpp @@ -0,0 +1,3 @@ +#include + +#include diff --git a/libs/flake/tests/MockShapes.h b/libs/flake/tests/MockShapes.h index 9f6da0bdb0..c4878b8a59 100644 --- a/libs/flake/tests/MockShapes.h +++ b/libs/flake/tests/MockShapes.h @@ -1,216 +1,220 @@ /* * This file is part of Calligra tests * * Copyright (C) 2006-2010 Thomas Zander * * 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 MOCKSHAPES_H #define MOCKSHAPES_H #include #include #include #include #include #include "KoShapeManager.h" #include "FlakeDebug.h" #include "KoSnapData.h" #include "KoUnit.h" -class MockShape : public KoShape +#include "kritaflake_export.h" + + +class KRITAFLAKE_EXPORT MockShape : public KoShape { public: MockShape() : paintedCount(0) {} void paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &) { Q_UNUSED(painter); Q_UNUSED(converter); //qDebug() << "Shape" << kBacktrace( 10 ); paintedCount++; } virtual void saveOdf(KoShapeSavingContext &) const {} virtual bool loadOdf(const KoXmlElement &, KoShapeLoadingContext &) { return true; } int paintedCount; }; -class MockContainer : public KoShapeContainer +class KRITAFLAKE_EXPORT MockContainer : public KoShapeContainer { public: MockContainer(KoShapeContainerModel *model = 0) : KoShapeContainer(model), paintedCount(0) {} void paintComponent(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &) { Q_UNUSED(painter); Q_UNUSED(converter); //qDebug() << "Container:" << kBacktrace( 10 ); paintedCount++; } virtual void saveOdf(KoShapeSavingContext &) const {} virtual bool loadOdf(const KoXmlElement &, KoShapeLoadingContext &) { return true; } int paintedCount; }; -class MockGroup : public KoShapeGroup +class KRITAFLAKE_EXPORT MockGroup : public KoShapeGroup { void paintComponent(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &) { Q_UNUSED(painter); Q_UNUSED(converter); } }; class KoToolProxy; -class MockCanvas : public KoCanvasBase +class KRITAFLAKE_EXPORT MockCanvas : public KoCanvasBase { + Q_OBJECT public: MockCanvas(KoShapeBasedDocumentBase *aKoShapeBasedDocumentBase =0)//made for TestSnapStrategy.cpp : KoCanvasBase(aKoShapeBasedDocumentBase), m_shapeManager(new KoShapeManager(this)) {} ~MockCanvas() {} void setHorz(qreal pHorz){ m_horz = pHorz; } void setVert(qreal pVert){ m_vert = pVert; } void gridSize(QPointF *offset, QSizeF *spacing) const { Q_UNUSED(offset); spacing->setWidth(m_horz); spacing->setHeight(m_vert); } bool snapToGrid() const { return true; } void addCommand(KUndo2Command*) { } KoShapeManager *shapeManager() const { return m_shapeManager; } void updateCanvas(const QRectF&) {} KoToolProxy * toolProxy() const { return 0; } KoViewConverter *viewConverter() const { return 0; } QWidget* canvasWidget() { return 0; } const QWidget* canvasWidget() const { return 0; } KoUnit unit() const { return KoUnit(KoUnit::Millimeter); } void updateInputMethodInfo() {} void setCursor(const QCursor &) {} private: KoShapeManager *m_shapeManager; qreal m_horz; qreal m_vert; }; -class MockShapeController : public KoShapeBasedDocumentBase +class KRITAFLAKE_EXPORT MockShapeController : public KoShapeBasedDocumentBase { public: void addShape(KoShape* shape) { m_shapes.insert(shape); } void removeShape(KoShape* shape) { m_shapes.remove(shape); } bool contains(KoShape* shape) { return m_shapes.contains(shape); } private: QSet m_shapes; }; class MockContainerModel : public KoShapeContainerModel { public: MockContainerModel() { resetCounts(); } /// reimplemented void add(KoShape *child) { m_children.append(child); // note that we explicitly do not check for duplicates here! } /// reimplemented void remove(KoShape *child) { m_children.removeAll(child); } /// reimplemented void setClipped(const KoShape *, bool) { } // ignored /// reimplemented bool isClipped(const KoShape *) const { return false; }// ignored /// reimplemented bool isChildLocked(const KoShape *child) const { return child->isGeometryProtected(); } /// reimplemented int count() const { return m_children.count(); } /// reimplemented QList shapes() const { return m_children; } /// reimplemented void containerChanged(KoShapeContainer *, KoShape::ChangeType) { m_containerChangedCalled++; } /// reimplemented void proposeMove(KoShape *, QPointF &) { m_proposeMoveCalled++; } /// reimplemented void childChanged(KoShape *, KoShape::ChangeType) { m_childChangedCalled++; } void setInheritsTransform(const KoShape *, bool) { } bool inheritsTransform(const KoShape *) const { return false; } int containerChangedCalled() const { return m_containerChangedCalled; } int childChangedCalled() const { return m_childChangedCalled; } int proposeMoveCalled() const { return m_proposeMoveCalled; } void resetCounts() { m_containerChangedCalled = 0; m_childChangedCalled = 0; m_proposeMoveCalled = 0; } private: QList m_children; int m_containerChangedCalled, m_childChangedCalled, m_proposeMoveCalled; }; #endif diff --git a/libs/image/commands/kis_image_set_projection_color_space_command.cpp b/libs/image/commands/kis_image_set_projection_color_space_command.cpp index e4d2a3293f..3eb9b8dfd7 100644 --- a/libs/image/commands/kis_image_set_projection_color_space_command.cpp +++ b/libs/image/commands/kis_image_set_projection_color_space_command.cpp @@ -1,52 +1,53 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 Sven Langkamp * * 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_image_commands.h" #include "KoColorSpace.h" #include "kis_image.h" #include KisImageSetProjectionColorSpaceCommand::KisImageSetProjectionColorSpaceCommand(KisImageWSP image, const KoColorSpace * afterColorSpace) : KisImageCommand(kundo2_i18n("Convert Image Type"), image) { KisImageSP imageSP = image.toStrongRef(); if (imageSP) { m_beforeColorSpace = imageSP->colorSpace(); m_afterColorSpace = afterColorSpace; + imageSP->setProjectionColorSpace(m_afterColorSpace); } } void KisImageSetProjectionColorSpaceCommand::redo() { KisImageSP image = m_image.toStrongRef(); if (image) { image->setProjectionColorSpace(m_afterColorSpace); } } void KisImageSetProjectionColorSpaceCommand::undo() { KisImageSP image = m_image.toStrongRef(); if (image) { image->setProjectionColorSpace(m_beforeColorSpace); } } diff --git a/libs/image/kis_image.cc b/libs/image/kis_image.cc index f934895b59..fefeedf1ff 100644 --- a/libs/image/kis_image.cc +++ b/libs/image/kis_image.cc @@ -1,1696 +1,1697 @@ /* * Copyright (c) 2002 Patrick Julien * Copyright (c) 2007 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_image.h" #include // WORDS_BIGENDIAN #include #include #include #include #include #include #include #include #include #include #include "KoColorSpaceRegistry.h" #include "KoColor.h" #include "KoColorProfile.h" #include #include "KisProofingConfiguration.h" #include "recorder/kis_action_recorder.h" #include "kis_adjustment_layer.h" #include "kis_annotation.h" #include "kis_change_profile_visitor.h" #include "kis_colorspace_convert_visitor.h" #include "kis_count_visitor.h" #include "kis_filter_strategy.h" #include "kis_group_layer.h" #include "commands/kis_image_commands.h" #include "kis_layer.h" #include "kis_meta_data_merge_strategy_registry.h" #include "kis_name_server.h" #include "kis_paint_layer.h" #include "kis_painter.h" #include "kis_selection.h" #include "kis_transaction.h" #include "kis_meta_data_merge_strategy.h" #include "kis_memory_statistics_server.h" #include "kis_image_config.h" #include "kis_update_scheduler.h" #include "kis_image_signal_router.h" #include "kis_image_animation_interface.h" #include "kis_stroke_strategy.h" #include "kis_image_barrier_locker.h" #include "kis_undo_stores.h" #include "kis_legacy_undo_adapter.h" #include "kis_post_execution_undo_adapter.h" #include "kis_transform_worker.h" #include "kis_processing_applicator.h" #include "processing/kis_crop_processing_visitor.h" #include "processing/kis_crop_selections_processing_visitor.h" #include "processing/kis_transform_processing_visitor.h" #include "commands_new/kis_image_resize_command.h" #include "commands_new/kis_image_set_resolution_command.h" #include "commands_new/kis_activate_selection_mask_command.h" #include "kis_composite_progress_proxy.h" #include "kis_layer_composition.h" #include "kis_wrapped_rect.h" #include "kis_crop_saved_extra_data.h" #include "kis_layer_utils.h" #include "kis_lod_transform.h" #include "kis_suspend_projection_updates_stroke_strategy.h" #include "kis_sync_lod_cache_stroke_strategy.h" #include "kis_projection_updates_filter.h" #include "kis_layer_projection_plane.h" #include "kis_update_time_monitor.h" #include "kis_image_barrier_locker.h" #include #include #include "kis_time_range.h" // #define SANITY_CHECKS #ifdef SANITY_CHECKS #define SANITY_CHECK_LOCKED(name) \ if (!locked()) warnKrita() << "Locking policy failed:" << name \ << "has been called without the image" \ "being locked"; #else #define SANITY_CHECK_LOCKED(name) #endif struct KisImageSPStaticRegistrar { KisImageSPStaticRegistrar() { qRegisterMetaType("KisImageSP"); } }; static KisImageSPStaticRegistrar __registrar; class KisImage::KisImagePrivate { public: KisImagePrivate(KisImage *_q, qint32 w, qint32 h, const KoColorSpace *c, KisUndoStore *undo, KisImageAnimationInterface *_animationInterface) : q(_q) , lockedForReadOnly(false) , width(w) , height(h) , colorSpace(c ? c : KoColorSpaceRegistry::instance()->rgb8()) , nserver(1) , undoStore(undo ? undo : new KisDumbUndoStore()) , legacyUndoAdapter(undoStore.data(), _q) , postExecutionUndoAdapter(undoStore.data(), _q) , recorder(_q) , signalRouter(_q) , animationInterface(_animationInterface) , scheduler(_q) , axesCenter(QPointF(0.5, 0.5)) { { KisImageConfig cfg; if (cfg.enableProgressReporting()) { scheduler.setProgressProxy(&compositeProgressProxy); } // Each of these lambdas defines a new factory function. scheduler.setLod0ToNStrokeStrategyFactory( [=](bool forgettable) { return KisLodSyncPair( new KisSyncLodCacheStrokeStrategy(KisImageWSP(q), forgettable), KisSyncLodCacheStrokeStrategy::createJobsData(KisImageWSP(q))); }); scheduler.setSuspendUpdatesStrokeStrategyFactory( [=]() { return KisSuspendResumePair( new KisSuspendProjectionUpdatesStrokeStrategy(KisImageWSP(q), true), KisSuspendProjectionUpdatesStrokeStrategy::createSuspendJobsData(KisImageWSP(q))); }); scheduler.setResumeUpdatesStrokeStrategyFactory( [=]() { return KisSuspendResumePair( new KisSuspendProjectionUpdatesStrokeStrategy(KisImageWSP(q), false), KisSuspendProjectionUpdatesStrokeStrategy::createResumeJobsData(KisImageWSP(q))); }); } connect(q, SIGNAL(sigImageModified()), KisMemoryStatisticsServer::instance(), SLOT(notifyImageChanged())); } ~KisImagePrivate() { /** * Stop animation interface. It may use the rootLayer. */ delete animationInterface; /** * First delete the nodes, while strokes * and undo are still alive */ rootLayer.clear(); } KisImage *q; quint32 lockCount = 0; bool lockedForReadOnly; qint32 width; qint32 height; double xres = 1.0; double yres = 1.0; const KoColorSpace * colorSpace; KisProofingConfigurationSP proofingConfig; KisSelectionSP deselectedGlobalSelection; KisGroupLayerSP rootLayer; // The layers are contained in here QList compositions; KisNodeSP isolatedRootNode; bool wrapAroundModePermitted = false; KisNameServer nserver; QScopedPointer undoStore; KisLegacyUndoAdapter legacyUndoAdapter; KisPostExecutionUndoAdapter postExecutionUndoAdapter; KisActionRecorder recorder; vKisAnnotationSP annotations; QAtomicInt disableUIUpdateSignals; KisProjectionUpdatesFilterSP projectionUpdatesFilter; KisImageSignalRouter signalRouter; KisImageAnimationInterface *animationInterface; KisUpdateScheduler scheduler; QAtomicInt disableDirtyRequests; KisCompositeProgressProxy compositeProgressProxy; bool blockLevelOfDetail = false; QPointF axesCenter; bool tryCancelCurrentStrokeAsync(); void notifyProjectionUpdatedInPatches(const QRect &rc); }; KisImage::KisImage(KisUndoStore *undoStore, qint32 width, qint32 height, const KoColorSpace * colorSpace, const QString& name) : QObject(0) , KisShared() , m_d(new KisImagePrivate(this, width, height, colorSpace, undoStore, new KisImageAnimationInterface(this))) { setObjectName(name); setRootLayer(new KisGroupLayer(this, "root", OPACITY_OPAQUE_U8)); } KisImage::~KisImage() { qDebug() << "deleting kisimage" << objectName(); /** * Request the tools to end currently running strokes */ waitForDone(); delete m_d; disconnect(); // in case Qt gets confused } KisImage *KisImage::clone(bool exactCopy) { return new KisImage(*this, 0, exactCopy); } KisImage::KisImage(const KisImage& rhs, KisUndoStore *undoStore, bool exactCopy) : KisNodeFacade(), KisNodeGraphListener(), KisShared(), m_d(new KisImagePrivate(this, rhs.width(), rhs.height(), rhs.colorSpace(), undoStore ? undoStore : new KisDumbUndoStore(), new KisImageAnimationInterface(*rhs.animationInterface(), this))) { setObjectName(rhs.objectName()); m_d->xres = rhs.m_d->xres; m_d->yres = rhs.m_d->yres; if (rhs.m_d->proofingConfig) { m_d->proofingConfig = toQShared(new KisProofingConfiguration(*rhs.m_d->proofingConfig)); } KisNodeSP newRoot = rhs.root()->clone(); newRoot->setGraphListener(this); newRoot->setImage(this); m_d->rootLayer = dynamic_cast(newRoot.data()); setRoot(newRoot); if (exactCopy) { QQueue linearizedNodes; KisLayerUtils::recursiveApplyNodes(rhs.root(), [&linearizedNodes](KisNodeSP node) { linearizedNodes.enqueue(node); }); KisLayerUtils::recursiveApplyNodes(newRoot, [&linearizedNodes](KisNodeSP node) { KisNodeSP refNode = linearizedNodes.dequeue(); node->setUuid(refNode->uuid()); }); } Q_FOREACH (KisLayerCompositionSP comp, rhs.m_d->compositions) { m_d->compositions << toQShared(new KisLayerComposition(*comp, this)); } rhs.m_d->nserver = KisNameServer(rhs.m_d->nserver); vKisAnnotationSP newAnnotations; Q_FOREACH (KisAnnotationSP annotation, rhs.m_d->annotations) { newAnnotations << annotation->clone(); } m_d->annotations = newAnnotations; KIS_ASSERT_RECOVER_NOOP(!rhs.m_d->projectionUpdatesFilter); KIS_ASSERT_RECOVER_NOOP(!rhs.m_d->disableUIUpdateSignals); KIS_ASSERT_RECOVER_NOOP(!rhs.m_d->disableDirtyRequests); m_d->blockLevelOfDetail = rhs.m_d->blockLevelOfDetail; } void KisImage::aboutToAddANode(KisNode *parent, int index) { KisNodeGraphListener::aboutToAddANode(parent, index); SANITY_CHECK_LOCKED("aboutToAddANode"); } void KisImage::nodeHasBeenAdded(KisNode *parent, int index) { KisNodeGraphListener::nodeHasBeenAdded(parent, index); SANITY_CHECK_LOCKED("nodeHasBeenAdded"); m_d->signalRouter.emitNodeHasBeenAdded(parent, index); KisNodeSP newNode = parent->at(index); if (!dynamic_cast(newNode.data())) { stopIsolatedMode(); } } void KisImage::aboutToRemoveANode(KisNode *parent, int index) { KisNodeSP deletedNode = parent->at(index); if (!dynamic_cast(deletedNode.data())) { stopIsolatedMode(); } KisNodeGraphListener::aboutToRemoveANode(parent, index); SANITY_CHECK_LOCKED("aboutToRemoveANode"); m_d->signalRouter.emitAboutToRemoveANode(parent, index); } void KisImage::nodeChanged(KisNode* node) { KisNodeGraphListener::nodeChanged(node); requestStrokeEnd(); m_d->signalRouter.emitNodeChanged(node); } void KisImage::invalidateAllFrames() { invalidateFrames(KisTimeRange::infinite(0), QRect()); } KisSelectionSP KisImage::globalSelection() const { KisSelectionMaskSP selectionMask = m_d->rootLayer->selectionMask(); if (selectionMask) { return selectionMask->selection(); } else { return 0; } } void KisImage::setGlobalSelection(KisSelectionSP globalSelection) { KisSelectionMaskSP selectionMask = m_d->rootLayer->selectionMask(); if (!globalSelection) { if (selectionMask) { removeNode(selectionMask); } } else { if (!selectionMask) { selectionMask = new KisSelectionMask(this); selectionMask->initSelection(m_d->rootLayer); addNode(selectionMask); // If we do not set the selection now, the setActive call coming next // can be very, very expensive, depending on the size of the image. selectionMask->setSelection(globalSelection); selectionMask->setActive(true); } else { selectionMask->setSelection(globalSelection); } Q_ASSERT(m_d->rootLayer->childCount() > 0); Q_ASSERT(m_d->rootLayer->selectionMask()); } m_d->deselectedGlobalSelection = 0; m_d->legacyUndoAdapter.emitSelectionChanged(); } void KisImage::deselectGlobalSelection() { KisSelectionSP savedSelection = globalSelection(); setGlobalSelection(0); m_d->deselectedGlobalSelection = savedSelection; } bool KisImage::canReselectGlobalSelection() { return m_d->deselectedGlobalSelection; } void KisImage::reselectGlobalSelection() { if(m_d->deselectedGlobalSelection) { setGlobalSelection(m_d->deselectedGlobalSelection); } } QString KisImage::nextLayerName(const QString &_baseName) const { QString baseName = _baseName; if (m_d->nserver.currentSeed() == 0) { m_d->nserver.number(); return i18n("background"); } if (baseName.isEmpty()) { baseName = i18n("Layer"); } return QString("%1 %2").arg(baseName).arg(m_d->nserver.number()); } void KisImage::rollBackLayerName() { m_d->nserver.rollback(); } KisCompositeProgressProxy* KisImage::compositeProgressProxy() { return &m_d->compositeProgressProxy; } bool KisImage::locked() const { return m_d->lockCount != 0; } void KisImage::barrierLock(bool readOnly) { if (!locked()) { requestStrokeEnd(); m_d->scheduler.barrierLock(); m_d->lockedForReadOnly = readOnly; } else { m_d->lockedForReadOnly &= readOnly; } m_d->lockCount++; } bool KisImage::tryBarrierLock(bool readOnly) { bool result = true; if (!locked()) { result = m_d->scheduler.tryBarrierLock(); m_d->lockedForReadOnly = readOnly; } if (result) { m_d->lockCount++; m_d->lockedForReadOnly &= readOnly; } return result; } bool KisImage::isIdle(bool allowLocked) { return (allowLocked || !locked()) && m_d->scheduler.isIdle(); } void KisImage::lock() { if (!locked()) { requestStrokeEnd(); m_d->scheduler.lock(); } m_d->lockCount++; m_d->lockedForReadOnly = false; } void KisImage::unlock() { Q_ASSERT(locked()); if (locked()) { m_d->lockCount--; if (m_d->lockCount == 0) { m_d->scheduler.unlock(!m_d->lockedForReadOnly); } } } void KisImage::blockUpdates() { m_d->scheduler.blockUpdates(); } void KisImage::unblockUpdates() { m_d->scheduler.unblockUpdates(); } void KisImage::setSize(const QSize& size) { m_d->width = size.width(); m_d->height = size.height(); } void KisImage::resizeImageImpl(const QRect& newRect, bool cropLayers) { if (newRect == bounds() && !cropLayers) return; KUndo2MagicString actionName = cropLayers ? kundo2_i18n("Crop Image") : kundo2_i18n("Resize Image"); KisImageSignalVector emitSignals; emitSignals << ComplexSizeChangedSignal(newRect, newRect.size()); emitSignals << ModifiedSignal; KisCropSavedExtraData *extraData = new KisCropSavedExtraData(cropLayers ? KisCropSavedExtraData::CROP_IMAGE : KisCropSavedExtraData::RESIZE_IMAGE, newRect); KisProcessingApplicator applicator(this, m_d->rootLayer, KisProcessingApplicator::RECURSIVE | KisProcessingApplicator::NO_UI_UPDATES, emitSignals, actionName, extraData); if (cropLayers || !newRect.topLeft().isNull()) { KisProcessingVisitorSP visitor = new KisCropProcessingVisitor(newRect, cropLayers, true); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); } applicator.applyCommand(new KisImageResizeCommand(this, newRect.size())); applicator.end(); } void KisImage::resizeImage(const QRect& newRect) { resizeImageImpl(newRect, false); } void KisImage::cropImage(const QRect& newRect) { resizeImageImpl(newRect, true); } void KisImage::cropNode(KisNodeSP node, const QRect& newRect) { bool isLayer = qobject_cast(node.data()); KUndo2MagicString actionName = isLayer ? kundo2_i18n("Crop Layer") : kundo2_i18n("Crop Mask"); KisImageSignalVector emitSignals; emitSignals << ModifiedSignal; KisCropSavedExtraData *extraData = new KisCropSavedExtraData(KisCropSavedExtraData::CROP_LAYER, newRect, node); KisProcessingApplicator applicator(this, node, KisProcessingApplicator::RECURSIVE, emitSignals, actionName, extraData); KisProcessingVisitorSP visitor = new KisCropProcessingVisitor(newRect, true, false); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); applicator.end(); } void KisImage::scaleImage(const QSize &size, qreal xres, qreal yres, KisFilterStrategy *filterStrategy) { bool resolutionChanged = xres != xRes() && yres != yRes(); bool sizeChanged = size != this->size(); if (!resolutionChanged && !sizeChanged) return; KisImageSignalVector emitSignals; if (resolutionChanged) emitSignals << ResolutionChangedSignal; if (sizeChanged) emitSignals << ComplexSizeChangedSignal(bounds(), size); emitSignals << ModifiedSignal; KUndo2MagicString actionName = sizeChanged ? kundo2_i18n("Scale Image") : kundo2_i18n("Change Image Resolution"); KisProcessingApplicator::ProcessingFlags signalFlags = (resolutionChanged || sizeChanged) ? KisProcessingApplicator::NO_UI_UPDATES : KisProcessingApplicator::NONE; KisProcessingApplicator applicator(this, m_d->rootLayer, KisProcessingApplicator::RECURSIVE | signalFlags, emitSignals, actionName); qreal sx = qreal(size.width()) / this->size().width(); qreal sy = qreal(size.height()) / this->size().height(); QTransform shapesCorrection; if (resolutionChanged) { shapesCorrection = QTransform::fromScale(xRes() / xres, yRes() / yres); } KisProcessingVisitorSP visitor = new KisTransformProcessingVisitor(sx, sy, 0, 0, QPointF(), 0, 0, 0, filterStrategy, shapesCorrection); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); if (resolutionChanged) { KUndo2Command *parent = new KisResetShapesCommand(m_d->rootLayer); new KisImageSetResolutionCommand(this, xres, yres, parent); applicator.applyCommand(parent); } if (sizeChanged) { applicator.applyCommand(new KisImageResizeCommand(this, size)); } applicator.end(); } void KisImage::scaleNode(KisNodeSP node, qreal scaleX, qreal scaleY, KisFilterStrategy *filterStrategy) { KUndo2MagicString actionName(kundo2_i18n("Scale Layer")); KisImageSignalVector emitSignals; emitSignals << ModifiedSignal; KisProcessingApplicator applicator(this, node, KisProcessingApplicator::RECURSIVE, emitSignals, actionName); KisProcessingVisitorSP visitor = new KisTransformProcessingVisitor(scaleX, scaleY, 0, 0, QPointF(), 0, 0, 0, filterStrategy); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); applicator.end(); } void KisImage::rotateImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, bool resizeImage, double radians) { QPointF offset; QSize newSize; { KisTransformWorker worker(0, 1.0, 1.0, 0, 0, 0, 0, radians, 0, 0, 0, 0); QTransform transform = worker.transform(); if (resizeImage) { QRect newRect = transform.mapRect(bounds()); newSize = newRect.size(); offset = -newRect.topLeft(); } else { QPointF origin = QRectF(rootNode->exactBounds()).center(); newSize = size(); offset = -(transform.map(origin) - origin); } } bool sizeChanged = resizeImage && (newSize.width() != width() || newSize.height() != height()); // These signals will be emitted after processing is done KisImageSignalVector emitSignals; if (sizeChanged) emitSignals << ComplexSizeChangedSignal(bounds(), newSize); emitSignals << ModifiedSignal; // These flags determine whether updates are transferred to the UI during processing KisProcessingApplicator::ProcessingFlags signalFlags = sizeChanged ? KisProcessingApplicator::NO_UI_UPDATES : KisProcessingApplicator::NONE; KisProcessingApplicator applicator(this, rootNode, KisProcessingApplicator::RECURSIVE | signalFlags, emitSignals, actionName); KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value("Bicubic"); KisProcessingVisitorSP visitor = new KisTransformProcessingVisitor(1.0, 1.0, 0.0, 0.0, QPointF(), radians, offset.x(), offset.y(), filter); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); if (sizeChanged) { applicator.applyCommand(new KisImageResizeCommand(this, newSize)); } applicator.end(); } void KisImage::rotateImage(double radians) { rotateImpl(kundo2_i18n("Rotate Image"), root(), true, radians); } void KisImage::rotateNode(KisNodeSP node, double radians) { rotateImpl(kundo2_i18n("Rotate Layer"), node, false, radians); } void KisImage::shearImpl(const KUndo2MagicString &actionName, KisNodeSP rootNode, bool resizeImage, double angleX, double angleY, const QPointF &origin) { //angleX, angleY are in degrees const qreal pi = 3.1415926535897932385; const qreal deg2rad = pi / 180.0; qreal tanX = tan(angleX * deg2rad); qreal tanY = tan(angleY * deg2rad); QPointF offset; QSize newSize; { KisTransformWorker worker(0, 1.0, 1.0, tanX, tanY, origin.x(), origin.y(), 0, 0, 0, 0, 0); QRect newRect = worker.transform().mapRect(bounds()); newSize = newRect.size(); if (resizeImage) offset = -newRect.topLeft(); } if (newSize == size()) return; KisImageSignalVector emitSignals; if (resizeImage) emitSignals << ComplexSizeChangedSignal(bounds(), newSize); emitSignals << ModifiedSignal; KisProcessingApplicator::ProcessingFlags signalFlags = KisProcessingApplicator::RECURSIVE; if (resizeImage) signalFlags |= KisProcessingApplicator::NO_UI_UPDATES; KisProcessingApplicator applicator(this, rootNode, signalFlags, emitSignals, actionName); KisFilterStrategy *filter = KisFilterStrategyRegistry::instance()->value("Bilinear"); KisProcessingVisitorSP visitor = new KisTransformProcessingVisitor(1.0, 1.0, tanX, tanY, origin, 0, offset.x(), offset.y(), filter); applicator.applyVisitorAllFrames(visitor, KisStrokeJobData::CONCURRENT); if (resizeImage) { applicator.applyCommand(new KisImageResizeCommand(this, newSize)); } applicator.end(); } void KisImage::shearNode(KisNodeSP node, double angleX, double angleY) { QPointF shearOrigin = QRectF(bounds()).center(); shearImpl(kundo2_i18n("Shear layer"), node, false, angleX, angleY, shearOrigin); } void KisImage::shear(double angleX, double angleY) { shearImpl(kundo2_i18n("Shear Image"), m_d->rootLayer, true, angleX, angleY, QPointF()); } void KisImage::convertImageColorSpace(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) { if (!dstColorSpace) return; const KoColorSpace *srcColorSpace = m_d->colorSpace; undoAdapter()->beginMacro(kundo2_i18n("Convert Image Color Space")); undoAdapter()->addCommand(new KisImageLockCommand(KisImageWSP(this), true)); undoAdapter()->addCommand(new KisImageSetProjectionColorSpaceCommand(KisImageWSP(this), dstColorSpace)); KisColorSpaceConvertVisitor visitor(this, srcColorSpace, dstColorSpace, renderingIntent, conversionFlags); m_d->rootLayer->accept(visitor); undoAdapter()->addCommand(new KisImageLockCommand(KisImageWSP(this), false)); undoAdapter()->endMacro(); setModified(); } bool KisImage::assignImageProfile(const KoColorProfile *profile) { if (!profile) return false; const KoColorSpace *dstCs = KoColorSpaceRegistry::instance()->colorSpace(colorSpace()->colorModelId().id(), colorSpace()->colorDepthId().id(), profile); const KoColorSpace *srcCs = colorSpace(); if (!dstCs) return false; m_d->colorSpace = dstCs; KisChangeProfileVisitor visitor(srcCs, dstCs); bool rv = m_d->rootLayer->accept(visitor); if (rv) { emit sigProfileChanged(profile); } return rv; } void KisImage::convertProjectionColorSpace(const KoColorSpace *dstColorSpace) { if (*m_d->colorSpace == *dstColorSpace) return; undoAdapter()->beginMacro(kundo2_i18n("Convert Projection Color Space")); undoAdapter()->addCommand(new KisImageLockCommand(KisImageWSP(this), true)); undoAdapter()->addCommand(new KisImageSetProjectionColorSpaceCommand(KisImageWSP(this), dstColorSpace)); undoAdapter()->addCommand(new KisImageLockCommand(KisImageWSP(this), false)); undoAdapter()->endMacro(); setModified(); } void KisImage::setProjectionColorSpace(const KoColorSpace * colorSpace) { m_d->colorSpace = colorSpace; + assignImageProfile(colorSpace->profile()); m_d->rootLayer->resetCache(); m_d->signalRouter.emitNotification(ColorSpaceChangedSignal); } const KoColorSpace * KisImage::colorSpace() const { return m_d->colorSpace; } const KoColorProfile * KisImage::profile() const { return colorSpace()->profile(); } double KisImage::xRes() const { return m_d->xres; } double KisImage::yRes() const { return m_d->yres; } void KisImage::setResolution(double xres, double yres) { m_d->xres = xres; m_d->yres = yres; m_d->signalRouter.emitNotification(ResolutionChangedSignal); } QPointF KisImage::documentToPixel(const QPointF &documentCoord) const { return QPointF(documentCoord.x() * xRes(), documentCoord.y() * yRes()); } QPoint KisImage::documentToIntPixel(const QPointF &documentCoord) const { QPointF pixelCoord = documentToPixel(documentCoord); return QPoint((int)pixelCoord.x(), (int)pixelCoord.y()); } QRectF KisImage::documentToPixel(const QRectF &documentRect) const { return QRectF(documentToPixel(documentRect.topLeft()), documentToPixel(documentRect.bottomRight())); } QRect KisImage::documentToIntPixel(const QRectF &documentRect) const { return documentToPixel(documentRect).toAlignedRect(); } QPointF KisImage::pixelToDocument(const QPointF &pixelCoord) const { return QPointF(pixelCoord.x() / xRes(), pixelCoord.y() / yRes()); } QPointF KisImage::pixelToDocument(const QPoint &pixelCoord) const { return QPointF((pixelCoord.x() + 0.5) / xRes(), (pixelCoord.y() + 0.5) / yRes()); } QRectF KisImage::pixelToDocument(const QRectF &pixelCoord) const { return QRectF(pixelToDocument(pixelCoord.topLeft()), pixelToDocument(pixelCoord.bottomRight())); } qint32 KisImage::width() const { return m_d->width; } qint32 KisImage::height() const { return m_d->height; } KisGroupLayerSP KisImage::rootLayer() const { Q_ASSERT(m_d->rootLayer); return m_d->rootLayer; } KisPaintDeviceSP KisImage::projection() const { if (m_d->isolatedRootNode) { return m_d->isolatedRootNode->projection(); } Q_ASSERT(m_d->rootLayer); KisPaintDeviceSP projection = m_d->rootLayer->projection(); Q_ASSERT(projection); return projection; } qint32 KisImage::nlayers() const { QStringList list; list << "KisLayer"; KisCountVisitor visitor(list, KoProperties()); m_d->rootLayer->accept(visitor); return visitor.count(); } qint32 KisImage::nHiddenLayers() const { QStringList list; list << "KisLayer"; KoProperties properties; properties.setProperty("visible", false); KisCountVisitor visitor(list, properties); m_d->rootLayer->accept(visitor); return visitor.count(); } void KisImage::flatten() { KisLayerUtils::flattenImage(this); } void KisImage::mergeMultipleLayers(QList mergedNodes, KisNodeSP putAfter) { if (!KisLayerUtils::tryMergeSelectionMasks(this, mergedNodes, putAfter)) { KisLayerUtils::mergeMultipleLayers(this, mergedNodes, putAfter); } } void KisImage::mergeDown(KisLayerSP layer, const KisMetaData::MergeStrategy* strategy) { KisLayerUtils::mergeDown(this, layer, strategy); } void KisImage::flattenLayer(KisLayerSP layer) { KisLayerUtils::flattenLayer(this, layer); } void KisImage::setModified() { m_d->signalRouter.emitNotification(ModifiedSignal); } QImage KisImage::convertToQImage(QRect imageRect, const KoColorProfile * profile) { qint32 x; qint32 y; qint32 w; qint32 h; imageRect.getRect(&x, &y, &w, &h); return convertToQImage(x, y, w, h, profile); } QImage KisImage::convertToQImage(qint32 x, qint32 y, qint32 w, qint32 h, const KoColorProfile * profile) { KisPaintDeviceSP dev = projection(); if (!dev) return QImage(); QImage image = dev->convertToQImage(const_cast(profile), x, y, w, h, KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); return image; } QImage KisImage::convertToQImage(const QSize& scaledImageSize, const KoColorProfile *profile) { if (scaledImageSize.isEmpty()) { return QImage(); } KisPaintDeviceSP dev = new KisPaintDevice(colorSpace()); KisPainter gc; gc.copyAreaOptimized(QPoint(0, 0), projection(), dev, bounds()); gc.end(); double scaleX = qreal(scaledImageSize.width()) / width(); double scaleY = qreal(scaledImageSize.height()) / height(); QPointer updater = new KoDummyUpdater(); KisTransformWorker worker(dev, scaleX, scaleY, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, updater, KisFilterStrategyRegistry::instance()->value("Bicubic")); worker.run(); delete updater; return dev->convertToQImage(profile); } void KisImage::notifyLayersChanged() { m_d->signalRouter.emitNotification(LayersChangedSignal); } QRect KisImage::bounds() const { return QRect(0, 0, width(), height()); } QRect KisImage::effectiveLodBounds() const { QRect boundRect = bounds(); const int lod = currentLevelOfDetail(); if (lod > 0) { KisLodTransform t(lod); boundRect = t.map(boundRect); } return boundRect; } KisPostExecutionUndoAdapter* KisImage::postExecutionUndoAdapter() const { const int lod = currentLevelOfDetail(); return lod > 0 ? m_d->scheduler.lodNPostExecutionUndoAdapter() : &m_d->postExecutionUndoAdapter; } void KisImage::setUndoStore(KisUndoStore *undoStore) { m_d->legacyUndoAdapter.setUndoStore(undoStore); m_d->postExecutionUndoAdapter.setUndoStore(undoStore); m_d->undoStore.reset(undoStore); } KisUndoStore* KisImage::undoStore() { return m_d->undoStore.data(); } KisUndoAdapter* KisImage::undoAdapter() const { return &m_d->legacyUndoAdapter; } KisActionRecorder* KisImage::actionRecorder() const { return &m_d->recorder; } void KisImage::setDefaultProjectionColor(const KoColor &color) { KIS_ASSERT_RECOVER_RETURN(m_d->rootLayer); m_d->rootLayer->setDefaultProjectionColor(color); } KoColor KisImage::defaultProjectionColor() const { KIS_ASSERT_RECOVER(m_d->rootLayer) { return KoColor(Qt::transparent, m_d->colorSpace); } return m_d->rootLayer->defaultProjectionColor(); } void KisImage::setRootLayer(KisGroupLayerSP rootLayer) { stopIsolatedMode(); KoColor defaultProjectionColor(Qt::transparent, m_d->colorSpace); if (m_d->rootLayer) { m_d->rootLayer->setGraphListener(0); m_d->rootLayer->disconnect(); KisPaintDeviceSP original = m_d->rootLayer->original(); defaultProjectionColor = original->defaultPixel(); } m_d->rootLayer = rootLayer; m_d->rootLayer->disconnect(); m_d->rootLayer->setGraphListener(this); m_d->rootLayer->setImage(this); KisPaintDeviceSP newOriginal = m_d->rootLayer->original(); newOriginal->setDefaultPixel(defaultProjectionColor); setRoot(m_d->rootLayer.data()); } void KisImage::addAnnotation(KisAnnotationSP annotation) { // Find the icc annotation, if there is one vKisAnnotationSP_it it = m_d->annotations.begin(); while (it != m_d->annotations.end()) { if ((*it)->type() == annotation->type()) { *it = annotation; return; } ++it; } m_d->annotations.push_back(annotation); } KisAnnotationSP KisImage::annotation(const QString& type) { vKisAnnotationSP_it it = m_d->annotations.begin(); while (it != m_d->annotations.end()) { if ((*it)->type() == type) { return *it; } ++it; } return KisAnnotationSP(0); } void KisImage::removeAnnotation(const QString& type) { vKisAnnotationSP_it it = m_d->annotations.begin(); while (it != m_d->annotations.end()) { if ((*it)->type() == type) { m_d->annotations.erase(it); return; } ++it; } } vKisAnnotationSP_it KisImage::beginAnnotations() { return m_d->annotations.begin(); } vKisAnnotationSP_it KisImage::endAnnotations() { return m_d->annotations.end(); } void KisImage::notifyAboutToBeDeleted() { emit sigAboutToBeDeleted(); } KisImageSignalRouter* KisImage::signalRouter() { return &m_d->signalRouter; } void KisImage::waitForDone() { requestStrokeEnd(); m_d->scheduler.waitForDone(); } KisStrokeId KisImage::startStroke(KisStrokeStrategy *strokeStrategy) { /** * Ask open strokes to end gracefully. All the strokes clients * (including the one calling this method right now) will get * a notification that they should probably end their strokes. * However this is purely their choice whether to end a stroke * or not. */ if (strokeStrategy->requestsOtherStrokesToEnd()) { requestStrokeEnd(); } /** * Some of the strokes can cancel their work with undoing all the * changes they did to the paint devices. The problem is that undo * stack will know nothing about it. Therefore, just notify it * explicitly */ if (strokeStrategy->clearsRedoOnStart()) { m_d->undoStore->purgeRedoState(); } return m_d->scheduler.startStroke(strokeStrategy); } void KisImage::KisImagePrivate::notifyProjectionUpdatedInPatches(const QRect &rc) { KisImageConfig imageConfig; int patchWidth = imageConfig.updatePatchWidth(); int patchHeight = imageConfig.updatePatchHeight(); for (int y = 0; y < rc.height(); y += patchHeight) { for (int x = 0; x < rc.width(); x += patchWidth) { QRect patchRect(x, y, patchWidth, patchHeight); patchRect &= rc; QtConcurrent::run(std::bind(&KisImage::notifyProjectionUpdated, q, patchRect)); } } } bool KisImage::startIsolatedMode(KisNodeSP node) { if (!tryBarrierLock()) return false; unlock(); m_d->isolatedRootNode = node; emit sigIsolatedModeChanged(); // the GUI uses our thread to do the color space conversion so we // need to emit this signal in multiple threads m_d->notifyProjectionUpdatedInPatches(bounds()); invalidateAllFrames(); return true; } void KisImage::stopIsolatedMode() { if (!m_d->isolatedRootNode) return; KisNodeSP oldRootNode = m_d->isolatedRootNode; m_d->isolatedRootNode = 0; emit sigIsolatedModeChanged(); // the GUI uses our thread to do the color space conversion so we // need to emit this signal in multiple threads m_d->notifyProjectionUpdatedInPatches(bounds()); invalidateAllFrames(); // TODO: Substitute notifyProjectionUpdated() with this code // when update optimization is implemented // // QRect updateRect = bounds() | oldRootNode->extent(); // oldRootNode->setDirty(updateRect); } KisNodeSP KisImage::isolatedModeRoot() const { return m_d->isolatedRootNode; } void KisImage::addJob(KisStrokeId id, KisStrokeJobData *data) { KisUpdateTimeMonitor::instance()->reportJobStarted(data); m_d->scheduler.addJob(id, data); } void KisImage::endStroke(KisStrokeId id) { m_d->scheduler.endStroke(id); } bool KisImage::cancelStroke(KisStrokeId id) { return m_d->scheduler.cancelStroke(id); } bool KisImage::KisImagePrivate::tryCancelCurrentStrokeAsync() { return scheduler.tryCancelCurrentStrokeAsync(); } void KisImage::requestUndoDuringStroke() { emit sigUndoDuringStrokeRequested(); } void KisImage::requestStrokeCancellation() { if (!m_d->tryCancelCurrentStrokeAsync()) { emit sigStrokeCancellationRequested(); } } UndoResult KisImage::tryUndoUnfinishedLod0Stroke() { return m_d->scheduler.tryUndoLastStrokeAsync(); } void KisImage::requestStrokeEnd() { emit sigStrokeEndRequested(); emit sigStrokeEndRequestedActiveNodeFiltered(); } void KisImage::requestStrokeEndActiveNode() { emit sigStrokeEndRequested(); } void KisImage::refreshGraph(KisNodeSP root) { refreshGraph(root, bounds(), bounds()); } void KisImage::refreshGraph(KisNodeSP root, const QRect &rc, const QRect &cropRect) { if (!root) root = m_d->rootLayer; m_d->animationInterface->notifyNodeChanged(root.data(), rc, true); m_d->scheduler.fullRefresh(root, rc, cropRect); } void KisImage::initialRefreshGraph() { /** * NOTE: Tricky part. We set crop rect to null, so the clones * will not rely on precalculated projections of their sources */ refreshGraphAsync(0, bounds(), QRect()); waitForDone(); } void KisImage::refreshGraphAsync(KisNodeSP root) { refreshGraphAsync(root, bounds(), bounds()); } void KisImage::refreshGraphAsync(KisNodeSP root, const QRect &rc) { refreshGraphAsync(root, rc, bounds()); } void KisImage::refreshGraphAsync(KisNodeSP root, const QRect &rc, const QRect &cropRect) { if (!root) root = m_d->rootLayer; m_d->animationInterface->notifyNodeChanged(root.data(), rc, true); m_d->scheduler.fullRefreshAsync(root, rc, cropRect); } void KisImage::requestProjectionUpdateNoFilthy(KisNodeSP pseudoFilthy, const QRect &rc, const QRect &cropRect) { KIS_ASSERT_RECOVER_RETURN(pseudoFilthy); m_d->animationInterface->notifyNodeChanged(pseudoFilthy.data(), rc, false); m_d->scheduler.updateProjectionNoFilthy(pseudoFilthy, rc, cropRect); } void KisImage::addSpontaneousJob(KisSpontaneousJob *spontaneousJob) { m_d->scheduler.addSpontaneousJob(spontaneousJob); } void KisImage::setProjectionUpdatesFilter(KisProjectionUpdatesFilterSP filter) { // udpate filters are *not* recursive! KIS_ASSERT_RECOVER_NOOP(!filter || !m_d->projectionUpdatesFilter); m_d->projectionUpdatesFilter = filter; } KisProjectionUpdatesFilterSP KisImage::projectionUpdatesFilter() const { return m_d->projectionUpdatesFilter; } void KisImage::disableDirtyRequests() { setProjectionUpdatesFilter(KisProjectionUpdatesFilterSP(new KisDropAllProjectionUpdatesFilter())); } void KisImage::enableDirtyRequests() { setProjectionUpdatesFilter(KisProjectionUpdatesFilterSP()); } void KisImage::disableUIUpdates() { m_d->disableUIUpdateSignals.ref(); } void KisImage::enableUIUpdates() { m_d->disableUIUpdateSignals.deref(); } void KisImage::notifyProjectionUpdated(const QRect &rc) { KisUpdateTimeMonitor::instance()->reportUpdateFinished(rc); if (!m_d->disableUIUpdateSignals) { int lod = currentLevelOfDetail(); QRect dirtyRect = !lod ? rc : KisLodTransform::upscaledRect(rc, lod); if (dirtyRect.isEmpty()) return; emit sigImageUpdated(dirtyRect); } } void KisImage::notifySelectionChanged() { /** * The selection is calculated asynchromously, so it is not * handled by disableUIUpdates() and other special signals of * KisImageSignalRouter */ m_d->legacyUndoAdapter.emitSelectionChanged(); /** * Editing of selection masks doesn't necessary produce a * setDirty() call, so in the end of the stroke we need to request * direct update of the UI's cache. */ if (m_d->isolatedRootNode && dynamic_cast(m_d->isolatedRootNode.data())) { notifyProjectionUpdated(bounds()); } } void KisImage::requestProjectionUpdateImpl(KisNode *node, const QRect &rect, const QRect &cropRect) { if (rect.isEmpty()) return; KisNodeGraphListener::requestProjectionUpdate(node, rect); m_d->scheduler.updateProjection(node, rect, cropRect); } void KisImage::requestProjectionUpdate(KisNode *node, const QRect& rect) { if (m_d->projectionUpdatesFilter && m_d->projectionUpdatesFilter->filter(this, node, rect)) { return; } m_d->animationInterface->notifyNodeChanged(node, rect, false); /** * Here we use 'permitted' instead of 'active' intentively, * because the updates may come after the actual stroke has been * finished. And having some more updates for the stroke not * supporting the wrap-around mode will not make much harm. */ if (m_d->wrapAroundModePermitted) { const QRect boundRect = effectiveLodBounds(); KisWrappedRect splitRect(rect, boundRect); Q_FOREACH (const QRect &rc, splitRect) { requestProjectionUpdateImpl(node, rc, boundRect); } } else { requestProjectionUpdateImpl(node, rect, bounds()); } } void KisImage::invalidateFrames(const KisTimeRange &range, const QRect &rect) { m_d->animationInterface->invalidateFrames(range, rect); } void KisImage::requestTimeSwitch(int time) { m_d->animationInterface->requestTimeSwitchNonGUI(time); } QList KisImage::compositions() { return m_d->compositions; } void KisImage::addComposition(KisLayerCompositionSP composition) { m_d->compositions.append(composition); } void KisImage::removeComposition(KisLayerCompositionSP composition) { m_d->compositions.removeAll(composition); } bool checkMasksNeedConversion(KisNodeSP root, const QRect &bounds) { KisSelectionMask *mask = dynamic_cast(root.data()); if (mask && (!bounds.contains(mask->paintDevice()->exactBounds()) || mask->selection()->hasShapeSelection())) { return true; } KisNodeSP node = root->firstChild(); while (node) { if (checkMasksNeedConversion(node, bounds)) { return true; } node = node->nextSibling(); } return false; } void KisImage::setWrapAroundModePermitted(bool value) { m_d->wrapAroundModePermitted = value; if (m_d->wrapAroundModePermitted && checkMasksNeedConversion(root(), bounds())) { KisProcessingApplicator applicator(this, root(), KisProcessingApplicator::RECURSIVE, KisImageSignalVector() << ModifiedSignal, kundo2_i18n("Crop Selections")); KisProcessingVisitorSP visitor = new KisCropSelectionsProcessingVisitor(bounds()); applicator.applyVisitor(visitor, KisStrokeJobData::CONCURRENT); applicator.end(); } } bool KisImage::wrapAroundModePermitted() const { return m_d->wrapAroundModePermitted; } bool KisImage::wrapAroundModeActive() const { return m_d->wrapAroundModePermitted && m_d->scheduler.wrapAroundModeSupported(); } void KisImage::setDesiredLevelOfDetail(int lod) { if (m_d->blockLevelOfDetail) { qWarning() << "WARNING: KisImage::setDesiredLevelOfDetail()" << "was called while LoD functionality was being blocked!"; return; } m_d->scheduler.setDesiredLevelOfDetail(lod); } int KisImage::currentLevelOfDetail() const { if (m_d->blockLevelOfDetail) { return 0; } return m_d->scheduler.currentLevelOfDetail(); } void KisImage::setLevelOfDetailBlocked(bool value) { KisImageBarrierLockerRaw l(this); if (value && !m_d->blockLevelOfDetail) { m_d->scheduler.setDesiredLevelOfDetail(0); } m_d->blockLevelOfDetail = value; } void KisImage::explicitRegenerateLevelOfDetail() { if (!m_d->blockLevelOfDetail) { m_d->scheduler.explicitRegenerateLevelOfDetail(); } } bool KisImage::levelOfDetailBlocked() const { return m_d->blockLevelOfDetail; } void KisImage::notifyNodeCollpasedChanged() { emit sigNodeCollapsedChanged(); } KisImageAnimationInterface* KisImage::animationInterface() const { return m_d->animationInterface; } void KisImage::setProofingConfiguration(KisProofingConfigurationSP proofingConfig) { m_d->proofingConfig = proofingConfig; emit sigProofingConfigChanged(); } KisProofingConfigurationSP KisImage::proofingConfiguration() const { if (!m_d->proofingConfig) { KisImageConfig cfg; m_d->proofingConfig = cfg.defaultProofingconfiguration(); } return m_d->proofingConfig; } QPointF KisImage::mirrorAxesCenter() const { return m_d->axesCenter; } void KisImage::setMirrorAxesCenter(const QPointF &value) const { m_d->axesCenter = value; } diff --git a/libs/pigment/KoCmykColorSpaceTraits.h b/libs/pigment/KoCmykColorSpaceTraits.h index 657c50157f..a81385468f 100644 --- a/libs/pigment/KoCmykColorSpaceTraits.h +++ b/libs/pigment/KoCmykColorSpaceTraits.h @@ -1,120 +1,238 @@ /* * Copyright (c) 2006-2007 Cyrille Berger + * Copyright (c) 2016 L. E. Segovia * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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. */ #ifndef _KO_CMYK_COLORSPACE_TRAITS_H_ #define _KO_CMYK_COLORSPACE_TRAITS_H_ #include #include "KoColorSpaceConstants.h" #include "KoColorSpaceMaths.h" #include "DebugPigment.h" /** * Base class for CMYK traits, it provides some convenient functions to * access CMYK channels through an explicit API. */ template struct KoCmykTraits : public KoColorSpaceTrait<_channels_type_, 5, 4> { typedef _channels_type_ channels_type; typedef KoColorSpaceTrait<_channels_type_, 5, 4> parent; static const qint32 c_pos = 0; static const qint32 m_pos = 1; static const qint32 y_pos = 2; static const qint32 k_pos = 3; /** * An CMYK pixel */ struct Pixel { channels_type cyan; channels_type magenta; channels_type yellow; channels_type black; channels_type alpha; }; /// @return the Cyan component inline static channels_type C(quint8* data) { channels_type* d = parent::nativeArray(data); return d[c_pos]; } /// Set the Cyan component inline static void setC(quint8* data, channels_type nv) { channels_type* d = parent::nativeArray(data); d[c_pos] = nv; } /// @return the Magenta component inline static channels_type M(quint8* data) { channels_type* d = parent::nativeArray(data); return d[m_pos]; } /// Set the Magenta component inline static void setM(quint8* data, channels_type nv) { channels_type* d = parent::nativeArray(data); d[m_pos] = nv; } /// @return the Yellow component inline static channels_type Y(quint8* data) { channels_type* d = parent::nativeArray(data); return d[y_pos]; } /// Set the Yellow component inline static void setY(quint8* data, channels_type nv) { channels_type* d = parent::nativeArray(data); d[y_pos] = nv; } /// @return the Key component inline static channels_type k(quint8* data) { channels_type* d = parent::nativeArray(data); return d[k_pos]; } /// Set the Key component inline static void setK(quint8* data, channels_type nv) { channels_type* d = parent::nativeArray(data); d[k_pos] = nv; } }; struct KoCmykU8Traits : public KoCmykTraits { }; struct KoCmykU16Traits : public KoCmykTraits { }; #include #ifdef HAVE_OPENEXR #include struct KoCmykF16Traits : public KoCmykTraits { + static constexpr float MAX_CHANNEL_CMYK = 100; + + inline static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) { + return channelValueText(pixel, channelIndex); + } + + inline static void normalisedChannelsValue(const quint8 *pixel, QVector &channels) { + Q_ASSERT((int)channels.count() == (int)parent::channels_nb); + channels_type c; + for (uint i = 0; i < parent::channels_nb; i++) { + c = parent::nativeArray(pixel)[i]; + channels[i] = (qreal)c; + } + } + + inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) { + Q_ASSERT((int)values.count() == (int)parent::channels_nb); + channels_type c; + for (uint i = 0; i < parent::channels_nb; i++) { + float b = 0; + switch(i) { + case c_pos: + case m_pos: + case y_pos: + case k_pos: + b = qBound((float)0, + (float)KoColorSpaceMathsTraits::unitValue * values[i], + (float)MAX_CHANNEL_CMYK); + break; + default: + b = qBound((float)KoColorSpaceMathsTraits::min, + (float)KoColorSpaceMathsTraits::unitValue * values[i], + (float)KoColorSpaceMathsTraits::max); + break; + } + c = (channels_type)b; + parent::nativeArray(pixel)[i] = c; + } + } }; #endif struct KoCmykF32Traits : public KoCmykTraits { + static constexpr float MAX_CHANNEL_CMYK = 100; + + inline static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) { + return channelValueText(pixel, channelIndex); + } + + inline static void normalisedChannelsValue(const quint8 *pixel, QVector &channels) { + Q_ASSERT((int)channels.count() == (int)parent::channels_nb); + channels_type c; + for (uint i = 0; i < parent::channels_nb; i++) { + c = parent::nativeArray(pixel)[i]; + channels[i] = (qreal)c; + } + } + + inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) { + Q_ASSERT((int)values.count() == (int)parent::channels_nb); + channels_type c; + for (uint i = 0; i < parent::channels_nb; i++) { + float b = 0; + switch(i) { + case c_pos: + case m_pos: + case y_pos: + case k_pos: + b = qBound((float)0, + (float)KoColorSpaceMathsTraits::unitValue * values[i], + (float)MAX_CHANNEL_CMYK); + break; + default: + b = qBound((float)KoColorSpaceMathsTraits::min, + (float)KoColorSpaceMathsTraits::unitValue * values[i], + (float)KoColorSpaceMathsTraits::max); + break; + } + c = (channels_type)b; + parent::nativeArray(pixel)[i] = c; + } + } }; struct KoCmykF64Traits : public KoCmykTraits { + static constexpr double MAX_CHANNEL_CMYK = 100; + + inline static QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) { + return channelValueText(pixel, channelIndex); + } + + inline static void normalisedChannelsValue(const quint8 *pixel, QVector &channels) { + Q_ASSERT((int)channels.count() == (int)parent::channels_nb); + channels_type c; + for (uint i = 0; i < parent::channels_nb; i++) { + c = parent::nativeArray(pixel)[i]; + channels[i] = (qreal)c; + } + } + + inline static void fromNormalisedChannelsValue(quint8 *pixel, const QVector &values) { + Q_ASSERT((int)values.count() == (int)parent::channels_nb); + channels_type c; + for (uint i = 0; i < parent::channels_nb; i++) { + float b = 0; + switch(i) { + case c_pos: + case m_pos: + case y_pos: + case k_pos: + b = qBound((double)0, + (double)KoColorSpaceMathsTraits::unitValue * values[i], + (double)MAX_CHANNEL_CMYK); + break; + default: + b = qBound((double)KoColorSpaceMathsTraits::min, + (double)KoColorSpaceMathsTraits::unitValue * values[i], + (double)KoColorSpaceMathsTraits::max); + break; + } + c = (channels_type)b; + parent::nativeArray(pixel)[i] = c; + } + } }; #endif diff --git a/libs/ui/KisMainWindow.cpp b/libs/ui/KisMainWindow.cpp index 05fbf0b380..bfbab36822 100644 --- a/libs/ui/KisMainWindow.cpp +++ b/libs/ui/KisMainWindow.cpp @@ -1,2403 +1,2403 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Torben Weis Copyright (C) 2000-2006 David Faure Copyright (C) 2007, 2009 Thomas zander Copyright (C) 2010 Benjamin Port 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 "KisMainWindow.h" #include // qt includes #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 #ifdef HAVE_KIO #include #endif #include #include #include #include #include #include #include #include #include #include #include "KoDockFactoryBase.h" #include "KoDockWidgetTitleBar.h" #include "KoDocumentInfoDlg.h" #include "KoDocumentInfo.h" #include "KoFileDialog.h" #include #include #include #include #include #include "KoToolDocker.h" #include #include #include #include #include #include #include "dialogs/kis_about_application.h" #include "dialogs/kis_delayed_save_dialog.h" #include "dialogs/kis_dlg_preferences.h" #include "kis_action.h" #include "kis_action_manager.h" #include "KisApplication.h" #include "kis_canvas2.h" #include "kis_canvas_controller.h" #include "kis_canvas_resource_provider.h" #include "kis_clipboard.h" #include "kis_config.h" #include "kis_config_notifier.h" #include "kis_custom_image_widget.h" #include #include "KisDocument.h" #include "KisDocument.h" #include "kis_group_layer.h" #include "kis_icon_utils.h" #include "kis_image_from_clipboard_widget.h" #include "kis_image.h" #include #include "KisImportExportManager.h" #include "kis_mainwindow_observer.h" #include "kis_node.h" #include "KisOpenPane.h" #include "kis_paintop_box.h" #include "KisPart.h" #include "KisPrintJob.h" #include "kis_resource_server_provider.h" #include "kis_signal_compressor_with_param.h" #include "KisView.h" #include "KisViewManager.h" #include "thememanager.h" #include "kis_animation_importer.h" #include "dialogs/kis_dlg_import_image_sequence.h" #include "kis_animation_exporter.h" #include #ifdef Q_OS_WIN #include #endif class ToolDockerFactory : public KoDockFactoryBase { public: ToolDockerFactory() : KoDockFactoryBase() { } QString id() const override { return "sharedtooldocker"; } QDockWidget* createDockWidget() override { KoToolDocker* dockWidget = new KoToolDocker(); dockWidget->setTabEnabled(false); return dockWidget; } DockPosition defaultDockPosition() const override { return DockRight; } }; class Q_DECL_HIDDEN KisMainWindow::Private { public: Private(KisMainWindow *parent) : q(parent) , dockWidgetMenu(new KActionMenu(i18nc("@action:inmenu", "&Dockers"), parent)) , windowMenu(new KActionMenu(i18nc("@action:inmenu", "&Window"), parent)) , documentMenu(new KActionMenu(i18nc("@action:inmenu", "New &View"), parent)) , mdiArea(new QMdiArea(parent)) , windowMapper(new QSignalMapper(parent)) , documentMapper(new QSignalMapper(parent)) { } ~Private() { qDeleteAll(toolbarList); } KisMainWindow *q {0}; KisViewManager *viewManager {0}; QPointer activeView; QPointer progress; QPointer progressCancel; QMutex progressMutex; QList toolbarList; bool firstTime {true}; bool windowSizeDirty {false}; bool readOnly {false}; bool isImporting {false}; bool isExporting {false}; bool noCleanup {false}; KisAction *showDocumentInfo {0}; KisAction *saveAction {0}; KisAction *saveActionAs {0}; // KisAction *printAction; // KisAction *printActionPreview; // KisAction *exportPdf {0}; KisAction *importAnimation {0}; KisAction *closeAll {0}; // KisAction *reloadFile; KisAction *importFile {0}; KisAction *exportFile {0}; KisAction *undo {0}; KisAction *redo {0}; KisAction *newWindow {0}; KisAction *close {0}; KisAction *mdiCascade {0}; KisAction *mdiTile {0}; KisAction *mdiNextWindow {0}; KisAction *mdiPreviousWindow {0}; KisAction *toggleDockers {0}; KisAction *toggleDockerTitleBars {0}; KisAction *expandingSpacers[2]; KActionMenu *dockWidgetMenu; KActionMenu *windowMenu; KActionMenu *documentMenu; KHelpMenu *helpMenu {0}; KRecentFilesAction *recentFiles {0}; QUrl lastExportUrl; QMap dockWidgetsMap; QMap dockWidgetVisibilityMap; QByteArray dockerStateBeforeHiding; KoToolDocker *toolOptionsDocker {0}; QCloseEvent *deferredClosingEvent {0}; Digikam::ThemeManager *themeManager {0}; QMdiArea *mdiArea; QMdiSubWindow *activeSubWindow {0}; QSignalMapper *windowMapper; QSignalMapper *documentMapper; QByteArray lastExportedFormat; QScopedPointer > tabSwitchCompressor; QMutex savingEntryMutex; KisActionManager * actionManager() { return viewManager->actionManager(); } QTabBar* findTabBarHACK() { QObjectList objects = mdiArea->children(); Q_FOREACH (QObject *object, objects) { QTabBar *bar = qobject_cast(object); if (bar) { return bar; } } return 0; } }; KisMainWindow::KisMainWindow() : KXmlGuiWindow() , d(new Private(this)) { KisConfig cfg; d->viewManager = new KisViewManager(this, actionCollection()); KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager = new Digikam::ThemeManager(group.readEntry("Theme", "Krita dark"), this); setAcceptDrops(true); setStandardToolBarMenuEnabled(true); setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::North); setDockNestingEnabled(true); qApp->setStartDragDistance(25); // 25 px is a distance that works well for Tablet and Mouse events #ifdef Q_OS_OSX setUnifiedTitleAndToolBarOnMac(true); #endif connect(this, SIGNAL(restoringDone()), this, SLOT(forceDockTabFonts())); connect(this, SIGNAL(themeChanged()), d->viewManager, SLOT(updateIcons())); connect(KisPart::instance(), SIGNAL(documentClosed(QString)), SLOT(updateWindowMenu())); connect(KisPart::instance(), SIGNAL(documentOpened(QString)), SLOT(updateWindowMenu())); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), this, SLOT(configChanged())); actionCollection()->addAssociatedWidget(this); KoPluginLoader::instance()->load("Krita/ViewPlugin", "Type == 'Service' and ([X-Krita-Version] == 28)", KoPluginLoader::PluginsConfig(), d->viewManager); KoToolBoxFactory toolBoxFactory; QDockWidget *toolbox = createDockWidget(&toolBoxFactory); toolbox->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable); if (cfg.toolOptionsInDocker()) { ToolDockerFactory toolDockerFactory; d->toolOptionsDocker = qobject_cast(createDockWidget(&toolDockerFactory)); d->toolOptionsDocker->toggleViewAction()->setEnabled(true); } QMap dockwidgetActions; dockwidgetActions[toolbox->toggleViewAction()->text()] = toolbox->toggleViewAction(); Q_FOREACH (const QString & docker, KoDockRegistry::instance()->keys()) { KoDockFactoryBase *factory = KoDockRegistry::instance()->value(docker); QDockWidget *dw = createDockWidget(factory); dockwidgetActions[dw->toggleViewAction()->text()] = dw->toggleViewAction(); } if (d->toolOptionsDocker) { dockwidgetActions[d->toolOptionsDocker->toggleViewAction()->text()] = d->toolOptionsDocker->toggleViewAction(); } connect(KoToolManager::instance(), SIGNAL(toolOptionWidgetsChanged(KoCanvasController*, QList >)), this, SLOT(newOptionWidgets(KoCanvasController*, QList >))); Q_FOREACH (QString title, dockwidgetActions.keys()) { d->dockWidgetMenu->addAction(dockwidgetActions[title]); } Q_FOREACH (QDockWidget *wdg, dockWidgets()) { if ((wdg->features() & QDockWidget::DockWidgetClosable) == 0) { wdg->setVisible(true); } } Q_FOREACH (KoCanvasObserverBase* observer, canvasObservers()) { observer->setObservedCanvas(0); KisMainwindowObserver* mainwindowObserver = dynamic_cast(observer); if (mainwindowObserver) { mainwindowObserver->setMainWindow(d->viewManager); } } d->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); d->mdiArea->setTabPosition(QTabWidget::North); d->mdiArea->setTabsClosable(true); setCentralWidget(d->mdiArea); connect(d->mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(subWindowActivated())); connect(d->windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*))); connect(d->documentMapper, SIGNAL(mapped(QObject*)), this, SLOT(newView(QObject*))); createActions(); setAutoSaveSettings("krita", false); subWindowActivated(); updateWindowMenu(); if (isHelpMenuEnabled() && !d->helpMenu) { // workaround for KHelpMenu (or rather KAboutData::applicationData()) internally // not using the Q*Application metadata ATM, which results e.g. in the bugreport wizard // not having the app version preset // fixed hopefully in KF5 5.22.0, patch pending QGuiApplication *app = qApp; KAboutData aboutData(app->applicationName(), app->applicationDisplayName(), app->applicationVersion()); aboutData.setOrganizationDomain(app->organizationDomain().toUtf8()); d->helpMenu = new KHelpMenu(this, aboutData, false); // workaround-less version: // d->helpMenu = new KHelpMenu(this, QString()/*unused*/, false); // The difference between using KActionCollection->addAction() is that // these actions do not get tied to the MainWindow. What does this all do? KActionCollection *actions = d->viewManager->actionCollection(); QAction *helpContentsAction = d->helpMenu->action(KHelpMenu::menuHelpContents); QAction *whatsThisAction = d->helpMenu->action(KHelpMenu::menuWhatsThis); QAction *reportBugAction = d->helpMenu->action(KHelpMenu::menuReportBug); QAction *switchLanguageAction = d->helpMenu->action(KHelpMenu::menuSwitchLanguage); QAction *aboutAppAction = d->helpMenu->action(KHelpMenu::menuAboutApp); QAction *aboutKdeAction = d->helpMenu->action(KHelpMenu::menuAboutKDE); if (helpContentsAction) { actions->addAction(helpContentsAction->objectName(), helpContentsAction); } if (whatsThisAction) { actions->addAction(whatsThisAction->objectName(), whatsThisAction); } if (reportBugAction) { actions->addAction(reportBugAction->objectName(), reportBugAction); } if (switchLanguageAction) { actions->addAction(switchLanguageAction->objectName(), switchLanguageAction); } if (aboutAppAction) { actions->addAction(aboutAppAction->objectName(), aboutAppAction); } if (aboutKdeAction) { actions->addAction(aboutKdeAction->objectName(), aboutKdeAction); } connect(d->helpMenu, SIGNAL(showAboutApplication()), SLOT(showAboutApplication())); } // KDE' libs 4''s help contents action is broken outside kde, for some reason... We can handle it just as easily ourselves QAction *helpAction = actionCollection()->action("help_contents"); helpAction->disconnect(); connect(helpAction, SIGNAL(triggered()), this, SLOT(showManual())); #if 0 //check for colliding shortcuts QSet existingShortcuts; Q_FOREACH (QAction* action, actionCollection()->actions()) { if(action->shortcut() == QKeySequence(0)) { continue; } dbgKrita << "shortcut " << action->text() << " " << action->shortcut(); Q_ASSERT(!existingShortcuts.contains(action->shortcut())); existingShortcuts.insert(action->shortcut()); } #endif configChanged(); // If we have customized the toolbars, load that first setLocalXMLFile(KoResourcePaths::locateLocal("data", "krita.xmlgui")); setXMLFile(":/kxmlgui5/krita.xmlgui"); guiFactory()->addClient(this); // Create and plug toolbar list for Settings menu QList toolbarList; Q_FOREACH (QWidget* it, guiFactory()->containers("ToolBar")) { KToolBar * toolBar = ::qobject_cast(it); if (toolBar) { if (toolBar->objectName() == "BrushesAndStuff") { toolBar->setEnabled(false); } KToggleAction* act = new KToggleAction(i18n("Show %1 Toolbar", toolBar->windowTitle()), this); actionCollection()->addAction(toolBar->objectName().toUtf8(), act); act->setCheckedState(KGuiItem(i18n("Hide %1 Toolbar", toolBar->windowTitle()))); connect(act, SIGNAL(toggled(bool)), this, SLOT(slotToolbarToggled(bool))); act->setChecked(!toolBar->isHidden()); toolbarList.append(act); } else warnUI << "Toolbar list contains a " << it->metaObject()->className() << " which is not a toolbar!"; } plugActionList("toolbarlist", toolbarList); setToolbarList(toolbarList); applyToolBarLayout(); d->viewManager->updateGUI(); d->viewManager->updateIcons(); #ifdef Q_OS_WIN auto w = qApp->activeWindow(); if (w) QWindowsWindowFunctions::setHasBorderInFullScreen(w->windowHandle(), true); #endif QTimer::singleShot(1000, this, SLOT(checkSanity())); { using namespace std::placeholders; // For _1 placeholder std::function callback( std::bind(&KisMainWindow::switchTab, this, _1)); d->tabSwitchCompressor.reset( new KisSignalCompressorWithParam(500, callback, KisSignalCompressor::FIRST_INACTIVE)); } } void KisMainWindow::setNoCleanup(bool noCleanup) { d->noCleanup = noCleanup; } KisMainWindow::~KisMainWindow() { // Q_FOREACH (QAction *ac, actionCollection()->actions()) { // QAction *action = qobject_cast(ac); // if (action) { // dbgKrita << "", "").replace("", "") // << "iconText=" << action->iconText().replace("&", "&") // << "shortcut=" << action->shortcut(QAction::ActiveShortcut).toString() // << "defaultShortcut=" << action->shortcut(QAction::DefaultShortcut).toString() // << "isCheckable=" << QString((action->isChecked() ? "true" : "false")) // << "statusTip=" << action->statusTip() // << "/>" ; // } // else { // dbgKrita << "Got a QAction:" << ac->objectName(); // } // } // The doc and view might still exist (this is the case when closing the window) KisPart::instance()->removeMainWindow(this); if (d->noCleanup) return; delete d->viewManager; delete d; } void KisMainWindow::addView(KisView *view) { if (d->activeView == view) return; if (d->activeView) { d->activeView->disconnect(this); } showView(view); updateCaption(); emit restoringDone(); if (d->activeView) { connect(d->activeView, SIGNAL(titleModified(QString,bool)), SLOT(slotDocumentTitleModified(QString,bool))); } } void KisMainWindow::showView(KisView *imageView) { if (imageView && activeView() != imageView ) { // XXX: find a better way to initialize this! imageView->setViewManager(d->viewManager); imageView->canvasBase()->setFavoriteResourceManager(d->viewManager->paintOpBox()->favoriteResourcesManager()); imageView->slotLoadingFinished(); QMdiSubWindow *subwin = d->mdiArea->addSubWindow(imageView); subwin->setAttribute(Qt::WA_DeleteOnClose, true); connect(subwin, SIGNAL(destroyed()), SLOT(updateWindowMenu())); KisConfig cfg; subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setWindowIcon(qApp->windowIcon()); /** * Hack alert! * * Here we explicitly request KoToolManager to emit all the tool * activation signals, to reinitialize the tool options docker. * * That is needed due to a design flaw we have in the * initialization procedure. The tool in the KoToolManager is * initialized in KisView::setViewManager() calls, which * happens early enough. During this call the tool manager * requests KoCanvasControllerWidget to emit the signal to * update the widgets in the tool docker. *But* at that moment * of time the view is not yet connected to the main window, * because it happens in KisViewManager::setCurrentView a bit * later. This fact makes the widgets updating signals be lost * and never reach the tool docker. * * So here we just explicitly call the tool activation stub. */ KoToolManager::instance()->initializeCurrentToolForCanvas(); if (d->mdiArea->subWindowList().size() == 1) { imageView->showMaximized(); } else { imageView->show(); } // No, no, no: do not try to call this _before_ the show() has // been called on the view; only when that has happened is the // opengl context active, and very bad things happen if we tell // the dockers to update themselves with a view if the opengl // context is not active. setActiveView(imageView); updateWindowMenu(); updateCaption(); } } void KisMainWindow::slotPreferences() { if (KisDlgPreferences::editPreferences()) { KisConfigNotifier::instance()->notifyConfigChanged(); // XXX: should this be changed for the views in other windows as well? Q_FOREACH (QPointer koview, KisPart::instance()->views()) { KisViewManager *view = qobject_cast(koview); if (view) { // Update the settings for all nodes -- they don't query // KisConfig directly because they need the settings during // compositing, and they don't connect to the config notifier // because nodes are not QObjects (because only one base class // can be a QObject). KisNode* node = dynamic_cast(view->image()->rootLayer().data()); node->updateSettings(); } } d->viewManager->showHideScrollbars(); } } void KisMainWindow::slotThemeChanged() { // save theme changes instantly KConfigGroup group( KSharedConfig::openConfig(), "theme"); group.writeEntry("Theme", d->themeManager->currentThemeName()); // reload action icons! Q_FOREACH (QAction *action, actionCollection()->actions()) { KisIconUtils::updateIcon(action); } emit themeChanged(); } void KisMainWindow::updateReloadFileAction(KisDocument *doc) { Q_UNUSED(doc); // d->reloadFile->setEnabled(doc && !doc->url().isEmpty()); } void KisMainWindow::setReadWrite(bool readwrite) { d->saveAction->setEnabled(readwrite); d->importFile->setEnabled(readwrite); d->readOnly = !readwrite; updateCaption(); } void KisMainWindow::addRecentURL(const QUrl &url) { dbgUI << "KisMainWindow::addRecentURL url=" << url.toDisplayString(); // Add entry to recent documents list // (call coming from KisDocument because it must work with cmd line, template dlg, file/open, etc.) if (!url.isEmpty()) { bool ok = true; if (url.isLocalFile()) { QString path = url.adjusted(QUrl::StripTrailingSlash).toLocalFile(); const QStringList tmpDirs = KoResourcePaths::resourceDirs("tmp"); for (QStringList::ConstIterator it = tmpDirs.begin() ; ok && it != tmpDirs.end() ; ++it) if (path.contains(*it)) ok = false; // it's in the tmp resource #ifdef HAVE_KIO if (ok) { KRecentDocument::add(QUrl::fromLocalFile(path)); } #endif } #ifdef HAVE_KIO else { KRecentDocument::add(url.adjusted(QUrl::StripTrailingSlash)); } #endif if (ok) { d->recentFiles->addUrl(url); } saveRecentFiles(); } } void KisMainWindow::saveRecentFiles() { // Save list of recent files KSharedConfigPtr config = KSharedConfig::openConfig(); d->recentFiles->saveEntries(config->group("RecentFiles")); config->sync(); // Tell all windows to reload their list, after saving // Doesn't work multi-process, but it's a start Q_FOREACH (KMainWindow* window, KMainWindow::memberList()) static_cast(window)->reloadRecentFileList(); } void KisMainWindow::reloadRecentFileList() { d->recentFiles->loadEntries( KSharedConfig::openConfig()->group("RecentFiles")); } void KisMainWindow::updateCaption() { if (!d->mdiArea->activeSubWindow()) { updateCaption(QString(), false); } - else { + else if (d->activeView && d->activeView->document()){ QString caption( d->activeView->document()->caption() ); if (d->readOnly) { caption += ' ' + i18n("(write protected)"); } d->activeView->setWindowTitle(caption); updateCaption(caption, d->activeView->document()->isModified()); if (!d->activeView->document()->url().fileName().isEmpty()) d->saveAction->setToolTip(i18n("Save as %1", d->activeView->document()->url().fileName())); else d->saveAction->setToolTip(i18n("Save")); } } void KisMainWindow::updateCaption(const QString & caption, bool mod) { dbgUI << "KisMainWindow::updateCaption(" << caption << "," << mod << ")"; #ifdef KRITA_ALPHA setCaption(QString("ALPHA %1: %2").arg(KRITA_ALPHA).arg(caption), mod); return; #endif #ifdef KRITA_BETA setCaption(QString("BETA %1: %2").arg(KRITA_BETA).arg(caption), mod); return; #endif #ifdef KRITA_RC setCaption(QString("RELEASE CANDIDATE %1: %2").arg(KRITA_RC).arg(caption), mod); return; #endif setCaption(caption, mod); } KisView *KisMainWindow::activeView() const { if (d->activeView) { return d->activeView; } return 0; } bool KisMainWindow::openDocument(const QUrl &url) { if (!QFile(url.toLocalFile()).exists()) { QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("The file %1 does not exist.", url.url())); d->recentFiles->removeUrl(url); //remove the file from the recent-opened-file-list saveRecentFiles(); return false; } return openDocumentInternal(url); } bool KisMainWindow::openDocumentInternal(const QUrl &url, KisDocument *newdoc) { if (!url.isLocalFile()) { qDebug() << "KisMainWindow::openDocumentInternal. Not a local file:" << url; return false; } if (!newdoc) { newdoc = KisPart::instance()->createDocument(); } d->firstTime = true; connect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); connect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); connect(newdoc, SIGNAL(canceled(const QString &)), this, SLOT(slotLoadCanceled(const QString &))); bool openRet = (!d->isImporting) ? newdoc->openUrl(url) : newdoc->importDocument(url); if (!openRet) { delete newdoc; return false; } KisPart::instance()->addDocument(newdoc); updateReloadFileAction(newdoc); if (!QFileInfo(url.toLocalFile()).isWritable()) { setReadWrite(false); } return true; } void KisMainWindow::addViewAndNotifyLoadingCompleted(KisDocument *document) { KisView *view = KisPart::instance()->createView(document, resourceManager(), actionCollection(), this); addView(view); emit guiLoadingFinished(); } QStringList KisMainWindow::showOpenFileDialog() { KoFileDialog dialog(this, KoFileDialog::ImportFiles, "OpenDocument"); dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); dialog.setMimeTypeFilters(KisImportExportManager::mimeFilter(KisImportExportManager::Import)); dialog.setCaption(d->isImporting ? i18n("Import Images") : i18n("Open Images")); return dialog.filenames(); } // Separate from openDocument to handle async loading (remote URLs) void KisMainWindow::slotLoadCompleted() { KisDocument *newdoc = qobject_cast(sender()); if (newdoc && newdoc->image()) { addViewAndNotifyLoadingCompleted(newdoc); disconnect(newdoc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); disconnect(newdoc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(newdoc, SIGNAL(canceled(const QString &)), this, SLOT(slotLoadCanceled(const QString &))); emit loadCompleted(); } } void KisMainWindow::slotLoadCanceled(const QString & errMsg) { dbgUI << "KisMainWindow::slotLoadCanceled"; if (!errMsg.isEmpty()) // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); // ... can't delete the document, it's the one who emitted the signal... KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); disconnect(doc, SIGNAL(completed()), this, SLOT(slotLoadCompleted())); disconnect(doc, SIGNAL(canceled(const QString &)), this, SLOT(slotLoadCanceled(const QString &))); } void KisMainWindow::slotSaveCanceled(const QString &errMsg) { dbgUI << "KisMainWindow::slotSaveCanceled"; if (!errMsg.isEmpty()) // empty when canceled by user QMessageBox::critical(this, i18nc("@title:window", "Krita"), errMsg); slotSaveCompleted(); } void KisMainWindow::slotSaveCompleted() { dbgUI << "KisMainWindow::slotSaveCompleted"; KisDocument* doc = qobject_cast(sender()); Q_ASSERT(doc); disconnect(doc, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); disconnect(doc, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); disconnect(doc, SIGNAL(canceled(const QString &)), this, SLOT(slotSaveCanceled(const QString &))); if (d->deferredClosingEvent) { KXmlGuiWindow::closeEvent(d->deferredClosingEvent); } } bool KisMainWindow::hackIsSaving() const { StdLockableWrapper wrapper(&d->savingEntryMutex); std::unique_lock> l(wrapper, std::try_to_lock); return !l.owns_lock(); } bool KisMainWindow::saveDocument(KisDocument *document, bool saveas) { if (!document) { return true; } /** * Make sure that we cannot enter this method twice! * * The lower level functions may call processEvents() so * double-entry is quite possible to achieve. Here we try to lock * the mutex, and if it is failed, just cancel saving. */ StdLockableWrapper wrapper(&d->savingEntryMutex); std::unique_lock> l(wrapper, std::try_to_lock); if (!l.owns_lock()) return false; // no busy wait for saving because it is dangerous! KisDelayedSaveDialog dlg(document->image(), KisDelayedSaveDialog::SaveDialog, 0, this); dlg.blockIfImageIsBusy(); if (dlg.result() != QDialog::Accepted) { return false; } bool reset_url; if (document->url().isEmpty()) { reset_url = true; saveas = true; } else { reset_url = false; } connect(document, SIGNAL(sigProgress(int)), this, SLOT(slotProgress(int))); connect(document, SIGNAL(completed()), this, SLOT(slotSaveCompleted())); connect(document, SIGNAL(canceled(const QString &)), this, SLOT(slotSaveCanceled(const QString &))); QUrl oldURL = document->url(); QString oldFile = document->localFilePath(); QByteArray _native_format = document->nativeFormatMimeType(); QByteArray oldOutputFormat = document->outputMimeType(); QUrl suggestedURL = document->url(); QStringList mimeFilter; mimeFilter = KisImportExportManager::mimeFilter(KisImportExportManager::Export); if (!mimeFilter.contains(oldOutputFormat) && !d->isExporting) { dbgUI << "KisMainWindow::saveDocument no export filter for" << oldOutputFormat; // --- don't setOutputMimeType in case the user cancels the Save As // dialog and then tries to just plain Save --- // suggest a different filename extension (yes, we fortunately don't all live in a world of magic :)) QString suggestedFilename = suggestedURL.fileName(); if (!suggestedFilename.isEmpty()) { // ".kra" looks strange for a name int c = suggestedFilename.lastIndexOf('.'); const QString ext = KisMimeDatabase::suffixesForMimeType(_native_format).first(); if (!ext.isEmpty()) { if (c < 0) suggestedFilename = suggestedFilename + "." + ext; else suggestedFilename = suggestedFilename.left(c) + "." + ext; } else { // current filename extension wrong anyway if (c > 0) { // this assumes that a . signifies an extension, not just a . suggestedFilename = suggestedFilename.left(c); } } suggestedURL = suggestedURL.adjusted(QUrl::RemoveFilename); suggestedURL.setPath(suggestedURL.path() + suggestedFilename); } // force the user to choose outputMimeType saveas = true; } bool ret = false; if (document->url().isEmpty() || saveas) { // if you're just File/Save As'ing to change filter options you // don't want to be reminded about overwriting files etc. bool justChangingFilterOptions = false; KoFileDialog dialog(this, KoFileDialog::SaveFile, "SaveAs"); dialog.setCaption(i18n("untitled")); if (d->isExporting && !d->lastExportUrl.isEmpty()) { dialog.setDefaultDir(d->lastExportUrl.toLocalFile()); } else { dialog.setDefaultDir(suggestedURL.toLocalFile()); } // Default to all supported file types if user is exporting, otherwise use Krita default dialog.setMimeTypeFilters(mimeFilter, QString(_native_format)); QUrl newURL = QUrl::fromUserInput(dialog.filename()); if (newURL.isLocalFile()) { QString fn = newURL.toLocalFile(); if (QFileInfo(fn).completeSuffix().isEmpty()) { fn.append(KisMimeDatabase::suffixesForMimeType(_native_format).first()); newURL = QUrl::fromLocalFile(fn); } } if (document->documentInfo()->aboutInfo("title") == i18n("Unnamed")) { QString fn = newURL.toLocalFile(); QFileInfo info(fn); document->documentInfo()->setAboutInfo("title", info.baseName()); } QByteArray outputFormat = _native_format; QString outputFormatString = KisMimeDatabase::mimeTypeForFile(newURL.toLocalFile()); outputFormat = outputFormatString.toLatin1(); if (!d->isExporting) { justChangingFilterOptions = (newURL == document->url()) && (outputFormat == document->mimeType()); } else { justChangingFilterOptions = (newURL == d->lastExportUrl) && (outputFormat == d->lastExportedFormat); } bool bOk = true; if (newURL.isEmpty()) { bOk = false; } if (bOk) { bool wantToSave = true; // don't change this line unless you know what you're doing :) if (!justChangingFilterOptions) { if (!document->isNativeFormat(outputFormat)) wantToSave = true; } if (wantToSave) { // // Note: // If the user is stupid enough to Export to the current URL, // we do _not_ change this operation into a Save As. Reasons // follow: // // 1. A check like "d->isExporting && oldURL == newURL" // doesn't _always_ work on case-insensitive filesystems // and inconsistent behaviour is bad. // 2. It is probably not a good idea to change document->mimeType // and friends because the next time the user File/Save's, // (not Save As) they won't be expecting that they are // using their File/Export settings // // As a bad side-effect of this, the modified flag will not // be updated and it is possible that what is currently on // their screen is not what is stored on disk (through loss // of formatting). But if you are dumb enough to change // mimetype but not the filename, then arguably, _you_ are // the "bug" :) // // - Clarence // document->setOutputMimeType(outputFormat); if (!d->isExporting) { // Save As ret = document->saveAs(newURL); if (ret) { dbgUI << "Successful Save As!"; addRecentURL(newURL); setReadWrite(true); } else { dbgUI << "Failed Save As!"; document->setUrl(oldURL); document->setLocalFilePath(oldFile); document->setOutputMimeType(oldOutputFormat); } } else { // Export ret = document->exportDocument(newURL); if (ret) { // a few file dialog convenience things d->lastExportUrl = newURL; d->lastExportedFormat = outputFormat; } // always restore output format document->setOutputMimeType(oldOutputFormat); } } // if (wantToSave) { else ret = false; } // if (bOk) { else ret = false; } else { // saving // be sure document has the correct outputMimeType! if (d->isExporting || document->isModified()) { ret = document->save(); } if (!ret) { dbgUI << "Failed Save!"; document->setUrl(oldURL); document->setLocalFilePath(oldFile); } } if (!ret && reset_url) document->resetURL(); //clean the suggested filename as the save dialog was rejected updateReloadFileAction(document); updateCaption(); return ret; } void KisMainWindow::undo() { if (activeView()) { activeView()->undoAction()->trigger(); d->undo->setText(activeView()->undoAction()->text()); } } void KisMainWindow::redo() { if (activeView()) { activeView()->redoAction()->trigger(); d->redo->setText(activeView()->redoAction()->text()); } } void KisMainWindow::closeEvent(QCloseEvent *e) { d->mdiArea->closeAllSubWindows(); QAction *action= d->viewManager->actionCollection()->action("view_show_canvas_only"); if ((action) && (action->isChecked())) { action->setChecked(false); } KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow"); cfg.writeEntry("ko_geometry", saveGeometry().toBase64()); cfg.writeEntry("ko_windowstate", saveState().toBase64()); { KConfigGroup group( KSharedConfig::openConfig(), "theme"); group.writeEntry("Theme", d->themeManager->currentThemeName()); } QList childrenList = d->mdiArea->subWindowList(); if (childrenList.isEmpty()) { d->deferredClosingEvent = e; if (!d->dockerStateBeforeHiding.isEmpty()) { restoreState(d->dockerStateBeforeHiding); } statusBar()->setVisible(true); menuBar()->setVisible(true); saveWindowSettings(); if (d->noCleanup) return; Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { KisView *view = dynamic_cast(subwin); if (view) { KisPart::instance()->removeView(view); } } if (!d->dockWidgetVisibilityMap.isEmpty()) { // re-enable dockers for persistency Q_FOREACH (QDockWidget* dockWidget, d->dockWidgetsMap) dockWidget->setVisible(d->dockWidgetVisibilityMap.value(dockWidget)); } } else { e->setAccepted(false); } } void KisMainWindow::saveWindowSettings() { KSharedConfigPtr config = KSharedConfig::openConfig(); if (d->windowSizeDirty ) { dbgUI << "KisMainWindow::saveWindowSettings"; KConfigGroup group = config->group("MainWindow"); KWindowConfig::saveWindowSize(windowHandle(), group); config->sync(); d->windowSizeDirty = false; } if (!d->activeView || d->activeView->document()) { // Save toolbar position into the config file of the app, under the doc's component name KConfigGroup group = KSharedConfig::openConfig()->group("krita"); saveMainWindowSettings(group); // Save collapsable state of dock widgets for (QMap::const_iterator i = d->dockWidgetsMap.constBegin(); i != d->dockWidgetsMap.constEnd(); ++i) { if (i.value()->widget()) { KConfigGroup dockGroup = group.group(QString("DockWidget ") + i.key()); dockGroup.writeEntry("Collapsed", i.value()->widget()->isHidden()); dockGroup.writeEntry("Locked", i.value()->property("Locked").toBool()); dockGroup.writeEntry("DockArea", (int) dockWidgetArea(i.value())); dockGroup.writeEntry("xPosition", (int) i.value()->widget()->x()); dockGroup.writeEntry("yPosition", (int) i.value()->widget()->y()); dockGroup.writeEntry("width", (int) i.value()->widget()->width()); dockGroup.writeEntry("height", (int) i.value()->widget()->height()); } } } KSharedConfig::openConfig()->sync(); resetAutoSaveSettings(); // Don't let KMainWindow override the good stuff we wrote down } void KisMainWindow::resizeEvent(QResizeEvent * e) { d->windowSizeDirty = true; KXmlGuiWindow::resizeEvent(e); } void KisMainWindow::setActiveView(KisView* view) { d->activeView = view; updateCaption(); actionCollection()->action("edit_undo")->setText(activeView()->undoAction()->text()); actionCollection()->action("edit_redo")->setText(activeView()->redoAction()->text()); d->viewManager->setCurrentView(view); } void KisMainWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasFormat("application/x-qt-image")) { event->accept(); } } void KisMainWindow::dropEvent(QDropEvent *event) { if (event->mimeData()->hasUrls() && event->mimeData()->urls().size() > 0) { Q_FOREACH (const QUrl &url, event->mimeData()->urls()) { openDocument(url); } } } void KisMainWindow::dragMoveEvent(QDragMoveEvent * event) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar && d->mdiArea->viewMode() == QMdiArea::TabbedView) { qWarning() << "WARNING!!! Cannot find QTabBar in the main window! Looks like Qt has changed behavior. Drag & Drop between multiple tabs might not work properly (tabs will not switch automatically)!"; } if (tabBar && tabBar->isVisible()) { QPoint pos = tabBar->mapFromGlobal(mapToGlobal(event->pos())); if (tabBar->rect().contains(pos)) { const int tabIndex = tabBar->tabAt(pos); if (tabIndex >= 0 && tabBar->currentIndex() != tabIndex) { d->tabSwitchCompressor->start(tabIndex); } } else if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } } void KisMainWindow::dragLeaveEvent(QDragLeaveEvent * /*event*/) { if (d->tabSwitchCompressor->isActive()) { d->tabSwitchCompressor->stop(); } } void KisMainWindow::switchTab(int index) { QTabBar *tabBar = d->findTabBarHACK(); if (!tabBar) return; tabBar->setCurrentIndex(index); } void KisMainWindow::slotFileNew() { const QStringList mimeFilter = KisImportExportManager::mimeFilter(KisImportExportManager::Import); KisOpenPane *startupWidget = new KisOpenPane(this, mimeFilter, QStringLiteral("templates/")); startupWidget->setWindowModality(Qt::WindowModal); KisConfig cfg; int w = cfg.defImageWidth(); int h = cfg.defImageHeight(); const double resolution = cfg.defImageResolution(); const QString colorModel = cfg.defColorModel(); const QString colorDepth = cfg.defaultColorDepth(); const QString colorProfile = cfg.defColorProfile(); CustomDocumentWidgetItem item; item.widget = new KisCustomImageWidget(startupWidget, w, h, resolution, colorModel, colorDepth, colorProfile, i18n("Unnamed")); item.icon = "document-new"; startupWidget->addCustomDocumentWidget(item.widget, item.title, item.icon); QSize sz = KisClipboard::instance()->clipSize(); if (sz.isValid() && sz.width() != 0 && sz.height() != 0) { w = sz.width(); h = sz.height(); } item.widget = new KisImageFromClipboard(startupWidget, w, h, resolution, colorModel, colorDepth, colorProfile, i18n("Unnamed")); item.title = i18n("Create from Clipboard"); item.icon = "tab-new"; startupWidget->addCustomDocumentWidget(item.widget, item.title, item.icon); // calls deleteLater connect(startupWidget, SIGNAL(documentSelected(KisDocument*)), KisPart::instance(), SLOT(startCustomDocument(KisDocument*))); // calls deleteLater connect(startupWidget, SIGNAL(openTemplate(const QUrl&)), KisPart::instance(), SLOT(openTemplate(const QUrl&))); startupWidget->exec(); // Cancel calls deleteLater... } void KisMainWindow::slotFileOpen() { QStringList urls = showOpenFileDialog(); if (urls.isEmpty()) return; Q_FOREACH (const QString& url, urls) { if (!url.isEmpty()) { bool res = openDocument(QUrl::fromLocalFile(url)); if (!res) { warnKrita << "Loading" << url << "failed"; } } } } void KisMainWindow::slotFileOpenRecent(const QUrl &url) { (void) openDocument(QUrl::fromLocalFile(url.toLocalFile())); } void KisMainWindow::slotFileSave() { if (saveDocument(d->activeView->document())) { emit documentSaved(); } } void KisMainWindow::slotFileSaveAs() { if (saveDocument(d->activeView->document(), true)) { emit documentSaved(); } } KoCanvasResourceManager *KisMainWindow::resourceManager() const { return d->viewManager->resourceProvider()->resourceManager(); } int KisMainWindow::viewCount() const { return d->mdiArea->subWindowList().size(); } bool KisMainWindow::restoreWorkspace(const QByteArray &state) { QByteArray oldState = saveState(); const bool showTitlebars = KisConfig().showDockerTitleBars(); // needed because otherwise the layout isn't correctly restored in some situations Q_FOREACH (QDockWidget *dock, dockWidgets()) { dock->hide(); dock->titleBarWidget()->setVisible(showTitlebars); } bool success = KXmlGuiWindow::restoreState(state); if (!success) { KXmlGuiWindow::restoreState(oldState); Q_FOREACH (QDockWidget *dock, dockWidgets()) { if (dock->titleBarWidget()) { dock->titleBarWidget()->setVisible(showTitlebars || dock->isFloating()); } } return false; } Q_FOREACH (QDockWidget *dock, dockWidgets()) { if (dock->titleBarWidget()) { const bool isCollapsed = (dock->widget() && dock->widget()->isHidden()) || !dock->widget(); dock->titleBarWidget()->setVisible(showTitlebars || (dock->isFloating() && isCollapsed)); } } return success; } KisViewManager *KisMainWindow::viewManager() const { return d->viewManager; } void KisMainWindow::slotDocumentInfo() { if (!d->activeView->document()) return; KoDocumentInfo *docInfo = d->activeView->document()->documentInfo(); if (!docInfo) return; KoDocumentInfoDlg *dlg = d->activeView->document()->createDocumentInfoDialog(this, docInfo); if (dlg->exec()) { if (dlg->isDocumentSaved()) { d->activeView->document()->setModified(false); } else { d->activeView->document()->setModified(true); } d->activeView->document()->setTitleModified(); } delete dlg; } bool KisMainWindow::slotFileCloseAll() { Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { if (subwin) { if(!subwin->close()) return false; } } updateCaption(); return true; } void KisMainWindow::slotFileQuit() { if(!slotFileCloseAll()) return; close(); Q_FOREACH (QPointer mainWin, KisPart::instance()->mainWindows()) { if (mainWin != this) { if(!mainWin->slotFileCloseAll()) return; mainWin->close(); } } } void KisMainWindow::slotFilePrint() { if (!activeView()) return; KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return; applyDefaultSettings(printJob->printer()); QPrintDialog *printDialog = activeView()->createPrintDialog( printJob, this ); if (printDialog && printDialog->exec() == QDialog::Accepted) { printJob->printer().setPageMargins(0.0, 0.0, 0.0, 0.0, QPrinter::Point); printJob->printer().setPaperSize(QSizeF(activeView()->image()->width() / (72.0 * activeView()->image()->xRes()), activeView()->image()->height()/ (72.0 * activeView()->image()->yRes())), QPrinter::Inch); printJob->startPrinting(KisPrintJob::DeleteWhenDone); } else { delete printJob; } delete printDialog; } void KisMainWindow::slotFilePrintPreview() { if (!activeView()) return; KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return; /* Sets the startPrinting() slot to be blocking. The Qt print-preview dialog requires the printing to be completely blocking and only return when the full document has been printed. By default the KisPrintingDialog is non-blocking and multithreading, setting blocking to true will allow it to be used in the preview dialog */ printJob->setProperty("blocking", true); QPrintPreviewDialog *preview = new QPrintPreviewDialog(&printJob->printer(), this); printJob->setParent(preview); // will take care of deleting the job connect(preview, SIGNAL(paintRequested(QPrinter*)), printJob, SLOT(startPrinting())); preview->exec(); delete preview; } KisPrintJob* KisMainWindow::exportToPdf(QString pdfFileName) { if (!activeView()) return 0; if (!activeView()->document()) return 0; KoPageLayout pageLayout; pageLayout.width = 0; pageLayout.height = 0; pageLayout.topMargin = 0; pageLayout.bottomMargin = 0; pageLayout.leftMargin = 0; pageLayout.rightMargin = 0; if (pdfFileName.isEmpty()) { KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); QString defaultDir = group.readEntry("SavePdfDialog"); if (defaultDir.isEmpty()) defaultDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation); QUrl startUrl = QUrl::fromLocalFile(defaultDir); KisDocument* pDoc = d->activeView->document(); /** if document has a file name, take file name and replace extension with .pdf */ if (pDoc && pDoc->url().isValid()) { startUrl = pDoc->url(); QString fileName = startUrl.toLocalFile(); fileName = fileName.replace( QRegExp( "\\.\\w{2,5}$", Qt::CaseInsensitive ), ".pdf" ); startUrl = startUrl.adjusted(QUrl::RemoveFilename); startUrl.setPath(startUrl.path() + fileName ); } QPointer layoutDlg(new KoPageLayoutDialog(this, pageLayout)); layoutDlg->setWindowModality(Qt::WindowModal); if (layoutDlg->exec() != QDialog::Accepted || !layoutDlg) { delete layoutDlg; return 0; } pageLayout = layoutDlg->pageLayout(); delete layoutDlg; KoFileDialog dialog(this, KoFileDialog::SaveFile, "OpenDocument"); dialog.setCaption(i18n("Export as PDF")); dialog.setDefaultDir(startUrl.toLocalFile()); dialog.setMimeTypeFilters(QStringList() << "application/pdf"); QUrl url = QUrl::fromUserInput(dialog.filename()); pdfFileName = url.toLocalFile(); if (pdfFileName.isEmpty()) return 0; } KisPrintJob *printJob = activeView()->createPrintJob(); if (printJob == 0) return 0; if (isHidden()) { printJob->setProperty("noprogressdialog", true); } applyDefaultSettings(printJob->printer()); // TODO for remote files we have to first save locally and then upload. printJob->printer().setOutputFileName(pdfFileName); printJob->printer().setDocName(pdfFileName); printJob->printer().setColorMode(QPrinter::Color); if (pageLayout.format == KoPageFormat::CustomSize) { printJob->printer().setPaperSize(QSizeF(pageLayout.width, pageLayout.height), QPrinter::Millimeter); } else { printJob->printer().setPaperSize(KoPageFormat::printerPageSize(pageLayout.format)); } printJob->printer().setPageMargins(pageLayout.leftMargin, pageLayout.topMargin, pageLayout.rightMargin, pageLayout.bottomMargin, QPrinter::Millimeter); switch (pageLayout.orientation) { case KoPageFormat::Portrait: printJob->printer().setOrientation(QPrinter::Portrait); break; case KoPageFormat::Landscape: printJob->printer().setOrientation(QPrinter::Landscape); break; } //before printing check if the printer can handle printing if (!printJob->canPrint()) { QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Cannot export to the specified file")); } printJob->startPrinting(KisPrintJob::DeleteWhenDone); return printJob; } void KisMainWindow::importAnimation() { if (!activeView()) return; KisDocument *document = activeView()->document(); if (!document) return; KisDlgImportImageSequence dlg(this, document); if (dlg.exec() == QDialog::Accepted) { QStringList files = dlg.files(); int firstFrame = dlg.firstFrame(); int step = dlg.step(); document->setFileProgressProxy(); document->setFileProgressUpdater(i18n("Import frames")); KisAnimationImporter importer(document); KisImportExportFilter::ConversionStatus status = importer.import(files, firstFrame, step); document->clearFileProgressUpdater(); document->clearFileProgressProxy(); if (status != KisImportExportFilter::OK && status != KisImportExportFilter::InternalError) { QString msg = KisImportExportFilter::conversionStatusString(status); if (!msg.isEmpty()) QMessageBox::critical(0, i18nc("@title:window", "Krita"), i18n("Could not finish import animation:\n%1", msg)); } activeView()->canvasBase()->refetchDataFromImage(); } } void KisMainWindow::slotConfigureToolbars() { KConfigGroup group = KSharedConfig::openConfig()->group("krita"); saveMainWindowSettings(group); KEditToolBar edit(factory(), this); connect(&edit, SIGNAL(newToolBarConfig()), this, SLOT(slotNewToolbarConfig())); (void) edit.exec(); applyToolBarLayout(); } void KisMainWindow::slotNewToolbarConfig() { applyMainWindowSettings(KSharedConfig::openConfig()->group("krita")); KXMLGUIFactory *factory = guiFactory(); Q_UNUSED(factory); // Check if there's an active view if (!d->activeView) return; plugActionList("toolbarlist", d->toolbarList); applyToolBarLayout(); } void KisMainWindow::slotToolbarToggled(bool toggle) { //dbgUI <<"KisMainWindow::slotToolbarToggled" << sender()->name() <<" toggle=" << true; // The action (sender) and the toolbar have the same name KToolBar * bar = toolBar(sender()->objectName()); if (bar) { if (toggle) { bar->show(); } else { bar->hide(); } if (d->activeView && d->activeView->document()) { KConfigGroup group = KSharedConfig::openConfig()->group("krita"); saveMainWindowSettings(group); } } else warnUI << "slotToolbarToggled : Toolbar " << sender()->objectName() << " not found!"; } void KisMainWindow::viewFullscreen(bool fullScreen) { KisConfig cfg; cfg.setFullscreenMode(fullScreen); if (fullScreen) { setWindowState(windowState() | Qt::WindowFullScreen); // set } else { setWindowState(windowState() & ~Qt::WindowFullScreen); // reset } } void KisMainWindow::slotProgress(int value) { qApp->processEvents(); StdLockableWrapper wrapper(&d->progressMutex); std::unique_lock> l(wrapper, std::try_to_lock); if (!l.owns_lock()) return; dbgUI << "KisMainWindow::slotProgress" << value; if (value <= -1 || value >= 100) { if (d->progress) { statusBar()->removeWidget(d->progress); delete d->progress; d->progress = 0; disconnect(d->progressCancel, SIGNAL(clicked()), this, SLOT(slotProgressCanceled())); statusBar()->removeWidget(d->progressCancel); delete d->progressCancel; d->progressCancel = 0; } d->firstTime = true; return; } if (d->firstTime || !d->progress) { // The statusbar might not even be created yet. // So check for that first, and create it if necessary QStatusBar *bar = findChild(); if (!bar) { statusBar()->show(); QApplication::sendPostedEvents(this, QEvent::ChildAdded); } if (d->progress) { statusBar()->removeWidget(d->progress); delete d->progress; d->progress = 0; disconnect(d->progressCancel, SIGNAL(clicked()), this, SLOT(slotProgressCanceled())); statusBar()->removeWidget(d->progressCancel); delete d->progressCancel; d->progress = 0; } d->progressCancel = new QToolButton(statusBar()); d->progressCancel->setMaximumHeight(statusBar()->fontMetrics().height()); d->progressCancel->setIcon(KisIconUtils::loadIcon("process-stop")); statusBar()->addPermanentWidget(d->progressCancel); d->progress = new QProgressBar(statusBar()); d->progress->setMaximumHeight(statusBar()->fontMetrics().height()); d->progress->setRange(0, 100); statusBar()->addPermanentWidget(d->progress); connect(d->progressCancel, SIGNAL(clicked()), this, SLOT(slotProgressCanceled())); d->progress->show(); d->progressCancel->show(); d->firstTime = false; } if (!d->progress.isNull()) { d->progress->setValue(value); } qApp->processEvents(); } void KisMainWindow::slotProgressCanceled() { emit sigProgressCanceled(); } void KisMainWindow::setMaxRecentItems(uint _number) { d->recentFiles->setMaxItems(_number); } void KisMainWindow::slotReloadFile() { KisDocument* document = d->activeView->document(); if (!document || document->url().isEmpty()) return; if (document->isModified()) { bool ok = QMessageBox::question(this, i18nc("@title:window", "Krita"), i18n("You will lose all changes made since your last save\n" "Do you want to continue?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes) == QMessageBox::Yes; if (!ok) return; } QUrl url = document->url(); saveWindowSettings(); if (!document->reload()) { QMessageBox::critical(this, i18nc("@title:window", "Krita"), i18n("Error: Could not reload this document")); } return; } void KisMainWindow::slotImportFile() { dbgUI << "slotImportFile()"; d->isImporting = true; slotFileOpen(); d->isImporting = false; } void KisMainWindow::slotExportFile() { dbgUI << "slotExportFile()"; d->isExporting = true; slotFileSaveAs(); d->isExporting = false; } QDockWidget* KisMainWindow::createDockWidget(KoDockFactoryBase* factory) { QDockWidget* dockWidget = 0; if (!d->dockWidgetsMap.contains(factory->id())) { dockWidget = factory->createDockWidget(); // It is quite possible that a dock factory cannot create the dock; don't // do anything in that case. if (!dockWidget) { warnKrita << "Could not create docker for" << factory->id(); return 0; } KoDockWidgetTitleBar *titleBar = dynamic_cast(dockWidget->titleBarWidget()); // Check if the dock widget is supposed to be collapsable if (!dockWidget->titleBarWidget()) { titleBar = new KoDockWidgetTitleBar(dockWidget); dockWidget->setTitleBarWidget(titleBar); titleBar->setCollapsable(factory->isCollapsable()); } titleBar->setFont(KoDockRegistry::dockFont()); dockWidget->setObjectName(factory->id()); dockWidget->setParent(this); if (dockWidget->widget() && dockWidget->widget()->layout()) dockWidget->widget()->layout()->setContentsMargins(1, 1, 1, 1); Qt::DockWidgetArea side = Qt::RightDockWidgetArea; bool visible = true; switch (factory->defaultDockPosition()) { case KoDockFactoryBase::DockTornOff: dockWidget->setFloating(true); // position nicely? break; case KoDockFactoryBase::DockTop: side = Qt::TopDockWidgetArea; break; case KoDockFactoryBase::DockLeft: side = Qt::LeftDockWidgetArea; break; case KoDockFactoryBase::DockBottom: side = Qt::BottomDockWidgetArea; break; case KoDockFactoryBase::DockRight: side = Qt::RightDockWidgetArea; break; case KoDockFactoryBase::DockMinimized: default: side = Qt::RightDockWidgetArea; visible = false; } KConfigGroup group = KSharedConfig::openConfig()->group("krita").group("DockWidget " + factory->id()); side = static_cast(group.readEntry("DockArea", static_cast(side))); if (side == Qt::NoDockWidgetArea) side = Qt::RightDockWidgetArea; addDockWidget(side, dockWidget); if (!visible) { dockWidget->hide(); } bool collapsed = factory->defaultCollapsed(); bool locked = false; group = KSharedConfig::openConfig()->group("krita").group("DockWidget " + factory->id()); collapsed = group.readEntry("Collapsed", collapsed); locked = group.readEntry("Locked", locked); //dbgKrita << "docker" << factory->id() << dockWidget << "collapsed" << collapsed << "locked" << locked << "titlebar" << titleBar; if (titleBar && collapsed) titleBar->setCollapsed(true); if (titleBar && locked) titleBar->setLocked(true); d->dockWidgetsMap.insert(factory->id(), dockWidget); } else { dockWidget = d->dockWidgetsMap[factory->id()]; } #ifdef Q_OS_OSX dockWidget->setAttribute(Qt::WA_MacSmallSize, true); #endif dockWidget->setFont(KoDockRegistry::dockFont()); connect(dockWidget, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)), this, SLOT(forceDockTabFonts())); return dockWidget; } void KisMainWindow::forceDockTabFonts() { Q_FOREACH (QObject *child, children()) { if (child->inherits("QTabBar")) { ((QTabBar *)child)->setFont(KoDockRegistry::dockFont()); } } } QList KisMainWindow::dockWidgets() const { return d->dockWidgetsMap.values(); } QDockWidget* KisMainWindow::dockWidget(const QString &id) { if (!d->dockWidgetsMap.contains(id)) return 0; return d->dockWidgetsMap[id]; } QList KisMainWindow::canvasObservers() const { QList observers; Q_FOREACH (QDockWidget *docker, dockWidgets()) { KoCanvasObserverBase *observer = dynamic_cast(docker); if (observer) { observers << observer; } else { warnKrita << docker << "is not a canvas observer"; } } return observers; } void KisMainWindow::toggleDockersVisibility(bool visible) { if (!visible) { d->dockerStateBeforeHiding = saveState(); Q_FOREACH (QObject* widget, children()) { if (widget->inherits("QDockWidget")) { QDockWidget* dw = static_cast(widget); if (dw->isVisible()) { dw->hide(); } } } } else { restoreState(d->dockerStateBeforeHiding); } } void KisMainWindow::setToolbarList(QList toolbarList) { qDeleteAll(d->toolbarList); d->toolbarList = toolbarList; } void KisMainWindow::slotDocumentTitleModified(const QString &caption, bool mod) { updateCaption(); updateCaption(caption, mod); updateReloadFileAction(d->activeView ? d->activeView->document() : 0); } void KisMainWindow::subWindowActivated() { bool enabled = (activeKisView() != 0); d->mdiCascade->setEnabled(enabled); d->mdiNextWindow->setEnabled(enabled); d->mdiPreviousWindow->setEnabled(enabled); d->mdiTile->setEnabled(enabled); d->close->setEnabled(enabled); d->closeAll->setEnabled(enabled); setActiveSubWindow(d->mdiArea->activeSubWindow()); Q_FOREACH (QToolBar *tb, toolBars()) { if (tb->objectName() == "BrushesAndStuff") { tb->setEnabled(enabled); } } updateCaption(); d->actionManager()->updateGUI(); } void KisMainWindow::updateWindowMenu() { QMenu *menu = d->windowMenu->menu(); menu->clear(); menu->addAction(d->newWindow); menu->addAction(d->documentMenu); QMenu *docMenu = d->documentMenu->menu(); docMenu->clear(); Q_FOREACH (QPointer doc, KisPart::instance()->documents()) { if (doc) { QString title = doc->url().toDisplayString(); if (title.isEmpty() && doc->image()) { title = doc->image()->objectName(); } QAction *action = docMenu->addAction(title); action->setIcon(qApp->windowIcon()); connect(action, SIGNAL(triggered()), d->documentMapper, SLOT(map())); d->documentMapper->setMapping(action, doc); } } menu->addSeparator(); menu->addAction(d->close); menu->addAction(d->closeAll); if (d->mdiArea->viewMode() == QMdiArea::SubWindowView) { menu->addSeparator(); menu->addAction(d->mdiTile); menu->addAction(d->mdiCascade); } menu->addSeparator(); menu->addAction(d->mdiNextWindow); menu->addAction(d->mdiPreviousWindow); menu->addSeparator(); QList windows = d->mdiArea->subWindowList(); for (int i = 0; i < windows.size(); ++i) { QPointerchild = qobject_cast(windows.at(i)->widget()); - if (child) { + if (child && child->document()) { QString text; if (i < 9) { text = i18n("&%1 %2", i + 1, child->document()->url().toDisplayString()); } else { text = i18n("%1 %2", i + 1, child->document()->url().toDisplayString()); } QAction *action = menu->addAction(text); action->setIcon(qApp->windowIcon()); action->setCheckable(true); action->setChecked(child == activeKisView()); connect(action, SIGNAL(triggered()), d->windowMapper, SLOT(map())); d->windowMapper->setMapping(action, windows.at(i)); } } updateCaption(); } void KisMainWindow::setActiveSubWindow(QWidget *window) { if (!window) return; QMdiSubWindow *subwin = qobject_cast(window); //dbgKrita << "setActiveSubWindow();" << subwin << d->activeSubWindow; if (subwin && subwin != d->activeSubWindow) { KisView *view = qobject_cast(subwin->widget()); //dbgKrita << "\t" << view << activeView(); if (view && view != activeView()) { setActiveView(view); } d->activeSubWindow = subwin; } updateWindowMenu(); d->actionManager()->updateGUI(); } void KisMainWindow::configChanged() { KisConfig cfg; QMdiArea::ViewMode viewMode = (QMdiArea::ViewMode)cfg.readEntry("mdi_viewmode", (int)QMdiArea::TabbedView); d->mdiArea->setViewMode(viewMode); Q_FOREACH (QMdiSubWindow *subwin, d->mdiArea->subWindowList()) { subwin->setOption(QMdiSubWindow::RubberBandMove, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); subwin->setOption(QMdiSubWindow::RubberBandResize, cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); } KConfigGroup group( KSharedConfig::openConfig(), "theme"); d->themeManager->setCurrentTheme(group.readEntry("Theme", "Krita dark")); d->actionManager()->updateGUI(); QBrush brush(cfg.getMDIBackgroundColor()); d->mdiArea->setBackground(brush); QString backgroundImage = cfg.getMDIBackgroundImage(); if (backgroundImage != "") { QImage image(backgroundImage); QBrush brush(image); d->mdiArea->setBackground(brush); } d->mdiArea->update(); } void KisMainWindow::newView(QObject *document) { KisDocument *doc = qobject_cast(document); addViewAndNotifyLoadingCompleted(doc); d->actionManager()->updateGUI(); } void KisMainWindow::newWindow() { KisPart::instance()->createMainWindow()->show(); } void KisMainWindow::closeCurrentWindow() { d->mdiArea->currentSubWindow()->close(); d->actionManager()->updateGUI(); } void KisMainWindow::checkSanity() { // print error if the lcms engine is not available if (!KoColorSpaceEngineRegistry::instance()->contains("icc")) { // need to wait 1 event since exiting here would not work. m_errorMessage = i18n("The Calligra LittleCMS color management plugin is not installed. Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } KisPaintOpPresetResourceServer * rserver = KisResourceServerProvider::instance()->paintOpPresetServer(); if (rserver->resources().isEmpty()) { m_errorMessage = i18n("Krita cannot find any brush presets! Krita will quit now."); m_dieOnError = true; QTimer::singleShot(0, this, SLOT(showErrorAndDie())); return; } } void KisMainWindow::showErrorAndDie() { QMessageBox::critical(0, i18nc("@title:window", "Installation error"), m_errorMessage); if (m_dieOnError) { exit(10); } } void KisMainWindow::showAboutApplication() { KisAboutApplication dlg(this); dlg.exec(); } QPointerKisMainWindow::activeKisView() { if (!d->mdiArea) return 0; QMdiSubWindow *activeSubWindow = d->mdiArea->activeSubWindow(); //dbgKrita << "activeKisView" << activeSubWindow; if (!activeSubWindow) return 0; return qobject_cast(activeSubWindow->widget()); } void KisMainWindow::newOptionWidgets(KoCanvasController *controller, const QList > &optionWidgetList) { KIS_ASSERT_RECOVER_NOOP(controller == KoToolManager::instance()->activeCanvasController()); bool isOurOwnView = false; Q_FOREACH (QPointer view, KisPart::instance()->views()) { if (view && view->canvasController() == controller) { isOurOwnView = view->mainWindow() == this; } } if (!isOurOwnView) return; Q_FOREACH (QWidget *w, optionWidgetList) { #ifdef Q_OS_OSX w->setAttribute(Qt::WA_MacSmallSize, true); #endif w->setFont(KoDockRegistry::dockFont()); } if (d->toolOptionsDocker) { d->toolOptionsDocker->setOptionWidgets(optionWidgetList); } else { d->viewManager->paintOpBox()->newOptionWidgets(optionWidgetList); } } void KisMainWindow::applyDefaultSettings(QPrinter &printer) { if (!d->activeView) return; QString title = d->activeView->document()->documentInfo()->aboutInfo("title"); if (title.isEmpty()) { title = d->activeView->document()->url().fileName(); // strip off the native extension (I don't want foobar.kwd.ps when printing into a file) QString extension = KisMimeDatabase::suffixesForMimeType(d->activeView->document()->outputMimeType()).first(); if (title.endsWith(extension)) { title.chop(extension.length()); } } if (title.isEmpty()) { // #139905 title = i18n("%1 unsaved document (%2)", qApp->applicationDisplayName(), QLocale().toString(QDate::currentDate(), QLocale::ShortFormat)); } printer.setDocName(title); } void KisMainWindow::createActions() { KisActionManager *actionManager = d->actionManager(); KisConfig cfg; actionManager->createStandardAction(KStandardAction::New, this, SLOT(slotFileNew())); actionManager->createStandardAction(KStandardAction::Open, this, SLOT(slotFileOpen())); actionManager->createStandardAction(KStandardAction::Quit, this, SLOT(slotFileQuit())); actionManager->createStandardAction(KStandardAction::ConfigureToolbars, this, SLOT(slotConfigureToolbars())); actionManager->createStandardAction(KStandardAction::FullScreen, this, SLOT(viewFullscreen(bool))); d->recentFiles = KStandardAction::openRecent(this, SLOT(slotFileOpenRecent(QUrl)), actionCollection()); connect(d->recentFiles, SIGNAL(recentListCleared()), this, SLOT(saveRecentFiles())); KSharedConfigPtr configPtr = KSharedConfig::openConfig(); d->recentFiles->loadEntries(configPtr->group("RecentFiles")); d->saveAction = actionManager->createStandardAction(KStandardAction::Save, this, SLOT(slotFileSave())); d->saveAction->setActivationFlags(KisAction::ACTIVE_IMAGE); d->saveActionAs = actionManager->createStandardAction(KStandardAction::SaveAs, this, SLOT(slotFileSaveAs())); d->saveActionAs->setActivationFlags(KisAction::ACTIVE_IMAGE); // d->printAction = actionManager->createStandardAction(KStandardAction::Print, this, SLOT(slotFilePrint())); // d->printAction->setActivationFlags(KisAction::ACTIVE_IMAGE); // d->printActionPreview = actionManager->createStandardAction(KStandardAction::PrintPreview, this, SLOT(slotFilePrintPreview())); // d->printActionPreview->setActivationFlags(KisAction::ACTIVE_IMAGE); d->undo = actionManager->createStandardAction(KStandardAction::Undo, this, SLOT(undo())); d->undo ->setActivationFlags(KisAction::ACTIVE_IMAGE); d->redo = actionManager->createStandardAction(KStandardAction::Redo, this, SLOT(redo())); d->redo->setActivationFlags(KisAction::ACTIVE_IMAGE); // d->exportPdf = actionManager->createAction("file_export_pdf"); // connect(d->exportPdf, SIGNAL(triggered()), this, SLOT(exportToPdf())); d->importAnimation = actionManager->createAction("file_import_animation"); connect(d->importAnimation, SIGNAL(triggered()), this, SLOT(importAnimation())); d->closeAll = actionManager->createAction("file_close_all"); connect(d->closeAll, SIGNAL(triggered()), this, SLOT(slotFileCloseAll())); // d->reloadFile = actionManager->createAction("file_reload_file"); // d->reloadFile->setActivationFlags(KisAction::CURRENT_IMAGE_MODIFIED); // connect(d->reloadFile, SIGNAL(triggered(bool)), this, SLOT(slotReloadFile())); d->importFile = actionManager->createAction("file_import_file"); connect(d->importFile, SIGNAL(triggered(bool)), this, SLOT(slotImportFile())); d->exportFile = actionManager->createAction("file_export_file"); connect(d->exportFile, SIGNAL(triggered(bool)), this, SLOT(slotExportFile())); /* The following entry opens the document information dialog. Since the action is named so it intends to show data this entry should not have a trailing ellipses (...). */ d->showDocumentInfo = actionManager->createAction("file_documentinfo"); connect(d->showDocumentInfo, SIGNAL(triggered(bool)), this, SLOT(slotDocumentInfo())); d->themeManager->setThemeMenuAction(new KActionMenu(i18nc("@action:inmenu", "&Themes"), this)); d->themeManager->registerThemeActions(actionCollection()); connect(d->themeManager, SIGNAL(signalThemeChanged()), this, SLOT(slotThemeChanged())); d->toggleDockers = actionManager->createAction("view_toggledockers"); cfg.showDockers(true); d->toggleDockers->setChecked(true); connect(d->toggleDockers, SIGNAL(toggled(bool)), SLOT(toggleDockersVisibility(bool))); d->toggleDockerTitleBars = actionManager->createAction("view_toggledockertitlebars"); d->toggleDockerTitleBars->setChecked(cfg.showDockerTitleBars()); connect(d->toggleDockerTitleBars, SIGNAL(toggled(bool)), SLOT(showDockerTitleBars(bool))); actionCollection()->addAction("settings_dockers_menu", d->dockWidgetMenu); actionCollection()->addAction("window", d->windowMenu); d->mdiCascade = actionManager->createAction("windows_cascade"); connect(d->mdiCascade, SIGNAL(triggered()), d->mdiArea, SLOT(cascadeSubWindows())); d->mdiTile = actionManager->createAction("windows_tile"); connect(d->mdiTile, SIGNAL(triggered()), d->mdiArea, SLOT(tileSubWindows())); d->mdiNextWindow = actionManager->createAction("windows_next"); connect(d->mdiNextWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activateNextSubWindow())); d->mdiPreviousWindow = actionManager->createAction("windows_previous"); connect(d->mdiPreviousWindow, SIGNAL(triggered()), d->mdiArea, SLOT(activatePreviousSubWindow())); d->newWindow = actionManager->createAction("view_newwindow"); connect(d->newWindow, SIGNAL(triggered(bool)), this, SLOT(newWindow())); d->close = actionManager->createAction("file_close"); connect(d->close, SIGNAL(triggered()), SLOT(closeCurrentWindow())); actionManager->createStandardAction(KStandardAction::Preferences, this, SLOT(slotPreferences())); for (int i = 0; i < 2; i++) { d->expandingSpacers[i] = new KisAction(i18n("Expanding Spacer")); d->expandingSpacers[i]->setDefaultWidget(new QWidget(this)); d->expandingSpacers[i]->defaultWidget()->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); actionManager->addAction(QString("expanding_spacer_%1").arg(i), d->expandingSpacers[i]); } } void KisMainWindow::applyToolBarLayout() { const bool isPlastiqueStyle = style()->objectName() == "plastique"; Q_FOREACH (KToolBar *toolBar, toolBars()) { toolBar->layout()->setSpacing(4); if (isPlastiqueStyle) { toolBar->setContentsMargins(0, 0, 0, 2); } //Hide text for buttons with an icon in the toolbar Q_FOREACH (QAction *ac, toolBar->actions()){ if (ac->icon().pixmap(QSize(1,1)).isNull() == false){ ac->setPriority(QAction::LowPriority); }else { ac->setIcon(QIcon()); } } } } void KisMainWindow::initializeGeometry() { // if the user didn's specify the geometry on the command line (does anyone do that still?), // we first figure out some good default size and restore the x,y position. See bug 285804Z. KConfigGroup cfg( KSharedConfig::openConfig(), "MainWindow"); QByteArray geom = QByteArray::fromBase64(cfg.readEntry("ko_geometry", QByteArray())); if (!restoreGeometry(geom)) { const int scnum = QApplication::desktop()->screenNumber(parentWidget()); QRect desk = QApplication::desktop()->availableGeometry(scnum); // if the desktop is virtual then use virtual screen size if (QApplication::desktop()->isVirtualDesktop()) { desk = QApplication::desktop()->availableGeometry(QApplication::desktop()->screen(scnum)); } quint32 x = desk.x(); quint32 y = desk.y(); quint32 w = 0; quint32 h = 0; // Default size -- maximize on small screens, something useful on big screens const int deskWidth = desk.width(); if (deskWidth > 1024) { // a nice width, and slightly less than total available // height to componensate for the window decs w = (deskWidth / 3) * 2; h = (desk.height() / 3) * 2; } else { w = desk.width(); h = desk.height(); } x += (desk.width() - w) / 2; y += (desk.height() - h) / 2; move(x,y); setGeometry(geometry().x(), geometry().y(), w, h); } restoreWorkspace(QByteArray::fromBase64(cfg.readEntry("ko_windowstate", QByteArray()))); } void KisMainWindow::showManual() { QDesktopServices::openUrl(QUrl("https://docs.krita.org")); } void KisMainWindow::showDockerTitleBars(bool show) { Q_FOREACH (QDockWidget *dock, dockWidgets()) { if (dock->titleBarWidget()) { const bool isCollapsed = (dock->widget() && dock->widget()->isHidden()) || !dock->widget(); dock->titleBarWidget()->setVisible(show || (dock->isFloating() && isCollapsed)); } } KisConfig cfg; cfg.setShowDockerTitleBars(show); } void KisMainWindow::moveEvent(QMoveEvent *e) { if (qApp->desktop()->screenNumber(this) != qApp->desktop()->screenNumber(e->oldPos())) { KisConfigNotifier::instance()->notifyConfigChanged(); } } #include diff --git a/libs/ui/KisPaletteModel.h b/libs/ui/KisPaletteModel.h index 413f0b54ee..de073121e6 100644 --- a/libs/ui/KisPaletteModel.h +++ b/libs/ui/KisPaletteModel.h @@ -1,65 +1,68 @@ /* * Copyright (c) 2013 Sven Langkamp * * 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_PALETTEMODEL_H #define KIS_PALETTEMODEL_H +#include #include +#include + #include #include "kritaui_export.h" class KoColorSet; -class KoColorDisplayRendererInterface; + class KRITAUI_EXPORT KisPaletteModel : public QAbstractTableModel { Q_OBJECT public: KisPaletteModel(QObject* parent = 0); virtual ~KisPaletteModel(); virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; virtual int rowCount(const QModelIndex& parent = QModelIndex()) const; virtual int columnCount(const QModelIndex& parent = QModelIndex()) const; virtual Qt::ItemFlags flags(const QModelIndex& index) const; virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const; void setColorSet(KoColorSet* colorSet); KoColorSet* colorSet() const; /** * Installs a display renderer object for a palette that will * convert the KoColor to the displayable QColor. Default is the * dumb renderer. */ void setDisplayRenderer(KoColorDisplayRendererInterface *displayRenderer); QModelIndex indexFromId(int i) const; int idFromIndex(const QModelIndex &index) const; private Q_SLOTS: void slotDisplayConfigurationChanged(); private: KoColorSet* m_colorSet; - KoColorDisplayRendererInterface *m_displayRenderer; + QPointer m_displayRenderer; }; #endif diff --git a/libs/ui/KisView.cpp b/libs/ui/KisView.cpp index be34b20847..e58d0fc408 100644 --- a/libs/ui/KisView.cpp +++ b/libs/ui/KisView.cpp @@ -1,954 +1,954 @@ /* * Copyright (C) 2014 Boudewijn Rempt * * 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 "KisView.h" #include "KisView_p.h" #include #include #include #include "KoDocumentInfo.h" #include "KoPageLayout.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 "kis_canvas2.h" #include "kis_canvas_controller.h" #include "kis_canvas_resource_provider.h" #include "kis_config.h" #include "KisDocument.h" #include "kis_image_manager.h" #include "KisMainWindow.h" #include "kis_mimedata.h" #include "kis_mirror_axis.h" #include "kis_node_commands_adapter.h" #include "kis_node_manager.h" #include "KisPart.h" #include "KisPrintJob.h" #include "kis_shape_controller.h" #include "kis_tool_freehand.h" #include "KisUndoStackAction.h" #include "KisViewManager.h" #include "kis_zoom_manager.h" #include "kis_composite_progress_proxy.h" #include "kis_statusbar.h" #include "kis_painting_assistants_decoration.h" #include "kis_progress_widget.h" #include "kis_signal_compressor.h" #include "kis_filter_manager.h" #include "kis_file_layer.h" #include "krita_utils.h" #include "input/kis_input_manager.h" #include "KisRemoteFileFetcher.h" //static QString KisView::newObjectName() { static int s_viewIFNumber = 0; QString name; name.setNum(s_viewIFNumber++); name.prepend("view_"); return name; } bool KisView::s_firstView = true; class Q_DECL_HIDDEN KisView::Private { public: Private(KisView *_q, KisDocument *document, KoCanvasResourceManager *resourceManager, KActionCollection *actionCollection) : actionCollection(actionCollection) , viewConverter() , canvasController(_q, actionCollection) , canvas(&viewConverter, resourceManager, _q, document->shapeController()) , zoomManager(_q, &this->viewConverter, &this->canvasController) , paintingAssistantsDecoration(new KisPaintingAssistantsDecoration(_q)) , floatingMessageCompressor(100, KisSignalCompressor::POSTPONE) { } KisUndoStackAction *undo = 0; KisUndoStackAction *redo = 0; bool inOperation; //in the middle of an operation (no screen refreshing)? QPointer document; // our KisDocument QWidget *tempActiveWidget = 0; /** * Signals the document has been deleted. Can't use document==0 since this * only happens in ~QObject, and views get deleted by ~KisDocument. * XXX: either provide a better justification to do things this way, or * rework the mechanism. */ bool documentDeleted = false; KActionCollection* actionCollection; KisCoordinatesConverter viewConverter; KisCanvasController canvasController; KisCanvas2 canvas; KisZoomManager zoomManager; KisViewManager *viewManager = 0; KisNodeSP currentNode; KisPaintingAssistantsDecorationSP paintingAssistantsDecoration; bool isCurrent = false; bool showFloatingMessage = false; QPointer savedFloatingMessage; KisSignalCompressor floatingMessageCompressor; bool softProofing = false; bool gamutCheck = false; // Hmm sorry for polluting the private class with such a big inner class. // At the beginning it was a little struct :) class StatusBarItem { public: StatusBarItem(QWidget * widget, int stretch, bool permanent) : m_widget(widget), m_stretch(stretch), m_permanent(permanent), m_connected(false), m_hidden(false) {} bool operator==(const StatusBarItem& rhs) { return m_widget == rhs.m_widget; } bool operator!=(const StatusBarItem& rhs) { return m_widget != rhs.m_widget; } QWidget * widget() const { return m_widget; } void ensureItemShown(QStatusBar * sb) { Q_ASSERT(m_widget); if (!m_connected) { if (m_permanent) sb->addPermanentWidget(m_widget, m_stretch); else sb->addWidget(m_widget, m_stretch); if(!m_hidden) m_widget->show(); m_connected = true; } } void ensureItemHidden(QStatusBar * sb) { if (m_connected) { m_hidden = m_widget->isHidden(); sb->removeWidget(m_widget); m_widget->hide(); m_connected = false; } } private: QWidget * m_widget = 0; int m_stretch; bool m_permanent; bool m_connected = false; bool m_hidden = false; }; }; KisView::KisView(KisDocument *document, KoCanvasResourceManager *resourceManager, KActionCollection *actionCollection, QWidget *parent) : QWidget(parent) , d(new Private(this, document, resourceManager, actionCollection)) { Q_ASSERT(document); connect(document, SIGNAL(titleModified(QString,bool)), this, SIGNAL(titleModified(QString,bool))); setObjectName(newObjectName()); d->document = document; setFocusPolicy(Qt::StrongFocus); d->undo = new KisUndoStackAction(d->document->undoStack(), KisUndoStackAction::UNDO); d->redo = new KisUndoStackAction(d->document->undoStack(), KisUndoStackAction::RED0); QStatusBar * sb = statusBar(); if (sb) { // No statusbar in e.g. konqueror connect(d->document, SIGNAL(statusBarMessage(const QString&)), this, SLOT(slotActionStatusText(const QString&))); connect(d->document, SIGNAL(clearStatusBarMessage()), this, SLOT(slotClearStatusText())); } d->canvas.setup(); KisConfig cfg; d->canvasController.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); d->canvasController.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); d->canvasController.setDrawShadow(false); d->canvasController.setCanvasMode(KoCanvasController::Infinite); d->canvasController.setVastScrolling(cfg.vastScrolling()); d->canvasController.setCanvas(&d->canvas); d->zoomManager.setup(d->actionCollection); connect(&d->canvasController, SIGNAL(documentSizeChanged()), &d->zoomManager, SLOT(slotScrollAreaSizeChanged())); setAcceptDrops(true); connect(d->document, SIGNAL(sigLoadingFinished()), this, SLOT(slotLoadingFinished())); connect(d->document, SIGNAL(sigSavingFinished()), this, SLOT(slotSavingFinished())); d->canvas.addDecoration(d->paintingAssistantsDecoration); d->paintingAssistantsDecoration->setVisible(true); d->showFloatingMessage = cfg.showCanvasMessages(); } KisView::~KisView() { if (d->viewManager) { KoProgressProxy *proxy = d->viewManager->statusBar()->progress()->progressProxy(); KIS_ASSERT_RECOVER_NOOP(proxy); image()->compositeProgressProxy()->removeProxy(proxy); if (d->viewManager->filterManager()->isStrokeRunning()) { d->viewManager->filterManager()->cancel(); } } - - KisPart::instance()->removeView(this); KoToolManager::instance()->removeCanvasController(&d->canvasController); + KisPart::instance()->removeView(this); + delete d; } void KisView::notifyCurrentStateChanged(bool isCurrent) { d->isCurrent = isCurrent; if (!d->isCurrent && d->savedFloatingMessage) { d->savedFloatingMessage->removeMessage(); } KisInputManager *inputManager = globalInputManager(); if (d->isCurrent) { inputManager->attachPriorityEventFilter(&d->canvasController); } else { inputManager->detachPriorityEventFilter(&d->canvasController); } } void KisView::setShowFloatingMessage(bool show) { d->showFloatingMessage = show; } void KisView::showFloatingMessageImpl(const QString &message, const QIcon& icon, int timeout, KisFloatingMessage::Priority priority, int alignment) { if (!d->viewManager) return; if(d->isCurrent && d->showFloatingMessage && d->viewManager->qtMainWindow()) { if (d->savedFloatingMessage) { d->savedFloatingMessage->tryOverrideMessage(message, icon, timeout, priority, alignment); } else { d->savedFloatingMessage = new KisFloatingMessage(message, this->canvasBase()->canvasWidget(), false, timeout, priority, alignment); d->savedFloatingMessage->setShowOverParent(true); d->savedFloatingMessage->setIcon(icon); connect(&d->floatingMessageCompressor, SIGNAL(timeout()), d->savedFloatingMessage, SLOT(showMessage())); d->floatingMessageCompressor.start(); } } } bool KisView::canvasIsMirrored() const { return d->canvas.xAxisMirrored() || d->canvas.yAxisMirrored(); } void KisView::setViewManager(KisViewManager *view) { d->viewManager = view; KoToolManager::instance()->addController(&d->canvasController); KoToolManager::instance()->registerToolActions(d->actionCollection, &d->canvasController); dynamic_cast(d->document->shapeController())->setInitialShapeForCanvas(&d->canvas); if (resourceProvider()) { resourceProvider()->slotImageSizeChanged(); } if (d->viewManager && d->viewManager->nodeManager()) { d->viewManager->nodeManager()->nodesUpdated(); } connect(image(), SIGNAL(sigSizeChanged(const QPointF&, const QPointF&)), this, SLOT(slotImageSizeChanged(const QPointF&, const QPointF&))); connect(image(), SIGNAL(sigResolutionChanged(double,double)), this, SLOT(slotImageResolutionChanged())); // executed in a context of an image thread connect(image(), SIGNAL(sigNodeAddedAsync(KisNodeSP)), SLOT(slotImageNodeAdded(KisNodeSP)), Qt::DirectConnection); // executed in a context of the gui thread connect(this, SIGNAL(sigContinueAddNode(KisNodeSP)), SLOT(slotContinueAddNode(KisNodeSP)), Qt::AutoConnection); // executed in a context of an image thread connect(image(), SIGNAL(sigRemoveNodeAsync(KisNodeSP)), SLOT(slotImageNodeRemoved(KisNodeSP)), Qt::DirectConnection); // executed in a context of the gui thread connect(this, SIGNAL(sigContinueRemoveNode(KisNodeSP)), SLOT(slotContinueRemoveNode(KisNodeSP)), Qt::AutoConnection); /* * WARNING: Currently we access the global progress bar in two ways: * connecting to composite progress proxy (strokes) and creating * progress updaters. The latter way should be deprecated in favour * of displaying the status of the global strokes queue */ image()->compositeProgressProxy()->addProxy(d->viewManager->statusBar()->progress()->progressProxy()); connect(d->viewManager->statusBar()->progress(), SIGNAL(sigCancellationRequested()), image(), SLOT(requestStrokeCancellation())); d->viewManager->updateGUI(); KoToolManager::instance()->switchToolRequested("KritaShape/KisToolBrush"); } KisViewManager* KisView::viewManager() const { return d->viewManager; } void KisView::slotImageNodeAdded(KisNodeSP node) { emit sigContinueAddNode(node); } void KisView::slotContinueAddNode(KisNodeSP newActiveNode) { /** * When deleting the last layer, root node got selected. We should * fix it when the first layer is added back. * * Here we basically reimplement what Qt's view/model do. But * since they are not connected, we should do it manually. */ if (!d->isCurrent && (!d->currentNode || !d->currentNode->parent())) { d->currentNode = newActiveNode; } } void KisView::slotImageNodeRemoved(KisNodeSP node) { emit sigContinueRemoveNode(KritaUtils::nearestNodeAfterRemoval(node)); } void KisView::slotContinueRemoveNode(KisNodeSP newActiveNode) { if (!d->isCurrent) { d->currentNode = newActiveNode; } } QAction *KisView::undoAction() const { return d->undo; } QAction *KisView::redoAction() const { return d->redo; } KoZoomController *KisView::zoomController() const { return d->zoomManager.zoomController(); } KisZoomManager *KisView::zoomManager() const { return &d->zoomManager; } KisCanvasController *KisView::canvasController() const { return &d->canvasController; } KisCanvasResourceProvider *KisView::resourceProvider() const { if (d->viewManager) { return d->viewManager->resourceProvider(); } return 0; } KisInputManager* KisView::globalInputManager() const { return d->viewManager ? d->viewManager->inputManager() : 0; } KisCanvas2 *KisView::canvasBase() const { return &d->canvas; } KisImageWSP KisView::image() const { if (d->document) { return d->document->image(); } return 0; } KisCoordinatesConverter *KisView::viewConverter() const { return &d->viewConverter; } void KisView::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasImage() || event->mimeData()->hasUrls() || event->mimeData()->hasFormat("application/x-krita-node")) { event->accept(); // activate view if it should accept the drop this->setFocus(); } else { event->ignore(); } } void KisView::dropEvent(QDropEvent *event) { KisImageWSP kisimage = image(); Q_ASSERT(kisimage); QPoint cursorPos = canvasBase()->coordinatesConverter()->widgetToImage(event->pos()).toPoint(); QRect imageBounds = kisimage->bounds(); QPoint pasteCenter; bool forceRecenter; if (event->keyboardModifiers() & Qt::ShiftModifier && imageBounds.contains(cursorPos)) { pasteCenter = cursorPos; forceRecenter = true; } else { pasteCenter = imageBounds.center(); forceRecenter = false; } if (event->mimeData()->hasFormat("application/x-krita-node") || event->mimeData()->hasImage()) { KisShapeController *kritaShapeController = dynamic_cast(d->document->shapeController()); QList nodes = KisMimeData::loadNodes(event->mimeData(), imageBounds, pasteCenter, forceRecenter, kisimage, kritaShapeController); Q_FOREACH (KisNodeSP node, nodes) { if (node) { KisNodeCommandsAdapter adapter(viewManager()); if (!viewManager()->nodeManager()->activeLayer()) { adapter.addNode(node, kisimage->rootLayer() , 0); } else { adapter.addNode(node, viewManager()->nodeManager()->activeLayer()->parent(), viewManager()->nodeManager()->activeLayer()); } } } } else if (event->mimeData()->hasUrls()) { QList urls = event->mimeData()->urls(); if (urls.length() > 0) { QMenu popup; popup.setObjectName("drop_popup"); QAction *insertAsNewLayer = new QAction(i18n("Insert as New Layer"), &popup); QAction *insertManyLayers = new QAction(i18n("Insert Many Layers"), &popup); QAction *insertAsNewFileLayer = new QAction(i18n("Insert as New File Layer"), &popup); QAction *insertManyFileLayers = new QAction(i18n("Insert Many File Layers"), &popup); QAction *openInNewDocument = new QAction(i18n("Open in New Document"), &popup); QAction *openManyDocuments = new QAction(i18n("Open Many Documents"), &popup); QAction *cancel = new QAction(i18n("Cancel"), &popup); popup.addAction(insertAsNewLayer); popup.addAction(insertAsNewFileLayer); popup.addAction(openInNewDocument); popup.addAction(insertManyLayers); popup.addAction(insertManyFileLayers); popup.addAction(openManyDocuments); insertAsNewLayer->setEnabled(image() && urls.count() == 1); insertAsNewFileLayer->setEnabled(image() && urls.count() == 1); openInNewDocument->setEnabled(urls.count() == 1); insertManyLayers->setEnabled(image() && urls.count() > 1); insertManyFileLayers->setEnabled(image() && urls.count() > 1); openManyDocuments->setEnabled(urls.count() > 1); popup.addSeparator(); popup.addAction(cancel); QAction *action = popup.exec(QCursor::pos()); if (action != 0 && action != cancel) { QTemporaryFile *tmp = 0; for (QUrl url : urls) { if (!url.isLocalFile()) { // download the file and substitute the url KisRemoteFileFetcher fetcher; tmp = new QTemporaryFile(); tmp->setAutoRemove(true); if (!fetcher.fetchFile(url, tmp)) { qDebug() << "Fetching" << url << "failed"; continue; } url = url.fromLocalFile(tmp->fileName()); } if (url.isLocalFile()) { if (action == insertAsNewLayer || action == insertManyLayers) { d->viewManager->imageManager()->importImage(url); activateWindow(); } else if (action == insertAsNewFileLayer || action == insertManyFileLayers) { KisNodeCommandsAdapter adapter(viewManager()); KisFileLayer *fileLayer = new KisFileLayer(image(), "", url.toLocalFile(), KisFileLayer::None, image()->nextLayerName(), OPACITY_OPAQUE_U8); adapter.addNode(fileLayer, viewManager()->activeNode()->parent(), viewManager()->activeNode()); } else { Q_ASSERT(action == openInNewDocument || action == openManyDocuments); if (mainWindow()) { mainWindow()->openDocument(url); } } } delete tmp; tmp = 0; } } } } } KisDocument *KisView::document() const { return d->document; } void KisView::setDocument(KisDocument *document) { d->document->disconnect(this); d->document = document; QStatusBar *sb = statusBar(); if (sb) { // No statusbar in e.g. konqueror connect(d->document, SIGNAL(statusBarMessage(const QString&)), this, SLOT(slotActionStatusText(const QString&))); connect(d->document, SIGNAL(clearStatusBarMessage()), this, SLOT(slotClearStatusText())); } } void KisView::setDocumentDeleted() { d->documentDeleted = true; } QPrintDialog *KisView::createPrintDialog(KisPrintJob *printJob, QWidget *parent) { Q_UNUSED(parent); QPrintDialog *printDialog = new QPrintDialog(&printJob->printer(), this); printDialog->setMinMax(printJob->printer().fromPage(), printJob->printer().toPage()); printDialog->setEnabledOptions(printJob->printDialogOptions()); return printDialog; } KisMainWindow * KisView::mainWindow() const { return dynamic_cast(window()); } QStatusBar * KisView::statusBar() const { KisMainWindow *mw = mainWindow(); return mw ? mw->statusBar() : 0; } void KisView::slotActionStatusText(const QString &text) { QStatusBar *sb = statusBar(); if (sb) sb->showMessage(text); } void KisView::slotClearStatusText() { QStatusBar *sb = statusBar(); if (sb) sb->clearMessage(); } QList KisView::createChangeUnitActions(bool addPixelUnit) { UnitActionGroup* unitActions = new UnitActionGroup(d->document, addPixelUnit, this); return unitActions->actions(); } void KisView::closeEvent(QCloseEvent *event) { // Check whether we're the last view int viewCount = KisPart::instance()->viewCount(document()); if (viewCount > 1) { // there are others still, so don't bother the user event->accept(); return; } if (queryClose()) { d->viewManager->removeStatusBarItem(zoomManager()->zoomActionWidget()); event->accept(); return; } event->ignore(); } bool KisView::queryClose() { if (!document()) return true; if (document()->isModified()) { QString name; if (document()->documentInfo()) { name = document()->documentInfo()->aboutInfo("title"); } if (name.isEmpty()) name = document()->url().fileName(); if (name.isEmpty()) name = i18n("Untitled"); int res = QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("

The document '%1' has been modified.

Do you want to save it?

", name), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes); switch (res) { case QMessageBox::Yes : { bool isNative = (document()->outputMimeType() == document()->nativeFormatMimeType()); if (!viewManager()->mainWindow()->saveDocument(document(), !isNative)) return false; break; } case QMessageBox::No : document()->removeAutoSaveFiles(); document()->setModified(false); // Now when queryClose() is called by closeEvent it won't do anything. break; default : // case QMessageBox::Cancel : return false; } } return true; } void KisView::resetImageSizeAndScroll(bool changeCentering, const QPointF &oldImageStillPoint, const QPointF &newImageStillPoint) { const KisCoordinatesConverter *converter = d->canvas.coordinatesConverter(); QPointF oldPreferredCenter = d->canvasController.preferredCenter(); /** * Calculating the still point in old coordinates depending on the * parameters given */ QPointF oldStillPoint; if (changeCentering) { oldStillPoint = converter->imageToWidget(oldImageStillPoint) + converter->documentOffset(); } else { QSize oldDocumentSize = d->canvasController.documentSize(); oldStillPoint = QPointF(0.5 * oldDocumentSize.width(), 0.5 * oldDocumentSize.height()); } /** * Updating the document size */ QSizeF size(image()->width() / image()->xRes(), image()->height() / image()->yRes()); KoZoomController *zc = d->zoomManager.zoomController(); zc->setZoom(KoZoomMode::ZOOM_CONSTANT, zc->zoomAction()->effectiveZoom()); zc->setPageSize(size); zc->setDocumentSize(size, true); /** * Calculating the still point in new coordinates depending on the * parameters given */ QPointF newStillPoint; if (changeCentering) { newStillPoint = converter->imageToWidget(newImageStillPoint) + converter->documentOffset(); } else { QSize newDocumentSize = d->canvasController.documentSize(); newStillPoint = QPointF(0.5 * newDocumentSize.width(), 0.5 * newDocumentSize.height()); } d->canvasController.setPreferredCenter(oldPreferredCenter - oldStillPoint + newStillPoint); } void KisView::setCurrentNode(KisNodeSP node) { d->currentNode = node; } KisNodeSP KisView::currentNode() const { return d->currentNode; } KisLayerSP KisView::currentLayer() const { KisNodeSP node; KisMaskSP mask = currentMask(); if (mask) { node = mask->parent(); } else { node = d->currentNode; } return qobject_cast(node.data()); } KisMaskSP KisView::currentMask() const { return dynamic_cast(d->currentNode.data()); } KisSelectionSP KisView::selection() { KisLayerSP layer = currentLayer(); if (layer) return layer->selection(); // falls through to the global // selection, or 0 in the end if (image()) { return image()->globalSelection(); } return 0; } void KisView::slotSoftProofing(bool softProofing) { d->softProofing = softProofing; QString message; if (canvasBase()->image()->colorSpace()->colorDepthId().id().contains("F")) { message = i18n("Soft Proofing doesn't work in floating point."); viewManager()->showFloatingMessage(message,QIcon()); return; } if (softProofing){ message = i18n("Soft Proofing turned on."); } else { message = i18n("Soft Proofing turned off."); } viewManager()->showFloatingMessage(message,QIcon()); canvasBase()->slotSoftProofing(softProofing); } void KisView::slotGamutCheck(bool gamutCheck) { d->gamutCheck = gamutCheck; QString message; if (canvasBase()->image()->colorSpace()->colorDepthId().id().contains("F")) { message = i18n("Gamut Warnings don't work in floating point."); viewManager()->showFloatingMessage(message,QIcon()); return; } if (gamutCheck){ message = i18n("Gamut Warnings turned on."); if (!d->softProofing){ message += "\n "+i18n("But Soft Proofing is still off."); } } else { message = i18n("Gamut Warnings turned off."); } viewManager()->showFloatingMessage(message,QIcon()); canvasBase()->slotGamutCheck(gamutCheck); } bool KisView::softProofing() { return d->softProofing; } bool KisView::gamutCheck() { return d->gamutCheck; } void KisView::slotLoadingFinished() { if (!document()) return; /** * Cold-start of image size/resolution signals */ slotImageResolutionChanged(); if (image()->locked()) { // If this is the first view on the image, the image will have been locked // so unlock it. image()->blockSignals(false); image()->unlock(); } canvasBase()->initializeImage(); /** * Dirty hack alert */ d->zoomManager.zoomController()->setAspectMode(true); if (viewConverter()) { viewConverter()->setZoomMode(KoZoomMode::ZOOM_PAGE); } connect(image(), SIGNAL(sigColorSpaceChanged(const KoColorSpace*)), this, SIGNAL(sigColorSpaceChanged(const KoColorSpace*))); connect(image(), SIGNAL(sigProfileChanged(const KoColorProfile*)), this, SIGNAL(sigProfileChanged(const KoColorProfile*))); connect(image(), SIGNAL(sigSizeChanged(QPointF,QPointF)), this, SIGNAL(sigSizeChanged(QPointF,QPointF))); KisNodeSP activeNode = document()->preActivatedNode(); document()->setPreActivatedNode(0); // to make sure that we don't keep a reference to a layer the user can later delete. if (!activeNode) { activeNode = image()->rootLayer()->lastChild(); } while (activeNode && !activeNode->inherits("KisLayer")) { activeNode = activeNode->prevSibling(); } setCurrentNode(activeNode); zoomManager()->updateImageBoundsSnapping(); } void KisView::slotSavingFinished() { if (d->viewManager && d->viewManager->mainWindow()) { d->viewManager->mainWindow()->updateCaption(); } } KisPrintJob * KisView::createPrintJob() { return new KisPrintJob(image()); } void KisView::slotImageResolutionChanged() { resetImageSizeAndScroll(false); zoomManager()->updateImageBoundsSnapping(); zoomManager()->updateGUI(); // update KoUnit value for the document if (resourceProvider()) { resourceProvider()->resourceManager()-> setResource(KoCanvasResourceManager::Unit, d->canvas.unit()); } } void KisView::slotImageSizeChanged(const QPointF &oldStillPoint, const QPointF &newStillPoint) { resetImageSizeAndScroll(true, oldStillPoint, newStillPoint); zoomManager()->updateImageBoundsSnapping(); zoomManager()->updateGUI(); } diff --git a/libs/ui/actions/kis_selection_action_factories.cpp b/libs/ui/actions/kis_selection_action_factories.cpp index 464d392433..cd44168a82 100644 --- a/libs/ui/actions/kis_selection_action_factories.cpp +++ b/libs/ui/actions/kis_selection_action_factories.cpp @@ -1,641 +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 (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; 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 KisInvertSelectionOperation::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/canvas/kis_canvas2.h b/libs/ui/canvas/kis_canvas2.h index 45ad14de1a..ec20b09c83 100644 --- a/libs/ui/canvas/kis_canvas2.h +++ b/libs/ui/canvas/kis_canvas2.h @@ -1,295 +1,295 @@ /* This file is part of the KDE project * Copyright (C) 2006, 2010 Boudewijn Rempt * Copyright (C) 2011 Silvio Heinrich * * 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_CANVAS_H #define KIS_CANVAS_H #include #include #include #include #include #include #include #include #include #include #include "opengl/kis_opengl.h" #include "kis_ui_types.h" #include "kis_coordinates_converter.h" #include "kis_canvas_decoration.h" #include "kis_painting_assistants_decoration.h" class KoToolProxy; class KoColorProfile; class KisViewManager; class KisFavoriteResourceManager; class KisDisplayFilter; class KisDisplayColorConverter; struct KisExposureGammaCorrectionInterface; class KisView; class KisInputManager; class KisAnimationPlayer; class KisShapeController; class KisCoordinatesConverter; class KoViewConverter; /** * KisCanvas2 is not an actual widget class, but rather an adapter for * the widget it contains, which may be either a QPainter based * canvas, or an OpenGL based canvas: that are the real widgets. */ -class KRITAUI_EXPORT KisCanvas2 : public QObject, public KoCanvasBase +class KRITAUI_EXPORT KisCanvas2 : public KoCanvasBase { Q_OBJECT public: /** * Create a new canvas. The canvas manages a widget that will do * the actual painting: the canvas itself is not a widget. * * @param viewConverter the viewconverter for converting between * window and document coordinates. */ KisCanvas2(KisCoordinatesConverter *coordConverter, KoCanvasResourceManager *resourceManager, KisView *view, KoShapeBasedDocumentBase *sc); virtual ~KisCanvas2(); void notifyZoomChanged(); virtual void disconnectCanvasObserver(QObject *object); public: // KoCanvasBase implementation bool canvasIsOpenGL() const; KisOpenGL::FilterMode openGLFilterMode() const; void gridSize(QPointF *offset, QSizeF *spacing) const; bool snapToGrid() const; // This method only exists to support flake-related operations void addCommand(KUndo2Command *command); virtual QPoint documentOrigin() const; QPoint documentOffset() const; /** * Return the right shape manager for the current layer. That is * to say, if the current layer is a vector layer, return the shape * layer's canvas' shapemanager, else the shapemanager associated * with the global krita canvas. */ KoShapeManager *shapeManager() const; /** * Return the shape manager associated with this canvas */ KoShapeManager *globalShapeManager() const; void updateCanvas(const QRectF& rc); virtual void updateInputMethodInfo(); const KisCoordinatesConverter* coordinatesConverter() const; virtual KoViewConverter *viewConverter() const; virtual QWidget* canvasWidget(); virtual const QWidget* canvasWidget() const; virtual KoUnit unit() const; virtual KoToolProxy* toolProxy() const; const KoColorProfile* monitorProfile(); // FIXME: // Temporary! Either get the current layer and image from the // resource provider, or use this, which gets them from the // current shape selection. KisImageWSP currentImage() const; /** * Filters events and sends them to canvas actions. Shared * among all the views/canvases * * NOTE: May be null while initialization! */ KisInputManager* globalInputManager() const; KisPaintingAssistantsDecorationSP paintingAssistantsDecoration() const; public: // KisCanvas2 methods KisImageWSP image() const; KisViewManager* viewManager() const; QPointer imageView() const; /// @return true if the canvas image should be displayed in vertically mirrored mode void addDecoration(KisCanvasDecorationSP deco); KisCanvasDecorationSP decoration(const QString& id) const; void setDisplayFilter(QSharedPointer displayFilter); QSharedPointer displayFilter() const; KisDisplayColorConverter *displayColorConverter() const; KisExposureGammaCorrectionInterface* exposureGammaCorrectionInterface() const; /** * @brief setProofingOptions * set the options for softproofing, without affecting the proofing options as stored inside the image. */ void setProofingOptions(bool softProof, bool gamutCheck); KisProofingConfigurationSP proofingConfiguration() const; /** * @brief setProofingConfigUpdated This function is to set whether the proofing config is updated, * this is needed for determining whether or not to generate a new proofing transform. * @param updated whether it's updated. Just set it to false in normal usage. */ void setProofingConfigUpdated(bool updated); /** * @brief proofingConfigUpdated ask the canvas whether or not it updated the proofing config. * @return whether or not the proofing config is updated, if so, a new proofing transform needs to be made * in KisOpenGL canvas. */ bool proofingConfigUpdated(); void setCursor(const QCursor &cursor); KisAnimationFrameCacheSP frameCache() const; KisAnimationPlayer *animationPlayer() const; void refetchDataFromImage(); Q_SIGNALS: void imageChanged(KisImageWSP image); void sigCanvasCacheUpdated(); void sigContinueResizeImage(qint32 w, qint32 h); void documentOffsetUpdateFinished(); // emitted whenever the canvas widget thinks sketch should update void updateCanvasRequested(const QRect &rc); public Q_SLOTS: /// Update the entire canvas area void updateCanvas(); void startResizingImage(); void finishResizingImage(qint32 w, qint32 h); /// canvas rotation in degrees qreal rotationAngle() const; /// Bools indicating canvasmirroring. bool xAxisMirrored() const; bool yAxisMirrored() const; void slotSoftProofing(bool softProofing); void slotGamutCheck(bool gamutCheck); void slotChangeProofingConfig(); void slotZoomChanged(int zoom); void channelSelectionChanged(); /** * Called whenever the display monitor profile resource changes */ void slotSetDisplayProfile(const KoColorProfile *profile); void startUpdateInPatches(const QRect &imageRect); private Q_SLOTS: /// The image projection has changed, now start an update /// of the canvas representation. void startUpdateCanvasProjection(const QRect & rc); void updateCanvasProjection(); /** * Called whenever the view widget needs to show a different part of * the document * * @param documentOffset the offset in widget pixels */ void documentOffsetMoved(const QPoint &documentOffset); /** * Called whenever the configuration settings change. */ void slotConfigChanged(); void slotSelectionChanged(); void slotDoCanvasUpdate(); void bootstrapFinished(); public: bool isPopupPaletteVisible() const; void slotShowPopupPalette(const QPoint& = QPoint(0,0)); // interface for KisCanvasController only void setWrapAroundViewingMode(bool value); bool wrapAroundViewingMode() const; void setLodAllowedInCanvas(bool value); bool lodAllowedInCanvas() const; void initializeImage(); void setFavoriteResourceManager(KisFavoriteResourceManager* favoriteResourceManager); private: Q_DISABLE_COPY(KisCanvas2) void connectCurrentCanvas(); void createCanvas(bool useOpenGL); void createQPainterCanvas(); void createOpenGLCanvas(); void updateCanvasWidgetImpl(const QRect &rc = QRect()); void setCanvasWidget(QWidget *widget); void resetCanvas(bool useOpenGL); void notifyLevelOfDetailChange(); // Completes construction of canvas. // To be called by KisView in its constructor, once it has been setup enough // (to be defined what that means) for things KisCanvas2 expects from KisView // TODO: see to avoid that void setup(); private: friend class KisView; // calls setup() class KisCanvas2Private; KisCanvas2Private * const m_d; }; #endif diff --git a/libs/ui/canvas/kis_infinity_manager.h b/libs/ui/canvas/kis_infinity_manager.h index 349b5a20ee..ef25bebf75 100644 --- a/libs/ui/canvas/kis_infinity_manager.h +++ b/libs/ui/canvas/kis_infinity_manager.h @@ -1,68 +1,72 @@ /* * 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. */ #ifndef __KIS_INFINITY_MANAGER_H #define __KIS_INFINITY_MANAGER_H #include "kis_canvas_decoration.h" + +#include #include #include +#include + class KisView; static const QString INFINITY_DECORATION_ID = "infinity-decorations"; class KRITAUI_EXPORT KisInfinityManager : public KisCanvasDecoration { Q_OBJECT public: KisInfinityManager(QPointerview, KisCanvas2 *canvas); protected: void drawDecoration(QPainter& gc, const QRectF& updateArea, const KisCoordinatesConverter *converter, KisCanvas2 *canvas); bool eventFilter(QObject *obj, QEvent *event); public Q_SLOTS: void imagePositionChanged(); private: enum Side { Right = 0, Bottom, Left, Top, NSides }; inline void addDecoration(const QRect &areaRect, const QPointF &handlePoint, qreal angle, Side side); private: QPainterPath m_decorationPath; bool m_filteringEnabled; bool m_cursorSwitched; QCursor m_oldCursor; QVector m_handleTransform; QVector m_sideRects; - KisCanvas2 *m_canvas; + QPointer m_canvas; }; #endif /* __KIS_INFINITY_MANAGER_H */ diff --git a/libs/ui/canvas/kis_paintop_transformation_connector.h b/libs/ui/canvas/kis_paintop_transformation_connector.h index 397b1ba974..68c751ee0a 100644 --- a/libs/ui/canvas/kis_paintop_transformation_connector.h +++ b/libs/ui/canvas/kis_paintop_transformation_connector.h @@ -1,42 +1,43 @@ /* * 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. */ #ifndef __KIS_PAINTOP_TRANSFORMATION_CONNECTOR_H #define __KIS_PAINTOP_TRANSFORMATION_CONNECTOR_H #include +#include -class KisCanvas2; +#include class KisPaintopTransformationConnector : public QObject { Q_OBJECT public: KisPaintopTransformationConnector(KisCanvas2 *canvas, QObject *parent); public: void notifyTransformationChanged(); public Q_SLOTS: void slotCanvasResourceChanged(int key, const QVariant &resource); private: - KisCanvas2 *m_canvas; + QPointer m_canvas; }; #endif /* __KIS_PAINTOP_TRANSFORMATION_CONNECTOR_H */ diff --git a/libs/ui/dialogs/kis_dlg_preferences.cc b/libs/ui/dialogs/kis_dlg_preferences.cc index fccce9d34f..3003738cec 100644 --- a/libs/ui/dialogs/kis_dlg_preferences.cc +++ b/libs/ui/dialogs/kis_dlg_preferences.cc @@ -1,1099 +1,1102 @@ /* * preferencesdlg.cc - part of KImageShop * * Copyright (c) 1999 Michael Koch * Copyright (c) 2003-2011 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_dlg_preferences.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 "KoID.h" #include #include #include #include #include #include "kis_action_registry.h" #include "widgets/squeezedcombobox.h" #include "kis_clipboard.h" #include "widgets/kis_cmb_idlist.h" #include "KoColorSpace.h" #include "KoColorSpaceRegistry.h" #include "KoColorConversionTransformation.h" #include "kis_cursor.h" #include "kis_config.h" #include "kis_canvas_resource_provider.h" #include "kis_preference_set_registry.h" #include "kis_color_manager.h" #include "KisProofingConfiguration.h" #include "kis_image_config.h" #include "slider_and_spin_box_sync.h" // for the performance update #include #include "input/config/kis_input_configuration_page.h" GeneralTab::GeneralTab(QWidget *_parent, const char *_name) : WdgGeneralSettings(_parent, _name) { KisConfig cfg; m_cmbCursorShape->addItem(i18n("No Cursor")); m_cmbCursorShape->addItem(i18n("Tool Icon")); m_cmbCursorShape->addItem(i18n("Arrow")); m_cmbCursorShape->addItem(i18n("Small Circle")); m_cmbCursorShape->addItem(i18n("Crosshair")); m_cmbCursorShape->addItem(i18n("Triangle Righthanded")); m_cmbCursorShape->addItem(i18n("Triangle Lefthanded")); m_cmbCursorShape->addItem(i18n("Black Pixel")); m_cmbCursorShape->addItem(i18n("White Pixel")); m_cmbOutlineShape->addItem(i18n("No Outline")); m_cmbOutlineShape->addItem(i18n("Circle Outline")); m_cmbOutlineShape->addItem(i18n("Preview Outline")); m_cmbOutlineShape->addItem(i18n("Tilt Outline")); m_cmbCursorShape->setCurrentIndex(cfg.newCursorStyle()); m_cmbOutlineShape->setCurrentIndex(cfg.newOutlineStyle()); chkShowRootLayer->setChecked(cfg.showRootLayer()); int autosaveInterval = cfg.autoSaveInterval(); //convert to minutes m_autosaveSpinBox->setValue(autosaveInterval / 60); m_autosaveCheckBox->setChecked(autosaveInterval > 0); m_undoStackSize->setValue(cfg.undoStackLimit()); m_backupFileCheckBox->setChecked(cfg.backupFile()); m_showOutlinePainting->setChecked(cfg.showOutlineWhilePainting()); m_hideSplashScreen->setChecked(cfg.hideSplashScreen()); KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); m_chkNativeFileDialog->setChecked(!group.readEntry("DontUseNativeFileDialog", true)); intMaxBrushSize->setValue(cfg.readEntry("maximumBrushSize", 1000)); m_cmbMDIType->setCurrentIndex(cfg.readEntry("mdi_viewmode", (int)QMdiArea::TabbedView)); m_chkRubberBand->setChecked(cfg.readEntry("mdi_rubberband", cfg.useOpenGL())); m_favoritePresetsSpinBox->setValue(cfg.favoritePresets()); KoColor mdiColor; mdiColor.fromQColor(cfg.getMDIBackgroundColor()); m_mdiColor->setColor(mdiColor); m_backgroundimage->setText(cfg.getMDIBackgroundImage()); m_chkCanvasMessages->setChecked(cfg.showCanvasMessages()); m_chkCompressKra->setChecked(cfg.compressKra()); + m_chkHiDPI->setChecked(cfg.readEntry("EnableHiDPI", false)); m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker()); m_chkSwitchSelectionCtrlAlt->setChecked(cfg.switchSelectionCtrlAlt()); m_chkConvertOnImport->setChecked(cfg.convertToImageColorspaceOnImport()); connect(m_bnFileName, SIGNAL(clicked()), SLOT(getBackgroundImage())); connect(clearBgImageButton, SIGNAL(clicked()), SLOT(clearBackgroundImage())); } void GeneralTab::setDefault() { KisConfig cfg; m_cmbCursorShape->setCurrentIndex(cfg.newCursorStyle(true)); m_cmbOutlineShape->setCurrentIndex(cfg.newOutlineStyle(true)); chkShowRootLayer->setChecked(cfg.showRootLayer(true)); m_autosaveCheckBox->setChecked(cfg.autoSaveInterval(true) > 0); //convert to minutes m_autosaveSpinBox->setValue(cfg.autoSaveInterval(true) / 60); m_undoStackSize->setValue(cfg.undoStackLimit(true)); m_backupFileCheckBox->setChecked(cfg.backupFile(true)); m_showOutlinePainting->setChecked(cfg.showOutlineWhilePainting(true)); m_hideSplashScreen->setChecked(cfg.hideSplashScreen(true)); m_chkNativeFileDialog->setChecked(false); intMaxBrushSize->setValue(1000); m_cmbMDIType->setCurrentIndex((int)QMdiArea::TabbedView); m_chkRubberBand->setChecked(cfg.useOpenGL(true)); m_favoritePresetsSpinBox->setValue(cfg.favoritePresets(true)); KoColor mdiColor; mdiColor.fromQColor(cfg.getMDIBackgroundColor(true)); m_mdiColor->setColor(mdiColor); m_backgroundimage->setText(cfg.getMDIBackgroundImage(true)); m_chkCanvasMessages->setChecked(cfg.showCanvasMessages(true)); m_chkCompressKra->setChecked(cfg.compressKra(true)); + m_chkHiDPI->setChecked(true); m_radioToolOptionsInDocker->setChecked(cfg.toolOptionsInDocker(true)); m_chkSwitchSelectionCtrlAlt->setChecked(cfg.switchSelectionCtrlAlt(true)); m_chkConvertOnImport->setChecked(cfg.convertToImageColorspaceOnImport(true)); } CursorStyle GeneralTab::cursorStyle() { return (CursorStyle)m_cmbCursorShape->currentIndex(); } OutlineStyle GeneralTab::outlineStyle() { return (OutlineStyle)m_cmbOutlineShape->currentIndex(); } bool GeneralTab::showRootLayer() { return chkShowRootLayer->isChecked(); } int GeneralTab::autoSaveInterval() { //convert to seconds return m_autosaveCheckBox->isChecked() ? m_autosaveSpinBox->value() * 60 : 0; } int GeneralTab::undoStackSize() { return m_undoStackSize->value(); } bool GeneralTab::showOutlineWhilePainting() { return m_showOutlinePainting->isChecked(); } bool GeneralTab::hideSplashScreen() { return m_hideSplashScreen->isChecked(); } int GeneralTab::mdiMode() { return m_cmbMDIType->currentIndex(); } int GeneralTab::favoritePresets() { return m_favoritePresetsSpinBox->value(); } bool GeneralTab::showCanvasMessages() { return m_chkCanvasMessages->isChecked(); } bool GeneralTab::compressKra() { return m_chkCompressKra->isChecked(); } bool GeneralTab::toolOptionsInDocker() { return m_radioToolOptionsInDocker->isChecked(); } bool GeneralTab::switchSelectionCtrlAlt() { return m_chkSwitchSelectionCtrlAlt->isChecked(); } bool GeneralTab::convertToImageColorspaceOnImport() { return m_chkConvertOnImport->isChecked(); } void GeneralTab::getBackgroundImage() { KoFileDialog dialog(this, KoFileDialog::OpenFile, "BackgroundImages"); dialog.setCaption(i18n("Select a Background Image")); dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::PicturesLocation)); dialog.setImageFilters(); QString fn = dialog.filename(); // dialog box was canceled or somehow no file was selected if (fn.isEmpty()) { return; } QImage image(fn); if (image.isNull()) { QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("%1 is not a valid image file!", fn)); } else { m_backgroundimage->setText(fn); } } void GeneralTab::clearBackgroundImage() { // clearing the background image text will implicitly make the background color be used m_backgroundimage->setText(""); } #include "kactioncollection.h" #include "KisActionsSnapshot.h" ShortcutSettingsTab::ShortcutSettingsTab(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgShortcutSettings(this); l->addWidget(m_page, 0, 0); m_snapshot.reset(new KisActionsSnapshot); KActionCollection *collection = KisPart::instance()->currentMainwindow()->actionCollection(); Q_FOREACH (QAction *action, collection->actions()) { m_snapshot->addAction(action->objectName(), action); } QMap sortedCollections = m_snapshot->actionCollections(); for (auto it = sortedCollections.constBegin(); it != sortedCollections.constEnd(); ++it) { m_page->addCollection(it.value(), it.key()); } } ShortcutSettingsTab::~ShortcutSettingsTab() { } void ShortcutSettingsTab::setDefault() { m_page->allDefault(); } void ShortcutSettingsTab::saveChanges() { m_page->save(); KisActionRegistry::instance()->settingsPageSaved(); } void ShortcutSettingsTab::cancelChanges() { m_page->undo(); } ColorSettingsTab::ColorSettingsTab(QWidget *parent, const char *name) : QWidget(parent) { setObjectName(name); // XXX: Make sure only profiles that fit the specified color model // are shown in the profile combos QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgColorSettings(this); l->addWidget(m_page, 0, 0); KisConfig cfg; m_page->chkUseSystemMonitorProfile->setChecked(cfg.useSystemMonitorProfile()); connect(m_page->chkUseSystemMonitorProfile, SIGNAL(toggled(bool)), this, SLOT(toggleAllowMonitorProfileSelection(bool))); m_page->cmbWorkingColorSpace->setIDList(KoColorSpaceRegistry::instance()->listKeys()); m_page->cmbWorkingColorSpace->setCurrent(cfg.workingColorSpace()); m_page->bnAddColorProfile->setIcon(KisIconUtils::loadIcon("document-open")); m_page->bnAddColorProfile->setToolTip( i18n("Open Color Profile") ); connect(m_page->bnAddColorProfile, SIGNAL(clicked()), SLOT(installProfile())); QFormLayout *monitorProfileGrid = new QFormLayout(m_page->monitorprofileholder); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { QLabel *lbl = new QLabel(i18nc("The number of the screen", "Screen %1:", i + 1)); m_monitorProfileLabels << lbl; SqueezedComboBox *cmb = new SqueezedComboBox(); cmb->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); monitorProfileGrid->addRow(lbl, cmb); m_monitorProfileWidgets << cmb; } refillMonitorProfiles(KoID("RGBA", "")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } m_page->chkBlackpoint->setChecked(cfg.useBlackPointCompensation()); m_page->chkAllowLCMSOptimization->setChecked(cfg.allowLCMSOptimization()); KisImageConfig cfgImage; KisProofingConfigurationSP proofingConfig = cfgImage.defaultProofingconfiguration(); m_page->sldAdaptationState->setMaximum(20); m_page->sldAdaptationState->setMinimum(0); m_page->sldAdaptationState->setValue((int)proofingConfig->adaptationState*20); //probably this should become the screenprofile? KoColor ga(KoColorSpaceRegistry::instance()->rgb8()); ga.fromKoColor(proofingConfig->warningColor); m_page->gamutAlarm->setColor(ga); const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(proofingConfig->proofingModel, proofingConfig->proofingDepth, proofingConfig->proofingProfile); m_page->proofingSpaceSelector->setCurrentColorSpace(proofingSpace); m_page->cmbProofingIntent->setCurrentIndex((int)proofingConfig->intent); m_page->ckbProofBlackPoint->setChecked(proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::BlackpointCompensation)); m_pasteBehaviourGroup.addButton(m_page->radioPasteWeb, PASTE_ASSUME_WEB); m_pasteBehaviourGroup.addButton(m_page->radioPasteMonitor, PASTE_ASSUME_MONITOR); m_pasteBehaviourGroup.addButton(m_page->radioPasteAsk, PASTE_ASK); QAbstractButton *button = m_pasteBehaviourGroup.button(cfg.pasteBehaviour()); Q_ASSERT(button); if (button) { button->setChecked(true); } m_page->cmbMonitorIntent->setCurrentIndex(cfg.monitorRenderIntent()); toggleAllowMonitorProfileSelection(cfg.useSystemMonitorProfile()); } void ColorSettingsTab::installProfile() { KoFileDialog dialog(this, KoFileDialog::OpenFiles, "OpenDocumentICC"); dialog.setCaption(i18n("Install Color Profiles")); dialog.setDefaultDir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation)); dialog.setMimeTypeFilters(QStringList() << "application/vnd.iccprofile", "application/vnd.iccprofile"); QStringList profileNames = dialog.filenames(); KoColorSpaceEngine *iccEngine = KoColorSpaceEngineRegistry::instance()->get("icc"); Q_ASSERT(iccEngine); QString saveLocation = KoResourcePaths::saveLocation("icc_profiles"); Q_FOREACH (const QString &profileName, profileNames) { if (!QFile::copy(profileName, saveLocation + QFileInfo(profileName).fileName())) { qWarning() << "Could not install profile!" << saveLocation + QFileInfo(profileName).fileName(); continue; } iccEngine->addProfile(saveLocation + QFileInfo(profileName).fileName()); } KisConfig cfg; refillMonitorProfiles(KoID("RGBA", "")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } } void ColorSettingsTab::toggleAllowMonitorProfileSelection(bool useSystemProfile) { if (useSystemProfile) { KisConfig cfg; QStringList devices = KisColorManager::instance()->devices(); if (devices.size() == QApplication::desktop()->screenCount()) { for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->clear(); QString monitorForScreen = cfg.monitorForScreen(i, devices[i]); Q_FOREACH (const QString &device, devices) { m_monitorProfileLabels[i]->setText(i18nc("The display/screen we got from Qt", "Screen %1:", i + 1)); m_monitorProfileWidgets[i]->addSqueezedItem(KisColorManager::instance()->deviceName(device), device); if (devices[i] == monitorForScreen) { m_monitorProfileWidgets[i]->setCurrentIndex(i); } } } } } else { KisConfig cfg; refillMonitorProfiles(KoID("RGBA", "")); for(int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (m_monitorProfileWidgets[i]->contains(cfg.monitorProfile(i))) { m_monitorProfileWidgets[i]->setCurrent(cfg.monitorProfile(i)); } } } } void ColorSettingsTab::setDefault() { m_page->cmbWorkingColorSpace->setCurrent("RGBA"); refillMonitorProfiles(KoID("RGBA", "")); KisConfig cfg; KisImageConfig cfgImage; KisProofingConfigurationSP proofingConfig = cfgImage.defaultProofingconfiguration(); const KoColorSpace *proofingSpace = KoColorSpaceRegistry::instance()->colorSpace(proofingConfig->proofingModel,proofingConfig->proofingDepth,proofingConfig->proofingProfile); m_page->proofingSpaceSelector->setCurrentColorSpace(proofingSpace); m_page->cmbProofingIntent->setCurrentIndex((int)proofingConfig->intent); m_page->ckbProofBlackPoint->setChecked(proofingConfig->conversionFlags.testFlag(KoColorConversionTransformation::BlackpointCompensation)); m_page->sldAdaptationState->setValue(0); //probably this should become the screenprofile? KoColor ga(KoColorSpaceRegistry::instance()->rgb8()); ga.fromKoColor(proofingConfig->warningColor); m_page->gamutAlarm->setColor(ga); m_page->chkBlackpoint->setChecked(cfg.useBlackPointCompensation(true)); m_page->chkAllowLCMSOptimization->setChecked(cfg.allowLCMSOptimization(true)); m_page->cmbMonitorIntent->setCurrentIndex(cfg.monitorRenderIntent(true)); m_page->chkUseSystemMonitorProfile->setChecked(cfg.useSystemMonitorProfile(true)); QAbstractButton *button = m_pasteBehaviourGroup.button(cfg.pasteBehaviour(true)); Q_ASSERT(button); if (button) { button->setChecked(true); } } void ColorSettingsTab::refillMonitorProfiles(const KoID & s) { const KoColorSpaceFactory * csf = KoColorSpaceRegistry::instance()->colorSpaceFactory(s.id()); for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->clear(); } if (!csf) return; QMap profileList; Q_FOREACH(const KoColorProfile *profile, KoColorSpaceRegistry::instance()->profilesFor(csf)) { profileList[profile->name()] = profile; } Q_FOREACH (const KoColorProfile *profile, profileList.values()) { //qDebug() << "Profile" << profile->name() << profile->isSuitableForDisplay() << csf->defaultProfile(); if (profile->isSuitableForDisplay()) { for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileWidgets[i]->addSqueezedItem(profile->name()); } } } for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { m_monitorProfileLabels[i]->setText(i18nc("The number of the screen", "Screen %1:", i + 1)); m_monitorProfileWidgets[i]->setCurrent(csf->defaultProfile()); } } //--------------------------------------------------------------------------------------------------- void TabletSettingsTab::setDefault() { KisCubicCurve curve; curve.fromString(DEFAULT_CURVE_STRING); m_page->pressureCurve->setCurve(curve); } TabletSettingsTab::TabletSettingsTab(QWidget* parent, const char* name): QWidget(parent) { setObjectName(name); QGridLayout * l = new QGridLayout(this); l->setMargin(0); m_page = new WdgTabletSettings(this); l->addWidget(m_page, 0, 0); KisConfig cfg; KisCubicCurve curve; curve.fromString( cfg.pressureTabletCurve() ); m_page->pressureCurve->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)); m_page->pressureCurve->setCurve(curve); } //--------------------------------------------------------------------------------------------------- #include "kis_acyclic_signal_connector.h" int getTotalRAM() { KisImageConfig cfg; return cfg.totalRAM(); } int PerformanceTab::realTilesRAM() { return intMemoryLimit->value() - intPoolLimit->value(); } PerformanceTab::PerformanceTab(QWidget *parent, const char *name) : WdgPerformanceSettings(parent, name) { KisImageConfig cfg; const int totalRAM = cfg.totalRAM(); lblTotalMemory->setText(i18n("%1 MiB", totalRAM)); sliderMemoryLimit->setSuffix(i18n(" %")); sliderMemoryLimit->setRange(1, 100, 2); sliderMemoryLimit->setSingleStep(0.01); sliderPoolLimit->setSuffix(i18n(" %")); sliderPoolLimit->setRange(0, 20, 2); sliderMemoryLimit->setSingleStep(0.01); sliderUndoLimit->setSuffix(i18n(" %")); sliderUndoLimit->setRange(0, 50, 2); sliderMemoryLimit->setSingleStep(0.01); intMemoryLimit->setMinimumWidth(80); intPoolLimit->setMinimumWidth(80); intUndoLimit->setMinimumWidth(80); SliderAndSpinBoxSync *sync1 = new SliderAndSpinBoxSync(sliderMemoryLimit, intMemoryLimit, getTotalRAM); sync1->slotParentValueChanged(); m_syncs << sync1; SliderAndSpinBoxSync *sync2 = new SliderAndSpinBoxSync(sliderPoolLimit, intPoolLimit, std::bind(&KisIntParseSpinBox::value, intMemoryLimit)); connect(intMemoryLimit, SIGNAL(valueChanged(int)), sync2, SLOT(slotParentValueChanged())); sync2->slotParentValueChanged(); m_syncs << sync2; SliderAndSpinBoxSync *sync3 = new SliderAndSpinBoxSync(sliderUndoLimit, intUndoLimit, std::bind(&PerformanceTab::realTilesRAM, this)); connect(intPoolLimit, SIGNAL(valueChanged(int)), sync3, SLOT(slotParentValueChanged())); sync3->slotParentValueChanged(); m_syncs << sync3; sliderSwapSize->setSuffix(i18n(" GiB")); sliderSwapSize->setRange(1, 64); intSwapSize->setRange(1, 64); KisAcyclicSignalConnector *swapSizeConnector = new KisAcyclicSignalConnector(this); swapSizeConnector->connectForwardInt(sliderSwapSize, SIGNAL(valueChanged(int)), intSwapSize, SLOT(setValue(int))); swapSizeConnector->connectBackwardInt(intSwapSize, SIGNAL(valueChanged(int)), sliderSwapSize, SLOT(setValue(int))); lblSwapFileLocation->setText(cfg.swapDir()); connect(bnSwapFile, SIGNAL(clicked()), SLOT(selectSwapDir())); load(false); } PerformanceTab::~PerformanceTab() { qDeleteAll(m_syncs); } void PerformanceTab::load(bool requestDefault) { KisImageConfig cfg; sliderMemoryLimit->setValue(cfg.memoryHardLimitPercent(requestDefault)); sliderPoolLimit->setValue(cfg.memoryPoolLimitPercent(requestDefault)); sliderUndoLimit->setValue(cfg.memorySoftLimitPercent(requestDefault)); chkPerformanceLogging->setChecked(cfg.enablePerfLog(requestDefault)); chkProgressReporting->setChecked(cfg.enableProgressReporting(requestDefault)); sliderSwapSize->setValue(cfg.maxSwapSize(requestDefault) / 1024); lblSwapFileLocation->setText(cfg.swapDir(requestDefault)); { KisConfig cfg2; chkOpenGLLogging->setChecked(cfg2.enableOpenGLDebugging(requestDefault)); chkDisableVectorOptimizations->setChecked(cfg2.enableAmdVectorizationWorkaround(requestDefault)); } } void PerformanceTab::save() { KisImageConfig cfg; cfg.setMemoryHardLimitPercent(sliderMemoryLimit->value()); cfg.setMemorySoftLimitPercent(sliderUndoLimit->value()); cfg.setMemoryPoolLimitPercent(sliderPoolLimit->value()); cfg.setEnablePerfLog(chkPerformanceLogging->isChecked()); cfg.setEnableProgressReporting(chkProgressReporting->isChecked()); cfg.setMaxSwapSize(sliderSwapSize->value() * 1024); cfg.setSwapDir(lblSwapFileLocation->text()); { KisConfig cfg2; cfg2.setEnableOpenGLDebugging(chkOpenGLLogging->isChecked()); cfg2.setEnableAmdVectorizationWorkaround(chkDisableVectorOptimizations->isChecked()); } } void PerformanceTab::selectSwapDir() { KisImageConfig cfg; QString swapDir = cfg.swapDir(); swapDir = QFileDialog::getExistingDirectory(0, i18nc("@title:window", "Select a swap directory"), swapDir); lblSwapFileLocation->setText(swapDir); } //--------------------------------------------------------------------------------------------------- #include "KoColor.h" DisplaySettingsTab::DisplaySettingsTab(QWidget *parent, const char *name) : WdgDisplaySettings(parent, name) { KisConfig cfg; if (!KisOpenGL::hasOpenGL()) { grpOpenGL->setEnabled(false); grpOpenGL->setChecked(false); chkUseTextureBuffer->setEnabled(false); chkDisableVsync->setEnabled(false); cmbFilterMode->setEnabled(false); } else { grpOpenGL->setEnabled(true); grpOpenGL->setChecked(cfg.useOpenGL()); chkUseTextureBuffer->setEnabled(cfg.useOpenGL()); chkUseTextureBuffer->setChecked(cfg.useOpenGLTextureBuffer()); chkDisableVsync->setVisible(cfg.showAdvancedOpenGLSettings()); chkDisableVsync->setEnabled(cfg.useOpenGL()); chkDisableVsync->setChecked(cfg.disableVSync()); cmbFilterMode->setEnabled(cfg.useOpenGL()); cmbFilterMode->setCurrentIndex(cfg.openGLFilteringMode()); // Don't show the high quality filtering mode if it's not available if (!KisOpenGL::supportsLoD()) { cmbFilterMode->removeItem(3); } } if (qApp->applicationName() == "kritasketch" || qApp->applicationName() == "kritagemini") { grpOpenGL->setVisible(false); grpOpenGL->setMaximumHeight(0); } KoColor c; c.fromQColor(cfg.selectionOverlayMaskColor()); c.setOpacity(1.0); btnSelectionOverlayColor->setColor(c); sldSelectionOverlayOpacity->setRange(0.0, 1.0, 2); sldSelectionOverlayOpacity->setSingleStep(0.05); sldSelectionOverlayOpacity->setValue(cfg.selectionOverlayMaskColor().alphaF()); intCheckSize->setValue(cfg.checkSize()); chkMoving->setChecked(cfg.scrollCheckers()); KoColor ck1(KoColorSpaceRegistry::instance()->rgb8()); ck1.fromQColor(cfg.checkersColor1()); colorChecks1->setColor(ck1); KoColor ck2(KoColorSpaceRegistry::instance()->rgb8()); ck2.fromQColor(cfg.checkersColor2()); colorChecks2->setColor(ck2); KoColor cb(KoColorSpaceRegistry::instance()->rgb8()); cb.fromQColor(cfg.canvasBorderColor()); canvasBorder->setColor(cb); hideScrollbars->setChecked(cfg.hideScrollbars()); chkCurveAntialiasing->setChecked(cfg.antialiasCurves()); chkSelectionOutlineAntialiasing->setChecked(cfg.antialiasSelectionOutline()); chkChannelsAsColor->setChecked(cfg.showSingleChannelAsColor()); chkHidePopups->setChecked(cfg.hidePopups()); connect(grpOpenGL, SIGNAL(toggled(bool)), SLOT(slotUseOpenGLToggled(bool))); } void DisplaySettingsTab::setDefault() { KisConfig cfg; if (!KisOpenGL::hasOpenGL()) { grpOpenGL->setEnabled(false); grpOpenGL->setChecked(false); chkUseTextureBuffer->setEnabled(false); chkDisableVsync->setEnabled(false); cmbFilterMode->setEnabled(false); } else { grpOpenGL->setEnabled(true); grpOpenGL->setChecked(cfg.useOpenGL(true)); chkUseTextureBuffer->setChecked(cfg.useOpenGLTextureBuffer(true)); chkUseTextureBuffer->setEnabled(true); chkDisableVsync->setEnabled(true); chkDisableVsync->setChecked(cfg.disableVSync(true)); cmbFilterMode->setEnabled(true); cmbFilterMode->setCurrentIndex(cfg.openGLFilteringMode(true)); } chkMoving->setChecked(cfg.scrollCheckers(true)); intCheckSize->setValue(cfg.checkSize(true)); KoColor ck1(KoColorSpaceRegistry::instance()->rgb8()); ck1.fromQColor(cfg.checkersColor1(true)); colorChecks1->setColor(ck1); KoColor ck2(KoColorSpaceRegistry::instance()->rgb8()); ck2.fromQColor(cfg.checkersColor2(true)); colorChecks2->setColor(ck2); KoColor cvb(KoColorSpaceRegistry::instance()->rgb8()); cvb.fromQColor(cfg.canvasBorderColor(true)); canvasBorder->setColor(cvb); hideScrollbars->setChecked(cfg.hideScrollbars(true)); chkCurveAntialiasing->setChecked(cfg.antialiasCurves(true)); chkSelectionOutlineAntialiasing->setChecked(cfg.antialiasSelectionOutline(true)); chkChannelsAsColor->setChecked(cfg.showSingleChannelAsColor(true)); chkHidePopups->setChecked(cfg.hidePopups(true)); } void DisplaySettingsTab::slotUseOpenGLToggled(bool isChecked) { chkUseTextureBuffer->setEnabled(isChecked); chkDisableVsync->setEnabled(isChecked); cmbFilterMode->setEnabled(isChecked); } //--------------------------------------------------------------------------------------------------- FullscreenSettingsTab::FullscreenSettingsTab(QWidget* parent) : WdgFullscreenSettingsBase(parent) { KisConfig cfg; chkDockers->setChecked(cfg.hideDockersFullscreen()); chkMenu->setChecked(cfg.hideMenuFullscreen()); chkScrollbars->setChecked(cfg.hideScrollbarsFullscreen()); chkStatusbar->setChecked(cfg.hideStatusbarFullscreen()); chkTitlebar->setChecked(cfg.hideTitlebarFullscreen()); chkToolbar->setChecked(cfg.hideToolbarFullscreen()); } void FullscreenSettingsTab::setDefault() { KisConfig cfg; chkDockers->setChecked(cfg.hideDockersFullscreen(true)); chkMenu->setChecked(cfg.hideMenuFullscreen(true)); chkScrollbars->setChecked(cfg.hideScrollbarsFullscreen(true)); chkStatusbar->setChecked(cfg.hideStatusbarFullscreen(true)); chkTitlebar->setChecked(cfg.hideTitlebarFullscreen(true)); chkToolbar->setChecked(cfg.hideToolbarFullscreen(true)); } //--------------------------------------------------------------------------------------------------- KisDlgPreferences::KisDlgPreferences(QWidget* parent, const char* name) : KPageDialog(parent) { Q_UNUSED(name); setWindowTitle(i18n("Configure Krita")); setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::RestoreDefaults); button(QDialogButtonBox::Ok)->setDefault(true); setFaceType(KPageDialog::List); // General KoVBox *vbox = new KoVBox(); KPageWidgetItem *page = new KPageWidgetItem(vbox, i18n("General")); page->setObjectName("general"); page->setHeader(i18n("General")); page->setIcon(KisIconUtils::loadIcon("go-home")); addPage(page); m_general = new GeneralTab(vbox); // Shortcuts vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Keyboard Shortcuts")); page->setObjectName("shortcuts"); page->setHeader(i18n("Shortcuts")); page->setIcon(KisIconUtils::loadIcon("document-export")); addPage(page); m_shortcutSettings = new ShortcutSettingsTab(vbox); connect(this, SIGNAL(accepted()), m_shortcutSettings, SLOT(saveChanges())); connect(this, SIGNAL(rejected()), m_shortcutSettings, SLOT(cancelChanges())); // Canvas input settings m_inputConfiguration = new KisInputConfigurationPage(); page = addPage(m_inputConfiguration, i18n("Canvas Input Settings")); page->setHeader(i18n("Canvas Input")); page->setObjectName("canvasinput"); page->setIcon(KisIconUtils::loadIcon("configure")); // Display vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Display")); page->setObjectName("display"); page->setHeader(i18n("Display")); page->setIcon(KisIconUtils::loadIcon("preferences-desktop-display")); addPage(page); m_displaySettings = new DisplaySettingsTab(vbox); // Color vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Color Management")); page->setObjectName("colormanagement"); page->setHeader(i18n("Color")); page->setIcon(KisIconUtils::loadIcon("preferences-desktop-color")); addPage(page); m_colorSettings = new ColorSettingsTab(vbox); // Performance vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Performance")); page->setObjectName("performance"); page->setHeader(i18n("Performance")); page->setIcon(KisIconUtils::loadIcon("applications-system")); addPage(page); m_performanceSettings = new PerformanceTab(vbox); // Tablet vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Tablet settings")); page->setObjectName("tablet"); page->setHeader(i18n("Tablet")); page->setIcon(KisIconUtils::loadIcon("document-edit")); addPage(page); m_tabletSettings = new TabletSettingsTab(vbox); // full-screen mode vbox = new KoVBox(); page = new KPageWidgetItem(vbox, i18n("Canvas-only settings")); page->setObjectName("canvasonly"); page->setHeader(i18n("Canvas-only")); page->setIcon(KisIconUtils::loadIcon("folder-pictures")); addPage(page); m_fullscreenSettings = new FullscreenSettingsTab(vbox); // Author profiles m_authorPage = new KoConfigAuthorPage(); page = addPage(m_authorPage, i18nc("@title:tab Author page", "Author" )); page->setObjectName("author"); page->setHeader(i18n("Author")); page->setIcon(KisIconUtils::loadIcon("im-user")); QPushButton *restoreDefaultsButton = button(QDialogButtonBox::RestoreDefaults); connect(this, SIGNAL(accepted()), m_inputConfiguration, SLOT(saveChanges())); connect(this, SIGNAL(rejected()), m_inputConfiguration, SLOT(revertChanges())); KisPreferenceSetRegistry *preferenceSetRegistry = KisPreferenceSetRegistry::instance(); Q_FOREACH (KisAbstractPreferenceSetFactory *preferenceSetFactory, preferenceSetRegistry->values()) { KisPreferenceSet* preferenceSet = preferenceSetFactory->createPreferenceSet(); vbox = new KoVBox(); page = new KPageWidgetItem(vbox, preferenceSet->name()); page->setHeader(preferenceSet->header()); page->setIcon(preferenceSet->icon()); addPage(page); preferenceSet->setParent(vbox); preferenceSet->loadPreferences(); connect(restoreDefaultsButton, SIGNAL(clicked(bool)), preferenceSet, SLOT(loadDefaultPreferences()), Qt::UniqueConnection); connect(this, SIGNAL(accepted()), preferenceSet, SLOT(savePreferences()), Qt::UniqueConnection); } connect(restoreDefaultsButton, SIGNAL(clicked(bool)), this, SLOT(slotDefault())); } KisDlgPreferences::~KisDlgPreferences() { } void KisDlgPreferences::slotDefault() { if (currentPage()->objectName() == "general") { m_general->setDefault(); } else if (currentPage()->objectName() == "shortcuts") { m_shortcutSettings->setDefault(); } else if (currentPage()->objectName() == "display") { m_displaySettings->setDefault(); } else if (currentPage()->objectName() == "colormanagement") { m_colorSettings->setDefault(); } else if (currentPage()->objectName() == "performance") { m_performanceSettings->load(true); } else if (currentPage()->objectName() == "tablet") { m_tabletSettings->setDefault(); } else if (currentPage()->objectName() == "canvasonly") { m_fullscreenSettings->setDefault(); } else if (currentPage()->objectName() == "canvasinput") { m_inputConfiguration->setDefaults(); } } bool KisDlgPreferences::editPreferences() { KisDlgPreferences* dialog; dialog = new KisDlgPreferences(); bool baccept = (dialog->exec() == Accepted); if (baccept) { // General settings KisConfig cfg; cfg.setNewCursorStyle(dialog->m_general->cursorStyle()); cfg.setNewOutlineStyle(dialog->m_general->outlineStyle()); cfg.setShowRootLayer(dialog->m_general->showRootLayer()); cfg.setShowOutlineWhilePainting(dialog->m_general->showOutlineWhilePainting()); cfg.setHideSplashScreen(dialog->m_general->hideSplashScreen()); KConfigGroup group = KSharedConfig::openConfig()->group("File Dialogs"); group.writeEntry("DontUseNativeFileDialog", !dialog->m_general->m_chkNativeFileDialog->isChecked()); cfg.writeEntry("maximumBrushSize", dialog->m_general->intMaxBrushSize->value()); cfg.writeEntry("mdi_viewmode", dialog->m_general->mdiMode()); cfg.setMDIBackgroundColor(dialog->m_general->m_mdiColor->color().toQColor()); cfg.setMDIBackgroundImage(dialog->m_general->m_backgroundimage->text()); cfg.setAutoSaveInterval(dialog->m_general->autoSaveInterval()); cfg.setBackupFile(dialog->m_general->m_backupFileCheckBox->isChecked()); cfg.setShowCanvasMessages(dialog->m_general->showCanvasMessages()); cfg.setCompressKra(dialog->m_general->compressKra()); + cfg.writeEntry("EnableHiDPI", dialog->m_general->m_chkHiDPI->isChecked()); cfg.setToolOptionsInDocker(dialog->m_general->toolOptionsInDocker()); cfg.setSwitchSelectionCtrlAlt(dialog->m_general->switchSelectionCtrlAlt()); cfg.setConvertToImageColorspaceOnImport(dialog->m_general->convertToImageColorspaceOnImport()); KisPart *part = KisPart::instance(); if (part) { Q_FOREACH (QPointer doc, part->documents()) { if (doc) { doc->setAutoSaveDelay(dialog->m_general->autoSaveInterval()); doc->setBackupFile(dialog->m_general->m_backupFileCheckBox->isChecked()); doc->undoStack()->setUndoLimit(dialog->m_general->undoStackSize()); } } } cfg.setUndoStackLimit(dialog->m_general->undoStackSize()); cfg.setFavoritePresets(dialog->m_general->favoritePresets()); // Color settings cfg.setUseSystemMonitorProfile(dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()); for (int i = 0; i < QApplication::desktop()->screenCount(); ++i) { if (dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()) { int currentIndex = dialog->m_colorSettings->m_monitorProfileWidgets[i]->currentIndex(); QString monitorid = dialog->m_colorSettings->m_monitorProfileWidgets[i]->itemData(currentIndex).toString(); cfg.setMonitorForScreen(i, monitorid); } else { cfg.setMonitorProfile(i, dialog->m_colorSettings->m_monitorProfileWidgets[i]->itemHighlighted(), dialog->m_colorSettings->m_page->chkUseSystemMonitorProfile->isChecked()); } } cfg.setWorkingColorSpace(dialog->m_colorSettings->m_page->cmbWorkingColorSpace->currentItem().id()); KisImageConfig cfgImage; cfgImage.setDefaultProofingConfig(dialog->m_colorSettings->m_page->proofingSpaceSelector->currentColorSpace(), dialog->m_colorSettings->m_page->cmbProofingIntent->currentIndex(), dialog->m_colorSettings->m_page->ckbProofBlackPoint->isChecked(), dialog->m_colorSettings->m_page->gamutAlarm->color(), (double)dialog->m_colorSettings->m_page->sldAdaptationState->value()/20); cfg.setUseBlackPointCompensation(dialog->m_colorSettings->m_page->chkBlackpoint->isChecked()); cfg.setAllowLCMSOptimization(dialog->m_colorSettings->m_page->chkAllowLCMSOptimization->isChecked()); cfg.setPasteBehaviour(dialog->m_colorSettings->m_pasteBehaviourGroup.checkedId()); cfg.setRenderIntent(dialog->m_colorSettings->m_page->cmbMonitorIntent->currentIndex()); // Tablet settings cfg.setPressureTabletCurve( dialog->m_tabletSettings->m_page->pressureCurve->curve().toString() ); dialog->m_performanceSettings->save(); if (!cfg.useOpenGL() && dialog->m_displaySettings->grpOpenGL->isChecked()) cfg.setCanvasState("TRY_OPENGL"); cfg.setUseOpenGL(dialog->m_displaySettings->grpOpenGL->isChecked()); cfg.setUseOpenGLTextureBuffer(dialog->m_displaySettings->chkUseTextureBuffer->isChecked()); cfg.setOpenGLFilteringMode(dialog->m_displaySettings->cmbFilterMode->currentIndex()); cfg.setDisableVSync(dialog->m_displaySettings->chkDisableVsync->isChecked()); cfg.setCheckSize(dialog->m_displaySettings->intCheckSize->value()); cfg.setScrollingCheckers(dialog->m_displaySettings->chkMoving->isChecked()); cfg.setCheckersColor1(dialog->m_displaySettings->colorChecks1->color().toQColor()); cfg.setCheckersColor2(dialog->m_displaySettings->colorChecks2->color().toQColor()); cfg.setCanvasBorderColor(dialog->m_displaySettings->canvasBorder->color().toQColor()); cfg.setHideScrollbars(dialog->m_displaySettings->hideScrollbars->isChecked()); KoColor c = dialog->m_displaySettings->btnSelectionOverlayColor->color(); c.setOpacity(dialog->m_displaySettings->sldSelectionOverlayOpacity->value()); cfg.setSelectionOverlayMaskColor(c.toQColor()); cfg.setAntialiasCurves(dialog->m_displaySettings->chkCurveAntialiasing->isChecked()); cfg.setAntialiasSelectionOutline(dialog->m_displaySettings->chkSelectionOutlineAntialiasing->isChecked()); cfg.setShowSingleChannelAsColor(dialog->m_displaySettings->chkChannelsAsColor->isChecked()); cfg.setHidePopups(dialog->m_displaySettings->chkHidePopups->isChecked()); cfg.setHideDockersFullscreen(dialog->m_fullscreenSettings->chkDockers->checkState()); cfg.setHideMenuFullscreen(dialog->m_fullscreenSettings->chkMenu->checkState()); cfg.setHideScrollbarsFullscreen(dialog->m_fullscreenSettings->chkScrollbars->checkState()); cfg.setHideStatusbarFullscreen(dialog->m_fullscreenSettings->chkStatusbar->checkState()); cfg.setHideTitlebarFullscreen(dialog->m_fullscreenSettings->chkTitlebar->checkState()); cfg.setHideToolbarFullscreen(dialog->m_fullscreenSettings->chkToolbar->checkState()); dialog->m_authorPage->apply(); } delete dialog; return baccept; } diff --git a/libs/ui/flake/kis_shape_layer_canvas.cpp b/libs/ui/flake/kis_shape_layer_canvas.cpp index f12859621c..ca4ed20e05 100644 --- a/libs/ui/flake/kis_shape_layer_canvas.cpp +++ b/libs/ui/flake/kis_shape_layer_canvas.cpp @@ -1,181 +1,180 @@ /* * Copyright (c) 2007 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_shape_layer_canvas.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kis_image_view_converter.h" #include //#define DEBUG_REPAINT KisShapeLayerCanvas::KisShapeLayerCanvas(KisShapeLayer *parent, KisImageWSP image) - : QObject() - , KoCanvasBase(0) + : KoCanvasBase(0) , m_isDestroying(false) , m_viewConverter(new KisImageViewConverter(image)) , m_shapeManager(new KoShapeManager(this)) , m_projection(0) , m_parentLayer(parent) { m_shapeManager->selection()->setActiveLayer(parent); connect(this, SIGNAL(forwardRepaint()), SLOT(repaint()), Qt::QueuedConnection); } KisShapeLayerCanvas::~KisShapeLayerCanvas() { delete m_shapeManager; } void KisShapeLayerCanvas::setImage(KisImageWSP image) { m_viewConverter->setImage(image); } void KisShapeLayerCanvas::prepareForDestroying() { m_isDestroying = true; } void KisShapeLayerCanvas::gridSize(QPointF *offset, QSizeF *spacing) const { Q_ASSERT(false); // This should never be called as this canvas should have no tools. Q_UNUSED(offset); Q_UNUSED(spacing); } bool KisShapeLayerCanvas::snapToGrid() const { Q_ASSERT(false); // This should never be called as this canvas should have no tools. return false; } void KisShapeLayerCanvas::addCommand(KUndo2Command *) { Q_ASSERT(false); // This should never be called as this canvas should have no tools. } KoShapeManager *KisShapeLayerCanvas::shapeManager() const { return m_shapeManager; } #ifdef DEBUG_REPAINT # include #endif void KisShapeLayerCanvas::updateCanvas(const QRectF& rc) { dbgUI << "KisShapeLayerCanvas::updateCanvas()" << rc; //image is 0, if parentLayer is being deleted so don't update if (!m_parentLayer->image() || m_isDestroying) { return; } QRect r = m_viewConverter->documentToView(rc).toRect(); r.adjust(-2, -2, 2, 2); // for antialias { QMutexLocker locker(&m_dirtyRegionMutex); m_dirtyRegion += r; qreal x, y; m_viewConverter->zoom(&x, &y); } emit forwardRepaint(); } void KisShapeLayerCanvas::repaint() { QRect r; { QMutexLocker locker(&m_dirtyRegionMutex); r = m_dirtyRegion.boundingRect(); m_dirtyRegion = QRegion(); } if (r.isEmpty()) return; r = r.intersected(m_parentLayer->image()->bounds()); QImage image(r.width(), r.height(), QImage::Format_ARGB32); image.fill(0); QPainter p(&image); p.setRenderHint(QPainter::Antialiasing); p.setRenderHint(QPainter::TextAntialiasing); p.translate(-r.x(), -r.y()); p.setClipRect(r); #ifdef DEBUG_REPAINT QColor color = QColor(random() % 255, random() % 255, random() % 255); p.fillRect(r, color); #endif m_shapeManager->paint(p, *m_viewConverter, false); p.end(); KisPaintDeviceSP dev = new KisPaintDevice(m_projection->colorSpace()); dev->convertFromQImage(image, 0); KisPainter::copyAreaOptimized(r.topLeft(), dev, m_projection, QRect(QPoint(), r.size())); m_parentLayer->setDirty(r); } KoToolProxy * KisShapeLayerCanvas::toolProxy() const { // Q_ASSERT(false); // This should never be called as this canvas should have no tools. return 0; } KoViewConverter* KisShapeLayerCanvas::viewConverter() const { return m_viewConverter.data(); } QWidget* KisShapeLayerCanvas::canvasWidget() { return 0; } const QWidget* KisShapeLayerCanvas::canvasWidget() const { return 0; } KoUnit KisShapeLayerCanvas::unit() const { Q_ASSERT(false); // This should never be called as this canvas should have no tools. return KoUnit(KoUnit::Point); } diff --git a/libs/ui/flake/kis_shape_layer_canvas.h b/libs/ui/flake/kis_shape_layer_canvas.h index 6b45fec6bd..a497222a25 100644 --- a/libs/ui/flake/kis_shape_layer_canvas.h +++ b/libs/ui/flake/kis_shape_layer_canvas.h @@ -1,87 +1,87 @@ /* * Copyright (c) 2007 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_SHAPE_LAYER_CANVAS_H #define KIS_SHAPE_LAYER_CANVAS_H #include #include #include #include class KoShapeManager; class KoToolProxy; class KoViewConverter; class KUndo2Command; class QWidget; class KoUnit; class KisImageViewConverter; /** * KisShapeLayerCanvas is a special canvas implementation that Krita * uses for non-krita shapes to request updates on. * * Do NOT give this canvas to tools or to the KoCanvasController, it's * not made for that. */ -class KisShapeLayerCanvas : public QObject, public KoCanvasBase +class KisShapeLayerCanvas : public KoCanvasBase { Q_OBJECT public: KisShapeLayerCanvas(KisShapeLayer *parent, KisImageWSP image); virtual ~KisShapeLayerCanvas(); /// This canvas won't render onto a widget, but a projection void setProjection(KisPaintDeviceSP projection) { m_projection = projection; } void setImage(KisImageWSP image); void prepareForDestroying(); void gridSize(QPointF *offset, QSizeF *spacing) const; bool snapToGrid() const; void addCommand(KUndo2Command *command); KoShapeManager *shapeManager() const; void updateCanvas(const QRectF& rc); KoToolProxy * toolProxy() const; KoViewConverter* viewConverter() const; QWidget* canvasWidget(); const QWidget* canvasWidget() const; KoUnit unit() const; virtual void updateInputMethodInfo() {} virtual void setCursor(const QCursor &) {} private Q_SLOTS: void repaint(); Q_SIGNALS: void forwardRepaint(); private: bool m_isDestroying; QScopedPointer m_viewConverter; KoShapeManager * m_shapeManager; KisPaintDeviceSP m_projection; KisShapeLayer *m_parentLayer; QRegion m_dirtyRegion; QMutex m_dirtyRegionMutex; }; #endif diff --git a/libs/ui/flake/kis_shape_selection_canvas.h b/libs/ui/flake/kis_shape_selection_canvas.h index 5cac711ca0..7fa652d6dc 100644 --- a/libs/ui/flake/kis_shape_selection_canvas.h +++ b/libs/ui/flake/kis_shape_selection_canvas.h @@ -1,60 +1,60 @@ /* * Copyright (c) 2007 Boudewijn Rempt * Copyright (c) 2007 Sven Langkamp * * 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_SHAPE_SELECTION_CANVAS_H #define KIS_SHAPE_SELECTION_CANVAS_H #include #include class KoShapeManager; class KoToolProxy; class KoViewConverter; class KUndo2Command; class QWidget; class KoUnit; /** * Dummy canvas just to have a shapemanager for the shape selection */ -class KisShapeSelectionCanvas : public QObject, public KoCanvasBase +class KisShapeSelectionCanvas : public KoCanvasBase { Q_OBJECT public: KisShapeSelectionCanvas(); virtual ~KisShapeSelectionCanvas(); void gridSize(QPointF *offset, QSizeF *spacing) const; bool snapToGrid() const; void addCommand(KUndo2Command *command); KoShapeManager *shapeManager() const; void updateCanvas(const QRectF& rc); KoToolProxy * toolProxy() const; KoViewConverter *viewConverter() const; QWidget* canvasWidget(); const QWidget* canvasWidget() const; KoUnit unit() const; virtual void updateInputMethodInfo() {} virtual void setCursor(const QCursor &) {} private: KoShapeManager * m_shapeManager; }; #endif diff --git a/libs/ui/forms/wdggeneralsettings.ui b/libs/ui/forms/wdggeneralsettings.ui index d07bd91b5d..f475a196b3 100644 --- a/libs/ui/forms/wdggeneralsettings.ui +++ b/libs/ui/forms/wdggeneralsettings.ui @@ -1,721 +1,669 @@ WdgGeneralSettings 0 0 759 468 0 0 552 295 Qt::LeftToRight - 3 + 0 Cursor 10 10 10 10 10 10 0 0 Cursor Shape: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Outline Shape: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 200 0 Show brush outline while painting Qt::Horizontal 40 20 Qt::Vertical 20 40 Window - - - - - Qt::Vertical - - - - 20 - 40 - + + + + + + 0 + 0 + - - - - - - 10 + + Multiple Document Mode: - - 10 + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - 10 + + + + + + + 0 + 0 + - - 10 + + 1 - - 10 + + + Subwindows + + + + + Tabs + + + + + + + + Background Image (overrides color): - - - - - 0 - 0 - + + + + + + + + + 200 + 0 + - - Multiple Document Mode: + + QFrame::StyledPanel - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Window Background: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - 200 - 0 - - - - QFrame::StyledPanel - - - QFrame::Sunken - - - - - - - - - - ... - - - - - - - - 0 - 0 - - - - Clear - - - - - - - - - - 0 - 0 - + + QFrame::Sunken - - + + - Background Image (overrides color): + ... - - + + - + 0 0 - - 1 + + Clear - - - Subwindows - - - - - Tabs - - - - - - - - - 0 - 0 - - - - - - - - - - - Don't show contents when moving sub-windows - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - - - Show on-canvas popup messages: - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - + + + + Window Background: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + + + + + + + Don't show contents when moving sub-windows: + + + + + + + + 0 + 0 + + + + + + + + + + + Show on-canvas popup messages: + + + + + + + + + + + + - Qt::Horizontal + Qt::Vertical - 40 - 20 + 20 + 40 + + + + + + + + + + + Enable Hi-DPI support: + + + Tools 10 10 10 10 10 Tool Options Location (needs restart) In Doc&ker In Tool&bar true Switch Control/Alt Selection Modifiers Qt::Vertical 20 40 Qt::Horizontal 40 20 Miscellaneous 0 0 Qt::RightToLeft Autosave every: true 0 0 75 0 min 1 1440 5 15 Compress .kra files more (slows loading/saving) Create backup file On importing images as layers, convert to the image colorspace 0 0 Undo stack size: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 75 0 0 1000 5 30 0 0 Number of Palette Presets Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 75 0 10 30 Show root layer Hide splash screen on startup Warning: if you enable this setting and the file dialogs do weird stuff, do not report a bug. Enable native file dialogs (warning: may not work correctly on some systems) Maximum brush size: 0 0 The maximum diameter of a brush in pixels. px 100 10000 1000 (Needs restart) Qt::Vertical 504 13 KisColorButton QPushButton
kis_color_button.h
KisIntParseSpinBox QSpinBox
kis_int_parse_spin_box.h
diff --git a/libs/ui/input/kis_input_manager_p.h b/libs/ui/input/kis_input_manager_p.h index 46229392ed..f14e9051c7 100644 --- a/libs/ui/input/kis_input_manager_p.h +++ b/libs/ui/input/kis_input_manager_p.h @@ -1,147 +1,147 @@ /* * Copyright (C) 2015 Michael Abrahams * * 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 #include #include #include #include #include "kis_input_manager.h" #include "kis_shortcut_matcher.h" #include "kis_shortcut_configuration.h" #include "kis_canvas2.h" #include "kis_tool_proxy.h" #include "kis_signal_compressor.h" #include "input/kis_tablet_debugger.h" #include "kis_timed_signal_threshold.h" #include "kis_signal_auto_connection.h" class KisToolInvocationAction; class KisInputManager::Private { public: Private(KisInputManager *qq); bool tryHidePopupPalette(); void addStrokeShortcut(KisAbstractInputAction* action, int index, const QList< Qt::Key >& modifiers, Qt::MouseButtons buttons); void addKeyShortcut(KisAbstractInputAction* action, int index,const QList &keys); void addTouchShortcut( KisAbstractInputAction* action, int index, KisShortcutConfiguration::GestureAction gesture ); void addWheelShortcut(KisAbstractInputAction* action, int index, const QList< Qt::Key >& modifiers, KisShortcutConfiguration::MouseWheelMovement wheelAction); bool processUnhandledEvent(QEvent *event); void setupActions(); void saveTouchEvent( QTouchEvent* event ); bool handleCompressedTabletEvent(QEvent *event); KisInputManager *q; - KisCanvas2 *canvas = 0; + QPointer canvas = 0; KisToolProxy *toolProxy = 0; bool forwardAllEventsToTool = false; bool ignoringQtCursorEvents(); bool disableTouchOnCanvas = false; bool touchHasBlockedPressEvents = false; KisShortcutMatcher matcher; QTouchEvent *lastTouchEvent = 0; KisToolInvocationAction *defaultInputAction = 0; QObject *eventsReceiver = 0; KisSignalCompressor moveEventCompressor; QScopedPointer compressedMoveEvent; bool testingAcceptCompressedTabletEvents = false; bool testingCompressBrushEvents = false; bool tabletActive = false; // Indicates whether or not tablet is in proximity typedef QPair > PriorityPair; typedef QList PriorityList; PriorityList priorityEventFilter; int priorityEventFilterSeqNo; void blockMouseEvents(); void allowMouseEvents(); void eatOneMousePress(); void maskSyntheticEvents(bool value); void setTabletActive(bool value); void resetCompressor(); template void debugEvent(QEvent *event) { if (!KisTabletDebugger::instance()->debugEnabled()) return; QString msg1 = useBlocking && ignoringQtCursorEvents() ? "[BLOCKED] " : "[ ]"; Event *specificEvent = static_cast(event); dbgTablet << KisTabletDebugger::instance()->eventToString(*specificEvent, msg1); } class ProximityNotifier : public QObject { public: ProximityNotifier(Private *_d, QObject *p); bool eventFilter(QObject* object, QEvent* event ); private: KisInputManager::Private *d; }; class CanvasSwitcher : public QObject { public: CanvasSwitcher(Private *_d, QObject *p); void addCanvas(KisCanvas2 *canvas); void removeCanvas(KisCanvas2 *canvas); bool eventFilter(QObject* object, QEvent* event ); private: void setupFocusThreshold(QObject *object); private: KisInputManager::Private *d; - QMap canvasResolver; + QMap> canvasResolver; int eatOneMouseStroke; KisTimedSignalThreshold focusSwitchThreshold; KisSignalAutoConnectionsStore thresholdConnections; }; CanvasSwitcher canvasSwitcher; struct EventEater { bool eventFilter(QObject* target, QEvent* event); // This should be called after we're certain a tablet stroke has started. void activate(); // This should be called after a tablet stroke has ended. void deactivate(); // On Windows, we sometimes receive mouse events very late, so watch & wait. void eatOneMousePress(); bool hungry{false}; // Continue eating mouse strokes bool peckish{false}; // Eat a single mouse press event bool eatSyntheticEvents{true}; // Mask all synthetic events }; EventEater eventEater; bool containsPointer = true; }; diff --git a/libs/ui/kis_action_manager.cpp b/libs/ui/kis_action_manager.cpp index 741c5773e0..82692284d6 100644 --- a/libs/ui/kis_action_manager.cpp +++ b/libs/ui/kis_action_manager.cpp @@ -1,482 +1,481 @@ /* * Copyright (c) 2013 Sven Langkamp * * 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_action_manager.h" #include #include #include #include "KisPart.h" #include "kis_action.h" #include "KisViewManager.h" #include "kis_selection_manager.h" #include "operations/kis_operation_ui_factory.h" #include "operations/kis_operation_registry.h" #include "operations/kis_operation.h" #include "kis_layer.h" #include "KisDocument.h" #include "kis_clipboard.h" #include #include "QFile" #include #include #include "QFile" #include #include class Q_DECL_HIDDEN KisActionManager::Private { public: Private() : viewManager(0) {} ~Private() { qDeleteAll(uiRegistry.values()); } KisViewManager* viewManager; KActionCollection *actionCollection; QList actions; KoGenericRegistry uiRegistry; KisOperationRegistry operationRegistry; }; KisActionManager::KisActionManager(KisViewManager* viewManager, KActionCollection *actionCollection) : d(new Private) { d->viewManager = viewManager; d->actionCollection = actionCollection; connect(d->actionCollection, SIGNAL(inserted(QAction*)), SLOT(slotActionAddedToCollection(QAction*))); } KisActionManager::~KisActionManager() { #if 0 if ((d->actions.size() > 0)) { QDomDocument doc; QDomElement e = doc.createElement("Actions"); e.setAttribute("version", "2"); doc.appendChild(e); Q_FOREACH (KisAction *action, d->actions) { QDomElement a = doc.createElement("Action"); a.setAttribute("name", action->objectName()); // But seriously, XML is the worst format ever designed auto addElement = [&](QString title, QString content) { QDomElement newNode = doc.createElement(title); QDomText newText = doc.createTextNode(content); newNode.appendChild(newText); a.appendChild(newNode); }; addElement("icon", action->icon().name()); addElement("text", action->text()); addElement("whatsThis" , action->whatsThis()); addElement("toolTip" , action->toolTip()); addElement("iconText" , action->iconText()); addElement("shortcut" , action->shortcut().toString()); addElement("activationFlags" , QString::number(action->activationFlags(),2));; addElement("activationConditions" , QString::number(action->activationConditions(),2)); addElement("defaultShortcut" , action->defaultShortcut().toString()); addElement("isCheckable" , QString((action->isChecked() ? "true" : "false"))); addElement("statusTip", action->statusTip()); e.appendChild(a); } QFile f("ActionManager.action"); f.open(QFile::WriteOnly); f.write(doc.toString().toUtf8()); f.close(); } #endif delete d; } void KisActionManager::setView(QPointer imageView) { Q_UNUSED(imageView); } void KisActionManager::slotActionAddedToCollection(QAction *action) { /** * Small hack alert: not all the actions are still created by the manager and * immediately added to the action collection. Some plugins add actions * directly to the action collection when a document is created. Here we * catch these cases */ - KisActionRegistry::instance()->updateShortcut(action->objectName(), action); } void KisActionManager::addAction(const QString& name, KisAction* action) { Q_ASSERT(!name.isEmpty()); Q_ASSERT(action); Q_ASSERT(d->viewManager); Q_ASSERT(d->actionCollection); d->actionCollection->addAction(name, action); action->setParent(d->actionCollection); d->actions.append(action); action->setActionManager(this); } void KisActionManager::takeAction(KisAction* action) { d->actions.removeOne(action); if (!action->objectName().isEmpty()) { KIS_ASSERT_RECOVER_RETURN(d->actionCollection); d->actionCollection->takeAction(action); } } KisAction *KisActionManager::actionByName(const QString &name) const { Q_FOREACH (KisAction *action, d->actions) { if (action->objectName() == name) { return action; } } return 0; } KisAction *KisActionManager::createAction(const QString &name) { KisAction *a = actionByName(name); // Check if the action already exists if (a) { return a; } // There is some tension here. KisActionManager is supposed to be in control // of global actions, but these actions are supposed to be duplicated. We // will add them to the KisActionRegistry for the time being so we can get // properly categorized shortcuts. a = new KisAction(); KisActionRegistry *actionRegistry = KisActionRegistry::instance(); // Add extra properties actionRegistry->propertizeAction(name, a); bool ok; // We will skip this check int activationFlags = actionRegistry->getActionProperty(name, "activationFlags").toInt(&ok, 2); int activationConditions = actionRegistry->getActionProperty(name, "activationConditions").toInt(&ok, 2); a->setActivationFlags((KisAction::ActivationFlags) activationFlags); a->setActivationConditions((KisAction::ActivationConditions) activationConditions); addAction(name, a); return a; } void KisActionManager::updateGUI() { //TODO other flags KisAction::ActivationFlags flags; KisImageWSP image; KisNodeSP node; KisLayerSP layer; KisPaintDeviceSP device; KisDocument* document = 0; KisSelectionManager* selectionManager = 0; KisAction::ActivationConditions conditions = KisAction::NO_CONDITION; if (d->viewManager) { // if there are no views, that means no document is open. // we cannot have nodes (selections), devices, or documents without a view if ( d->viewManager->viewCount() > 0 ) { image = d->viewManager->image(); flags |= KisAction::ACTIVE_IMAGE; if (image && image->animationInterface()->hasAnimation()) { flags |= KisAction::IMAGE_HAS_ANIMATION; } node = d->viewManager->activeNode(); device = d->viewManager->activeDevice(); document = d->viewManager->document(); selectionManager = d->viewManager->selectionManager(); if (d->viewManager->viewCount() > 1) { flags |= KisAction::MULTIPLE_IMAGES; } if (document && document->isModified()) { flags |= KisAction::CURRENT_IMAGE_MODIFIED; } if (device) { flags |= KisAction::ACTIVE_DEVICE; } } } // is there a selection/mask? // you have to have at least one view(document) open for this to be true if (node) { // if a node exists, we know there is an active layer as well flags |= KisAction::ACTIVE_NODE; layer = qobject_cast(node.data()); if (layer) { flags |= KisAction::ACTIVE_LAYER; } if (node->inherits("KisTransparencyMask")) { flags |= KisAction::ACTIVE_TRANSPARENCY_MASK; } if (layer && layer->inherits("KisShapeLayer")) { flags |= KisAction::ACTIVE_SHAPE_LAYER; } if (KisClipboard::instance()->hasLayers()) { flags |= KisAction::LAYERS_IN_CLIPBOARD; } if (selectionManager) { if (selectionManager->havePixelsSelected()) { flags |= KisAction::PIXELS_SELECTED; } if (selectionManager->haveShapesSelected()) { flags |= KisAction::SHAPES_SELECTED; } if (selectionManager->havePixelSelectionWithPixels()) { flags |= KisAction::PIXEL_SELECTION_WITH_PIXELS; } if (selectionManager->havePixelsInClipboard()) { flags |= KisAction::PIXELS_IN_CLIPBOARD; } if (selectionManager->haveShapesInClipboard()) { flags |= KisAction::SHAPES_IN_CLIPBOARD; } } if (node->isEditable(false)) { conditions |= KisAction::ACTIVE_NODE_EDITABLE; } if (node->hasEditablePaintDevice()) { conditions |= KisAction::ACTIVE_NODE_EDITABLE_PAINT_DEVICE; } if (d->viewManager->selectionEditable()) { conditions |= KisAction::SELECTION_EDITABLE; } } // loop through all actions in action manager and determine what should be enabled Q_FOREACH (KisAction* action, d->actions) { bool enable; if (action->activationFlags() == KisAction::NONE) { enable = true; } else { enable = action->activationFlags() & flags; // combine action flags with updateGUI flags } enable = enable && (int)(action->activationConditions() & conditions) == (int)action->activationConditions(); if (node && enable) { Q_FOREACH (const QString &type, action->excludedNodeTypes()) { if (node->inherits(type.toLatin1())) { enable = false; break; } } } action->setActionEnabled(enable); } } KisAction *KisActionManager::createStandardAction(KStandardAction::StandardAction actionType, const QObject *receiver, const char *member) { QAction *standardAction = KStandardAction::create(actionType, receiver, member, 0); KisAction *action = new KisAction(standardAction->icon(), standardAction->text()); const QList defaultShortcuts = standardAction->property("defaultShortcuts").value >(); const QKeySequence defaultShortcut = defaultShortcuts.isEmpty() ? QKeySequence() : defaultShortcuts.at(0); action->setDefaultShortcut(standardAction->shortcut()); #ifdef Q_OS_WIN if (actionType == KStandardAction::SaveAs && defaultShortcuts.isEmpty()) { action->setShortcut(QKeySequence("CTRL+SHIFT+S")); } #endif action->setCheckable(standardAction->isCheckable()); if (action->isCheckable()) { action->setChecked(standardAction->isChecked()); } action->setMenuRole(standardAction->menuRole()); action->setText(standardAction->text()); action->setToolTip(standardAction->toolTip()); if (receiver && member) { if (actionType == KStandardAction::OpenRecent) { QObject::connect(action, SIGNAL(urlSelected(QUrl)), receiver, member); } else if (actionType == KStandardAction::ConfigureToolbars) { QObject::connect(action, SIGNAL(triggered(bool)), receiver, member, Qt::QueuedConnection); } else { QObject::connect(action, SIGNAL(triggered(bool)), receiver, member); } } KisActionRegistry *actionRegistry = KisActionRegistry::instance(); actionRegistry->propertizeAction(standardAction->objectName(), action); addAction(standardAction->objectName(), action); delete standardAction; return action; } void KisActionManager::registerOperationUIFactory(KisOperationUIFactory* factory) { d->uiRegistry.add(factory); } void KisActionManager::registerOperation(KisOperation* operation) { d->operationRegistry.add(operation); } void KisActionManager::runOperation(const QString& id) { KisOperationConfigurationSP config = new KisOperationConfiguration(id); KisOperationUIFactory* uiFactory = d->uiRegistry.get(id); if (uiFactory) { bool gotConfig = uiFactory->fetchConfiguration(d->viewManager, config); if (!gotConfig) { return; } } runOperationFromConfiguration(config); } void KisActionManager::runOperationFromConfiguration(KisOperationConfigurationSP config) { KisOperation* operation = d->operationRegistry.get(config->id()); Q_ASSERT(operation); operation->runFromXML(d->viewManager, *config); } void KisActionManager::dumpActionFlags() { QFile data("actions.txt"); if (data.open(QFile::WriteOnly | QFile::Truncate)) { QTextStream out(&data); out.setCodec("UTF-8"); Q_FOREACH (KisAction* action, d->actions) { KisAction::ActivationFlags flags = action->activationFlags(); out << "-------- " << action->text() << " --------\n"; out << "Action will activate on: \n"; if (flags & KisAction::ACTIVE_IMAGE) { out << " Active image\n"; } if (flags & KisAction::MULTIPLE_IMAGES) { out << " More than one image open\n"; } if (flags & KisAction::CURRENT_IMAGE_MODIFIED) { out << " Active image modified\n"; } if (flags & KisAction::ACTIVE_DEVICE) { out << " Active device\n"; } if (flags & KisAction::ACTIVE_LAYER) { out << " Active layer\n"; } if (flags & KisAction::ACTIVE_TRANSPARENCY_MASK) { out << " Active transparency mask\n"; } if (flags & KisAction::ACTIVE_NODE) { out << " Active node\n"; } if (flags & KisAction::ACTIVE_SHAPE_LAYER) { out << " Active shape layer\n"; } if (flags & KisAction::PIXELS_SELECTED) { out << " Pixels selected\n"; } if (flags & KisAction::SHAPES_SELECTED) { out << " Shapes selected\n"; } if (flags & KisAction::PIXEL_SELECTION_WITH_PIXELS) { out << " Pixel selection with pixels\n"; } if (flags & KisAction::PIXELS_IN_CLIPBOARD) { out << " Pixels in clipboard\n"; } if (flags & KisAction::SHAPES_IN_CLIPBOARD) { out << " Shape in clipboard\n"; } if (flags & KisAction::IMAGE_HAS_ANIMATION) { out << " Image has animation\n"; } out << "\n\n"; out << "Action will only activate if the following conditions are met: \n"; KisAction::ActivationConditions conditions = action->activationConditions(); if ((int)conditions == 0) { out << " -\n"; } if (conditions & KisAction::ACTIVE_NODE_EDITABLE) { out << " Active Node editable\n"; } if (conditions & KisAction::ACTIVE_NODE_EDITABLE_PAINT_DEVICE) { out << " Active Node has editable paint device\n"; } if (conditions & KisAction::SELECTION_EDITABLE) { out << " Selection is editable\n"; } out << "\n\n"; } } } diff --git a/libs/ui/kis_import_catcher.cc b/libs/ui/kis_import_catcher.cc index 6f58699026..b1a2962f59 100644 --- a/libs/ui/kis_import_catcher.cc +++ b/libs/ui/kis_import_catcher.cc @@ -1,138 +1,143 @@ /* * 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_import_catcher.h" #include #include #include #include #include #include "kis_node_manager.h" #include "kis_count_visitor.h" #include "KisViewManager.h" #include "KisDocument.h" #include "kis_image.h" #include "kis_layer.h" #include "kis_painter.h" #include "kis_selection.h" #include "kis_node_commands_adapter.h" #include "kis_group_layer.h" #include "kis_statusbar.h" #include "kis_progress_widget.h" #include "kis_config.h" #include "KisPart.h" struct KisImportCatcher::Private { public: KisDocument* doc; KisViewManager* view; QUrl url; QString layerType; QString prettyLayerName() const; void importAsPaintLayer(KisPaintDeviceSP device); void importAsTransparencyMask(KisPaintDeviceSP device); }; QString KisImportCatcher::Private::prettyLayerName() const { QString name = url.fileName(); return !name.isEmpty() ? name : url.toDisplayString(); } void KisImportCatcher::Private::importAsPaintLayer(KisPaintDeviceSP device) { KisLayerSP newLayer = new KisPaintLayer(view->image(), prettyLayerName(), OPACITY_OPAQUE_U8, device); KisNodeSP parent = 0; KisLayerSP currentActiveLayer = view->activeLayer(); if (currentActiveLayer) { parent = currentActiveLayer->parent(); } if (parent.isNull()) { parent = view->image()->rootLayer(); } KisNodeCommandsAdapter adapter(view); adapter.addNode(newLayer, parent, currentActiveLayer); } KisImportCatcher::KisImportCatcher(const QUrl &url, KisViewManager *view, const QString &layerType) : m_d(new Private) { m_d->doc = KisPart::instance()->createDocument(); KoProgressProxy *progressProxy = view->statusBar()->progress()->progressProxy(); m_d->doc->setProgressProxy(progressProxy); m_d->view = view; m_d->url = url; m_d->layerType = layerType; connect(m_d->doc, SIGNAL(sigLoadingFinished()), this, SLOT(slotLoadingFinished())); bool result = m_d->doc->openUrl(url); if (!result) { deleteMyself(); } } void KisImportCatcher::slotLoadingFinished() { KisImageWSP importedImage = m_d->doc->image(); importedImage->waitForDone(); if (importedImage && importedImage->projection()->exactBounds().isValid()) { if (m_d->layerType != "KisPaintLayer") { m_d->view->nodeManager()->createNode(m_d->layerType, false, importedImage->projection()); } else { - KisConfig cfg; KisPaintDeviceSP dev = importedImage->projection(); - qDebug() << "dev" << dev->colorSpace() << "image" << m_d->view->image()->colorSpace() << "cfg" << cfg.convertToImageColorspaceOnImport(); - if (cfg.convertToImageColorspaceOnImport() && dev->colorSpace() != m_d->view->image()->colorSpace()) { - /// XXX: do we need intent here? - KUndo2Command* cmd = dev->convertTo(m_d->view->image()->colorSpace()); - delete cmd; - } + adaptClipToImageColorSpace(dev, m_d->view->image()); m_d->importAsPaintLayer(dev); } } deleteMyself(); } void KisImportCatcher::deleteMyself() { m_d->doc->deleteLater(); deleteLater(); } KisImportCatcher::~KisImportCatcher() { delete m_d; } +void KisImportCatcher::adaptClipToImageColorSpace(KisPaintDeviceSP dev, KisImageSP image) +{ + KisConfig cfg; + qDebug() << "dev" << dev->colorSpace() << "image" << image->colorSpace() << "cfg" << cfg.convertToImageColorspaceOnImport(); + if (cfg.convertToImageColorspaceOnImport() && *dev->colorSpace() != *image->colorSpace()) { + /// XXX: do we need intent here? + KUndo2Command* cmd = dev->convertTo(image->colorSpace()); + delete cmd; + } +} + diff --git a/libs/ui/kis_import_catcher.h b/libs/ui/kis_import_catcher.h index 719361a726..0f1bbcd906 100644 --- a/libs/ui/kis_import_catcher.h +++ b/libs/ui/kis_import_catcher.h @@ -1,60 +1,62 @@ /* * 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_IMPORT_CATCHER_H_ #define KIS_IMPORT_CATCHER_H_ #include #include class KisViewManager; class QUrl; /** * This small helper class takes an url and an image; tries to import * the image at the url and shove the layers of the imported image * into the first image after loading is done. This is a separate class * because loading can be asynchronous. * * Caveat: this class calls "delete this", which means that you new * it and then never touch it again. Thank you very much. */ class KisImportCatcher : QObject { Q_OBJECT public: KisImportCatcher(const QUrl &url, KisViewManager* view, const QString &layerType); ~KisImportCatcher(); + static void adaptClipToImageColorSpace(KisPaintDeviceSP dev, KisImageSP image); + private Q_SLOTS: void slotLoadingFinished(); private: void deleteMyself(); private: struct Private; Private* const m_d; }; #endif diff --git a/libs/ui/kis_node_model.cpp b/libs/ui/kis_node_model.cpp index 83d319d62c..f5ef58b838 100644 --- a/libs/ui/kis_node_model.cpp +++ b/libs/ui/kis_node_model.cpp @@ -1,644 +1,646 @@ /* * Copyright (c) 2007 Boudewijn Rempt * Copyright (c) 2008 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_node_model.h" #include #include #include +#include #include #include #include "kis_mimedata.h" #include #include #include #include #include #include #include #include #include #include #include - +#include #include "kis_dummies_facade_base.h" #include "kis_node_dummies_graph.h" #include "kis_model_index_converter.h" #include "kis_model_index_converter_show_all.h" #include "kis_node_selection_adapter.h" #include "kis_node_insertion_adapter.h" #include "kis_config.h" #include "kis_config_notifier.h" #include struct KisNodeModel::Private { KisImageWSP image; KisShapeController *shapeController = 0; KisNodeSelectionAdapter *nodeSelectionAdapter = 0; KisNodeInsertionAdapter *nodeInsertionAdapter = 0; QList updateQueue; QTimer updateTimer; KisModelIndexConverterBase *indexConverter = 0; - KisDummiesFacadeBase *dummiesFacade = 0; + QPointer dummiesFacade = 0; bool needFinishRemoveRows = false; bool needFinishInsertRows = false; bool showRootLayer = false; bool showGlobalSelection = false; QPersistentModelIndex activeNodeIndex; - KisNodeDummy* parentOfRemovedNode = 0; + QPointer parentOfRemovedNode = 0; }; KisNodeModel::KisNodeModel(QObject * parent) : QAbstractItemModel(parent) , m_d(new Private) { updateSettings(); connect(KisConfigNotifier::instance(), SIGNAL(configChanged()), this, SLOT(updateSettings())); m_d->updateTimer.setSingleShot(true); connect(&m_d->updateTimer, SIGNAL(timeout()), SLOT(processUpdateQueue())); } KisNodeModel::~KisNodeModel() { delete m_d->indexConverter; delete m_d; } KisNodeSP KisNodeModel::nodeFromIndex(const QModelIndex &index) const { Q_ASSERT(index.isValid()); KisNodeDummy *dummy = m_d->indexConverter->dummyFromIndex(index); - return dummy->node(); + if (dummy) { + return dummy->node(); + } + return 0; } QModelIndex KisNodeModel::indexFromNode(KisNodeSP node) const { KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(node); if(dummy) return m_d->indexConverter->indexFromDummy(dummy); return QModelIndex(); } bool KisNodeModel::belongsToIsolatedGroup(KisImageSP image, KisNodeSP node, KisDummiesFacadeBase *dummiesFacade) { KisNodeSP isolatedRoot = image->isolatedModeRoot(); if (!isolatedRoot) return true; KisNodeDummy *isolatedRootDummy = dummiesFacade->dummyForNode(isolatedRoot); KisNodeDummy *dummy = dummiesFacade->dummyForNode(node); while (dummy) { if (dummy == isolatedRootDummy) { return true; } dummy = dummy->parent(); } return false; } bool KisNodeModel::belongsToIsolatedGroup(KisNodeSP node) const { return belongsToIsolatedGroup(m_d->image, node, m_d->dummiesFacade); } void KisNodeModel::resetIndexConverter() { delete m_d->indexConverter; m_d->indexConverter = 0; if(m_d->dummiesFacade) { m_d->indexConverter = createIndexConverter(); } } KisModelIndexConverterBase *KisNodeModel::createIndexConverter() { if(m_d->showRootLayer) { return new KisModelIndexConverterShowAll(m_d->dummiesFacade, this); } else { return new KisModelIndexConverter(m_d->dummiesFacade, this, m_d->showGlobalSelection); } } void KisNodeModel::regenerateItems(KisNodeDummy *dummy) { const QModelIndex &index = m_d->indexConverter->indexFromDummy(dummy); emit dataChanged(index, index); dummy = dummy->firstChild(); while (dummy) { regenerateItems(dummy); dummy = dummy->nextSibling(); } } void KisNodeModel::slotIsolatedModeChanged() { regenerateItems(m_d->dummiesFacade->rootDummy()); } bool KisNodeModel::showGlobalSelection() const { KisConfig cfg; return cfg.showGlobalSelection(); } void KisNodeModel::setShowGlobalSelection(bool value) { KisConfig cfg; cfg.setShowGlobalSelection(value); updateSettings(); } void KisNodeModel::updateSettings() { KisConfig cfg; bool oldShowRootLayer = m_d->showRootLayer; bool oldShowGlobalSelection = m_d->showGlobalSelection; m_d->showRootLayer = cfg.showRootLayer(); m_d->showGlobalSelection = cfg.showGlobalSelection(); if (m_d->showRootLayer != oldShowRootLayer || m_d->showGlobalSelection != oldShowGlobalSelection) { resetIndexConverter(); reset(); } } void KisNodeModel::progressPercentageChanged(int, const KisNodeSP node) { if(!m_d->dummiesFacade) return; // Need to check here as the node might already be removed, but there might // still be some signals arriving from another thread if (m_d->dummiesFacade->hasDummyForNode(node)) { QModelIndex index = indexFromNode(node); emit dataChanged(index, index); } } KisModelIndexConverterBase * KisNodeModel::indexConverter() const { return m_d->indexConverter; } KisDummiesFacadeBase *KisNodeModel::dummiesFacade() const { return m_d->dummiesFacade; } void KisNodeModel::connectDummy(KisNodeDummy *dummy, bool needConnect) { KisNodeSP node = dummy->node(); if (!node) { qWarning() << "Dummy node has no node!" << dummy << dummy->node(); return; } KisNodeProgressProxy *progressProxy = node->nodeProgressProxy(); if(progressProxy) { if(needConnect) { connect(progressProxy, SIGNAL(percentageChanged(int,KisNodeSP)), SLOT(progressPercentageChanged(int,KisNodeSP))); } else { progressProxy->disconnect(this); } } } void KisNodeModel::connectDummies(KisNodeDummy *dummy, bool needConnect) { connectDummy(dummy, needConnect); dummy = dummy->firstChild(); while(dummy) { connectDummies(dummy, needConnect); dummy = dummy->nextSibling(); } } void KisNodeModel::setDummiesFacade(KisDummiesFacadeBase *dummiesFacade, KisImageWSP image, KisShapeController *shapeController, KisNodeSelectionAdapter *nodeSelectionAdapter, KisNodeInsertionAdapter *nodeInsertionAdapter) { - KisDummiesFacadeBase *oldDummiesFacade; - KisShapeController *oldShapeController; - oldShapeController = m_d->shapeController; - oldDummiesFacade = m_d->dummiesFacade; + QPointer oldDummiesFacade(m_d->dummiesFacade); + KisShapeController *oldShapeController = m_d->shapeController; m_d->shapeController = shapeController; m_d->nodeSelectionAdapter = nodeSelectionAdapter; m_d->nodeInsertionAdapter = nodeInsertionAdapter; - if(oldDummiesFacade && m_d->image) { + if (oldDummiesFacade && m_d->image) { m_d->image->disconnect(this); oldDummiesFacade->disconnect(this); connectDummies(m_d->dummiesFacade->rootDummy(), false); } m_d->image = image; m_d->dummiesFacade = dummiesFacade; m_d->parentOfRemovedNode = 0; resetIndexConverter(); - if(m_d->dummiesFacade) { + if (m_d->dummiesFacade) { KisNodeDummy *rootDummy = m_d->dummiesFacade->rootDummy(); - if(rootDummy) { + if (rootDummy) { connectDummies(rootDummy, true); } connect(m_d->dummiesFacade, SIGNAL(sigBeginInsertDummy(KisNodeDummy*,int,QString)), SLOT(slotBeginInsertDummy(KisNodeDummy*,int,QString))); connect(m_d->dummiesFacade, SIGNAL(sigEndInsertDummy(KisNodeDummy*)), SLOT(slotEndInsertDummy(KisNodeDummy*))); connect(m_d->dummiesFacade, SIGNAL(sigBeginRemoveDummy(KisNodeDummy*)), SLOT(slotBeginRemoveDummy(KisNodeDummy*))); connect(m_d->dummiesFacade, SIGNAL(sigEndRemoveDummy()), SLOT(slotEndRemoveDummy())); connect(m_d->dummiesFacade, SIGNAL(sigDummyChanged(KisNodeDummy*)), SLOT(slotDummyChanged(KisNodeDummy*))); - if(m_d->image.isValid()) { + if (m_d->image.isValid()) { connect(m_d->image, SIGNAL(sigIsolatedModeChanged()), SLOT(slotIsolatedModeChanged())); } } - if(m_d->dummiesFacade != oldDummiesFacade || m_d->shapeController != oldShapeController) { + if (m_d->dummiesFacade != oldDummiesFacade || m_d->shapeController != oldShapeController) { reset(); } } void KisNodeModel::slotBeginInsertDummy(KisNodeDummy *parent, int index, const QString &metaObjectType) { int row = 0; QModelIndex parentIndex; bool willAdd = m_d->indexConverter->indexFromAddedDummy(parent, index, metaObjectType, parentIndex, row); if(willAdd) { beginInsertRows(parentIndex, row, row); m_d->needFinishInsertRows = true; } } void KisNodeModel::slotEndInsertDummy(KisNodeDummy *dummy) { if(m_d->needFinishInsertRows) { connectDummy(dummy, true); endInsertRows(); m_d->needFinishInsertRows = false; } } void KisNodeModel::slotBeginRemoveDummy(KisNodeDummy *dummy) { if (!dummy) return; // FIXME: is it really what we want? m_d->updateTimer.stop(); m_d->updateQueue.clear(); m_d->parentOfRemovedNode = dummy->parent(); QModelIndex parentIndex; if (m_d->parentOfRemovedNode) { parentIndex = m_d->indexConverter->indexFromDummy(m_d->parentOfRemovedNode); } QModelIndex itemIndex = m_d->indexConverter->indexFromDummy(dummy); if (itemIndex.isValid()) { connectDummy(dummy, false); beginRemoveRows(parentIndex, itemIndex.row(), itemIndex.row()); m_d->needFinishRemoveRows = true; } } void KisNodeModel::slotEndRemoveDummy() { if(m_d->needFinishRemoveRows) { endRemoveRows(); m_d->needFinishRemoveRows = false; } } void KisNodeModel::slotDummyChanged(KisNodeDummy *dummy) { if (!m_d->updateQueue.contains(dummy)) { m_d->updateQueue.append(dummy); } m_d->updateTimer.start(1000); } void addChangedIndex(const QModelIndex &index, QSet *indexes) { if (!index.isValid() || indexes->contains(index)) return; indexes->insert(index); const int rowCount = index.model()->rowCount(index); for (int i = 0; i < rowCount; i++) { addChangedIndex(index.child(i, 0), indexes); } } void KisNodeModel::processUpdateQueue() { QSet indexes; Q_FOREACH (KisNodeDummy *dummy, m_d->updateQueue) { QModelIndex index = m_d->indexConverter->indexFromDummy(dummy); addChangedIndex(index, &indexes); } Q_FOREACH (const QModelIndex &index, indexes) { emit dataChanged(index, index); } m_d->updateQueue.clear(); } QModelIndex KisNodeModel::index(int row, int col, const QModelIndex &parent) const { if(!m_d->dummiesFacade || !hasIndex(row, col, parent)) return QModelIndex(); QModelIndex itemIndex; KisNodeDummy *dummy = m_d->indexConverter->dummyFromRow(row, parent); if(dummy) { itemIndex = m_d->indexConverter->indexFromDummy(dummy); } return itemIndex; } int KisNodeModel::rowCount(const QModelIndex &parent) const { if(!m_d->dummiesFacade) return 0; return m_d->indexConverter->rowCount(parent); } int KisNodeModel::columnCount(const QModelIndex&) const { return 1; } QModelIndex KisNodeModel::parent(const QModelIndex &index) const { if(!m_d->dummiesFacade || !index.isValid()) return QModelIndex(); KisNodeDummy *dummy = m_d->indexConverter->dummyFromIndex(index); KisNodeDummy *parentDummy = dummy->parent(); QModelIndex parentIndex; if(parentDummy) { parentIndex = m_d->indexConverter->indexFromDummy(parentDummy); } return parentIndex; } QVariant KisNodeModel::data(const QModelIndex &index, int role) const { if (!m_d->dummiesFacade || !index.isValid() || !m_d->image.isValid()) return QVariant(); KisNodeSP node = nodeFromIndex(index); switch (role) { case Qt::DisplayRole: return node->name(); case Qt::DecorationRole: return node->icon(); case Qt::EditRole: return node->name(); case Qt::SizeHintRole: return m_d->image->size(); // FIXME case Qt::TextColorRole: return belongsToIsolatedGroup(node) && !node->projectionLeaf()->isDroppedMask() ? QVariant() : QVariant(QColor(Qt::gray)); case Qt::FontRole: { QFont baseFont; if (node->projectionLeaf()->isDroppedMask()) { baseFont.setStrikeOut(true); } if (m_d->activeNodeIndex == index) { baseFont.setBold(true); } return baseFont; } case KisNodeModel::PropertiesRole: return QVariant::fromValue(node->sectionModelProperties()); case KisNodeModel::AspectRatioRole: return double(m_d->image->width()) / m_d->image->height(); case KisNodeModel::ProgressRole: { KisNodeProgressProxy *proxy = node->nodeProgressProxy(); return proxy ? proxy->percentage() : -1; } case KisNodeModel::ActiveRole: { return m_d->activeNodeIndex == index; } case KisNodeModel::ShouldGrayOutRole: { return !node->visible(true); } case KisNodeModel::ColorLabelIndexRole: { return node->colorLabelIndex(); } default: if (role >= int(KisNodeModel::BeginThumbnailRole) && belongsToIsolatedGroup(node)) { const int maxSize = role - int(KisNodeModel::BeginThumbnailRole); QSize size = node->extent().size(); size.scale(maxSize, maxSize, Qt::KeepAspectRatio); if (size.width() == 0 || size.height() == 0) { // No thumbnail can be shown if there isn't width or height... return QVariant(); } return node->createThumbnail(size.width(), size.height()); } else { return QVariant(); } } return QVariant(); } Qt::ItemFlags KisNodeModel::flags(const QModelIndex &index) const { if(!m_d->dummiesFacade || !index.isValid()) return Qt::ItemIsDropEnabled; Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEditable | Qt::ItemIsDropEnabled; return flags; } bool KisNodeModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role == KisNodeModel::ActiveRole || role == KisNodeModel::AlternateActiveRole) { QModelIndex parentIndex; if (!index.isValid() && m_d->parentOfRemovedNode && m_d->dummiesFacade && m_d->indexConverter) { parentIndex = m_d->indexConverter->indexFromDummy(m_d->parentOfRemovedNode); m_d->parentOfRemovedNode = 0; } KisNodeSP activatedNode; if (index.isValid() && value.toBool()) { activatedNode = nodeFromIndex(index); } else if (parentIndex.isValid() && value.toBool()) { activatedNode = nodeFromIndex(parentIndex); } else { activatedNode = 0; } QModelIndex newActiveNode = activatedNode ? indexFromNode(activatedNode) : QModelIndex(); if (role == KisNodeModel::ActiveRole && value.toBool() && m_d->activeNodeIndex == newActiveNode) { return true; } m_d->activeNodeIndex = newActiveNode; if (m_d->nodeSelectionAdapter) { m_d->nodeSelectionAdapter->setActiveNode(activatedNode); } if (role == KisNodeModel::AlternateActiveRole) { emit toggleIsolateActiveNode(); } emit dataChanged(index, index); return true; } if(!m_d->dummiesFacade || !index.isValid()) return false; bool result = true; bool shouldUpdateRecursively = false; KisNodeSP node = nodeFromIndex(index); switch (role) { case Qt::DisplayRole: case Qt::EditRole: node->setName(value.toString()); break; case KisNodeModel::PropertiesRole: { // don't record undo/redo for visibility, locked or alpha locked changes KisBaseNode::PropertyList proplist = value.value(); KisNodePropertyListCommand::setNodePropertiesNoUndo(node, m_d->image, proplist); shouldUpdateRecursively = true; break; } default: result = false; } if(result) { if (shouldUpdateRecursively) { QSet indexes; addChangedIndex(index, &indexes); Q_FOREACH (const QModelIndex &index, indexes) { emit dataChanged(index, index); } } else { emit dataChanged(index, index); } } return result; } Qt::DropActions KisNodeModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions KisNodeModel::supportedDropActions() const { return Qt::MoveAction | Qt::CopyAction; } bool KisNodeModel::hasDummiesFacade() { return m_d->dummiesFacade != 0; } QStringList KisNodeModel::mimeTypes() const { QStringList types; types << QLatin1String("application/x-krita-node"); types << QLatin1String("application/x-qt-image"); return types; } QMimeData * KisNodeModel::mimeData(const QModelIndexList &indexes) const { KisNodeList nodes; Q_FOREACH (const QModelIndex &idx, indexes) { nodes << nodeFromIndex(idx); } return KisMimeData::mimeForLayers(nodes, m_d->image->rootLayer()); } bool KisNodeModel::dropMimeData(const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent) { Q_UNUSED(column); bool copyNode = (action == Qt::CopyAction); KisNodeDummy *parentDummy = 0; KisNodeDummy *aboveThisDummy = 0; parentDummy = parent.isValid() ? m_d->indexConverter->dummyFromIndex(parent) : m_d->dummiesFacade->rootDummy(); if (row == -1) { aboveThisDummy = parent.isValid() ? parentDummy->lastChild() : 0; } else { aboveThisDummy = row < m_d->indexConverter->rowCount(parent) ? m_d->indexConverter->dummyFromRow(row, parent) : 0; } return KisMimeData::insertMimeLayers(data, m_d->image, m_d->shapeController, parentDummy, aboveThisDummy, copyNode, m_d->nodeInsertionAdapter); } diff --git a/libs/ui/kis_zoom_manager.cc b/libs/ui/kis_zoom_manager.cc index 9f10707e6d..54d700ee10 100644 --- a/libs/ui/kis_zoom_manager.cc +++ b/libs/ui/kis_zoom_manager.cc @@ -1,343 +1,345 @@ /* * Copyright (C) 2006, 2010 Boudewijn Rempt * Copyright (C) 2009 Lukáš Tvrdý * * 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_zoom_manager.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisDocument.h" #include "KisViewManager.h" #include "canvas/kis_canvas2.h" #include "kis_coordinates_converter.h" #include "kis_image.h" #include "kis_statusbar.h" #include "kis_config.h" #include "krita_utils.h" #include "kis_canvas_resource_provider.h" #include "kis_lod_transform.h" #include "kis_snap_line_strategy.h" class KisZoomController : public KoZoomController { public: KisZoomController(KoCanvasController *co, KisCoordinatesConverter *zh, KActionCollection *actionCollection, KoZoomAction::SpecialButtons specialButtons, QObject *parent) : KoZoomController(co, zh, actionCollection, specialButtons, parent), m_converter(zh) { } protected: QSize documentToViewport(const QSizeF &size) override { QRectF docRect(QPointF(), size); return m_converter->documentToWidget(docRect).toRect().size(); } private: KisCoordinatesConverter *m_converter; }; KisZoomManager::KisZoomManager(QPointer view, KoZoomHandler * zoomHandler, KoCanvasController * canvasController) : m_view(view) , m_zoomHandler(zoomHandler) , m_canvasController(canvasController) , m_horizontalRuler(0) , m_verticalRuler(0) , m_zoomAction(0) , m_zoomActionWidget(0) { } KisZoomManager::~KisZoomManager() { if (m_zoomActionWidget && !m_zoomActionWidget->parent()) { delete m_zoomActionWidget; } } void KisZoomManager::setup(KActionCollection * actionCollection) { KisImageWSP image = m_view->image(); if (!image) return; connect(image, SIGNAL(sigSizeChanged(const QPointF &, const QPointF &)), this, SLOT(setMinMaxZoom())); KisCoordinatesConverter *converter = dynamic_cast(m_zoomHandler); m_zoomController = new KisZoomController(m_canvasController, converter, actionCollection, KoZoomAction::AspectMode, this); m_zoomHandler->setZoomMode(KoZoomMode::ZOOM_PIXELS); m_zoomHandler->setZoom(1.0); m_zoomController->setPageSize(QSizeF(image->width() / image->xRes(), image->height() / image->yRes())); m_zoomController->setDocumentSize(QSizeF(image->width() / image->xRes(), image->height() / image->yRes()), true); m_zoomAction = m_zoomController->zoomAction(); setMinMaxZoom(); m_zoomActionWidget = m_zoomAction->createWidget(0); // Put the canvascontroller in a layout so it resizes with us QGridLayout * layout = new QGridLayout(m_view); layout->setSpacing(0); layout->setMargin(0); m_view->setLayout(layout); m_view->document()->setUnit(KoUnit(KoUnit::Pixel)); m_horizontalRuler = new KoRuler(m_view, Qt::Horizontal, m_zoomHandler); m_horizontalRuler->setShowMousePosition(true); m_horizontalRuler->createGuideToolConnection(m_view->canvasBase()); m_horizontalRuler->setVisible(false); // this prevents the rulers from flashing on to off when a new document is created m_verticalRuler = new KoRuler(m_view, Qt::Vertical, m_zoomHandler); m_verticalRuler->setShowMousePosition(true); m_verticalRuler->createGuideToolConnection(m_view->canvasBase()); m_verticalRuler->setVisible(false); QList unitActions = m_view->createChangeUnitActions(true); m_horizontalRuler->setPopupActionList(unitActions); m_verticalRuler->setPopupActionList(unitActions); connect(m_view->document(), SIGNAL(unitChanged(const KoUnit&)), SLOT(applyRulersUnit(const KoUnit&))); layout->addWidget(m_horizontalRuler, 0, 1); layout->addWidget(m_verticalRuler, 1, 0); layout->addWidget(static_cast(m_canvasController), 1, 1); connect(m_canvasController->proxyObject, SIGNAL(canvasOffsetXChanged(int)), this, SLOT(pageOffsetChanged())); connect(m_canvasController->proxyObject, SIGNAL(canvasOffsetYChanged(int)), this, SLOT(pageOffsetChanged())); connect(m_zoomController, SIGNAL(zoomChanged(KoZoomMode::Mode, qreal)), this, SLOT(slotZoomChanged(KoZoomMode::Mode, qreal))); connect(m_zoomController, SIGNAL(aspectModeChanged(bool)), this, SLOT(changeAspectMode(bool))); applyRulersUnit(m_view->document()->unit()); } void KisZoomManager::updateImageBoundsSnapping() { const QRectF docRect = m_view->canvasBase()->coordinatesConverter()->imageRectInDocumentPixels(); const QPointF docCenter = docRect.center(); KoSnapGuide *snapGuide = m_view->canvasBase()->snapGuide(); { KisSnapLineStrategy *boundsSnap = new KisSnapLineStrategy(KoSnapGuide::DocumentBoundsSnapping); boundsSnap->addLine(Qt::Horizontal, docRect.y()); boundsSnap->addLine(Qt::Horizontal, docRect.bottom()); boundsSnap->addLine(Qt::Vertical, docRect.x()); boundsSnap->addLine(Qt::Vertical, docRect.right()); snapGuide->overrideSnapStrategy(KoSnapGuide::DocumentBoundsSnapping, boundsSnap); } { KisSnapLineStrategy *centerSnap = new KisSnapLineStrategy(KoSnapGuide::DocumentCenterSnapping); centerSnap->addLine(Qt::Horizontal, docCenter.y()); centerSnap->addLine(Qt::Vertical, docCenter.x()); snapGuide->overrideSnapStrategy(KoSnapGuide::DocumentCenterSnapping, centerSnap); } } void KisZoomManager::updateMouseTrackingConnections() { bool value = m_horizontalRuler->isVisible() && m_verticalRuler->isVisible() && m_horizontalRuler->showMousePosition() && m_verticalRuler->showMousePosition(); m_mouseTrackingConnections.clear(); if (value) { connect(m_canvasController->proxyObject, SIGNAL(canvasMousePositionChanged(const QPoint &)), SLOT(mousePositionChanged(const QPoint &))); } } KoRuler* KisZoomManager::horizontalRuler() const { return m_horizontalRuler; } KoRuler* KisZoomManager::verticalRuler() const { return m_verticalRuler; } qreal KisZoomManager::zoom() const { qreal zoomX; qreal zoomY; m_zoomHandler->zoom(&zoomX, &zoomY); qDebug() << zoomX << zoomY; return zoomX; } void KisZoomManager::mousePositionChanged(const QPoint &viewPos) { QPoint pt = viewPos - m_rulersOffset; m_horizontalRuler->updateMouseCoordinate(pt.x()); m_verticalRuler->updateMouseCoordinate(pt.y()); } void KisZoomManager::setShowRulers(bool show) { m_horizontalRuler->setVisible(show); m_verticalRuler->setVisible(show); updateMouseTrackingConnections(); } void KisZoomManager::setRulersTrackMouse(bool value) { m_horizontalRuler->setShowMousePosition(value); m_verticalRuler->setShowMousePosition(value); updateMouseTrackingConnections(); } void KisZoomManager::applyRulersUnit(const KoUnit &baseUnit) { - m_horizontalRuler->setUnit(KoUnit(baseUnit.type(), m_view->image()->xRes())); - m_verticalRuler->setUnit(KoUnit(baseUnit.type(), m_view->image()->yRes())); + if (m_view && m_view->image()) { + m_horizontalRuler->setUnit(KoUnit(baseUnit.type(), m_view->image()->xRes())); + m_verticalRuler->setUnit(KoUnit(baseUnit.type(), m_view->image()->yRes())); + } } void KisZoomManager::setMinMaxZoom() { KisImageWSP image = m_view->image(); if (!image) return; QSize imageSize = image->size(); qreal minDimension = qMin(imageSize.width(), imageSize.height()); qreal minZoom = qMin(100.0 / minDimension, 0.1); m_zoomAction->setMinimumZoom(minZoom); m_zoomAction->setMaximumZoom(90.0); } void KisZoomManager::updateGUI() { QRectF widgetRect = m_view->canvasBase()->coordinatesConverter()->imageRectInWidgetPixels(); QSize documentSize = m_view->canvasBase()->viewConverter()->viewToDocument(widgetRect).toAlignedRect().size(); m_horizontalRuler->setRulerLength(documentSize.width()); m_verticalRuler->setRulerLength(documentSize.height()); applyRulersUnit(m_horizontalRuler->unit()); } QWidget *KisZoomManager::zoomActionWidget() const { return m_zoomActionWidget; } void KisZoomManager::slotZoomChanged(KoZoomMode::Mode mode, qreal zoom) { Q_UNUSED(mode); Q_UNUSED(zoom); m_view->canvasBase()->notifyZoomChanged(); qreal humanZoom = zoom * 100.0; // XXX: KOMVC -- this is very irritating in MDI mode if (m_view->viewManager()) { m_view->viewManager()-> showFloatingMessage( i18nc("floating message about zoom", "Zoom: %1 %", KritaUtils::prettyFormatReal(humanZoom)), QIcon(), 500, KisFloatingMessage::Low, Qt::AlignCenter); } const qreal effectiveZoom = m_view->canvasBase()->coordinatesConverter()->effectiveZoom(); m_view->canvasBase()->resourceManager()->setResource(KisCanvasResourceProvider::EffectiveZoom, effectiveZoom); } void KisZoomManager::slotScrollAreaSizeChanged() { pageOffsetChanged(); updateGUI(); } void KisZoomManager::changeAspectMode(bool aspectMode) { KisImageWSP image = m_view->image(); KoZoomMode::Mode newMode = KoZoomMode::ZOOM_CONSTANT; qreal newZoom = m_zoomHandler->zoom(); qreal resolutionX = aspectMode ? image->xRes() : POINT_TO_INCH(static_cast(KoDpi::dpiX())); qreal resolutionY = aspectMode ? image->yRes() : POINT_TO_INCH(static_cast(KoDpi::dpiY())); m_zoomController->setZoom(newMode, newZoom, resolutionX, resolutionY); m_view->canvasBase()->notifyZoomChanged(); } void KisZoomManager::pageOffsetChanged() { QRectF widgetRect = m_view->canvasBase()->coordinatesConverter()->imageRectInWidgetPixels(); m_rulersOffset = widgetRect.topLeft().toPoint(); m_horizontalRuler->setOffset(m_rulersOffset.x()); m_verticalRuler->setOffset(m_rulersOffset.y()); } void KisZoomManager::zoomTo100() { m_zoomController->setZoom(KoZoomMode::ZOOM_CONSTANT, 1.0); m_view->canvasBase()->notifyZoomChanged(); } diff --git a/libs/ui/tool/kis_selection_tool_helper.h b/libs/ui/tool/kis_selection_tool_helper.h index a469699fa7..33fd928020 100644 --- a/libs/ui/tool/kis_selection_tool_helper.h +++ b/libs/ui/tool/kis_selection_tool_helper.h @@ -1,59 +1,61 @@ /* * Copyright (c) 2007 Sven Langkamp * * 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_SELECTION_TOOL_HELPER_H #define KIS_SELECTION_TOOL_HELPER_H #include +#include + #include "kundo2magicstring.h" #include "kis_layer.h" #include "kis_selection.h" +#include "kis_canvas2.h" class KoShape; -class KisCanvas2; /** * XXX: Doc! */ class KRITAUI_EXPORT KisSelectionToolHelper { public: KisSelectionToolHelper(KisCanvas2* canvas, const KUndo2MagicString& name); virtual ~KisSelectionToolHelper(); void selectPixelSelection(KisPixelSelectionSP selection, SelectionAction action); void addSelectionShape(KoShape* shape); void addSelectionShapes(QList shapes); void cropRectIfNeeded(QRect *rect, SelectionAction action); bool canShortcutToDeselect(const QRect &rect, SelectionAction action); bool canShortcutToNoop(const QRect &rect, SelectionAction action); void cropPathIfNeeded(QPainterPath *path); bool tryDeselectCurrentSelection(const QRectF selectionViewRect, SelectionAction action); private: - KisCanvas2* m_canvas; + QPointer m_canvas; KisImageSP m_image; KisLayerSP m_layer; KUndo2MagicString m_name; }; #endif diff --git a/libs/ui/widgets/kis_image_from_clipboard_widget.cpp b/libs/ui/widgets/kis_image_from_clipboard_widget.cpp index 72309d82e8..be37ff9cbb 100644 --- a/libs/ui/widgets/kis_image_from_clipboard_widget.cpp +++ b/libs/ui/widgets/kis_image_from_clipboard_widget.cpp @@ -1,137 +1,138 @@ /* This file is part of the Calligra project * Copyright (C) 2005 Thomas Zander * Copyright (C) 2005 C. Boemann * Copyright (C) 2007 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 "widgets/kis_image_from_clipboard_widget.h" #include "widgets/kis_custom_image_widget.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 "kis_import_catcher.h" #include "kis_clipboard.h" #include "KisDocument.h" #include "widgets/kis_cmb_idlist.h" #include "widgets/squeezedcombobox.h" KisImageFromClipboard::KisImageFromClipboard(QWidget* parent, qint32 defWidth, qint32 defHeight, double resolution, const QString& defColorModel, const QString& defColorDepth, const QString& defColorProfile, const QString& imageName) : KisCustomImageWidget(parent, defWidth, defHeight, resolution, defColorModel, defColorDepth, defColorProfile, imageName) { setObjectName("KisImageFromClipboard"); // create clipboard preview and show it createClipboardPreview(); grpClipboard->show(); imageGroupSpacer->changeSize(20, 40, QSizePolicy::Expanding, QSizePolicy::Expanding); connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(clipboardDataChanged())); connect(QApplication::clipboard(), SIGNAL(selectionChanged()), this, SLOT(clipboardDataChanged())); connect(QApplication::clipboard(), SIGNAL(changed(QClipboard::Mode)), this, SLOT(clipboardDataChanged())); disconnect(createButton, SIGNAL(clicked()), 0, 0); //disable normal signal connect(createButton, SIGNAL(clicked()), this, SLOT(createImage())); setNumberOfLayers(1); } KisImageFromClipboard::~KisImageFromClipboard() { } void KisImageFromClipboard::createImage() { KisDocument *doc = createNewImage(); - KisImageWSP image = doc->image(); + KisImageSP image = doc->image(); if (image && image->root() && image->root()->firstChild()) { KisLayer * layer = qobject_cast(image->root()->firstChild().data()); KisPaintDeviceSP clip = KisClipboard::instance()->clip(QRect(), true); if (clip) { - QRect r = clip->exactBounds(); + KisImportCatcher::adaptClipToImageColorSpace(clip, image); + QRect r = clip->exactBounds(); KisPainter::copyAreaOptimized(QPoint(), clip, layer->paintDevice(), r); layer->setDirty(); } - } doc->setModified(true); emit m_openPane->documentSelected(doc); } void KisImageFromClipboard::clipboardDataChanged() { createClipboardPreview(); } void KisImageFromClipboard::createClipboardPreview() { QClipboard *cb = QApplication::clipboard(); const QMimeData *cbData = cb->mimeData(); if (cbData->hasImage()) { QImage qimage = cb->image(); QByteArray mimeType("application/x-krita-selection"); if ((cbData && cbData->hasFormat(mimeType)) || !qimage.isNull()) { lblPreview->setPixmap(QPixmap::fromImage(qimage.scaled(75, 75, Qt::KeepAspectRatio))); lblPreview->show(); createButton->setEnabled(true); doubleWidth->setValue(qimage.width()); doubleHeight->setValue(qimage.height()); } } else { createButton->setEnabled(false); lblPreview->hide(); } } diff --git a/packaging/linux/snap/setup/gui/krita.desktop b/packaging/linux/snap/setup/gui/krita.desktop index 1ca80debea..86bb57a2e1 100644 --- a/packaging/linux/snap/setup/gui/krita.desktop +++ b/packaging/linux/snap/setup/gui/krita.desktop @@ -1,124 +1,125 @@ [Desktop Entry] Name=Krita Name[af]=Krita Name[bg]=Krita Name[br]=Krita Name[bs]=Krita Name[ca]=Krita Name[ca@valencia]=Krita Name[cs]=Krita Name[cy]=Krita Name[da]=Krita Name[de]=Krita Name[el]=Krita Name[en_GB]=Krita Name[eo]=Krita Name[es]=Krita Name[et]=Krita Name[eu]=Krita Name[fi]=Krita Name[fr]=Krita Name[fy]=Krita Name[ga]=Krita Name[gl]=Krita Name[he]=Krita Name[hi]=केरिता Name[hne]=केरिता Name[hr]=Krita Name[hu]=Krita Name[ia]=Krita Name[is]=Krita Name[it]=Krita Name[ja]=Krita Name[kk]=Krita Name[ko]=Krita Name[lt]=Krita Name[lv]=Krita Name[mr]=क्रिटा Name[ms]=Krita Name[nb]=Krita Name[nds]=Krita Name[ne]=क्रिता Name[nl]=Krita Name[pl]=Krita Name[pt]=Krita Name[pt_BR]=Krita Name[ro]=Krita Name[ru]=Krita Name[se]=Krita Name[sk]=Krita Name[sl]=Krita Name[sv]=Krita Name[ta]=கிரிட்டா Name[tg]=Krita Name[tr]=Krita Name[ug]=Krita Name[uk]=Krita Name[uz]=Krita Name[uz@cyrillic]=Krita Name[wa]=Krita Name[xh]=Krita Name[x-test]=xxKritaxx Name[zh_CN]=Krita Name[zh_TW]=繪圖_Krita Exec=krita %U GenericName=Digital Painting GenericName[bs]=Digitalno Bojenje GenericName[ca]=Dibuix digital GenericName[ca@valencia]=Dibuix digital GenericName[da]=Digital tegning GenericName[de]=Digitales Malen GenericName[el]=Ψηφιακή ζωγραφική GenericName[en_GB]=Digital Painting GenericName[es]=Pintura digital GenericName[et]=Digitaalne joonistamine GenericName[eu]=Pintura digitala GenericName[fi]=Digitaalimaalaus GenericName[fr]=Peinture numérique GenericName[gl]=Debuxo dixital GenericName[hu]=Digitális festészet GenericName[ia]=Pintura Digital GenericName[it]=Pittura digitale GenericName[ja]=デジタルペインティング GenericName[kk]=Цифрлық сурет салу GenericName[lt]=Skaitmeninis piešimas GenericName[mr]=डिजिटल पेंटिंग GenericName[nb]=Digital maling GenericName[nl]=Digitaal schilderen GenericName[pl]=Cyfrowe malowanie GenericName[pt]=Pintura Digital GenericName[pt_BR]=Pintura digital GenericName[ru]=Цифровая живопись GenericName[sk]=Digitálne maľovanie GenericName[sl]=Digitalno slikanje GenericName[sv]=Digital målning GenericName[tr]=Sayısal Boyama GenericName[ug]=سىفىرلىق رەسىم سىزغۇ GenericName[uk]=Цифрове малювання GenericName[x-test]=xxDigital Paintingxx GenericName[zh_CN]=数字绘画 MimeType=application/x-krita;image/openraster;application/x-krita-paintoppreset; Comment=Pixel-based image manipulation program for the Calligra Suite Comment[ca]=Programa de manipulació d'imatges basades en píxels per a la Suite Calligra Comment[ca@valencia]=Programa de manipulació d'imatges basades en píxels per a la Suite Calligra Comment[de]=Pixelbasiertes Bildbearbeitungsprogramm für die Calligra-Suite Comment[en_GB]=Pixel-based image manipulation program for the Calligra Suite Comment[es]=Programa de manipulación de imágenes basado en píxeles para la suite Calligra Comment[et]=Calligra pikslipõhine pilditöötluse rakendus Comment[it]=Programma di manipolazione delle immagini basato su pixel per Calligra Suite Comment[nl]=Afbeeldingsbewerkingsprogramma gebaseerd op pixels voor de Calligra Suite Comment[pl]=Program do obróbki obrazów na poziomie pikseli dla Pakietu Calligra Comment[pt]='Plugin' de manipulação de imagens em pixels para o Calligra Stage +Comment[pt_BR]=Programa de manipulação de imagens baseado em pixels para o Calligra Suite Comment[ru]=Программа редактирования пиксельной анимации для the Calligra Suite Comment[sk]=Program na manipuláciu s pixelmi pre Calligra Suite Comment[sv]=Bildpunktsbaserat bildbehandlingsprogram för Calligra-sviten Comment[uk]=Програма для роботи із растровими зображеннями для комплексу програм Calligra Comment[x-test]=xxPixel-based image manipulation program for the Calligra Suitexx Comment[zh_CN]=Calligra 套件的位图图像处理程序 Type=Application Icon=${SNAP}/meta/gui/calligrakrita.png Categories=Qt;KDE;Graphics; X-KDE-NativeMimeType=application/x-krita X-KDE-ExtraNativeMimeTypes= StartupNotify=true X-Krita-Version=28 diff --git a/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.h b/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.h index b2da63109f..99d0dd6da9 100644 --- a/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.h +++ b/plugins/assistants/RulerAssistant/kis_ruler_assistant_tool.h @@ -1,126 +1,128 @@ /* * Copyright (c) 2008 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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_RULER_ASSISTANT_TOOL_H_ #define _KIS_RULER_ASSISTANT_TOOL_H_ -#include +#include + #include -#include "kis_painting_assistant.h" -#include "ui_AssistantsToolOptions.h" #include -#include +#include +#include "kis_painting_assistant.h" +#include +#include -class KisCanvas2; +#include "ui_AssistantsToolOptions.h" class KisRulerAssistantTool : public KisTool { Q_OBJECT enum PerspectiveAssistantEditionMode { MODE_CREATION, // This is the mode when there is not yet a perspective grid MODE_EDITING, // This is the mode when the grid has been created, and we are waiting for the user to click on a control box MODE_DRAGGING_NODE, // In this mode one node is translated MODE_DRAGGING_TRANSLATING_TWONODES // This mode is used when creating a new sub perspective grid }; public: KisRulerAssistantTool(KoCanvasBase * canvas); virtual ~KisRulerAssistantTool(); virtual quint32 priority() { return 3; } void beginPrimaryAction(KoPointerEvent *event); void continuePrimaryAction(KoPointerEvent *event); void endPrimaryAction(KoPointerEvent *event); void mouseMoveEvent(KoPointerEvent *event); virtual QWidget *createOptionWidget(); private: void addAssistant(); void removeAssistant(KisPaintingAssistantSP assistant); void snappingOn(KisPaintingAssistantSP assistant); void snappingOff(KisPaintingAssistantSP assistant); void outlineOn(KisPaintingAssistantSP assistant); void outlineOff(KisPaintingAssistantSP assistant); bool mouseNear(const QPointF& mousep, const QPointF& point); KisPaintingAssistantHandleSP nodeNearPoint(KisPaintingAssistantSP grid, QPointF point); QPointF snapToGuide(KoPointerEvent *e, const QPointF &offset, bool useModifiers); QPointF snapToGuide(const QPointF& pt, const QPointF &offset); public Q_SLOTS: virtual void activate(ToolActivation toolActivation, const QSet &shapes); void deactivate(); private Q_SLOTS: void removeAllAssistants(); void saveAssistants(); void loadAssistants(); protected: virtual void paint(QPainter& gc, const KoViewConverter &converter); protected: - KisCanvas2* m_canvas; + QPointer m_canvas; QList m_handles, m_sideHandles; KisPaintingAssistantHandleSP m_handleDrag; KisPaintingAssistantHandleSP m_handleCombine; KisPaintingAssistantSP m_assistantDrag; KisPaintingAssistantSP m_newAssistant; QPointF m_cursorStart; QPointF m_currentAdjustment; Ui::AssistantsToolOptions m_options; QWidget* m_optionsWidget; QPointF m_dragStart; QLineF m_radius; bool m_snapIsRadial; QPointF m_dragEnd; private: PerspectiveAssistantEditionMode m_internalMode; qint32 m_handleSize, m_handleHalfSize; KisPaintingAssistantHandleSP m_selectedNode1, m_selectedNode2, m_higlightedNode; int m_assistantHelperYOffset; }; class KisRulerAssistantToolFactory : public KoToolFactoryBase { public: KisRulerAssistantToolFactory() : KoToolFactoryBase("KisRulerAssistantTool") { setToolTip(i18n("Assistant Tool")); setSection(TOOL_TYPE_VIEW); setIconName(koIconNameCStr("krita_tool_ruler_assistant")); setPriority(0); setActivationShapeId(KRITA_TOOL_ACTIVATION_ID); }; virtual ~KisRulerAssistantToolFactory() {} virtual KoToolBase * createTool(KoCanvasBase * canvas) { return new KisRulerAssistantTool(canvas); } }; #endif diff --git a/plugins/dockers/animation/kis_animation_curve_channel_list_model.cpp b/plugins/dockers/animation/kis_animation_curve_channel_list_model.cpp index be65141bdd..89821f91b0 100644 --- a/plugins/dockers/animation/kis_animation_curve_channel_list_model.cpp +++ b/plugins/dockers/animation/kis_animation_curve_channel_list_model.cpp @@ -1,240 +1,249 @@ /* * Copyright (c) 2016 Jouni Pentikäinen * * 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_animation_curve_channel_list_model.h" #include "kis_animation_curves_model.h" #include "kis_dummies_facade_base.h" #include "kis_node_dummies_graph.h" #include "kis_node.h" #include "kis_scalar_keyframe_channel.h" const quintptr ID_NODE = 0xffffffff; struct NodeListItem { NodeListItem(KisNodeDummy *dummy) : dummy(dummy) {} KisNodeDummy *dummy; QList curves; }; struct KisAnimationCurveChannelListModel::Private { KisAnimationCurvesModel *curvesModel; KisDummiesFacadeBase *dummiesFacade; QList items; Private(KisAnimationCurvesModel *curvesModel) : curvesModel(curvesModel) {} NodeListItem * itemForRow(int row) { if (row < 0 || row >= items.count()) return nullptr; return items.at(row); } int rowForDummy(KisNodeDummy *dummy) { for (int row=0; row < items.count(); row++) { if (items.at(row)->dummy == dummy) return row; } return -1; } void addCurveForChannel(NodeListItem *nodeItem, KisKeyframeChannel *channel) { KisScalarKeyframeChannel *scalarChannel = dynamic_cast(channel); if (scalarChannel) { KisAnimationCurve *curve = curvesModel->addCurve(scalarChannel); nodeItem->curves.append(curve); } } }; KisAnimationCurveChannelListModel::KisAnimationCurveChannelListModel(KisAnimationCurvesModel *curvesModel, QObject *parent) : QAbstractItemModel(parent) , m_d(new Private(curvesModel)) {} KisAnimationCurveChannelListModel::~KisAnimationCurveChannelListModel() { qDeleteAll(m_d->items); + m_d->items.clear(); } void KisAnimationCurveChannelListModel::setDummiesFacade(KisDummiesFacadeBase *facade) { m_d->dummiesFacade = facade; } void KisAnimationCurveChannelListModel::selectedNodesChanged(const KisNodeList &nodes) { // Remove unselected nodes - for (int i=m_d->items.count()-1; i >= 0; i--) { + for (int i = m_d->items.count()-1; i >= 0; i--) { NodeListItem *item = m_d->items.at(i); - - if (!nodes.contains(item->dummy->node())) { - beginRemoveRows(QModelIndex(), i, i); - m_d->items.removeAt(i); - endRemoveRows(); - - Q_FOREACH(KisAnimationCurve *curve, item->curves) { - m_d->curvesModel->removeCurve(curve); + if (item && item->dummy) { + if (!nodes.contains(item->dummy->node())) { + beginRemoveRows(QModelIndex(), i, i); + m_d->items.removeAt(i); + endRemoveRows(); + + Q_FOREACH(KisAnimationCurve *curve, item->curves) { + m_d->curvesModel->removeCurve(curve); + } + + item->dummy->node()->disconnect(this); + delete item; } - - item->dummy->node()->disconnect(this); - delete item; } } // Add newly selected nodes Q_FOREACH(KisNodeSP node, nodes) { KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(node); if (!dummy) continue; if (m_d->rowForDummy(dummy) == -1) { beginInsertRows(QModelIndex(), m_d->items.count(), m_d->items.count()); NodeListItem *item = new NodeListItem(dummy); m_d->items.append(item); Q_FOREACH(KisKeyframeChannel *channel, dummy->node()->keyframeChannels()) { m_d->addCurveForChannel(item, channel); } connect(node.data(), &KisNode::keyframeChannelAdded, this, &KisAnimationCurveChannelListModel::keyframeChannelAddedToNode); endInsertRows(); } } } void KisAnimationCurveChannelListModel::keyframeChannelAddedToNode(KisKeyframeChannel *channel) { KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(KisNodeSP(channel->node())); int row = m_d->rowForDummy(dummy); KIS_ASSERT_RECOVER_RETURN(row >= 0); NodeListItem *item = m_d->itemForRow(row); int newCurveRow = item->curves.count(); beginInsertRows(index(row, 0, QModelIndex()), newCurveRow, newCurveRow); m_d->addCurveForChannel(item, channel); endInsertRows(); } QModelIndex KisAnimationCurveChannelListModel::index(int row, int column, const QModelIndex &parent) const { Q_UNUSED(column); if (!parent.isValid()) { // Node NodeListItem *item = m_d->itemForRow(row); if (!item) return QModelIndex(); return createIndex(row, column, ID_NODE); } else { // Channel if (parent.parent().isValid()) return QModelIndex(); NodeListItem *parentItem = m_d->itemForRow(parent.row()); if (!parentItem) return QModelIndex(); if (row >= parentItem->curves.count()) return QModelIndex(); return createIndex(row, column, parent.row()); } } QModelIndex KisAnimationCurveChannelListModel::parent(const QModelIndex &child) const { quintptr parentIndex = child.internalId(); if (parentIndex == ID_NODE) return QModelIndex(); return createIndex(parentIndex, 0, ID_NODE); } int KisAnimationCurveChannelListModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid()) { // Root return m_d->items.count(); } else if (parent.internalId() == ID_NODE) { // Node NodeListItem *item = m_d->itemForRow(parent.row()); return item->curves.count(); } else { // Channel return 0; } } int KisAnimationCurveChannelListModel::columnCount(const QModelIndex &parent) const { Q_UNUSED(parent) return 1; } QVariant KisAnimationCurveChannelListModel::data(const QModelIndex &index, int role) const { quintptr parentRow = index.internalId(); bool indexIsNode = (parentRow == ID_NODE); NodeListItem *item = m_d->itemForRow(indexIsNode ? index.row() : parentRow); switch (role) { case Qt::DisplayRole: { if (indexIsNode) { return item->dummy->node()->name(); } else { KisKeyframeChannel *channel = item->curves.at(index.row())->channel(); return channel->name(); } } break; case CurveColorRole: return indexIsNode ? QVariant() : item->curves.at(index.row())->color(); case CurveVisibleRole: return indexIsNode ? QVariant() : item->curves.at(index.row())->visible(); } return QVariant(); } bool KisAnimationCurveChannelListModel::setData(const QModelIndex &index, const QVariant &value, int role) { quintptr parentRow = index.internalId(); bool indexIsNode = (parentRow == ID_NODE); NodeListItem *item = m_d->itemForRow(indexIsNode ? index.row() : parentRow); switch (role) { case CurveVisibleRole: KIS_ASSERT_RECOVER_BREAK(!indexIsNode); m_d->curvesModel->setCurveVisible(item->curves.at(index.row()), value.toBool()); break; } return false; } + + +void KisAnimationCurveChannelListModel::clear() +{ + qDeleteAll(m_d->items); + m_d->items.clear(); +} diff --git a/plugins/dockers/animation/kis_animation_curve_channel_list_model.h b/plugins/dockers/animation/kis_animation_curve_channel_list_model.h index 832d47418d..eb0509ab5b 100644 --- a/plugins/dockers/animation/kis_animation_curve_channel_list_model.h +++ b/plugins/dockers/animation/kis_animation_curve_channel_list_model.h @@ -1,62 +1,63 @@ /* * Copyright (c) 2016 Jouni Pentikäinen * * 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_ANIMATION_CURVE_CHANNEL_LIST_MODEL_H #define _KIS_ANIMATION_CURVE_CHANNEL_LIST_MODEL_H #include #include "kis_types.h" class KisAnimationCurvesModel; class KisDummiesFacadeBase; class KisKeyframeChannel; class KisAnimationCurveChannelListModel : public QAbstractItemModel { Q_OBJECT public: KisAnimationCurveChannelListModel(KisAnimationCurvesModel *curvesModel, QObject *parent); ~KisAnimationCurveChannelListModel(); void setDummiesFacade(KisDummiesFacadeBase *facade); QModelIndex index(int row, int column, const QModelIndex &parent) const; QModelIndex parent(const QModelIndex &child) const; int rowCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; bool setData(const QModelIndex &index, const QVariant &value, int role); enum ItemDataRole { CurveColorRole = Qt::UserRole, CurveVisibleRole }; public Q_SLOTS: void selectedNodesChanged(const KisNodeList &nodes); + void clear(); void keyframeChannelAddedToNode(KisKeyframeChannel *channel); private: struct Private; const QScopedPointer m_d; }; #endif diff --git a/plugins/dockers/animation/kis_animation_curve_docker.cpp b/plugins/dockers/animation/kis_animation_curve_docker.cpp index d6cc75044a..3ea1b75896 100644 --- a/plugins/dockers/animation/kis_animation_curve_docker.cpp +++ b/plugins/dockers/animation/kis_animation_curve_docker.cpp @@ -1,170 +1,171 @@ /* * Copyright (c) 2016 Jouni Pentikäinen * * 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 #include #include "kis_animation_curve_docker.h" #include "kis_animation_curves_model.h" #include "kis_animation_curves_view.h" #include "kis_animation_curve_channel_list_model.h" #include "kis_animation_curve_channel_list_delegate.h" #include "KisDocument.h" #include "kis_canvas2.h" #include "kis_shape_controller.h" #include "kis_signal_auto_connection.h" #include "KisViewManager.h" #include "kis_node_manager.h" #include "kis_animation_frame_cache.h" #include "klocalizedstring.h" #include "kis_icon_utils.h" #include "ui_wdg_animation_curves.h" struct KisAnimationCurveDocker::Private { Private(QWidget *parent) : curvesWidget() , curvesModel(new KisAnimationCurvesModel(parent)) { channelListModel = new KisAnimationCurveChannelListModel(curvesModel, parent); } Ui_WdgAnimationCurves curvesWidget; KisAnimationCurvesModel *curvesModel; KisAnimationCurveChannelListModel *channelListModel; QPointer canvas; KisSignalAutoConnectionsStore canvasConnections; }; KisAnimationCurveDocker::KisAnimationCurveDocker() : QDockWidget(i18n("Animation curves")) , m_d(new Private(this)) { QWidget *mainWidget = new QWidget(this); setWidget(mainWidget); m_d->curvesWidget.setupUi(mainWidget); KisAnimationCurvesView *curvesView = m_d->curvesWidget.curvesView; QTreeView *channelListView = m_d->curvesWidget.channelListView; KisAnimationCurveChannelListDelegate *listDelegate = new KisAnimationCurveChannelListDelegate(channelListView); curvesView->setModel(m_d->curvesModel); curvesView->setZoomButtons(m_d->curvesWidget.btnHorizontalZoom, m_d->curvesWidget.btnVerticalZoom); channelListView->setModel(m_d->channelListModel); channelListView->setItemDelegate(listDelegate); channelListView->setHeaderHidden(true); m_d->curvesWidget.splitter->setStretchFactor(0, 1); m_d->curvesWidget.splitter->setStretchFactor(1, 4); connect(m_d->channelListModel, &KisAnimationCurveChannelListModel::rowsInserted, this, &KisAnimationCurveDocker::slotListRowsInserted); connect(m_d->curvesWidget.btnConstantInterpolation, &QToolButton::clicked, curvesView, &KisAnimationCurvesView::applyConstantMode); connect(m_d->curvesWidget.btnLinearInterpolation, &QToolButton::clicked, curvesView, &KisAnimationCurvesView::applyLinearMode); connect(m_d->curvesWidget.btnBezierInterpolation, &QToolButton::clicked, curvesView, &KisAnimationCurvesView::applyBezierMode); connect(m_d->curvesWidget.btnSmooth, &QToolButton::clicked, curvesView, &KisAnimationCurvesView::applySmoothMode); connect(m_d->curvesWidget.btnSharp, &QToolButton::clicked, curvesView, &KisAnimationCurvesView::applySharpMode); connect(m_d->curvesWidget.btnAddKeyframe, &QToolButton::clicked, curvesView, &KisAnimationCurvesView::createKeyframe); connect(m_d->curvesWidget.btnRemoveKeyframes, &QToolButton::clicked, curvesView, &KisAnimationCurvesView::removeKeyframes); connect(m_d->curvesWidget.btnZoomToFit, &QToolButton::clicked, curvesView, &KisAnimationCurvesView::zoomToFit); } KisAnimationCurveDocker::~KisAnimationCurveDocker() {} -void KisAnimationCurveDocker::setCanvas(KoCanvasBase * canvas) +void KisAnimationCurveDocker::setCanvas(KoCanvasBase *canvas) { if (canvas && m_d->canvas == canvas) return; if (m_d->canvas) { m_d->canvasConnections.clear(); m_d->canvas->disconnectCanvasObserver(this); m_d->channelListModel->selectedNodesChanged(KisNodeList()); } m_d->canvas = dynamic_cast(canvas); setEnabled(m_d->canvas != 0); - if(m_d->canvas) { + if (m_d->canvas) { KisDocument *doc = static_cast(m_d->canvas->imageView()->document()); KisShapeController *kritaShapeController = dynamic_cast(doc->shapeController()); m_d->channelListModel->setDummiesFacade(kritaShapeController); m_d->curvesModel->setImage(m_d->canvas->image()); m_d->curvesModel->setFrameCache(m_d->canvas->frameCache()); m_d->curvesModel->setAnimationPlayer(m_d->canvas->animationPlayer()); m_d->canvasConnections.addConnection( m_d->canvas->viewManager()->nodeManager(), SIGNAL(sigUiNeedChangeSelectedNodes(KisNodeList)), m_d->channelListModel, SLOT(selectedNodesChanged(KisNodeList)) ); + m_d->channelListModel->clear(); m_d->channelListModel->selectedNodesChanged(m_d->canvas->viewManager()->nodeManager()->selectedNodes()); } } void KisAnimationCurveDocker::unsetCanvas() { setCanvas(0); } void KisAnimationCurveDocker::setMainWindow(KisViewManager *kisview) { connect(kisview->mainWindow(), SIGNAL(themeChanged()), this, SLOT(slotUpdateIcons())); slotUpdateIcons(); } void KisAnimationCurveDocker::slotUpdateIcons() { m_d->curvesWidget.btnConstantInterpolation->setIcon(KisIconUtils::loadIcon("interpolation_constant")); m_d->curvesWidget.btnLinearInterpolation->setIcon(KisIconUtils::loadIcon("interpolation_linear")); m_d->curvesWidget.btnBezierInterpolation->setIcon(KisIconUtils::loadIcon("interpolation_bezier")); m_d->curvesWidget.btnSmooth->setIcon(KisIconUtils::loadIcon("interpolation_smooth")); m_d->curvesWidget.btnSharp->setIcon(KisIconUtils::loadIcon("interpolation_sharp")); m_d->curvesWidget.btnHorizontalZoom->setIcon(KisIconUtils::loadIcon("zoom-horizontal")); m_d->curvesWidget.btnVerticalZoom->setIcon(KisIconUtils::loadIcon("zoom-vertical")); m_d->curvesWidget.btnZoomToFit->setIcon(KisIconUtils::loadIcon("zoom-fit")); m_d->curvesWidget.btnAddKeyframe->setIcon(KisIconUtils::loadIcon("keyframe-add")); m_d->curvesWidget.btnRemoveKeyframes->setIcon(KisIconUtils::loadIcon("keyframe-remove")); } void KisAnimationCurveDocker::slotListRowsInserted(const QModelIndex &parentIndex, int first, int last) { // Auto-expand nodes on the tree for (int r=first; r<=last; r++) { QModelIndex index = m_d->channelListModel->index(r, 0, parentIndex); m_d->curvesWidget.channelListView->expand(index); } } diff --git a/plugins/dockers/animation/timeline_frames_model.cpp b/plugins/dockers/animation/timeline_frames_model.cpp index d649712a00..47c821f734 100644 --- a/plugins/dockers/animation/timeline_frames_model.cpp +++ b/plugins/dockers/animation/timeline_frames_model.cpp @@ -1,707 +1,707 @@ /* * Copyright (c) 2015 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 "timeline_frames_model.h" #include #include #include #include #include #include "kis_layer.h" #include "kis_config.h" #include "kis_global.h" #include "kis_debug.h" #include "kis_image.h" #include "kis_image_animation_interface.h" #include "kis_undo_adapter.h" #include "kis_node_dummies_graph.h" #include "kis_dummies_facade_base.h" #include "kis_signal_compressor.h" #include "kis_signal_compressor_with_param.h" #include "kis_keyframe_channel.h" #include "kundo2command.h" #include "kis_post_execution_undo_adapter.h" #include #include "kis_animation_utils.h" #include "timeline_color_scheme.h" #include "kis_node_model.h" #include "kis_projection_leaf.h" #include "kis_time_range.h" #include "kis_node_view_color_scheme.h" #include "krita_utils.h" #include struct TimelineFramesModel::Private { Private() : activeLayerIndex(0), dummiesFacade(0), needFinishInsertRows(false), needFinishRemoveRows(false), updateTimer(200, KisSignalCompressor::FIRST_INACTIVE), parentOfRemovedNode(0) {} int activeLayerIndex; - KisDummiesFacadeBase *dummiesFacade; + QPointer dummiesFacade; KisImageWSP image; bool needFinishInsertRows; bool needFinishRemoveRows; QList updateQueue; KisSignalCompressor updateTimer; KisNodeDummy* parentOfRemovedNode; QScopedPointer converter; QScopedPointer nodeInterface; QPersistentModelIndex lastClickedIndex; QVariant layerName(int row) const { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return QVariant(); return dummy->node()->name(); } bool layerEditable(int row) const { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return true; return dummy->node()->visible() && !dummy->node()->userLocked(); } bool frameExists(int row, int column) const { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return false; KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id()); return (primaryChannel && primaryChannel->keyframeAt(column)); } bool specialKeyframeExists(int row, int column) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return false; QList channels = dummy->node()->keyframeChannels(); Q_FOREACH(KisKeyframeChannel *channel, channels) { if (channel->id() != KisKeyframeChannel::Content.id() && channel->keyframeAt(column)) { return true; } } return false; } int frameColorLabel(int row, int column) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return -1; KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id()); if (!primaryChannel) return -1; KisKeyframeSP frame = primaryChannel->keyframeAt(column); if (!frame) return -1; return frame->colorLabel(); } void setFrameColorLabel(int row, int column, int color) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return; KisKeyframeChannel *primaryChannel = dummy->node()->getKeyframeChannel(KisKeyframeChannel::Content.id()); if (!primaryChannel) return; KisKeyframeSP frame = primaryChannel->keyframeAt(column); if (!frame) return; frame->setColorLabel(color); } int layerColorLabel(int row) const { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return -1; return dummy->node()->colorLabelIndex(); } QVariant layerProperties(int row) const { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return QVariant(); PropertyList props = dummy->node()->sectionModelProperties(); return QVariant::fromValue(props); } bool setLayerProperties(int row, PropertyList props) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return false; KisNodePropertyListCommand::setNodePropertiesNoUndo(dummy->node(), image, props); return true; } bool addKeyframe(int row, int column, bool copy) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return false; KisNodeSP node = dummy->node(); if (!KisAnimationUtils::supportsContentFrames(node)) return false; return KisAnimationUtils::createKeyframeLazy(image, node, KisKeyframeChannel::Content.id(), column, copy); } bool addNewLayer(int row) { Q_UNUSED(row); if (nodeInterface) { KisLayerSP layer = nodeInterface->addPaintLayer(); layer->setUseInTimeline(true); } return true; } bool removeLayer(int row) { KisNodeDummy *dummy = converter->dummyFromRow(row); if (!dummy) return false; if (nodeInterface) { nodeInterface->removeNode(dummy->node()); } return true; } }; TimelineFramesModel::TimelineFramesModel(QObject *parent) : ModelWithExternalNotifications(parent), m_d(new Private) { connect(&m_d->updateTimer, SIGNAL(timeout()), SLOT(processUpdateQueue())); } TimelineFramesModel::~TimelineFramesModel() { } bool TimelineFramesModel::hasConnectionToCanvas() const { return m_d->dummiesFacade; } void TimelineFramesModel::setNodeManipulationInterface(NodeManipulationInterface *iface) { m_d->nodeInterface.reset(iface); } KisNodeSP TimelineFramesModel::nodeAt(QModelIndex index) const { return m_d->converter->dummyFromRow(index.row())->node(); } QList TimelineFramesModel::channelsAt(QModelIndex index) const { KisNodeDummy *srcDummy = m_d->converter->dummyFromRow(index.row()); return srcDummy->node()->keyframeChannels(); } void TimelineFramesModel::setDummiesFacade(KisDummiesFacadeBase *dummiesFacade, KisImageSP image) { KisDummiesFacadeBase *oldDummiesFacade = m_d->dummiesFacade; - if (m_d->dummiesFacade) { + if (m_d->dummiesFacade && m_d->image) { m_d->image->animationInterface()->disconnect(this); m_d->image->disconnect(this); m_d->dummiesFacade->disconnect(this); } m_d->image = image; KisTimeBasedItemModel::setImage(image); m_d->dummiesFacade = dummiesFacade; m_d->converter.reset(); if (m_d->dummiesFacade) { m_d->converter.reset(new TimelineNodeListKeeper(this, m_d->dummiesFacade)); connect(m_d->dummiesFacade, SIGNAL(sigDummyChanged(KisNodeDummy*)), SLOT(slotDummyChanged(KisNodeDummy*))); connect(m_d->image->animationInterface(), SIGNAL(sigFullClipRangeChanged()), SIGNAL(sigInfiniteTimelineUpdateNeeded())); connect(m_d->image->animationInterface(), SIGNAL(sigAudioChannelChanged()), SIGNAL(sigAudioChannelChanged())); connect(m_d->image->animationInterface(), SIGNAL(sigAudioVolumeChanged()), SIGNAL(sigAudioChannelChanged())); } if (m_d->dummiesFacade != oldDummiesFacade) { reset(); } if (m_d->dummiesFacade) { emit sigInfiniteTimelineUpdateNeeded(); emit sigAudioChannelChanged(); } } void TimelineFramesModel::slotDummyChanged(KisNodeDummy *dummy) { if (!m_d->updateQueue.contains(dummy)) { m_d->updateQueue.append(dummy); } m_d->updateTimer.start(); } void TimelineFramesModel::processUpdateQueue() { Q_FOREACH (KisNodeDummy *dummy, m_d->updateQueue) { int row = m_d->converter->rowForDummy(dummy); if (row >= 0) { emit headerDataChanged (Qt::Vertical, row, row); emit dataChanged(this->index(row, 0), this->index(row, columnCount() - 1)); } } m_d->updateQueue.clear(); } void TimelineFramesModel::slotCurrentNodeChanged(KisNodeSP node) { if (!node) { m_d->activeLayerIndex = -1; return; } KisNodeDummy *dummy = m_d->dummiesFacade->dummyForNode(node); KIS_ASSERT_RECOVER_RETURN(dummy); m_d->converter->updateActiveDummy(dummy); const int row = m_d->converter->rowForDummy(dummy); if (row < 0) { qWarning() << "WARNING: TimelineFramesModel::slotCurrentNodeChanged: node not found!"; } if (row >= 0 && m_d->activeLayerIndex != row) { setData(index(row, 0), true, ActiveLayerRole); } } int TimelineFramesModel::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); if(!m_d->dummiesFacade) return 0; return m_d->converter->rowCount(); } QVariant TimelineFramesModel::data(const QModelIndex &index, int role) const { if(!m_d->dummiesFacade) return QVariant(); switch (role) { case ActiveLayerRole: { return index.row() == m_d->activeLayerIndex; } case FrameEditableRole: { return m_d->layerEditable(index.row()); } case FrameExistsRole: { return m_d->frameExists(index.row(), index.column()); } case SpecialKeyframeExists: { return m_d->specialKeyframeExists(index.row(), index.column()); } case FrameColorLabelIndexRole: { int label = m_d->frameColorLabel(index.row(), index.column()); return label > 0 ? label : QVariant(); } case Qt::DisplayRole: { return QVariant(); } case Qt::TextAlignmentRole: { return QVariant(Qt::AlignHCenter | Qt::AlignVCenter); } } return ModelWithExternalNotifications::data(index, role); } bool TimelineFramesModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (!index.isValid() || !m_d->dummiesFacade) return false; switch (role) { case ActiveLayerRole: { if (value.toBool() && index.row() != m_d->activeLayerIndex) { int prevLayer = m_d->activeLayerIndex; m_d->activeLayerIndex = index.row(); emit dataChanged(this->index(prevLayer, 0), this->index(prevLayer, columnCount() - 1)); emit dataChanged(this->index(m_d->activeLayerIndex, 0), this->index(m_d->activeLayerIndex, columnCount() - 1)); emit headerDataChanged(Qt::Vertical, prevLayer, prevLayer); emit headerDataChanged(Qt::Vertical, m_d->activeLayerIndex, m_d->activeLayerIndex); KisNodeDummy *dummy = m_d->converter->dummyFromRow(m_d->activeLayerIndex); KIS_ASSERT_RECOVER(dummy) { return true; } emit requestCurrentNodeChanged(dummy->node()); emit sigEnsureRowVisible(m_d->activeLayerIndex); } break; } case FrameColorLabelIndexRole: { m_d->setFrameColorLabel(index.row(), index.column(), value.toInt()); } break; } return ModelWithExternalNotifications::setData(index, value, role); } QVariant TimelineFramesModel::headerData(int section, Qt::Orientation orientation, int role) const { if(!m_d->dummiesFacade) return QVariant(); if (orientation == Qt::Vertical) { switch (role) { case ActiveLayerRole: return section == m_d->activeLayerIndex; case Qt::DisplayRole: { QVariant value = headerData(section, orientation, Qt::ToolTipRole); if (!value.isValid()) return value; QString name = value.toString(); const int maxNameSize = 13; if (name.size() > maxNameSize) { name = QString("%1...").arg(name.left(maxNameSize)); } return name; } case Qt::TextColorRole: { // WARNING: this role doesn't work for header views! Use // bold font to show isolated mode instead! return QVariant(); } case Qt::FontRole: { KisNodeDummy *dummy = m_d->converter->dummyFromRow(section); if (!dummy) return QVariant(); KisNodeSP node = dummy->node(); QFont baseFont; if (node->projectionLeaf()->isDroppedMask()) { baseFont.setStrikeOut(true); } else if (m_d->image && m_d->image->isolatedModeRoot() && KisNodeModel::belongsToIsolatedGroup(m_d->image, node, m_d->dummiesFacade)) { baseFont.setBold(true); } return baseFont; } case Qt::ToolTipRole: { return m_d->layerName(section); } case TimelinePropertiesRole: { return QVariant::fromValue(m_d->layerProperties(section)); } case OtherLayersRole: { TimelineNodeListKeeper::OtherLayersList list = m_d->converter->otherLayersList(); return QVariant::fromValue(list); } case LayerUsedInTimelineRole: { KisNodeDummy *dummy = m_d->converter->dummyFromRow(section); if (!dummy) return QVariant(); return dummy->node()->useInTimeline(); } case Qt::BackgroundRole: { int label = m_d->layerColorLabel(section); if (label > 0) { KisNodeViewColorScheme scm; QColor color = scm.colorLabel(label); QPalette pal = qApp->palette(); color = KritaUtils::blendColors(color, pal.color(QPalette::Button), 0.3); return QBrush(color); } else { return QVariant(); } } } } return ModelWithExternalNotifications::headerData(section, orientation, role); } bool TimelineFramesModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) { if (!m_d->dummiesFacade) return false; if (orientation == Qt::Vertical) { switch (role) { case ActiveLayerRole: { setData(index(section, 0), value, role); break; } case TimelinePropertiesRole: { TimelineFramesModel::PropertyList props = value.value(); int result = m_d->setLayerProperties(section, props); emit headerDataChanged (Qt::Vertical, section, section); return result; } case LayerUsedInTimelineRole: { KisNodeDummy *dummy = m_d->converter->dummyFromRow(section); if (!dummy) return false; dummy->node()->setUseInTimeline(value.toBool()); return true; } } } return ModelWithExternalNotifications::setHeaderData(section, orientation, value, role); } Qt::DropActions TimelineFramesModel::supportedDragActions() const { return Qt::MoveAction | Qt::CopyAction; } Qt::DropActions TimelineFramesModel::supportedDropActions() const { return Qt::MoveAction | Qt::CopyAction; } QStringList TimelineFramesModel::mimeTypes() const { QStringList types; types << QLatin1String("application/x-krita-frame"); return types; } void TimelineFramesModel::setLastClickedIndex(const QModelIndex &index) { m_d->lastClickedIndex = index; } QMimeData* TimelineFramesModel::mimeData(const QModelIndexList &indexes) const { QMimeData *data = new QMimeData(); QByteArray encoded; QDataStream stream(&encoded, QIODevice::WriteOnly); const int baseRow = m_d->lastClickedIndex.row(); const int baseColumn = m_d->lastClickedIndex.column(); stream << indexes.size(); stream << baseRow << baseColumn; Q_FOREACH (const QModelIndex &index, indexes) { stream << index.row() - baseRow << index.column() - baseColumn; } data->setData("application/x-krita-frame", encoded); return data; } inline void decodeBaseIndex(QByteArray *encoded, int *row, int *col) { int size_UNUSED = 0; QDataStream stream(encoded, QIODevice::ReadOnly); stream >> size_UNUSED >> *row >> *col; } bool TimelineFramesModel::canDropFrameData(const QMimeData */*data*/, const QModelIndex &index) { if (!index.isValid()) return false; /** * Now we support D&D around any layer, so just return 'true' all * the time. */ return true; } bool TimelineFramesModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { Q_UNUSED(row); Q_UNUSED(column); bool result = false; if ((action != Qt::MoveAction && action != Qt::CopyAction) || !parent.isValid()) return result; const bool copyFrames = action == Qt::CopyAction; QByteArray encoded = data->data("application/x-krita-frame"); QDataStream stream(&encoded, QIODevice::ReadOnly); int size, baseRow, baseColumn; stream >> size >> baseRow >> baseColumn; QModelIndexList srcIndexes; for (int i = 0; i < size; i++) { int relRow, relColumn; stream >> relRow >> relColumn; int srcRow = baseRow + relRow; int srcColumn = baseColumn + relColumn; srcIndexes << index(srcRow, srcColumn); } const QPoint offset(parent.column() - baseColumn, parent.row() - baseRow); return offsetFrames(srcIndexes, offset, copyFrames); } Qt::ItemFlags TimelineFramesModel::flags(const QModelIndex &index) const { Qt::ItemFlags flags = ModelWithExternalNotifications::flags(index); if (!index.isValid()) return flags; if (m_d->frameExists(index.row(), index.column()) || m_d->specialKeyframeExists(index.row(), index.column())) { if (data(index, FrameEditableRole).toBool()) { flags |= Qt::ItemIsDragEnabled; } } /** * Basically we should forbid overrides only if we D&D a single frame * and allow it when we D&D multiple frames. But we cannot distinguish * it here... So allow all the time. */ flags |= Qt::ItemIsDropEnabled; return flags; } bool TimelineFramesModel::insertRows(int row, int count, const QModelIndex &parent) { Q_UNUSED(parent); KIS_ASSERT_RECOVER(count == 1) { return false; } if (row < 0 || row > rowCount()) return false; bool result = m_d->addNewLayer(row); return result; } bool TimelineFramesModel::removeRows(int row, int count, const QModelIndex &parent) { Q_UNUSED(parent); KIS_ASSERT_RECOVER(count == 1) { return false; } if (row < 0 || row >= rowCount()) return false; bool result = m_d->removeLayer(row); return result; } bool TimelineFramesModel::insertOtherLayer(int index, int dstRow) { Q_UNUSED(dstRow); TimelineNodeListKeeper::OtherLayersList list = m_d->converter->otherLayersList(); if (index < 0 || index >= list.size()) return false; list[index].dummy->node()->setUseInTimeline(true); dstRow = m_d->converter->rowForDummy(list[index].dummy); setData(this->index(dstRow, 0), true, ActiveLayerRole); return true; } int TimelineFramesModel::activeLayerRow() const { return m_d->activeLayerIndex; } bool TimelineFramesModel::createFrame(const QModelIndex &dstIndex) { if (!dstIndex.isValid()) return false; bool result = m_d->addKeyframe(dstIndex.row(), dstIndex.column(), false); if (result) { emit dataChanged(dstIndex, dstIndex); } return result; } bool TimelineFramesModel::copyFrame(const QModelIndex &dstIndex) { if (!dstIndex.isValid()) return false; bool result = m_d->addKeyframe(dstIndex.row(), dstIndex.column(), true); if (result) { emit dataChanged(dstIndex, dstIndex); } return result; } QString TimelineFramesModel::audioChannelFileName() const { return m_d->image ? m_d->image->animationInterface()->audioChannelFileName() : QString(); } void TimelineFramesModel::setAudioChannelFileName(const QString &fileName) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image); m_d->image->animationInterface()->setAudioChannelFileName(fileName); } bool TimelineFramesModel::isAudioMuted() const { return m_d->image ? m_d->image->animationInterface()->isAudioMuted() : false; } void TimelineFramesModel::setAudioMuted(bool value) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image); m_d->image->animationInterface()->setAudioMuted(value); } qreal TimelineFramesModel::audioVolume() const { return m_d->image ? m_d->image->animationInterface()->audioVolume() : 0.5; } void TimelineFramesModel::setAudioVolume(qreal value) { KIS_SAFE_ASSERT_RECOVER_RETURN(m_d->image); m_d->image->animationInterface()->setAudioVolume(value); } diff --git a/plugins/dockers/channeldocker/channeldocker_dock.h b/plugins/dockers/channeldocker/channeldocker_dock.h index e2ba26cf12..7a2543e94c 100644 --- a/plugins/dockers/channeldocker/channeldocker_dock.h +++ b/plugins/dockers/channeldocker/channeldocker_dock.h @@ -1,55 +1,58 @@ /* * Copyright (c) 2011 Sven Langkamp * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 CHANNELDOCKER_DOCK_H #define CHANNELDOCKER_DOCK_H +#include #include + #include +#include + class ChannelModel; class QTableView; -class KisCanvas2; class KisSignalCompressor; class KisIdleWatcher; class ChannelDockerDock : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT public: ChannelDockerDock(); QString observerName() { return "ChannelDockerDock"; } void setCanvas(KoCanvasBase *canvas); void unsetCanvas(); void showEvent(QShowEvent *event); public Q_SLOTS: void startUpdateCanvasProjection(); private Q_SLOTS: void updateChannelTable(void); private: KisIdleWatcher* m_imageIdleWatcher; KisSignalCompressor *m_compressor; - KisCanvas2 *m_canvas; + QPointer m_canvas; QTableView *m_channelTable; ChannelModel *m_model; }; #endif diff --git a/plugins/dockers/channeldocker/channelmodel.h b/plugins/dockers/channeldocker/channelmodel.h index 7e7a09014f..ac9f1f6159 100644 --- a/plugins/dockers/channeldocker/channelmodel.h +++ b/plugins/dockers/channeldocker/channelmodel.h @@ -1,67 +1,70 @@ /* * Copyright (c) 2011 Sven Langkamp * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 CHANNELMODEL_H #define CHANNELMODEL_H #include #include +#include + +#include #include class KoColorSpace; -class KisCanvas2; + class ChannelModel : public QAbstractTableModel { Q_OBJECT public: ChannelModel(QObject* parent = 0); virtual ~ChannelModel(); QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; int rowCount(const QModelIndex& parent = QModelIndex()) const; int columnCount(const QModelIndex& parent = QModelIndex()) const; bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole); Qt::ItemFlags flags(const QModelIndex& index) const; void unsetCanvas( void ); //set maximum size of the thumbnail image. This should be set based on screen resolution, etc. void setThumbnailSizeLimit(QSize size); public Q_SLOTS: void slotSetCanvas(KisCanvas2* canvas); void slotColorSpaceChanged(const KoColorSpace *colorSpace); void updateData(KisCanvas2 *canvas); void rowActivated(const QModelIndex &index); Q_SIGNALS: void channelFlagsChanged(); private: void updateThumbnails(); private: - KisCanvas2* m_canvas; + QPointer m_canvas; QVector m_thumbnails; QSize m_thumbnailSizeLimit; int m_oversampleRatio; int m_channelCount; }; #endif // CHANNELMODEL_H diff --git a/plugins/dockers/colorslider/kis_color_slider_dock.cpp b/plugins/dockers/colorslider/kis_color_slider_dock.cpp index f949ce7732..d1e939009d 100644 --- a/plugins/dockers/colorslider/kis_color_slider_dock.cpp +++ b/plugins/dockers/colorslider/kis_color_slider_dock.cpp @@ -1,131 +1,131 @@ /* * Copyright (c) 2008 Cyrille Berger * Copyright (c) 2014 Wolthera van Hövell * Copyright (c) 2015 Moritz Molch * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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_color_slider_dock.h" //#include #include #include #include #include #include #include "kis_config_notifier.h" #include #include #include #include #include #include #include #include "kis_color_slider_widget.h" ColorSliderDock::ColorSliderDock() : QDockWidget(i18n("Color Sliders")) , m_canvas(0) , m_view(0) , m_colorSliders(0) { } -void ColorSliderDock::setCanvas(KoCanvasBase * canvas) +void ColorSliderDock::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); if (m_canvas) { m_canvas->disconnectCanvasObserver(this); } if (m_view) { m_canvasConnections.clear(); } KisCanvas2* kisCanvas = dynamic_cast(canvas); if (kisCanvas) { KisViewManager* view = kisCanvas->viewManager(); if (m_colorSliders) { m_colorSliders->disconnect(); // explicit disconnect in case Qt gets confused. delete m_colorSliders; } QWidget *m_sliderdockerwidget = new QWidget; QVBoxLayout *m_layout = new QVBoxLayout(m_sliderdockerwidget); m_layout->setContentsMargins(4,4,4,0); m_layout->setSpacing(1); setWidget(m_sliderdockerwidget); //m_updateAllowed = true; //settings// QBitArray m_SlidersConfigArray(12); KConfigGroup cfg = KSharedConfig::openConfig()->group("hsxColorSlider"); m_SlidersConfigArray[0] =cfg.readEntry("hsvH", false); m_SlidersConfigArray[1] =cfg.readEntry("hsvS", false); m_SlidersConfigArray[2] =cfg.readEntry("hsvV", false); m_SlidersConfigArray[3] =cfg.readEntry("hslH", true); m_SlidersConfigArray[4] =cfg.readEntry("hslS", true); m_SlidersConfigArray[5] =cfg.readEntry("hslL", true); m_SlidersConfigArray[6] =cfg.readEntry("hsiH", false); m_SlidersConfigArray[7] =cfg.readEntry("hsiS", false); m_SlidersConfigArray[8] =cfg.readEntry("hsiI", false); m_SlidersConfigArray[9] =cfg.readEntry("hsyH", false); m_SlidersConfigArray[10]=cfg.readEntry("hsyS", false); m_SlidersConfigArray[11]=cfg.readEntry("hsyY", false); m_colorSliders = new KisColorSliderWidget(kisCanvas->displayColorConverter()->displayRendererInterface(), this, kisCanvas, m_SlidersConfigArray); m_layout->addWidget(m_colorSliders); m_canvasConnections.addConnection(m_colorSliders, SIGNAL(colorChanged(const KoColor&)), view->resourceProvider(), SLOT(slotSetFGColor(const KoColor&))); m_canvasConnections.addConnection(view->resourceProvider(), SIGNAL(sigFGColorChanged(const KoColor&)), m_colorSliders, SLOT(setColor(const KoColor&))); m_canvasConnections.addConnection(kisCanvas->displayColorConverter(), SIGNAL(displayConfigurationChanged()), this, SLOT(udpateSliders())); m_canvasConnections.addConnection(KisConfigNotifier::instance(), SIGNAL(configChanged()), m_colorSliders, SLOT(slotConfigChanged())); m_canvas = kisCanvas; m_view = view; } } void ColorSliderDock::unsetCanvas() { setEnabled(false); m_canvas = 0; m_view = 0; delete m_colorSliders; m_colorSliders = 0; } void ColorSliderDock::udpateSliders() { if (!m_colorSliders) return; m_colorSliders->setColor(m_view->resourceProvider()->fgColor()); } #include "moc_kis_color_slider_dock.cpp" diff --git a/plugins/dockers/colorslider/kis_color_slider_dock.h b/plugins/dockers/colorslider/kis_color_slider_dock.h index ae2650afc0..4e80411f72 100644 --- a/plugins/dockers/colorslider/kis_color_slider_dock.h +++ b/plugins/dockers/colorslider/kis_color_slider_dock.h @@ -1,52 +1,53 @@ /* * Copyright (c) 2008 Cyrille Berger * Copyright (c) 2014 Wolthera van Hövell * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 _COLORSLIDER_DOCK_H_ #define _COLORSLIDER_DOCK_H_ #include +#include #include #include "kis_signal_auto_connection.h" #include +#include class KisViewManager; -class KisCanvas2; class KisColorSliderWidget; class ColorSliderDock : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT public: ColorSliderDock(); QString observerName() { return "ColorSliderDock"; } /// reimplemented from KoCanvasObserverBase virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas(); public Q_SLOTS: void udpateSliders(); private: - KisCanvas2 *m_canvas; + QPointer m_canvas; KisViewManager *m_view; KisColorSliderWidget* m_colorSliders; KisSignalAutoConnectionsStore m_canvasConnections; }; #endif diff --git a/plugins/dockers/colorslider/kis_color_slider_input.h b/plugins/dockers/colorslider/kis_color_slider_input.h index 2b4b0c7f70..b9da0d3add 100644 --- a/plugins/dockers/colorslider/kis_color_slider_input.h +++ b/plugins/dockers/colorslider/kis_color_slider_input.h @@ -1,91 +1,92 @@ /* * Copyright (c) 2008 Cyrille Berger * Copyright (c) 2014 Wolthera van Hövell * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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_COLOR_SLIDER_INPUT_H_ #define _KIS_COLOR_SLIDER_INPUT_H_ #include +#include + #include "KoColorDisplayRendererInterface.h" -#include "kis_canvas2.h" +#include "kis_canvas2.h" class KoColor; class QWidget; class QDoubleSpinBox; class KisDoubleParseSpinBox; class KisHSVSlider; class KisDisplayColorConverter; - class KisColorSliderInput : public QWidget { Q_OBJECT public: KisColorSliderInput(QWidget* parent, KoColor* color, const int type, KoColorDisplayRendererInterface *displayRenderer, KisCanvas2* canvas); protected: void init(); virtual QWidget* createInput() = 0; Q_SIGNALS: void updated(); protected: const int m_type; KoColor* m_color; KoColorDisplayRendererInterface *m_displayRenderer; - KisCanvas2* m_canvas; + QPointer m_canvas; KisHSVSlider* m_hsvSlider; }; class KisHSXColorSliderInput : public KisColorSliderInput { Q_OBJECT public: KisHSXColorSliderInput(QWidget* parent, const int type, KoColor* color, KoColorDisplayRendererInterface *displayRenderer, KisCanvas2* canvas); KisDisplayColorConverter* converter() const; protected: virtual QWidget* createInput(); - KisCanvas2* m_canvas; + QPointer m_canvas; public Q_SLOTS: void setValue(double); void update(); void hueUpdate(int h); void satUpdate(int s, int type); void toneUpdate(int l, int type); void sliderChanged(int i); void sliderIn(); void sliderOut(); void numInputChanged(double v); Q_SIGNALS: void hueUpdated(int); void satUpdated(int, int); void toneUpdated(int, int); private: KisDoubleParseSpinBox* m_NumInput; qreal m_hue; qreal m_sat; qreal m_val; qreal R, G, B, Gamma; bool m_hueupdating; bool m_satupdating; bool m_toneupdating; bool m_sliderisupdating; }; #endif diff --git a/plugins/dockers/colorslider/kis_color_slider_widget.h b/plugins/dockers/colorslider/kis_color_slider_widget.h index 92c7f33e91..c3e39490d2 100644 --- a/plugins/dockers/colorslider/kis_color_slider_widget.h +++ b/plugins/dockers/colorslider/kis_color_slider_widget.h @@ -1,84 +1,87 @@ /* * Copyright (c) 2008 Cyrille Berger * Copyright (c) 2014 Wolthera van Hövell * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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_COLOR_SLIDER_WIDGET_H_ #define _KIS_COLOR_SLIDER_WIDGET_H_ #include -#include "kis_canvas2.h" +#include + #include +#include "kis_canvas2.h" + class KoColorSpace; class KoColorDisplayRendererInterface; class QVBoxLayout; class KisColorSliderInput; class KisSignalCompressor; class QBitArray; class KisColorSliderWidget : public QWidget { Q_OBJECT public: KisColorSliderWidget(KoColorDisplayRendererInterface *displayRenderer, QWidget* parent, KisCanvas2* canvas, QBitArray SlidersConfigArray); ~KisColorSliderWidget(); //bool customColorSpaceUsed(); public Q_SLOTS: //void setColorSpace(const KoColorSpace*); void setColor(const KoColor&); void slotConfigChanged(); private Q_SLOTS: void update(); void updateTimeout(); void hueUpdate(int h); void satUpdate(int s, int type); void toneUpdate(int l, int type); void setSlidersVisible(QBitArray SlidersConfigArray); void setConfig(); //void setCustomColorSpace(const KoColorSpace *); Q_SIGNALS: void colorChanged(const KoColor&); void updated(); void hueUpdated(int); void satUpdated(int, int); void toneUpdated(int, int); private: QList m_inputs; // const KoColorSpace* m_colorSpace; QVBoxLayout *m_layout; KoColor m_color; bool m_updateAllowed; KisSignalCompressor *m_updateCompressor; KisSignalCompressor *m_configCompressor; KoColorDisplayRendererInterface *m_displayRenderer; - KisCanvas2 *m_canvas; + QPointer m_canvas; KisColorSliderInput* hsvH; KisColorSliderInput* hsvS; KisColorSliderInput* hsvV; KisColorSliderInput* hslH; KisColorSliderInput* hslS; KisColorSliderInput* hslL; KisColorSliderInput* hsiH; KisColorSliderInput* hsiS; KisColorSliderInput* hsiI; KisColorSliderInput* hsyH; KisColorSliderInput* hsyS; KisColorSliderInput* hsyY; }; #endif diff --git a/plugins/dockers/colorslider/kis_hsv_slider.h b/plugins/dockers/colorslider/kis_hsv_slider.h index 88db3a89fb..daf4ed620d 100644 --- a/plugins/dockers/colorslider/kis_hsv_slider.h +++ b/plugins/dockers/colorslider/kis_hsv_slider.h @@ -1,60 +1,62 @@ /* This file is part of the KDE project Copyright (C) 2006 Sven Langkamp Copyright (C) 2014 Wolthera van Hövell Copyright (c) 2015 Moritz Molch 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. */ #ifndef KIS_HSVSLIDER_H #define KIS_HSVSLIDER_H +#include + #include #include "KoColorDisplayRendererInterface.h" #include "kis_canvas2.h" class KoColor; class KisDisplayColorConverter; class KisHSVSlider : public KSelector { Q_OBJECT public: explicit KisHSVSlider(QWidget *parent = 0, KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance()); explicit KisHSVSlider(Qt::Orientation orientation, QWidget *parent = 0, KoColorDisplayRendererInterface *displayRenderer = KoDumbColorDisplayRenderer::instance(), KisCanvas2* canvas = 0); virtual ~KisHSVSlider(); public: void setColors( const KoColor& currentcolor, const int type, qreal hue_backup, qreal l_R=0.2126, qreal l_G=0.7152, qreal l_B=0.0722, qreal gamma=2.2); /** * Return the current color */ KoColor currentColor() const; KoColor HSXcolor(int type, qreal t) const; KisDisplayColorConverter* converter() const; protected: virtual void drawContents( QPainter* ); virtual void drawArrow(QPainter *painter, const QPoint &pos); struct Private; Private* const d; private: qreal R, G, B, Gamma; KoColorDisplayRendererInterface *m_displayRenderer; - KisCanvas2* m_canvas; + QPointer m_canvas; }; #endif diff --git a/plugins/dockers/compositiondocker/compositiondocker_dock.h b/plugins/dockers/compositiondocker/compositiondocker_dock.h index 2537051d85..161aa6185c 100644 --- a/plugins/dockers/compositiondocker/compositiondocker_dock.h +++ b/plugins/dockers/compositiondocker/compositiondocker_dock.h @@ -1,62 +1,66 @@ /* * Copyright (c) 2012 Sven Langkamp * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 COMPOSITIONDOCKER_DOCK_H #define COMPOSITIONDOCKER_DOCK_H #include #include +#include + #include + +#include + #include "ui_wdgcompositiondocker.h" class CompositionModel; -class KisCanvas2; class KisAction; class CompositionDockerDock : public QDockWidget, public KoCanvasObserverBase, public Ui_WdgCompositionDocker { Q_OBJECT public: CompositionDockerDock(); ~CompositionDockerDock(); QString observerName() { return "CompositionDockerDock"; } virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas(); void updateModel(); protected: bool eventFilter(QObject *obj, QEvent *event); private Q_SLOTS: void activated (const QModelIndex& index); void deleteClicked(); void saveClicked(); void exportClicked(); void activateCurrentIndex(); void customContextMenuRequested(QPoint pos); void updateComposition(); void renameComposition(); private: - KisCanvas2 *m_canvas; + QPointer m_canvas; CompositionModel *m_model; QVector m_actions; }; #endif diff --git a/plugins/dockers/defaultdockers/kis_layer_box.cpp b/plugins/dockers/defaultdockers/kis_layer_box.cpp index 4b4116e120..a9ee53c095 100644 --- a/plugins/dockers/defaultdockers/kis_layer_box.cpp +++ b/plugins/dockers/defaultdockers/kis_layer_box.cpp @@ -1,930 +1,930 @@ /* * kis_layer_box.cc - part of Krita aka Krayon aka KimageShop * * Copyright (c) 2002 Patrick Julien * Copyright (C) 2006 Gábor Lehel * Copyright (C) 2007 Thomas Zander * Copyright (C) 2007 Boudewijn Rempt * Copyright (c) 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 "kis_layer_box.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 "kis_action.h" #include "kis_action_manager.h" #include "widgets/kis_cmb_composite.h" #include "widgets/kis_slider_spin_box.h" #include "KisViewManager.h" #include "kis_node_manager.h" #include "kis_node_model.h" #include "canvas/kis_canvas2.h" #include "KisDocument.h" #include "kis_dummies_facade_base.h" #include "kis_shape_controller.h" #include "kis_selection_mask.h" #include "kis_config.h" #include "KisView.h" #include "krita_utils.h" #include "sync_button_and_action.h" #include "kis_color_label_selector_widget.h" #include "kis_signals_blocker.h" #include "kis_color_filter_combo.h" #include "kis_node_filter_proxy_model.h" #include "kis_layer_utils.h" #include "ui_wdglayerbox.h" inline void KisLayerBox::connectActionToButton(KisViewManager* view, QAbstractButton *button, const QString &id) { if (!view || !button) return; KisAction *action = view->actionManager()->actionByName(id); if (!action) return; connect(button, SIGNAL(clicked()), action, SLOT(trigger())); connect(action, SIGNAL(sigEnableSlaves(bool)), button, SLOT(setEnabled(bool))); } inline void KisLayerBox::addActionToMenu(QMenu *menu, const QString &id) { if (m_canvas) { menu->addAction(m_canvas->viewManager()->actionManager()->actionByName(id)); } } KisLayerBox::KisLayerBox() : QDockWidget(i18n("Layers")) , m_canvas(0) , m_wdgLayerBox(new Ui_WdgLayerBox) , m_thumbnailCompressor(500, KisSignalCompressor::FIRST_INACTIVE) , m_colorLabelCompressor(900, KisSignalCompressor::FIRST_INACTIVE) { KisConfig cfg; QWidget* mainWidget = new QWidget(this); setWidget(mainWidget); m_opacityDelayTimer.setSingleShot(true); m_wdgLayerBox->setupUi(mainWidget); connect(m_wdgLayerBox->listLayers, SIGNAL(contextMenuRequested(const QPoint&, const QModelIndex&)), this, SLOT(slotContextMenuRequested(const QPoint&, const QModelIndex&))); connect(m_wdgLayerBox->listLayers, SIGNAL(collapsed(const QModelIndex&)), SLOT(slotCollapsed(const QModelIndex &))); connect(m_wdgLayerBox->listLayers, SIGNAL(expanded(const QModelIndex&)), SLOT(slotExpanded(const QModelIndex &))); connect(m_wdgLayerBox->listLayers, SIGNAL(selectionChanged(const QModelIndexList&)), SLOT(selectionChanged(const QModelIndexList&))); m_wdgLayerBox->bnAdd->setIcon(KisIconUtils::loadIcon("addlayer")); m_wdgLayerBox->bnDelete->setIcon(KisIconUtils::loadIcon("deletelayer")); m_wdgLayerBox->bnDelete->setIconSize(QSize(22, 22)); m_wdgLayerBox->bnRaise->setEnabled(false); m_wdgLayerBox->bnRaise->setIcon(KisIconUtils::loadIcon("arrowupblr")); m_wdgLayerBox->bnRaise->setIconSize(QSize(22, 22)); m_wdgLayerBox->bnLower->setEnabled(false); m_wdgLayerBox->bnLower->setIcon(KisIconUtils::loadIcon("arrowdown")); m_wdgLayerBox->bnLower->setIconSize(QSize(22, 22)); m_wdgLayerBox->bnProperties->setIcon(KisIconUtils::loadIcon("properties")); m_wdgLayerBox->bnProperties->setIconSize(QSize(22, 22)); m_wdgLayerBox->bnDuplicate->setIcon(KisIconUtils::loadIcon("duplicatelayer")); m_wdgLayerBox->bnDuplicate->setIconSize(QSize(22, 22)); if (cfg.sliderLabels()) { m_wdgLayerBox->opacityLabel->hide(); m_wdgLayerBox->doubleOpacity->setPrefix(QString("%1: ").arg(i18n("Opacity"))); } m_wdgLayerBox->doubleOpacity->setRange(0, 100, 0); m_wdgLayerBox->doubleOpacity->setSuffix("%"); connect(m_wdgLayerBox->doubleOpacity, SIGNAL(valueChanged(qreal)), SLOT(slotOpacitySliderMoved(qreal))); connect(&m_opacityDelayTimer, SIGNAL(timeout()), SLOT(slotOpacityChanged())); connect(m_wdgLayerBox->cmbComposite, SIGNAL(activated(int)), SLOT(slotCompositeOpChanged(int))); m_selectOpaque = new KisAction(i18n("&Select Opaque"), this); m_selectOpaque->setActivationFlags(KisAction::ACTIVE_LAYER); m_selectOpaque->setActivationConditions(KisAction::SELECTION_EDITABLE); m_selectOpaque->setObjectName("select_opaque"); connect(m_selectOpaque, SIGNAL(triggered(bool)), this, SLOT(slotSelectOpaque())); m_actions.append(m_selectOpaque); m_newLayerMenu = new QMenu(this); m_wdgLayerBox->bnAdd->setMenu(m_newLayerMenu); m_wdgLayerBox->bnAdd->setPopupMode(QToolButton::MenuButtonPopup); m_nodeModel = new KisNodeModel(this); m_filteringModel = new KisNodeFilterProxyModel(this); m_filteringModel->setNodeModel(m_nodeModel); /** * Connect model updateUI() to enable/disable controls. * Note: nodeActivated() is connected separately in setImage(), because * it needs particular order of calls: first the connection to the * node manager should be called, then updateUI() */ connect(m_nodeModel, SIGNAL(rowsInserted(const QModelIndex&, int, int)), SLOT(updateUI())); connect(m_nodeModel, SIGNAL(rowsRemoved(const QModelIndex&, int, int)), SLOT(updateUI())); connect(m_nodeModel, SIGNAL(rowsMoved(const QModelIndex&, int, int, const QModelIndex&, int)), SLOT(updateUI())); connect(m_nodeModel, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&)), SLOT(updateUI())); connect(m_nodeModel, SIGNAL(modelReset()), SLOT(slotModelReset())); KisAction *showGlobalSelectionMask = new KisAction(i18n("&Show Global Selection Mask"), this); showGlobalSelectionMask->setObjectName("show-global-selection-mask"); showGlobalSelectionMask->setActivationFlags(KisAction::ACTIVE_IMAGE); showGlobalSelectionMask->setToolTip(i18nc("@info:tooltip", "Shows global selection as a usual selection mask in Layers docker")); showGlobalSelectionMask->setCheckable(true); connect(showGlobalSelectionMask, SIGNAL(triggered(bool)), SLOT(slotEditGlobalSelection(bool))); m_actions.append(showGlobalSelectionMask); showGlobalSelectionMask->setChecked(cfg.showGlobalSelection()); m_colorSelector = new KisColorLabelSelectorWidget(this); connect(m_colorSelector, SIGNAL(currentIndexChanged(int)), SLOT(slotColorLabelChanged(int))); m_colorSelectorAction = new QWidgetAction(this); m_colorSelectorAction->setDefaultWidget(m_colorSelector); connect(m_nodeModel, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), &m_colorLabelCompressor, SLOT(start())); m_wdgLayerBox->listLayers->setModel(m_filteringModel); // this connection should be done *after* the setModel() call to // happen later than the internal selection model connect(m_filteringModel.data(), &KisNodeFilterProxyModel::rowsAboutToBeRemoved, this, &KisLayerBox::slotAboutToRemoveRows); connect(m_wdgLayerBox->cmbFilter, SIGNAL(selectedColorsChanged()), SLOT(updateLayerFiltering())); setEnabled(false); connect(&m_thumbnailCompressor, SIGNAL(timeout()), SLOT(updateThumbnail())); connect(&m_colorLabelCompressor, SIGNAL(timeout()), SLOT(updateAvailableLabels())); } KisLayerBox::~KisLayerBox() { delete m_wdgLayerBox; } void expandNodesRecursively(KisNodeSP root, QPointer filteringModel, KisNodeView *nodeView) { if (!root) return; if (filteringModel.isNull()) return; if (!nodeView) return; nodeView->blockSignals(true); KisNodeSP node = root->firstChild(); while (node) { QModelIndex idx = filteringModel->indexFromNode(node); if (idx.isValid()) { nodeView->setExpanded(idx, !node->collapsed()); } if (node->childCount() > 0) { expandNodesRecursively(node, filteringModel, nodeView); } node = node->nextSibling(); } nodeView->blockSignals(false); } void KisLayerBox::setMainWindow(KisViewManager* kisview) { m_nodeManager = kisview->nodeManager(); Q_FOREACH (KisAction *action, m_actions) { kisview->actionManager()-> addAction(action->objectName(), action); } connectActionToButton(kisview, m_wdgLayerBox->bnAdd, "add_new_paint_layer"); connectActionToButton(kisview, m_wdgLayerBox->bnDuplicate, "duplicatelayer"); KisActionManager *actionManager = kisview->actionManager(); KisAction *action = actionManager->createAction("RenameCurrentLayer"); Q_ASSERT(action); connect(action, SIGNAL(triggered()), this, SLOT(slotRenameCurrentNode())); m_propertiesAction = actionManager->createAction("layer_properties"); Q_ASSERT(m_propertiesAction); new SyncButtonAndAction(m_propertiesAction, m_wdgLayerBox->bnProperties, this); connect(m_propertiesAction, SIGNAL(triggered()), this, SLOT(slotPropertiesClicked())); m_removeAction = actionManager->createAction("remove_layer"); Q_ASSERT(m_removeAction); new SyncButtonAndAction(m_removeAction, m_wdgLayerBox->bnDelete, this); connect(m_removeAction, SIGNAL(triggered()), this, SLOT(slotRmClicked())); action = actionManager->createAction("move_layer_up"); Q_ASSERT(action); new SyncButtonAndAction(action, m_wdgLayerBox->bnRaise, this); connect(action, SIGNAL(triggered()), this, SLOT(slotRaiseClicked())); action = actionManager->createAction("move_layer_down"); Q_ASSERT(action); new SyncButtonAndAction(action, m_wdgLayerBox->bnLower, this); connect(action, SIGNAL(triggered()), this, SLOT(slotLowerClicked())); } void KisLayerBox::setCanvas(KoCanvasBase *canvas) { - if(m_canvas == canvas) + if (m_canvas == canvas) return; setEnabled(canvas != 0); if (m_canvas) { m_canvas->disconnectCanvasObserver(this); m_nodeModel->setDummiesFacade(0, 0, 0, 0, 0); if (m_image) { KisImageAnimationInterface *animation = m_image->animationInterface(); animation->disconnect(this); } disconnect(m_image, 0, this, 0); disconnect(m_nodeManager, 0, this, 0); disconnect(m_nodeModel, 0, m_nodeManager, 0); m_nodeManager->slotSetSelectedNodes(KisNodeList()); } m_canvas = dynamic_cast(canvas); if (m_canvas) { m_image = m_canvas->image(); connect(m_image, SIGNAL(sigImageUpdated(QRect)), &m_thumbnailCompressor, SLOT(start())); KisDocument* doc = static_cast(m_canvas->imageView()->document()); KisShapeController *kritaShapeController = dynamic_cast(doc->shapeController()); KisDummiesFacadeBase *kritaDummiesFacade = static_cast(kritaShapeController); m_nodeModel->setDummiesFacade(kritaDummiesFacade, m_image, kritaShapeController, m_nodeManager->nodeSelectionAdapter(), m_nodeManager->nodeInsertionAdapter()); connect(m_image, SIGNAL(sigAboutToBeDeleted()), SLOT(notifyImageDeleted())); connect(m_image, SIGNAL(sigNodeCollapsedChanged()), SLOT(slotNodeCollapsedChanged())); // cold start if (m_nodeManager) { setCurrentNode(m_nodeManager->activeNode()); // Connection KisNodeManager -> KisLayerBox connect(m_nodeManager, SIGNAL(sigUiNeedChangeActiveNode(KisNodeSP)), this, SLOT(setCurrentNode(KisNodeSP))); connect(m_nodeManager, SIGNAL(sigUiNeedChangeSelectedNodes(const QList &)), SLOT(slotNodeManagerChangedSelection(const QList &))); } else { setCurrentNode(m_canvas->imageView()->currentNode()); } // Connection KisLayerBox -> KisNodeManager (isolate layer) connect(m_nodeModel, SIGNAL(toggleIsolateActiveNode()), m_nodeManager, SLOT(toggleIsolateActiveNode())); KisImageAnimationInterface *animation = m_image->animationInterface(); connect(animation, &KisImageAnimationInterface::sigUiTimeChanged, this, &KisLayerBox::slotImageTimeChanged); expandNodesRecursively(m_image->rootLayer(), m_filteringModel, m_wdgLayerBox->listLayers); m_wdgLayerBox->listLayers->scrollTo(m_wdgLayerBox->listLayers->currentIndex()); updateAvailableLabels(); addActionToMenu(m_newLayerMenu, "add_new_paint_layer"); addActionToMenu(m_newLayerMenu, "add_new_group_layer"); addActionToMenu(m_newLayerMenu, "add_new_clone_layer"); addActionToMenu(m_newLayerMenu, "add_new_shape_layer"); addActionToMenu(m_newLayerMenu, "add_new_adjustment_layer"); addActionToMenu(m_newLayerMenu, "add_new_fill_layer"); addActionToMenu(m_newLayerMenu, "add_new_file_layer"); m_newLayerMenu->addSeparator(); addActionToMenu(m_newLayerMenu, "add_new_transparency_mask"); addActionToMenu(m_newLayerMenu, "add_new_filter_mask"); addActionToMenu(m_newLayerMenu, "add_new_colorize_mask"); addActionToMenu(m_newLayerMenu, "add_new_transform_mask"); addActionToMenu(m_newLayerMenu, "add_new_selection_mask"); } } void KisLayerBox::unsetCanvas() { setEnabled(false); if (m_canvas) { m_newLayerMenu->clear(); } m_filteringModel->unsetDummiesFacade(); disconnect(m_image, 0, this, 0); disconnect(m_nodeManager, 0, this, 0); disconnect(m_nodeModel, 0, m_nodeManager, 0); m_nodeManager->slotSetSelectedNodes(KisNodeList()); m_canvas = 0; } void KisLayerBox::notifyImageDeleted() { setCanvas(0); } void KisLayerBox::updateUI() { if (!m_canvas) return; if (!m_nodeManager) return; KisNodeSP activeNode = m_nodeManager->activeNode(); if (activeNode != m_activeNode) { if( !m_activeNode.isNull() ) m_activeNode->disconnect(this); m_activeNode = activeNode; if (activeNode) { KisKeyframeChannel *opacityChannel = activeNode->getKeyframeChannel(KisKeyframeChannel::Opacity.id(), false); if (opacityChannel) { watchOpacityChannel(opacityChannel); } else { watchOpacityChannel(0); connect(activeNode.data(), &KisNode::keyframeChannelAdded, this, &KisLayerBox::slotKeyframeChannelAdded); } } } m_wdgLayerBox->bnRaise->setEnabled(activeNode && activeNode->isEditable(false) && (activeNode->nextSibling() || (activeNode->parent() && activeNode->parent() != m_image->root()))); m_wdgLayerBox->bnLower->setEnabled(activeNode && activeNode->isEditable(false) && (activeNode->prevSibling() || (activeNode->parent() && activeNode->parent() != m_image->root()))); m_wdgLayerBox->doubleOpacity->setEnabled(activeNode && activeNode->isEditable(false)); m_wdgLayerBox->cmbComposite->setEnabled(activeNode && activeNode->isEditable(false)); if (activeNode) { if (m_nodeManager->activePaintDevice()) { slotFillCompositeOps(m_nodeManager->activeColorSpace()); } else { slotFillCompositeOps(m_image->colorSpace()); } if (activeNode->inherits("KisColorizeMask") || activeNode->inherits("KisLayer")) { m_wdgLayerBox->doubleOpacity->setEnabled(true); slotSetOpacity(activeNode->opacity() * 100.0 / 255); const KoCompositeOp* compositeOp = activeNode->compositeOp(); if (compositeOp) { slotSetCompositeOp(compositeOp); } else { m_wdgLayerBox->cmbComposite->setEnabled(false); } const KisGroupLayer *group = qobject_cast(activeNode.data()); bool compositeSelectionActive = !(group && group->passThroughMode()); m_wdgLayerBox->cmbComposite->setEnabled(compositeSelectionActive); } else if (activeNode->inherits("KisMask")) { m_wdgLayerBox->cmbComposite->setEnabled(false); m_wdgLayerBox->doubleOpacity->setEnabled(false); } } } /** * This method is called *only* when non-GUI code requested the * change of the current node */ void KisLayerBox::setCurrentNode(KisNodeSP node) { m_filteringModel->setActiveNode(node); QModelIndex index = node ? m_filteringModel->indexFromNode(node) : QModelIndex(); m_filteringModel->setData(index, true, KisNodeModel::ActiveRole); updateUI(); } void KisLayerBox::slotModelReset() { if(m_nodeModel->hasDummiesFacade()) { QItemSelection selection; Q_FOREACH (const KisNodeSP node, m_nodeManager->selectedNodes()) { const QModelIndex &idx = m_filteringModel->indexFromNode(node); if(idx.isValid()){ QItemSelectionRange selectionRange(idx); selection << selectionRange; } } m_wdgLayerBox->listLayers->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect); } updateUI(); } void KisLayerBox::slotSetCompositeOp(const KoCompositeOp* compositeOp) { KoID opId = KoCompositeOpRegistry::instance().getKoID(compositeOp->id()); m_wdgLayerBox->cmbComposite->blockSignals(true); m_wdgLayerBox->cmbComposite->selectCompositeOp(opId); m_wdgLayerBox->cmbComposite->blockSignals(false); } void KisLayerBox::slotFillCompositeOps(const KoColorSpace* colorSpace) { m_wdgLayerBox->cmbComposite->validate(colorSpace); } // range: 0-100 void KisLayerBox::slotSetOpacity(double opacity) { Q_ASSERT(opacity >= 0 && opacity <= 100); m_wdgLayerBox->doubleOpacity->blockSignals(true); m_wdgLayerBox->doubleOpacity->setValue(opacity); m_wdgLayerBox->doubleOpacity->blockSignals(false); } void KisLayerBox::slotContextMenuRequested(const QPoint &pos, const QModelIndex &index) { KisNodeList nodes = m_nodeManager->selectedNodes(); KisNodeSP activeNode = m_nodeManager->activeNode(); if (nodes.isEmpty() || !activeNode) return; if (m_canvas) { QMenu menu; const bool singleLayer = nodes.size() == 1; if (index.isValid()) { menu.addAction(m_propertiesAction); if (singleLayer) { addActionToMenu(&menu, "layer_style"); } { KisSignalsBlocker b(m_colorSelector); m_colorSelector->setCurrentIndex(singleLayer ? activeNode->colorLabelIndex() : -1); } menu.addAction(m_colorSelectorAction); menu.addSeparator(); addActionToMenu(&menu, "cut_layer_clipboard"); addActionToMenu(&menu, "copy_layer_clipboard"); addActionToMenu(&menu, "paste_layer_from_clipboard"); menu.addAction(m_removeAction); addActionToMenu(&menu, "duplicatelayer"); addActionToMenu(&menu, "merge_layer"); if (singleLayer) { addActionToMenu(&menu, "flatten_image"); addActionToMenu(&menu, "flatten_layer"); } menu.addSeparator(); QMenu *selectMenu = menu.addMenu(i18n("&Select")); addActionToMenu(selectMenu, "select_all_layers"); addActionToMenu(selectMenu, "select_visible_layers"); addActionToMenu(selectMenu, "select_invisible_layers"); addActionToMenu(selectMenu, "select_locked_layers"); addActionToMenu(selectMenu, "select_unlocked_layers"); QMenu *groupMenu = menu.addMenu(i18n("&Group")); addActionToMenu(groupMenu, "create_quick_group"); addActionToMenu(groupMenu, "create_quick_clipping_group"); addActionToMenu(groupMenu, "quick_ungroup"); if (singleLayer) { QMenu *addLayerMenu = menu.addMenu(i18n("&Add")); addActionToMenu(addLayerMenu, "add_new_transparency_mask"); addActionToMenu(addLayerMenu, "add_new_filter_mask"); addActionToMenu(addLayerMenu, "add_new_colorize_mask"); addActionToMenu(addLayerMenu, "add_new_transform_mask"); addActionToMenu(addLayerMenu, "add_new_selection_mask"); QMenu *convertToMenu = menu.addMenu(i18n("&Convert")); addActionToMenu(convertToMenu, "convert_to_paint_layer"); addActionToMenu(convertToMenu, "convert_to_transparency_mask"); addActionToMenu(convertToMenu, "convert_to_filter_mask"); addActionToMenu(convertToMenu, "convert_to_selection_mask"); QMenu *splitAlphaMenu = menu.addMenu(i18n("S&plit Alpha")); addActionToMenu(splitAlphaMenu, "split_alpha_into_mask"); addActionToMenu(splitAlphaMenu, "split_alpha_write"); addActionToMenu(splitAlphaMenu, "split_alpha_save_merged"); } menu.addSeparator(); if (singleLayer) { addActionToMenu(&menu, "show_in_timeline"); KisNodeSP node = m_filteringModel->nodeFromIndex(index); if (node && !node->inherits("KisTransformMask")) { addActionToMenu(&menu, "isolate_layer"); } menu.addAction(m_selectOpaque); } } menu.exec(pos); } } void KisLayerBox::slotMergeLayer() { if (!m_canvas) return; m_nodeManager->mergeLayer(); } void KisLayerBox::slotMinimalView() { m_wdgLayerBox->listLayers->setDisplayMode(KisNodeView::MinimalMode); } void KisLayerBox::slotDetailedView() { m_wdgLayerBox->listLayers->setDisplayMode(KisNodeView::DetailedMode); } void KisLayerBox::slotThumbnailView() { m_wdgLayerBox->listLayers->setDisplayMode(KisNodeView::ThumbnailMode); } void KisLayerBox::slotRmClicked() { if (!m_canvas) return; m_nodeManager->removeNode(); } void KisLayerBox::slotRaiseClicked() { if (!m_canvas) return; m_nodeManager->raiseNode(); } void KisLayerBox::slotLowerClicked() { if (!m_canvas) return; m_nodeManager->lowerNode(); } void KisLayerBox::slotPropertiesClicked() { if (!m_canvas) return; if (KisNodeSP active = m_nodeManager->activeNode()) { m_nodeManager->nodeProperties(active); } } void KisLayerBox::slotCompositeOpChanged(int index) { Q_UNUSED(index); if (!m_canvas) return; QString compositeOp = m_wdgLayerBox->cmbComposite->selectedCompositeOp().id(); m_nodeManager->nodeCompositeOpChanged(m_nodeManager->activeColorSpace()->compositeOp(compositeOp)); } void KisLayerBox::slotOpacityChanged() { if (!m_canvas) return; m_blockOpacityUpdate = true; m_nodeManager->nodeOpacityChanged(m_newOpacity, true); m_blockOpacityUpdate = false; } void KisLayerBox::slotOpacitySliderMoved(qreal opacity) { m_newOpacity = opacity; m_opacityDelayTimer.start(200); } void KisLayerBox::slotCollapsed(const QModelIndex &index) { KisNodeSP node = m_filteringModel->nodeFromIndex(index); if (node) { node->setCollapsed(true); } } void KisLayerBox::slotExpanded(const QModelIndex &index) { KisNodeSP node = m_filteringModel->nodeFromIndex(index); if (node) { node->setCollapsed(false); } } void KisLayerBox::slotSelectOpaque() { if (!m_canvas) return; QAction *action = m_canvas->viewManager()->actionManager()->actionByName("selectopaque"); if (action) { action->trigger(); } } void KisLayerBox::slotNodeCollapsedChanged() { expandNodesRecursively(m_image->rootLayer(), m_filteringModel, m_wdgLayerBox->listLayers); } inline bool isSelectionMask(KisNodeSP node) { return dynamic_cast(node.data()); } KisNodeSP KisLayerBox::findNonHidableNode(KisNodeSP startNode) { if (isSelectionMask(startNode) && startNode->parent() && !startNode->parent()->parent()) { KisNodeSP node = startNode->prevSibling(); while (node && isSelectionMask(node)) { node = node->prevSibling(); } if (!node) { node = startNode->nextSibling(); while (node && isSelectionMask(node)) { node = node->nextSibling(); } } if (!node) { node = m_image->root()->lastChild(); while (node && isSelectionMask(node)) { node = node->prevSibling(); } } KIS_ASSERT_RECOVER_NOOP(node && "cannot activate any node!"); startNode = node; } return startNode; } void KisLayerBox::slotEditGlobalSelection(bool showSelections) { KisNodeSP lastActiveNode = m_nodeManager->activeNode(); KisNodeSP activateNode = lastActiveNode; if (!showSelections) { activateNode = findNonHidableNode(activateNode); } m_nodeModel->setShowGlobalSelection(showSelections); if (showSelections) { KisNodeSP newMask = m_image->rootLayer()->selectionMask(); if (newMask) { activateNode = newMask; } } if (activateNode) { if (lastActiveNode != activateNode) { m_nodeManager->slotNonUiActivatedNode(activateNode); } else { setCurrentNode(lastActiveNode); } } } void KisLayerBox::selectionChanged(const QModelIndexList selection) { if (!m_nodeManager) return; /** * When the user clears the extended selection by clicking on the * empty area of the docker, the selection should be reset on to * the active layer, which might be even unselected(!). */ if (selection.isEmpty() && m_nodeManager->activeNode()) { QModelIndex selectedIndex = m_filteringModel->indexFromNode(m_nodeManager->activeNode()); m_wdgLayerBox->listLayers->selectionModel()-> setCurrentIndex(selectedIndex, QItemSelectionModel::ClearAndSelect); return; } QList selectedNodes; Q_FOREACH (const QModelIndex &idx, selection) { selectedNodes << m_filteringModel->nodeFromIndex(idx); } m_nodeManager->slotSetSelectedNodes(selectedNodes); updateUI(); } void KisLayerBox::slotAboutToRemoveRows(const QModelIndex &parent, int start, int end) { /** * Qt has changed its behavior when deleting an item. Previously * the selection priority was on the next item in the list, and * now it has shanged to the previous item. Here we just adjust * the selected item after the node removal. Please take care that * this method overrides what was done by the corresponding method * of QItemSelectionModel, which *has already done* its work. That * is why we use (start - 1) and (end + 1) in the activation * condition. * * See bug: https://bugs.kde.org/show_bug.cgi?id=345601 */ QModelIndex currentIndex = m_wdgLayerBox->listLayers->currentIndex(); QAbstractItemModel *model = m_filteringModel; if (currentIndex.isValid() && parent == currentIndex.parent() && currentIndex.row() >= start - 1 && currentIndex.row() <= end + 1) { QModelIndex old = currentIndex; if (model && end < model->rowCount(parent) - 1) // there are rows left below the change currentIndex = model->index(end + 1, old.column(), parent); else if (start > 0) // there are rows left above the change currentIndex = model->index(start - 1, old.column(), parent); else // there are no rows left in the table currentIndex = QModelIndex(); if (currentIndex.isValid() && currentIndex != old) { m_wdgLayerBox->listLayers->setCurrentIndex(currentIndex); } } } void KisLayerBox::slotNodeManagerChangedSelection(const KisNodeList &nodes) { if (!m_nodeManager) return; QModelIndexList newSelection; Q_FOREACH(KisNodeSP node, nodes) { newSelection << m_filteringModel->indexFromNode(node); } QItemSelectionModel *model = m_wdgLayerBox->listLayers->selectionModel(); if (KritaUtils::compareListsUnordered(newSelection, model->selectedIndexes())) { return; } QItemSelection selection; Q_FOREACH(const QModelIndex &idx, newSelection) { selection.select(idx, idx); } model->select(selection, QItemSelectionModel::ClearAndSelect); } void KisLayerBox::updateThumbnail() { m_wdgLayerBox->listLayers->updateNode(m_wdgLayerBox->listLayers->currentIndex()); } void KisLayerBox::slotRenameCurrentNode() { m_wdgLayerBox->listLayers->edit(m_wdgLayerBox->listLayers->currentIndex()); } void KisLayerBox::slotColorLabelChanged(int label) { KisNodeList nodes = m_nodeManager->selectedNodes(); Q_FOREACH(KisNodeSP node, nodes) { auto applyLabelFunc = [label](KisNodeSP node) { node->setColorLabelIndex(label); }; KisLayerUtils::recursiveApplyNodes(node, applyLabelFunc); } } void KisLayerBox::updateAvailableLabels() { if (!m_image) return; m_wdgLayerBox->cmbFilter->updateAvailableLabels(m_image->root()); } void KisLayerBox::updateLayerFiltering() { m_filteringModel->setAcceptedLabels(m_wdgLayerBox->cmbFilter->selectedColors()); } void KisLayerBox::slotKeyframeChannelAdded(KisKeyframeChannel *channel) { if (channel->id() == KisKeyframeChannel::Opacity.id()) { watchOpacityChannel(channel); } } void KisLayerBox::watchOpacityChannel(KisKeyframeChannel *channel) { if (m_opacityChannel) { m_opacityChannel->disconnect(this); } m_opacityChannel = channel; if (m_opacityChannel) { connect(m_opacityChannel, SIGNAL(sigKeyframeAdded(KisKeyframeSP)), this, SLOT(slotOpacityKeyframeChanged(KisKeyframeSP))); connect(m_opacityChannel, SIGNAL(sigKeyframeRemoved(KisKeyframeSP)), this, SLOT(slotOpacityKeyframeChanged(KisKeyframeSP))); connect(m_opacityChannel, SIGNAL(sigKeyframeMoved(KisKeyframeSP)), this, SLOT(slotOpacityKeyframeMoved(KisKeyframeSP))); connect(m_opacityChannel, SIGNAL(sigKeyframeChanged(KisKeyframeSP)), this, SLOT(slotOpacityKeyframeChanged(KisKeyframeSP))); } } void KisLayerBox::slotOpacityKeyframeChanged(KisKeyframeSP keyframe) { Q_UNUSED(keyframe); if (m_blockOpacityUpdate) return; updateUI(); } void KisLayerBox::slotOpacityKeyframeMoved(KisKeyframeSP keyframe, int fromTime) { Q_UNUSED(fromTime); slotOpacityKeyframeChanged(keyframe); } void KisLayerBox::slotImageTimeChanged(int time) { Q_UNUSED(time); updateUI(); } #include "moc_kis_layer_box.cpp" diff --git a/plugins/dockers/defaultdockers/kis_layer_box.h b/plugins/dockers/defaultdockers/kis_layer_box.h index d2a2975d07..f00fdb0396 100644 --- a/plugins/dockers/defaultdockers/kis_layer_box.h +++ b/plugins/dockers/defaultdockers/kis_layer_box.h @@ -1,191 +1,191 @@ /* * kis_layer_box.h - part of Krita aka Krayon aka KimageShop * * Copyright (c) 2002 Patrick Julien * Copyright (C) 2006 Gábor Lehel * Copyright (C) 2007 Thomas Zander * Copyright (C) 2007-2009 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_LAYERBOX_H #define KIS_LAYERBOX_H #include #include #include #include #include #include #include #include #include #include "kis_action.h" #include "KisViewManager.h" #include "kis_mainwindow_observer.h" #include "kis_signal_compressor.h" class QModelIndex; typedef QList QModelIndexList; class QMenu; class QAbstractButton; class KoCompositeOp; class KisCanvas2; class KisNodeModel; class KisNodeFilterProxyModel; class Ui_WdgLayerBox; class KisNodeJugglerCompressed; class KisColorLabelSelectorWidget; class QWidgetAction; class KisKeyframeChannel; /** * A widget that shows a visualization of the layer structure. * * The center of the layer box is KisNodeModel, which shows the actual layers. * This widget adds docking functionality and command buttons. * */ class KisLayerBox : public QDockWidget, public KisMainwindowObserver { Q_OBJECT public: KisLayerBox(); virtual ~KisLayerBox(); QString observerName() { return "KisLayerBox"; } /// reimplemented from KisMainwindowObserver virtual void setMainWindow(KisViewManager* kisview); virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas(); private Q_SLOTS: void notifyImageDeleted(); void slotContextMenuRequested(const QPoint &pos, const QModelIndex &index); void slotMinimalView(); void slotDetailedView(); void slotThumbnailView(); // From the node manager to the layerbox void slotSetCompositeOp(const KoCompositeOp* compositeOp); void slotSetOpacity(double opacity); void slotFillCompositeOps(const KoColorSpace * colorSpace); void updateUI(); void setCurrentNode(KisNodeSP node); void slotModelReset(); // from the layerbox to the node manager void slotRmClicked(); void slotRaiseClicked(); void slotLowerClicked(); void slotPropertiesClicked(); void slotMergeLayer(); void slotCompositeOpChanged(int index); void slotOpacityChanged(); void slotOpacitySliderMoved(qreal opacity); void slotCollapsed(const QModelIndex &index); void slotExpanded(const QModelIndex &index); void slotSelectOpaque(); void slotNodeCollapsedChanged(); void slotEditGlobalSelection(bool showSelections); void slotRenameCurrentNode(); void slotAboutToRemoveRows(const QModelIndex &parent, int first, int last); void selectionChanged(const QModelIndexList selection); void slotNodeManagerChangedSelection(const QList &nodes); void slotColorLabelChanged(int index); void updateThumbnail(); void updateAvailableLabels(); void updateLayerFiltering(); // Opacity keyframing void slotKeyframeChannelAdded(KisKeyframeChannel *channel); void slotOpacityKeyframeChanged(KisKeyframeSP keyframe); void slotOpacityKeyframeMoved(KisKeyframeSP keyframe, int fromTime); void slotImageTimeChanged(int time); private: inline void connectActionToButton(KisViewManager* view, QAbstractButton *button, const QString &id); inline void addActionToMenu(QMenu *menu, const QString &id); void watchOpacityChannel(KisKeyframeChannel *channel); KisNodeSP findNonHidableNode(KisNodeSP startNode); private: - KisCanvas2* m_canvas; + QPointer m_canvas; QMenu *m_newLayerMenu; KisImageWSP m_image; QPointer m_nodeModel; QPointer m_filteringModel; QPointer m_nodeManager; QPointer m_colorSelector; QPointer m_colorSelectorAction; Ui_WdgLayerBox* m_wdgLayerBox; QTimer m_opacityDelayTimer; int m_newOpacity; QVector m_actions; KisAction* m_removeAction; KisAction* m_propertiesAction; KisAction* m_selectOpaque; KisSignalCompressor m_thumbnailCompressor; KisSignalCompressor m_colorLabelCompressor; KisNodeSP m_activeNode; QPointer m_opacityChannel; bool m_blockOpacityUpdate {false}; }; class KisLayerBoxFactory : public KoDockFactoryBase { public: KisLayerBoxFactory() { } virtual QString id() const { return QString("KisLayerBox"); } virtual QDockWidget* createDockWidget() { KisLayerBox * dockWidget = new KisLayerBox(); dockWidget->setObjectName(id()); return dockWidget; } DockPosition defaultDockPosition() const { return DockRight; } }; #endif // KIS_LAYERBOX_H diff --git a/plugins/dockers/digitalmixer/digitalmixer_dock.h b/plugins/dockers/digitalmixer/digitalmixer_dock.h index 21677b3d54..ce14446472 100644 --- a/plugins/dockers/digitalmixer/digitalmixer_dock.h +++ b/plugins/dockers/digitalmixer/digitalmixer_dock.h @@ -1,59 +1,63 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 _DIGITALMIXER_DOCK_H_ #define _DIGITALMIXER_DOCK_H_ +#include #include + #include #include +#include + class KoColorPopupAction; class KoColorSlider; class KoColorPatch; class KisColorButton; class DigitalMixerDock : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT public: DigitalMixerDock( ); QString observerName() { return "DigitalMixerDock"; } /// reimplemented from KoCanvasObserverBase virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas() { m_canvas = 0; setEnabled(false);} public Q_SLOTS: void setCurrentColor(const KoColor& ); void canvasResourceChanged(int, const QVariant&); private Q_SLOTS: void popupColorChanged(int i); void colorSliderChanged(int i); void targetColorChanged(int); private: - KoCanvasBase* m_canvas; + QPointer m_canvas; KoColor m_currentColor; KoColorPatch* m_currentColorPatch; struct Mixer { KoColorPatch* targetColor; KoColorSlider* targetSlider; KisColorButton* actionColor; }; QList m_mixers; bool m_tellCanvas; }; #endif diff --git a/plugins/dockers/histogram/histogramdocker_dock.h b/plugins/dockers/histogram/histogramdocker_dock.h index 62bd11bdb6..5227cf04e2 100644 --- a/plugins/dockers/histogram/histogramdocker_dock.h +++ b/plugins/dockers/histogram/histogramdocker_dock.h @@ -1,57 +1,60 @@ /* * Copyright (c) 2016 Eugene Ingerman * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 _HISTOGRAM_DOCK_H_ #define _HISTOGRAM_DOCK_H_ #include +#include + #include + #include +#include class QVBoxLayout; -class KisCanvas2; class KisHistogramView; class KisIdleWatcher; class KoHistogramProducer; class HistogramDockerWidget; class HistogramDockerDock : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT public: HistogramDockerDock(); QString observerName() { return "HistogramDockerDock"; } virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas(); public Q_SLOTS: void startUpdateCanvasProjection(); void sigColorSpaceChanged(const KoColorSpace* cs); void updateHistogram(); protected: void showEvent(QShowEvent *event); private: QVBoxLayout *m_layout; KisIdleWatcher *m_imageIdleWatcher; HistogramDockerWidget *m_histogramWidget; - KisCanvas2 *m_canvas; + QPointer m_canvas; }; #endif diff --git a/plugins/dockers/historydocker/HistoryDock.cpp b/plugins/dockers/historydocker/HistoryDock.cpp index f253d7f001..ce36a274cb 100644 --- a/plugins/dockers/historydocker/HistoryDock.cpp +++ b/plugins/dockers/historydocker/HistoryDock.cpp @@ -1,75 +1,84 @@ /* This file is part of the KDE project * Copyright (C) 2010 Matus Talcik * * 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 "HistoryDock.h" #include #include #include #include #include #include #include #include #include HistoryDock::HistoryDock() : QDockWidget() , m_historyCanvas(0) { QWidget *page = new QWidget(this); QVBoxLayout *vl = new QVBoxLayout(page); m_undoView = new KisUndoView(this); vl->addWidget(m_undoView); QHBoxLayout *hl = new QHBoxLayout(page); hl->addSpacerItem(new QSpacerItem(10, 1, QSizePolicy::Expanding, QSizePolicy::Fixed)); m_bnConfigure = new QToolButton(page); m_bnConfigure->setIcon(KisIconUtils::loadIcon("configure")); connect(m_bnConfigure, SIGNAL(clicked(bool)), SLOT(configure())); hl->addWidget(m_bnConfigure); vl->addItem(hl); setWidget(page); setWindowTitle(i18n("Undo History")); } -void HistoryDock::setCanvas(KoCanvasBase *canvas) { - +void HistoryDock::setCanvas(KoCanvasBase *canvas) +{ setEnabled(canvas != 0); - - KisCanvas2* myCanvas = dynamic_cast( canvas ); - if (myCanvas) { + QPointer myCanvas = dynamic_cast(canvas); + if (myCanvas + && myCanvas->shapeController() + && myCanvas->shapeController()->resourceManager() + && myCanvas->shapeController()->resourceManager()->undoStack()) { KUndo2Stack* undoStack = canvas->shapeController()->resourceManager()->undoStack(); m_undoView->setStack(undoStack); KisConfig cfg; m_undoView->stack()->setUseCumulativeUndoRedo(cfg.useCumulativeUndoRedo()); m_undoView->stack()->setTimeT1(cfg.stackT1()); m_undoView->stack()->setTimeT2(cfg.stackT2()); m_undoView->stack()->setStrokesN(cfg.stackN()); } m_undoView->setCanvas( myCanvas ); } void HistoryDock::configure() { DlgConfigureHistoryDock dlg(m_undoView, m_undoView->stack(), this); dlg.exec(); } + +void HistoryDock::unsetCanvas() +{ + m_historyCanvas = 0; + setEnabled(false); + m_undoView->setStack(0); +} diff --git a/plugins/dockers/historydocker/HistoryDock.h b/plugins/dockers/historydocker/HistoryDock.h index 8e531b7b5a..a8d6ed8844 100644 --- a/plugins/dockers/historydocker/HistoryDock.h +++ b/plugins/dockers/historydocker/HistoryDock.h @@ -1,57 +1,57 @@ /* This file is part of the KDE project * Copyright (C) 2010 Matus Talcik * * 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. */ #ifndef _HISTORY_DOCK_H_ #define _HISTORY_DOCK_H_ #include #include #include "KisUndoView.h" #include #include #include #include #include #include "kis_types.h" #include "kis_canvas2.h" #include "KisViewManager.h" #include "kis_image.h" #include "kis_paint_device.h" class HistoryDock : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT public: HistoryDock(); QString observerName() { return "HistoryDock"; } virtual void setCanvas(KoCanvasBase *canvas); - virtual void unsetCanvas() { m_historyCanvas = 0; setEnabled(false); m_undoView->setStack(0); } + virtual void unsetCanvas(); private Q_SLOTS: void configure(); private: KisUndoView *m_undoView; QToolButton *m_bnConfigure; KoCanvasBase *m_historyCanvas; }; #endif diff --git a/plugins/dockers/historydocker/KisUndoModel.h b/plugins/dockers/historydocker/KisUndoModel.h index 41bdb4a74e..c5547ef818 100644 --- a/plugins/dockers/historydocker/KisUndoModel.h +++ b/plugins/dockers/historydocker/KisUndoModel.h @@ -1,111 +1,114 @@ /* This file is part of the KDE project * Copyright (C) 2010 Matus Talcik * * 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. */ /**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef KIS_UNDO_MODEL_H #define KIS_UNDO_MODEL_H #include #include #include #include +#include + #include + #include "kis_types.h" #include "kis_canvas2.h" #include "KisViewManager.h" #include "kis_image.h" #include "kis_paint_device.h" class KisUndoModel : public QAbstractItemModel { Q_OBJECT public: KisUndoModel(QObject *parent = 0); KUndo2QStack *stack() const; virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; virtual QModelIndex parent(const QModelIndex &child) const; virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; virtual int columnCount(const QModelIndex &parent = QModelIndex()) const; virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; QModelIndex selectedIndex() const; QItemSelectionModel *selectionModel() const; QString emptyLabel() const; void setEmptyLabel(const QString &label); void setCleanIcon(const QIcon &icon); QIcon cleanIcon() const; void setCanvas(KisCanvas2* canvas); bool checkMergedCommand(int index); public Q_SLOTS: void setStack(KUndo2QStack *stack); void addImage(int idx); private Q_SLOTS: void stackChanged(); void stackDestroyed(QObject *obj); void setStackCurrentIndex(const QModelIndex &index); private: bool m_blockOutgoingHistoryChange; KUndo2QStack *m_stack; QItemSelectionModel *m_sel_model; QString m_empty_label; QIcon m_clean_icon; - KisCanvas2* m_canvas; + QPointer m_canvas; QMap m_imageMap; }; #endif diff --git a/plugins/dockers/imagedocker/imagedocker_dock.h b/plugins/dockers/imagedocker/imagedocker_dock.h index 7eccc57a3d..4710adf0d2 100644 --- a/plugins/dockers/imagedocker/imagedocker_dock.h +++ b/plugins/dockers/imagedocker/imagedocker_dock.h @@ -1,109 +1,111 @@ /* * Copyright (c) 2011 Silvio Heinrich * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 H_IMAGEDOCKER_DOCK_H_ #define H_IMAGEDOCKER_DOCK_H_ +#include #include #include #include #include #include +#include + class QModelIndex; class QFileSystemModel; class QButtonGroup; -class KoCanvasBase; class ImageFilter; class ImageStripScene; class ImageListModel; class QTemporaryFile; struct ImageDockerUI; struct PopupWidgetUI; class ImageDockerDock: public QDockWidget, public KoCanvasObserverBase { Q_OBJECT struct ImageInfo { qint64 id; int viewMode; QString path; QString name; float scale; QPixmap pixmap; QPoint scrollPos; }; typedef QMap::iterator ImageInfoIter; public: ImageDockerDock(); virtual ~ImageDockerDock(); QString observerName() { return "ImageDockerDock"; } virtual void setCanvas(KoCanvasBase* canvas); virtual void unsetCanvas() { m_canvas = 0; // Intentionally not disabled if there's no canvas } private Q_SLOTS: void slotItemDoubleClicked(const QModelIndex& index); void slotBackButtonClicked(); void slotUpButtonClicked(); void slotHomeButtonClicked(); void slotCloseCurrentImage(); void slotNextImage(); void slotPrevImage(); void slotOpenImage(const QString& path); void slotImageChoosenFromComboBox(int index); void slotZoomChanged(int zoom); void slotColorSelected(const QColor& color); void slotViewModeChanged(int viewMode, qreal scale); void slotCloseZoomPopup(); void slotChangeRoot(const QString& path); protected: bool eventFilter(QObject *obj, QEvent *event); void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event); void showEvent(QShowEvent *); private: void addCurrentPathToHistory(); void updatePath(const QString& path); qint64 generateImageID() const; void setCurrentImage(qint64 imageID); bool isImageLoaded() const { return m_currImageID != -1; } void setZoom(const ImageInfo& info); private: QFileSystemModel* m_model; QButtonGroup* m_zoomButtons; - KoCanvasBase* m_canvas; + QPointer m_canvas; ImageFilter* m_proxyModel; ImageListModel* m_imgListModel; QStringList m_history; ImageStripScene* m_imageStripScene; ImageDockerUI* m_ui; PopupWidgetUI* m_popupUi; QMap m_imgInfoMap; qint64 m_currImageID; QList m_temporaryFiles; }; #endif // H_IMAGEDOCKER_DOCK_H_ diff --git a/plugins/dockers/lut/lutdocker_dock.h b/plugins/dockers/lut/lutdocker_dock.h index a9e55f4e90..b8c6671b28 100644 --- a/plugins/dockers/lut/lutdocker_dock.h +++ b/plugins/dockers/lut/lutdocker_dock.h @@ -1,119 +1,118 @@ /* * Copyright (c) 2004 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 LUT_DOCKER_DOCK_H #define LUT_DOCKER_DOCK_H #include #include - +#include #include #include #include #include +#include #include "ui_wdglut.h" #include #include "kis_signal_compressor_with_param.h" namespace OCIO = OCIO_NAMESPACE; - -class KisCanvas2; class BlackWhitePointChooser; #include "ocio_display_filter.h" #include "kis_exposure_gamma_correction_interface.h" class LutDockerDock : public QDockWidget, public KoCanvasObserverBase, public Ui_WdgLut, public KisExposureGammaCorrectionInterface { Q_OBJECT public: LutDockerDock(); ~LutDockerDock(); QString observerName() { return "LutDockerDock"; } /// reimplemented from KoCanvasObserverBase virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas(); bool canChangeExposureAndGamma() const; qreal currentExposure() const; void setCurrentExposure(qreal value); qreal currentGamma() const; void setCurrentGamma(qreal value); private Q_SLOTS: void slotImageColorSpaceChanged(); void exposureValueChanged(double exposure); void exposureSliderPressed(); void exposureSliderReleased(); void gammaValueChanged(double exposure); void gammaSliderPressed(); void gammaSliderReleased(); void updateDisplaySettings(); void slotColorManagementModeChanged(); void writeControls(); void selectOcioConfiguration(); void resetOcioConfiguration(); void refillViewCombobox(); void selectLut(); void clearLut(); void slotShowBWConfiguration(); void slotUpdateIcons(); private: void enableControls(); void refillControls(); void setCurrentExposureImpl(qreal value); void setCurrentGammaImpl(qreal value); private: QWidget *m_page; - KisCanvas2 *m_canvas; + QPointer m_canvas; OCIO::ConstConfigRcPtr m_ocioConfig; QSharedPointer m_displayFilter; bool m_draggingSlider; QScopedPointer > m_exposureCompressor; QScopedPointer > m_gammaCompressor; BlackWhitePointChooser *m_bwPointChooser; }; #endif // LUT_DOCKER_DOCK_H diff --git a/plugins/dockers/overview/overviewdocker_dock.h b/plugins/dockers/overview/overviewdocker_dock.h index 923f229612..194aa00ea5 100644 --- a/plugins/dockers/overview/overviewdocker_dock.h +++ b/plugins/dockers/overview/overviewdocker_dock.h @@ -1,44 +1,46 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 _OVERVIEW_DOCK_H_ #define _OVERVIEW_DOCK_H_ +#include #include #include +#include + class QVBoxLayout; -class KisCanvas2; class OverviewWidget; class OverviewDockerDock : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT public: OverviewDockerDock(); QString observerName() { return "OverviewDockerDock"; } virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas(); private: QVBoxLayout *m_layout; OverviewWidget *m_overviewWidget; QWidget *m_zoomSlider; - KisCanvas2 *m_canvas; + QPointer m_canvas; }; #endif diff --git a/plugins/dockers/overview/overviewwidget.h b/plugins/dockers/overview/overviewwidget.h index fa76f68536..bfb36337aa 100644 --- a/plugins/dockers/overview/overviewwidget.h +++ b/plugins/dockers/overview/overviewwidget.h @@ -1,110 +1,113 @@ /* * Copyright (c) 2009 Cyrille Berger * Copyright (c) 2014 Sven Langkamp * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 OVERVIEWWIDGET_H #define OVERVIEWWIDGET_H #include #include #include +#include + #include #include "kis_idle_watcher.h" #include "kis_simple_stroke_strategy.h" -class KisCanvas2; +#include + class KisSignalCompressor; class KoCanvasBase; class OverviewThumbnailStrokeStrategy : public QObject, public KisSimpleStrokeStrategy { Q_OBJECT public: OverviewThumbnailStrokeStrategy(KisImageWSP image); ~OverviewThumbnailStrokeStrategy(); static QList createJobsData(KisPaintDeviceSP dev, const QRect& imageRect, KisPaintDeviceSP thumbDev, const QSize &thumbnailSize); private: void initStrokeCallback(); void doStrokeCallback(KisStrokeJobData *data); void finishStrokeCallback(); void cancelStrokeCallback(); Q_SIGNALS: //Emitted when thumbnail is updated and overviewImage is fully generated. void thumbnailUpdated(QImage pixmap); private: struct Private; const QScopedPointer m_d; QMutex m_thumbnailMergeMutex; KisImageSP m_image; }; class OverviewWidget : public QWidget { Q_OBJECT public: OverviewWidget(QWidget * parent = 0); virtual ~OverviewWidget(); virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas() { m_canvas = 0; } public Q_SLOTS: void startUpdateCanvasProjection(); void generateThumbnail(); void updateThumbnail(QImage pixmap); protected: void resizeEvent(QResizeEvent *event); void showEvent(QShowEvent *event); void paintEvent(QPaintEvent *event); virtual void mousePressEvent(QMouseEvent* event); virtual void mouseMoveEvent(QMouseEvent* event); virtual void mouseReleaseEvent(QMouseEvent* event); virtual void wheelEvent(QWheelEvent* event); private: QSize calculatePreviewSize(); QPointF previewOrigin(); QTransform imageToPreviewTransform(); QPolygonF previewPolygon(); QPixmap m_pixmap; - KisCanvas2 *m_canvas; + QPointer m_canvas; bool m_dragging; QPointF m_lastPos; QColor m_outlineColor; KisIdleWatcher m_imageIdleWatcher; KisStrokeId strokeId; QMutex mutex; }; #endif /* OVERVIEWWIDGET_H */ diff --git a/plugins/dockers/palettedocker/palettedocker_dock.cpp b/plugins/dockers/palettedocker/palettedocker_dock.cpp index f05f43623a..3b6a42ec91 100644 --- a/plugins/dockers/palettedocker/palettedocker_dock.cpp +++ b/plugins/dockers/palettedocker/palettedocker_dock.cpp @@ -1,256 +1,256 @@ /* * Copyright (c) 2013 Sven Langkamp * * 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 "palettedocker_dock.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KisPaletteModel.h" #include "KisColorsetChooser.h" #include "ui_wdgpalettedock.h" #include "kis_palette_delegate.h" #include "kis_palette_view.h" PaletteDockerDock::PaletteDockerDock( ) : QDockWidget(i18n("Palette")) , m_wdgPaletteDock(new Ui_WdgPaletteDock()) , m_currentColorSet(0) , m_resourceProvider(0) , m_canvas(0) { QWidget* mainWidget = new QWidget(this); setWidget(mainWidget); m_wdgPaletteDock->setupUi(mainWidget); m_wdgPaletteDock->bnAdd->setIcon(KisIconUtils::loadIcon("list-add")); m_wdgPaletteDock->bnAdd->setIconSize(QSize(16, 16)); m_wdgPaletteDock->bnAddDialog->setIcon(KisIconUtils::loadIcon("document-new")); m_wdgPaletteDock->bnAddDialog->setIconSize(QSize(16, 16)); m_wdgPaletteDock->bnRemove->setIcon(KisIconUtils::loadIcon("edit-delete")); m_wdgPaletteDock->bnRemove->setIconSize(QSize(16, 16)); m_wdgPaletteDock->bnAdd->setEnabled(false); m_wdgPaletteDock->bnRemove->setEnabled(false); connect(m_wdgPaletteDock->bnAdd, SIGNAL(clicked(bool)), this, SLOT(addColorForeground())); connect(m_wdgPaletteDock->bnAddDialog, SIGNAL(clicked(bool)), this, SLOT(addColor())); connect(m_wdgPaletteDock->bnRemove, SIGNAL(clicked(bool)), this, SLOT(removeColor())); m_model = new KisPaletteModel(this); m_wdgPaletteDock->paletteView->setPaletteModel(m_model); connect(m_wdgPaletteDock->paletteView, SIGNAL(clicked(QModelIndex)), this, SLOT(entrySelected(QModelIndex))); KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(false); m_serverAdapter = QSharedPointer(new KoResourceServerAdapter(rServer)); m_serverAdapter->connectToResourceServer(); rServer->addObserver(this); m_colorSetChooser = new KisColorsetChooser(this); connect(m_colorSetChooser, SIGNAL(paletteSelected(KoColorSet*)), this, SLOT(setColorSet(KoColorSet*))); m_wdgPaletteDock->bnColorSets->setIcon(KisIconUtils::loadIcon("hi16-palette_library")); m_wdgPaletteDock->bnColorSets->setToolTip(i18n("Choose palette")); m_wdgPaletteDock->bnColorSets->setPopupWidget(m_colorSetChooser); KisConfig cfg; QString defaultPalette = cfg.defaultPalette(); KoColorSet* defaultColorSet = rServer->resourceByName(defaultPalette); if (defaultColorSet) { setColorSet(defaultColorSet); } } PaletteDockerDock::~PaletteDockerDock() { KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); rServer->removeObserver(this); if (m_currentColorSet) { KisConfig cfg; cfg.setDefaultPalette(m_currentColorSet->name()); } delete m_wdgPaletteDock->paletteView->itemDelegate(); delete m_wdgPaletteDock; } void PaletteDockerDock::setMainWindow(KisViewManager* kisview) { m_resourceProvider = kisview->resourceProvider(); connect(m_resourceProvider, SIGNAL(sigSavingWorkspace(KisWorkspaceResource*)), SLOT(saveToWorkspace(KisWorkspaceResource*))); connect(m_resourceProvider, SIGNAL(sigLoadingWorkspace(KisWorkspaceResource*)), SLOT(loadFromWorkspace(KisWorkspaceResource*))); kisview->nodeManager()->disconnect(m_model); } void PaletteDockerDock::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); if (canvas) { - KisCanvas2 *cv = dynamic_cast(canvas); + KisCanvas2 *cv = qobject_cast(canvas); m_model->setDisplayRenderer(cv->displayColorConverter()->displayRendererInterface()); } m_canvas = static_cast(canvas); } void PaletteDockerDock::unsetCanvas() { setEnabled(false); m_model->setDisplayRenderer(0); m_canvas = 0; } void PaletteDockerDock::unsetResourceServer() { KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); rServer->removeObserver(this); } void PaletteDockerDock::removingResource(KoColorSet *resource) { if (resource == m_currentColorSet) { setColorSet(0); } } void PaletteDockerDock::resourceChanged(KoColorSet *resource) { setColorSet(resource); } void PaletteDockerDock::setColorSet(KoColorSet* colorSet) { m_model->setColorSet(colorSet); if (colorSet && colorSet->removable()) { m_wdgPaletteDock->bnAdd->setEnabled(true); m_wdgPaletteDock->bnRemove->setEnabled(false); } else { m_wdgPaletteDock->bnAdd->setEnabled(false); m_wdgPaletteDock->bnRemove->setEnabled(false); } m_currentColorSet = colorSet; } void PaletteDockerDock::addColorForeground() { if (m_resourceProvider) { KoColorSetEntry newEntry; newEntry.color = m_resourceProvider->fgColor(); m_currentColorSet->add(newEntry); m_currentColorSet->save(); setColorSet(m_currentColorSet); // update model } } void PaletteDockerDock::addColor() { if (m_currentColorSet && m_resourceProvider) { const KoColorDisplayRendererInterface *displayRenderer = m_canvas->displayColorConverter()->displayRendererInterface(); KoColor currentFgColor = m_canvas->resourceManager()->foregroundColor(); QColor color = QColorDialog::getColor(displayRenderer->toQColor(currentFgColor)); if (color.isValid()) { KoColorSetEntry newEntry; newEntry.color = displayRenderer->approximateFromRenderedQColor(color); m_currentColorSet->add(newEntry); m_currentColorSet->save(); setColorSet(m_currentColorSet); // update model } } } void PaletteDockerDock::removeColor() { QModelIndex index = m_wdgPaletteDock->paletteView->currentIndex(); if (!index.isValid()) { return; } int i = index.row()*m_model->columnCount()+index.column(); m_currentColorSet->removeAt(i); m_currentColorSet->save(); setColorSet(m_currentColorSet); // update model } void PaletteDockerDock::entrySelected(QModelIndex index) { if (!index.isValid()) { return; } int i = index.row()*m_model->columnCount()+index.column(); if (i < m_currentColorSet->nColors()) { KoColorSetEntry entry = m_currentColorSet->getColor(i); m_wdgPaletteDock->lblColorName->setText(entry.name); if (m_resourceProvider) { m_resourceProvider->setFGColor(entry.color); } if (m_currentColorSet->removable()) { m_wdgPaletteDock->bnRemove->setEnabled(true); } } } void PaletteDockerDock::saveToWorkspace(KisWorkspaceResource* workspace) { if (m_currentColorSet) { workspace->setProperty("palette", m_currentColorSet->name()); } } void PaletteDockerDock::loadFromWorkspace(KisWorkspaceResource* workspace) { if (workspace->hasProperty("palette")) { KoResourceServer* rServer = KoResourceServerProvider::instance()->paletteServer(); KoColorSet* colorSet = rServer->resourceByName(workspace->getString("palette")); if (colorSet) { setColorSet(colorSet); } } } diff --git a/plugins/dockers/palettedocker/palettedocker_dock.h b/plugins/dockers/palettedocker/palettedocker_dock.h index 77b129a817..b39754a078 100644 --- a/plugins/dockers/palettedocker/palettedocker_dock.h +++ b/plugins/dockers/palettedocker/palettedocker_dock.h @@ -1,82 +1,84 @@ /* * Copyright (c) 2013 Sven Langkamp * * 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 PALETTEDOCKER_DOCK_H #define PALETTEDOCKER_DOCK_H #include #include +#include + #include #include #include #include +#include #include class KisViewManager; class KisCanvasResourceProvider; -class KisCanvas2; class KisWorkspaceResource; class KisColorsetChooser; class KisPaletteModel; class Ui_WdgPaletteDock; class PaletteDockerDock : public QDockWidget, public KisMainwindowObserver, public KoResourceServerObserver { Q_OBJECT public: PaletteDockerDock(); virtual ~PaletteDockerDock(); QString observerName() { return "PaletteDockerDock"; } virtual void setMainWindow(KisViewManager* kisview); virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas(); public: // KoResourceServerObserver virtual void unsetResourceServer(); virtual void resourceAdded(KoColorSet *) {} virtual void removingResource(KoColorSet *resource); virtual void resourceChanged(KoColorSet *resource); virtual void syncTaggedResourceView() {} virtual void syncTagAddition(const QString&) {} virtual void syncTagRemoval(const QString&) {} private Q_SLOTS: void addColorForeground(); void addColor(); void removeColor(); void entrySelected(QModelIndex index); void setColorSet(KoColorSet* colorSet); void saveToWorkspace(KisWorkspaceResource* workspace); void loadFromWorkspace(KisWorkspaceResource* workspace); private: Ui_WdgPaletteDock* m_wdgPaletteDock; KisPaletteModel *m_model; QSharedPointer m_serverAdapter; KoColorSet *m_currentColorSet; KisColorsetChooser *m_colorSetChooser; KisCanvasResourceProvider *m_resourceProvider; - KisCanvas2 *m_canvas; + QPointer m_canvas; }; #endif diff --git a/plugins/dockers/presetdocker/presetdocker_dock.cpp b/plugins/dockers/presetdocker/presetdocker_dock.cpp index 216b1f1588..748958ede7 100644 --- a/plugins/dockers/presetdocker/presetdocker_dock.cpp +++ b/plugins/dockers/presetdocker/presetdocker_dock.cpp @@ -1,78 +1,78 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 "presetdocker_dock.h" #include #include #include #include #include #include "kis_canvas2.h" #include "KisViewManager.h" #include "kis_paintop_box.h" #include "kis_paintop_presets_chooser_popup.h" #include "kis_canvas_resource_provider.h" #include PresetDockerDock::PresetDockerDock( ) : QDockWidget(i18n("Brush Presets")) , m_canvas(0) { m_presetChooser = new KisPaintOpPresetsChooserPopup(this); m_presetChooser->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); m_presetChooser->showButtons(false); setWidget(m_presetChooser); } -void PresetDockerDock::setCanvas(KoCanvasBase * canvas) +void PresetDockerDock::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); if (m_canvas) { m_canvas->disconnectCanvasObserver(this); m_presetChooser->disconnect(m_canvas->viewManager()->paintOpBox()); } m_canvas = dynamic_cast(canvas); if (!m_canvas || !m_canvas->viewManager() || !m_canvas->resourceManager()) return; connect(m_presetChooser, SIGNAL(resourceSelected(KoResource*)), m_canvas->viewManager()->paintOpBox(), SLOT(resourceSelected(KoResource*))); connect(m_presetChooser, SIGNAL(resourceClicked(KoResource*)), m_canvas->viewManager()->paintOpBox(), SLOT(resourceSelected(KoResource*))); connect(canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), this, SLOT(canvasResourceChanged(int,QVariant))); } void PresetDockerDock::canvasResourceChanged(int /*key*/, const QVariant& /*v*/) { - if (m_canvas) { + if (m_canvas && m_canvas->resourceManager()) { sender()->blockSignals(true); KisPaintOpPresetSP preset = m_canvas->resourceManager()->resource(KisCanvasResourceProvider::CurrentPaintOpPreset).value(); if(preset) m_presetChooser->canvasResourceChanged(preset); sender()->blockSignals(false); m_presetChooser->updateViewSettings(); } } diff --git a/plugins/dockers/presetdocker/presetdocker_dock.h b/plugins/dockers/presetdocker/presetdocker_dock.h index 03b7446c31..5bb9c1e83f 100644 --- a/plugins/dockers/presetdocker/presetdocker_dock.h +++ b/plugins/dockers/presetdocker/presetdocker_dock.h @@ -1,43 +1,44 @@ /* * Copyright (c) 2009 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 _PRESETDOCKER_DOCK_H_ #define _PRESETDOCKER_DOCK_H_ +#include #include #include +#include class KisPaintOpPresetsChooserPopup; -class KisCanvas2; class PresetDockerDock : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT public: PresetDockerDock( ); QString observerName() { return "PresetDockerDock"; } virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas() { m_canvas = 0; setEnabled(false);} public Q_SLOTS: void canvasResourceChanged(int key, const QVariant& v); private Q_SLOTS: private: - KisCanvas2* m_canvas; + QPointer m_canvas; KisPaintOpPresetsChooserPopup* m_presetChooser; }; #endif diff --git a/plugins/dockers/presethistory/presethistory_dock.h b/plugins/dockers/presethistory/presethistory_dock.h index 90542f8f34..6f23b8ee05 100644 --- a/plugins/dockers/presethistory/presethistory_dock.h +++ b/plugins/dockers/presethistory/presethistory_dock.h @@ -1,52 +1,53 @@ /* * Copyright (c) 2015 Boudewijn Rempt * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 _PRESETHISTORY_DOCK_H_ #define _PRESETHISTORY_DOCK_H_ #include +#include + #include +#include #include class QListWidget; class QListWidgetItem; -class KisCanvas2; - class PresetHistoryDock : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT public: PresetHistoryDock(); QString observerName() { return "PresetHistoryDock"; } virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas(); private Q_SLOTS: void presetSelected(QListWidgetItem* item); void canvasResourceChanged(int key, const QVariant& v); private: void addPreset(KisPaintOpPresetSP preset); private: - KisCanvas2 *m_canvas; + QPointer m_canvas; QListWidget *m_presetHistory; bool m_block; bool m_initialized; }; #endif diff --git a/plugins/dockers/shapedockers/shapeproperties/ShapePropertiesDocker.cpp b/plugins/dockers/shapedockers/shapeproperties/ShapePropertiesDocker.cpp index bf60258683..9f765120ec 100644 --- a/plugins/dockers/shapedockers/shapeproperties/ShapePropertiesDocker.cpp +++ b/plugins/dockers/shapedockers/shapeproperties/ShapePropertiesDocker.cpp @@ -1,188 +1,189 @@ /* This file is part of the KDE project Copyright (C) 2007 Jan Hambrecht This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "ShapePropertiesDocker.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include class ShapePropertiesDocker::Private { public: Private() : widgetStack(0) , currentShape(0) , currentPanel(0) , canvas(0) { } QStackedWidget *widgetStack; KoShape *currentShape; KoShapeConfigWidgetBase *currentPanel; - KoCanvasBase *canvas; + QPointer canvas; }; ShapePropertiesDocker::ShapePropertiesDocker(QWidget *parent) : QDockWidget(i18n("Shape Properties") , parent) , d(new Private()) { d->widgetStack = new QStackedWidget(); setWidget(d->widgetStack); } ShapePropertiesDocker::~ShapePropertiesDocker() { delete d; } void ShapePropertiesDocker::unsetCanvas() { setEnabled(false); d->canvas = 0; } void ShapePropertiesDocker::setCanvas(KoCanvasBase *canvas) { setEnabled(canvas != 0); if (d->canvas) { d->canvas->disconnectCanvasObserver(this); // "Every connection you make emits a signal, so duplicate connections emit two signals" } d->canvas = canvas; if (d->canvas) { connect(d->canvas->shapeManager(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); connect(d->canvas->shapeManager(), SIGNAL(selectionContentChanged()), this, SLOT(selectionChanged())); connect(d->canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)), this, SLOT(canvasResourceChanged(int,QVariant))); } } void ShapePropertiesDocker::selectionChanged() { if (!d->canvas) { return; } KoSelection *selection = d->canvas->shapeManager()->selection(); if (selection->count() == 1) { addWidgetForShape(selection->firstSelectedShape()); } else { addWidgetForShape(0); } } void ShapePropertiesDocker::addWidgetForShape(KoShape *shape) { // remove the config widget if a null shape is set, or the shape has changed if (!shape || shape != d->currentShape) { while (d->widgetStack->count()) { d->widgetStack->removeWidget(d->widgetStack->widget(0)); } } if (!shape) { d->currentShape = 0; d->currentPanel = 0; return; } else if (shape != d->currentShape) { // when a shape is set and is differs from the previous one // get the config widget and insert it into the option widget d->currentShape = shape; if (!d->currentShape) { return; } QString shapeId = shape->shapeId(); KoPathShape *path = dynamic_cast(shape); if (path) { // use the path specific shape id if shape is a path, otherwise use the shape id shapeId = path->pathShapeId(); // check if we have an edited parametric shape, then we use the path shape id KoParameterShape *paramShape = dynamic_cast(shape); if (paramShape && ! paramShape->isParametricShape()) { shapeId = shape->shapeId(); } } KoShapeFactoryBase *factory = KoShapeRegistry::instance()->value(shapeId); if (!factory) { return; } QList panels = factory->createShapeOptionPanels(); if (!panels.count()) { return; } d->currentPanel = 0; uint panelCount = panels.count(); for (uint i = 0; i < panelCount; ++i) { if (panels[i]->showOnShapeSelect()) { d->currentPanel = panels[i]; break; } } if (d->currentPanel) { if (d->canvas) { d->currentPanel->setUnit(d->canvas->unit()); } d->widgetStack->insertWidget(0, d->currentPanel); connect(d->currentPanel, SIGNAL(propertyChanged()), this, SLOT(shapePropertyChanged())); } } if (d->currentPanel) { d->currentPanel->open(shape); } } void ShapePropertiesDocker::shapePropertyChanged() { if (d->canvas && d->currentPanel) { KUndo2Command *cmd = d->currentPanel->createCommand(); if (!cmd) { return; } d->canvas->addCommand(cmd); } } void ShapePropertiesDocker::canvasResourceChanged(int key, const QVariant &variant) { if (key == KoCanvasResourceManager::Unit && d->currentPanel) { d->currentPanel->setUnit(variant.value()); } } diff --git a/plugins/dockers/smallcolorselector/smallcolorselector_dock.h b/plugins/dockers/smallcolorselector/smallcolorselector_dock.h index c3279498d2..f739f751bd 100644 --- a/plugins/dockers/smallcolorselector/smallcolorselector_dock.h +++ b/plugins/dockers/smallcolorselector/smallcolorselector_dock.h @@ -1,44 +1,47 @@ /* * Copyright (c) 2008 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 _SMALLCOLORSELECTOR_DOCK_H_ #define _SMALLCOLORSELECTOR_DOCK_H_ +#include #include + +#include #include class KisSmallColorWidget; class SmallColorSelectorDock : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT public: SmallColorSelectorDock(); QString observerName() { return "SmallColorSelectorDock"; } /// reimplemented from KoCanvasObserverBase virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas() { m_canvas = 0; setEnabled(false); } public Q_SLOTS: void colorChangedProxy(const QColor&); void canvasResourceChanged(int, const QVariant&); private: KisSmallColorWidget* m_smallColorWidget; - KoCanvasBase* m_canvas; + QPointer m_canvas; }; #endif diff --git a/plugins/dockers/specificcolorselector/specificcolorselector_dock.h b/plugins/dockers/specificcolorselector/specificcolorselector_dock.h index d1dd630580..bf6e287b14 100644 --- a/plugins/dockers/specificcolorselector/specificcolorselector_dock.h +++ b/plugins/dockers/specificcolorselector/specificcolorselector_dock.h @@ -1,49 +1,50 @@ /* * Copyright (c) 2008 Cyrille Berger * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 _SPECIFICCOLORSELECTOR_DOCK_H_ #define _SPECIFICCOLORSELECTOR_DOCK_H_ #include +#include #include #include +#include class KisViewManager; -class KisCanvas2; class KisSpecificColorSelectorWidget; class SpecificColorSelectorDock : public QDockWidget, public KisMainwindowObserver { Q_OBJECT public: SpecificColorSelectorDock(); QString observerName() { return "SpecificColorSelectorDock"; } /// reimplemented from KoCanvasObserverBase/KisMainwindowObserver virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas(); virtual void setMainWindow(KisViewManager* kisview); private: - KisCanvas2 *m_canvas; + QPointer m_canvas; KisViewManager *m_view; KisSpecificColorSelectorWidget* m_colorSelector; }; #endif diff --git a/plugins/dockers/tasksetdocker/tasksetdocker_dock.h b/plugins/dockers/tasksetdocker/tasksetdocker_dock.h index e57bb42956..cdab4d4068 100644 --- a/plugins/dockers/tasksetdocker/tasksetdocker_dock.h +++ b/plugins/dockers/tasksetdocker/tasksetdocker_dock.h @@ -1,60 +1,63 @@ /* * Copyright (c) 2011 Sven Langkamp * * This library is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; version 2.1 of the License. * * 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser 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 TASKSETDOCKER_DOCK_H #define TASKSETDOCKER_DOCK_H #include #include +#include + #include -#include "ui_wdgtasksetdocker.h" #include -#include "taskset_resource.h" +#include + +#include "taskset_resource.h" +#include "ui_wdgtasksetdocker.h" class KoResourceLoaderThread; class TasksetModel; -class KisCanvas2; class TasksetDockerDock : public QDockWidget, public KoCanvasObserverBase, public Ui_WdgTasksetDocker { Q_OBJECT public: TasksetDockerDock(); ~TasksetDockerDock(); QString observerName() { return "TasksetDockerDock"; } virtual void setCanvas(KoCanvasBase *canvas); virtual void unsetCanvas(); private Q_SLOTS: void actionTriggered(QAction* action); void activated (const QModelIndex& index); void recordClicked(); void saveClicked(); void clearClicked(); void resourceSelected( KoResource * resource ); private: - KisCanvas2 *m_canvas; + QPointer m_canvas; TasksetModel *m_model; bool m_blocked; KoResourceServer* m_rserver; KoResourceLoaderThread *m_taskThread; }; #endif diff --git a/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp b/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp index 4b7695d962..21959aeed2 100644 --- a/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp +++ b/plugins/filters/phongbumpmap/kis_phong_bumpmap_filter.cpp @@ -1,238 +1,238 @@ /* * Copyright (c) 2010-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 "kis_phong_bumpmap_filter.h" #include "kis_phong_bumpmap_config_widget.h" #include "phong_pixel_processor.h" #include "kis_debug.h" #include "kis_paint_device.h" #include "kis_config_widget.h" #include "KoUpdater.h" #include "kis_math_toolbox.h" #include "KoColorSpaceRegistry.h" #include #include #include "kis_iterator_ng.h" #include "kundo2command.h" #include "kis_painter.h" KisFilterPhongBumpmap::KisFilterPhongBumpmap() - : KisFilter(KoID("phongbumpmap" , i18n("PhongBumpmap")), - KisFilter::categoryMap(), i18n("&PhongBumpmap...")) + : KisFilter(KoID("phongbumpmap" , i18n("Phong Bumpmap")), + KisFilter::categoryMap(), i18n("&Phong Bumpmap...")) { setColorSpaceIndependence(TO_LAB16); setSupportsPainting(true); setSupportsLevelOfDetail(true); } void KisFilterPhongBumpmap::processImpl(KisPaintDeviceSP device, const QRect& applyRect, const KisFilterConfigurationSP config, KoUpdater *progressUpdater ) const { if (!config) return; if (progressUpdater) progressUpdater->setProgress(0); QString userChosenHeightChannel = config->getString(PHONG_HEIGHT_CHANNEL, "FAIL"); - bool m_usenormalmap = config->getBool(USE_NORMALMAP_IS_ENABLED); + bool m_usenormalmap = config->getBool(USE_NORMALMAP_IS_ENABLED); if (userChosenHeightChannel == "FAIL") { qDebug("FIX YOUR FILTER"); return; } KoChannelInfo *m_heightChannel = 0; Q_FOREACH (KoChannelInfo* channel, device->colorSpace()->channels()) { if (userChosenHeightChannel == channel->name()) { m_heightChannel = channel; } } if (!m_heightChannel) { m_heightChannel = device->colorSpace()->channels().first(); } KIS_ASSERT_RECOVER_RETURN(m_heightChannel); QRect inputArea = applyRect; QRect outputArea = applyRect; if (m_usenormalmap==false) { inputArea.adjust(-1, -1, 1, 1); } quint32 posup; quint32 posdown; quint32 posleft; quint32 posright; QColor I; //Reflected light if (progressUpdater) progressUpdater->setProgress(1); //======Preparation paraphlenalia======= //Hardcoded facts about Phong Bumpmap: it _will_ generate an RGBA16 bumpmap const quint8 BYTE_DEPTH_OF_BUMPMAP = 2; // 16 bits per channel const quint8 CHANNEL_COUNT_OF_BUMPMAP = 4; // RGBA const quint32 pixelsOfInputArea = abs(inputArea.width() * inputArea.height()); const quint32 pixelsOfOutputArea = abs(outputArea.width() * outputArea.height()); const quint8 pixelSize = BYTE_DEPTH_OF_BUMPMAP * CHANNEL_COUNT_OF_BUMPMAP; const quint32 bytesToFillBumpmapArea = pixelsOfOutputArea * pixelSize; QVector bumpmap(bytesToFillBumpmapArea); quint8 *bumpmapDataPointer = bumpmap.data(); quint32 ki = KoChannelInfo::displayPositionToChannelIndex(m_heightChannel->displayPosition(), device->colorSpace()->channels()); PhongPixelProcessor tileRenderer(pixelsOfInputArea, config); - + if (progressUpdater) progressUpdater->setProgress(2); //===============RENDER================= QVector toDoubleFuncPtr(device->colorSpace()->channels().count()); KisMathToolbox mathToolbox; if (!mathToolbox.getToDoubleChannelPtr(device->colorSpace()->channels(), toDoubleFuncPtr)) { return; } KisHLineConstIteratorSP iterator; quint32 curPixel = 0; iterator = device->createHLineConstIteratorNG(inputArea.x(), inputArea.y(), inputArea.width() ); if (m_usenormalmap==false) { for (qint32 srcRow = 0; srcRow < inputArea.height(); ++srcRow) { do { const quint8 *data = iterator->oldRawData(); tileRenderer.realheightmap[curPixel] = toDoubleFuncPtr[ki](data, device->colorSpace()->channels()[ki]->pos()); curPixel++; } while (iterator->nextPixel()); iterator->nextRow(); } if (progressUpdater) progressUpdater->setProgress(50); const int tileHeightMinus1 = inputArea.height() - 1; const int tileWidthMinus1 = inputArea.width() - 1; - + // Foreach INNER pixel in tile for (int y = 1; y < tileHeightMinus1; ++y) { for (int x = 1; x < tileWidthMinus1; ++x) { posup = (y + 1) * inputArea.width() + x; posdown = (y - 1) * inputArea.width() + x; posleft = y * inputArea.width() + x - 1; posright = y * inputArea.width() + x + 1; - + memcpy(bumpmapDataPointer, tileRenderer.IlluminatePixelFromHeightmap(posup, posdown, posleft, posright).data(), pixelSize); - + bumpmapDataPointer += pixelSize; } } } else { for (qint32 srcRow = 0; srcRow < inputArea.height(); ++srcRow) { do { const quint8 *data = iterator->oldRawData(); tileRenderer.realheightmap[curPixel] = toDoubleFuncPtr[ki](data, device->colorSpace()->channels()[ki]->pos()); QVector current_pixel_values(4); device->colorSpace()->normalisedChannelsValue(data, current_pixel_values ); //dbgKrita<< "Vector:" << current_pixel_values[2] << "," << current_pixel_values[1] << "," << current_pixel_values[0]; memcpy(bumpmapDataPointer, tileRenderer.IlluminatePixelFromNormalmap(current_pixel_values[2], current_pixel_values[1], current_pixel_values[0]).data(), pixelSize); - + curPixel++; //pointer that crashes here, but not in the other if statement. bumpmapDataPointer += pixelSize; - - - + + + } while (iterator->nextPixel()); iterator->nextRow(); } } if (progressUpdater) progressUpdater->setProgress(90); KisPaintDeviceSP bumpmapPaintDevice = new KisPaintDevice(KoColorSpaceRegistry::instance()->rgb16()); bumpmapPaintDevice->writeBytes(bumpmap.data(), outputArea.x(), outputArea.y(), outputArea.width(), outputArea.height()); KUndo2Command *leaker = bumpmapPaintDevice->convertTo(device->colorSpace(), KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::internalConversionFlags()); KisPainter copier(device); copier.bitBlt(outputArea.x(), outputArea.y(), bumpmapPaintDevice, outputArea.x(), outputArea.y(), outputArea.width(), outputArea.height()); //device->prepareClone(bumpmapPaintDevice); //device->makeCloneFrom(bumpmapPaintDevice, bumpmapPaintDevice->extent()); // THIS COULD BE BUG GY - + delete leaker; if (progressUpdater) progressUpdater->setProgress(100); } KisFilterConfigurationSP KisFilterPhongBumpmap::factoryConfiguration() const { KisFilterConfigurationSP config = new KisFilterConfiguration(id(), 2); config->setProperty(PHONG_AMBIENT_REFLECTIVITY, 0.2); config->setProperty(PHONG_DIFFUSE_REFLECTIVITY, 0.5); config->setProperty(PHONG_SPECULAR_REFLECTIVITY, 0.3); config->setProperty(PHONG_SHINYNESS_EXPONENT, 2); config->setProperty(USE_NORMALMAP_IS_ENABLED, false); config->setProperty(PHONG_DIFFUSE_REFLECTIVITY_IS_ENABLED, true); config->setProperty(PHONG_SPECULAR_REFLECTIVITY_IS_ENABLED, true); // Indexes are off by 1 simply because arrays start at 0 and the GUI naming scheme started at 1 config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[0], true); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[1], true); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[2], false); config->setProperty(PHONG_ILLUMINANT_IS_ENABLED[3], false); config->setProperty(PHONG_ILLUMINANT_COLOR[0], QColor(255, 255, 0)); config->setProperty(PHONG_ILLUMINANT_COLOR[1], QColor(255, 0, 0)); config->setProperty(PHONG_ILLUMINANT_COLOR[2], QColor(0, 0, 255)); config->setProperty(PHONG_ILLUMINANT_COLOR[3], QColor(0, 255, 0)); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[0], 50); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[1], 100); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[2], 150); config->setProperty(PHONG_ILLUMINANT_AZIMUTH[3], 200); config->setProperty(PHONG_ILLUMINANT_INCLINATION[0], 25); config->setProperty(PHONG_ILLUMINANT_INCLINATION[1], 20); config->setProperty(PHONG_ILLUMINANT_INCLINATION[2], 30); config->setProperty(PHONG_ILLUMINANT_INCLINATION[3], 40); return config; } QRect KisFilterPhongBumpmap::neededRect(const QRect &rect, const KisFilterConfigurationSP /*config*/, int /*lod*/) const { return rect.adjusted(-1, -1, 1, 1); } QRect KisFilterPhongBumpmap::changedRect(const QRect &rect, const KisFilterConfigurationSP /*config*/, int /*lod*/) const { return rect; } KisConfigWidget *KisFilterPhongBumpmap::createConfigurationWidget(QWidget *parent, const KisPaintDeviceSP dev) const { KisPhongBumpmapConfigWidget *w = new KisPhongBumpmapConfigWidget(dev, parent); return w; } diff --git a/plugins/filters/phongbumpmap/wdgphongbumpmap.ui b/plugins/filters/phongbumpmap/wdgphongbumpmap.ui index 7c1e8438ff..27393b62b6 100644 --- a/plugins/filters/phongbumpmap/wdgphongbumpmap.ui +++ b/plugins/filters/phongbumpmap/wdgphongbumpmap.ui @@ -1,1234 +1,1234 @@ WdgPhongBumpmap 0 0 670 346 0 0 570 323 570 323 QLayout::SetDefaultConstraint 0 0 0 0 0 0 0 General settings 0 0 Material properties true Specula&r Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter true true 0 3 0 0 Reflectivity: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 1 1 0 20 16777215 23 Shinyness exponent: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 1 1 0 20 16777215 23 Qt::Horizontal QSizePolicy::Fixed 150 0 Qt::LeftToRight Di&ffuse Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter true true 0 3 0 0 Reflectivity: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 1 1 0 20 16777215 23 Qt::Horizontal QSizePolicy::Fixed 150 0 Ambient true false 0 3 0 0 6 Reflectivity: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 1 1 0 20 16777215 23 Qt::Horizontal QSizePolicy::Fixed 150 0 Heightmap channel: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Qt::Vertical QSizePolicy::Fixed 20 16 Qt::Vertical QSizePolicy::MinimumExpanding 20 9 - Use Normalmap + Use Normal map false Light Sources 0 0 Light Source &4 true true false QFormLayout::AllNonFixedFieldsGrow 0 3 Color: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 255 255 0 Direction of the light, the dial tip represents where the light comes from. Azimuth: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Direction of the light, the dial tip represents where the light comes from. true ° 0 359 15 180 Vertical tilt of the light. 90° is perpendicular to the canvas, 0° is parallel. Inclination: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Vertical tilt of the light. 90° is perpendicular to the canvas, 0° is parallel. ° 0 90 15 45 Azimuth 359 5 45 180 180 true Qt::Horizontal false false true 45.000000000000000 false 0 0 Light Source &2 true true 0 3 Color: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 255 0 0 Direction of the light, the dial tip represents where the light comes from. Azimuth: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Direction of the light, the dial tip represents where the light comes from. true ° 0 359 15 33 Vertical tilt of the light. 90° is perpendicular to the canvas, 0° is parallel. Inclination: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Vertical tilt of the light. 90° is perpendicular to the canvas, 0° is parallel. ° 0 90 15 45 Azimuth 359 5 45 33 33 true Qt::Horizontal false false true 45.000000000000000 false 0 0 Light Source &1 true true 0 3 6 6 Color: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 255 255 0 Direction of the light, the dial tip represents where the light comes from. Azimuth: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Direction of the light, the dial tip represents where the light comes from. true ° 0 359 15 127 Vertical tilt of the light. 90° is perpendicular to the canvas, 0° is parallel. Inclination: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Vertical tilt of the light. 90° is perpendicular to the canvas, 0° is parallel. ° 0 90 15 45 Azimuth 359 5 45 127 127 true Qt::Horizontal false false true 45.000000000000000 false 0 0 Light Source &3 true true false 0 3 Color: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 255 0 Direction of the light, the dial tip represents where the light comes from. Azimuth: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Direction of the light, the dial tip represents where the light comes from. true ° 0 359 15 180 Vertical tilt of the light. 90° is perpendicular to the canvas, 0° is parallel. Inclination: Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 Vertical tilt of the light. 90° is perpendicular to the canvas, 0° is parallel. ° 0 90 15 45 Azimuth 359 5 45 180 180 true Qt::Horizontal false false true 45.000000000000000 false Qt::Vertical 20 0 KisIntParseSpinBox QSpinBox
kis_int_parse_spin_box.h
KColorCombo QComboBox
kcolorcombo.h
KisDoubleSliderSpinBox QWidget
kis_slider_spin_box.h
1
KisSliderSpinBox QWidget
kis_slider_spin_box.h
1
settingsTabWidget heightChannelComboBox diffuseReflectivityGroup specularReflectivityGroup lightSourceGroupBox1 lightKColorCombo1 azimuthSpinBox1 inclinationSpinBox1 azimuthDial1 lightSourceGroupBox2 lightKColorCombo2 azimuthSpinBox2 inclinationSpinBox2 azimuthDial2 lightSourceGroupBox3 lightKColorCombo3 azimuthSpinBox3 inclinationSpinBox3 azimuthDial3 lightSourceGroupBox4 lightKColorCombo4 azimuthSpinBox4 inclinationSpinBox4 azimuthDial4
diff --git a/plugins/flake/artistictextshape/ArtisticTextToolSelection.h b/plugins/flake/artistictextshape/ArtisticTextToolSelection.h index 1287e7896e..4b159adb59 100644 --- a/plugins/flake/artistictextshape/ArtisticTextToolSelection.h +++ b/plugins/flake/artistictextshape/ArtisticTextToolSelection.h @@ -1,74 +1,76 @@ /* This file is part of the KDE project * Copyright (C) 2011 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef ARTISTICTEXTTOOLSELECTION_H #define ARTISTICTEXTTOOLSELECTION_H #include #include +#include + +#include class ArtisticTextShape; -class KoCanvasBase; class KoViewConverter; class QPainter; class ArtisticTextToolSelection : public KoToolSelection { public: explicit ArtisticTextToolSelection(KoCanvasBase *canvas, QObject *parent = 0); virtual ~ArtisticTextToolSelection(); // reimplemented from KoToolSelection virtual bool hasSelection(); /// Sets the currently selected text shape void setSelectedShape(ArtisticTextShape *textShape); /// Returns the currently selected text shape ArtisticTextShape *selectedShape() const; /// Selects specified range of characters void selectText(int from, int to); /// Returns the start character index of the selection int selectionStart() const; /// Returns number of selected characters int selectionCount() const; /// Clears the selection void clear(); /// Paints the selection void paint(QPainter &painter, const KoViewConverter &converter); /// Triggers a repaint of the selection void repaintDecoration(); private: /// Returns the outline of the selection in document coordinates QPainterPath outline(); - KoCanvasBase *m_canvas; + QPointer m_canvas; ArtisticTextShape *m_currentShape; ///< the currently selected text shape int m_selectionStart; int m_selectionCount; }; #endif // ARTISTICTEXTTOOLSELECTION_H diff --git a/plugins/flake/textshape/ReferencesTool.h b/plugins/flake/textshape/ReferencesTool.h index e6c1618646..4e01db1eb7 100644 --- a/plugins/flake/textshape/ReferencesTool.h +++ b/plugins/flake/textshape/ReferencesTool.h @@ -1,134 +1,136 @@ /* This file is part of the KDE project * Copyright (C) 2011 C. Boemann * Copyright (C) 2013 Aman Madaan * * 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. */ #ifndef REFERENCESTOOL_H #define REFERENCESTOOL_H #include "TextTool.h" #include +#include + +#include -class KoCanvasBase; class TableOfContentsConfigure; class SimpleTableOfContentsWidget; class SimpleFootEndNotesWidget; class SimpleCitationBibliographyWidget; class KoInlineNote; class KoTextEditor; class KoBibliographyInfo; class KoTableOfContentsGeneratorInfo; class SimpleLinksWidget; class LabeledWidget; /// This tool is the ui for inserting Table of Contents, Citations/bibliography, footnotes, endnotes, index, table of illustrations etc class ReferencesTool : public TextTool { Q_OBJECT public: explicit ReferencesTool(KoCanvasBase *canvas); virtual ~ReferencesTool(); virtual void activate(ToolActivation toolActivation, const QSet &shapes); virtual void deactivate(); virtual void createActions(); KoTextEditor *editor(); /// inserts a ToC and open a configure dialog for customization void insertCustomToC(KoTableOfContentsGeneratorInfo *defaultTemplate); /// insert a bibliography and open a configure dialog for customization void insertCustomBibliography(KoBibliographyInfo *defaultTemplate); protected: /// reimplemented from superclass virtual QList > createOptionWidgets(); private Q_SLOTS: /// insert a citation void insertCitation(); /// configure a bibliography void configureBibliography(); /// format the table of contents template void formatTableOfContents(); /// shows the configuration dialog for a ToC void showConfigureDialog(QAction *action); /// hides the configuration dialog for ToC void hideCofigureDialog(); /// insert an autonumbered footnote void insertAutoFootNote(); /// insert a labeled footnote void insertLabeledFootNote(const QString &label); /// insert an autonumbered endnote void insertAutoEndNote(); /// insert a labeled endnote void insertLabeledEndNote(const QString &label); /// show the configuration dialog for footnotes void showFootnotesConfigureDialog(); /// show the configuration dialog for endnotes void showEndnotesConfigureDialog(); /// enable/disable buttons if cursor in notes' body or not void updateButtons(); void customToCGenerated(); /// insert a Link void insertLink(); ///insert a bookmark void insertBookmark(QString bookmarkName); /// validate a bookmark bool validateBookmark(QString bookmarkName); private: TableOfContentsConfigure *m_configure; SimpleTableOfContentsWidget *m_stocw; SimpleFootEndNotesWidget *m_sfenw; KoInlineNote *m_note; SimpleCitationBibliographyWidget *m_scbw; SimpleLinksWidget *m_slw; LabeledWidget *m_bmark; - KoCanvasBase *m_canvas; + QPointer m_canvas; }; class QAction; class QLineEdit; class QLabel; class LabeledWidget : public QWidget { Q_OBJECT public: enum LabelPosition {INLINE, ABOVE}; LabeledWidget(QAction *action, const QString &label, LabelPosition pos, bool warningLabelRequired); void setWarningText(int pos, const QString &warning); void clearLineEdit(); Q_SIGNALS: void triggered(const QString &label); void lineEditChanged(const QString &); private Q_SLOTS: void returnPressed(); protected: virtual void enterEvent(QEvent *event); private : QLineEdit *m_lineEdit; QLabel *m_warningLabel[2]; QAction *m_action; }; #endif // REFERENCESTOOL_H diff --git a/plugins/flake/textshape/ReviewTool.h b/plugins/flake/textshape/ReviewTool.h index 6ef37a85f4..17ded8cbf6 100644 --- a/plugins/flake/textshape/ReviewTool.h +++ b/plugins/flake/textshape/ReviewTool.h @@ -1,70 +1,72 @@ /* This file is part of the KDE project * Copyright (C) 2009 Pierre Stirnweiss * * 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. */ #ifndef REVIEWTOOL_H #define REVIEWTOOL_H -class KoCanvasBase; +#include +#include + class KoPointerEvent; class KoTextEditor; class KoTextShapeData; class KoViewConverter; class TextShape; class QAction; class QPainter; class QKeyEvent; template class QVector; /// This tool allows to manipulate the tracked changes of a document. You can accept or reject changes. #include class ReviewTool : public TextTool { Q_OBJECT public: explicit ReviewTool(KoCanvasBase *canvas); ~ReviewTool(); virtual void mouseReleaseEvent(KoPointerEvent *event); virtual void mouseMoveEvent(KoPointerEvent *event); virtual void mousePressEvent(KoPointerEvent *event); virtual void paint(QPainter &painter, const KoViewConverter &converter); virtual void keyPressEvent(QKeyEvent *event); virtual void activate(ToolActivation toolActivation, const QSet &shapes); virtual void deactivate(); virtual void createActions(); virtual QList > createOptionWidgets(); public Q_SLOTS: void removeAnnotation(); private: KoTextEditor *m_textEditor; KoTextShapeData *m_textShapeData; - KoCanvasBase *m_canvas; + QPointer m_canvas; TextShape *m_textShape; QAction *m_removeAnnotationAction; KoShape *m_currentAnnotationShape; }; #endif // REVIEWTOOL_H diff --git a/plugins/flake/textshape/commands/ShowChangesCommand.h b/plugins/flake/textshape/commands/ShowChangesCommand.h index bf20ac2731..2ac4691bd4 100644 --- a/plugins/flake/textshape/commands/ShowChangesCommand.h +++ b/plugins/flake/textshape/commands/ShowChangesCommand.h @@ -1,66 +1,70 @@ /* This file is part of the KDE project * Copyright (C) 2009 Ganesh Paramasivam * Copyright (C) 2009 Pierre Stirnweiss * * 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.*/ #ifndef SHOWCHANGECOMMAND_H #define SHOWCHANGECOMMAND_H #include "KoTextCommandBase.h" + #include +#include #include +#include + class KoChangeTracker; class KoTextEditor; -class KoCanvasBase; + class QTextDocument; class ShowChangesCommand : public QObject, public KoTextCommandBase { Q_OBJECT public: ShowChangesCommand(bool showChanges, QTextDocument *document, KoCanvasBase *canvas, KUndo2Command *parent = 0); ~ShowChangesCommand(); virtual void undo(); virtual void redo(); Q_SIGNALS: void toggledShowChange(bool on); private: void enableDisableChanges(); void enableDisableStates(bool showChanges); void insertDeletedChanges(); void checkAndAddAnchoredShapes(int position, int length); void removeDeletedChanges(); void checkAndRemoveAnchoredShapes(int position, int length); QTextDocument *m_document; KoChangeTracker *m_changeTracker; KoTextEditor *m_textEditor; bool m_first; bool m_showChanges; - KoCanvasBase *m_canvas; + QPointer m_canvas; QList m_shapeCommands; }; #endif // SHOWCHANGECOMMAND_H diff --git a/plugins/flake/textshape/kotext/InsertInlineObjectActionBase_p.h b/plugins/flake/textshape/kotext/InsertInlineObjectActionBase_p.h index a6dd41feda..7b527b2050 100644 --- a/plugins/flake/textshape/kotext/InsertInlineObjectActionBase_p.h +++ b/plugins/flake/textshape/kotext/InsertInlineObjectActionBase_p.h @@ -1,47 +1,49 @@ /* This file is part of the KDE project * Copyright (C) 2007 Thomas Zander * * 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. */ #ifndef INSERTINLINEOBJECTACTIONBASE_H #define INSERTINLINEOBJECTACTIONBASE_H #include +#include + +#include -class KoCanvasBase; class KoInlineObject; /** * helper class */ class InsertInlineObjectActionBase : public QAction { Q_OBJECT public: InsertInlineObjectActionBase(KoCanvasBase *canvas, const QString &name); virtual ~InsertInlineObjectActionBase(); private Q_SLOTS: void activated(); protected: virtual KoInlineObject *createInlineObject() = 0; - KoCanvasBase *m_canvas; + QPointer m_canvas; }; #endif diff --git a/plugins/flake/textshape/kotext/commands/TextPasteCommand.h b/plugins/flake/textshape/kotext/commands/TextPasteCommand.h index 8bd673a2ba..a9158dfdd0 100644 --- a/plugins/flake/textshape/kotext/commands/TextPasteCommand.h +++ b/plugins/flake/textshape/kotext/commands/TextPasteCommand.h @@ -1,57 +1,58 @@ /* This file is part of the KDE project * Copyright (C) 2009 Pierre Stirnweiss * * 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.*/ #ifndef TEXTPASTECOMMAND_H #define TEXTPASTECOMMAND_H +#include #include #include #include +#include class QTextDocument; class KoDocumentRdfBase; class KoShapeController; class QMimeData; -class KoCanvasBase; class TextPasteCommand : public KUndo2Command { public: TextPasteCommand(const QMimeData *mimeData, QTextDocument *document, KoShapeController *shapeController, KoCanvasBase *canvas, KUndo2Command *parent = 0, bool pasteAsText = false); virtual void undo(); virtual void redo(); private: const QMimeData *m_mimeData; QWeakPointer m_document; KoDocumentRdfBase *m_rdf; KoShapeController *m_shapeController; - KoCanvasBase *m_canvas; + QPointer m_canvas; bool m_pasteAsText; bool m_first; }; #endif // TEXTPASTECOMMAND_H diff --git a/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp b/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp index e2346f550c..0920a5f7b8 100644 --- a/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp +++ b/plugins/paintops/libpaintop/kis_clipboard_brush_widget.cpp @@ -1,159 +1,160 @@ /* * Copyright (c) 2005 Bart Coppens * Copyright (c) 2010 Lukáš Tvrdý * Copyright (c) 2013 Somsubhra Bairi * * 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_clipboard_brush_widget.h" #include #include #include #include #include #include #include #include "kis_image.h" #include "kis_clipboard.h" #include "kis_paint_device.h" #include "kis_gbr_brush.h" #include "kis_brush_server.h" KisClipboardBrushWidget::KisClipboardBrushWidget(QWidget *parent, const QString &caption, KisImageWSP image) : KisWdgClipboardBrush(parent), m_image(image) { setWindowTitle(caption); preview->setScaledContents(true); preview->setFixedSize(preview->size()); preview->setStyleSheet("border: 2px solid #222; border-radius: 4px; padding: 5px; font: normal 10px;"); KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer(); m_rServerAdapter = QSharedPointer(new KisBrushResourceServerAdapter(rServer)); m_brush = 0; m_clipboard = KisClipboard::instance(); connect(m_clipboard, SIGNAL(clipChanged()), this, SLOT(slotCreateBrush())); connect(colorAsmask, SIGNAL(toggled(bool)), this, SLOT(slotUpdateUseColorAsMask(bool))); connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotAddPredefined())); spacingWidget->setSpacing(true, 1.0); connect(spacingWidget, SIGNAL(sigSpacingChanged()), SLOT(slotSpacingChanged())); } KisClipboardBrushWidget::~KisClipboardBrushWidget() { } void KisClipboardBrushWidget::slotCreateBrush() { // do nothing if it's hidden otherwise it can break the active brush is something is copied if (m_clipboard->hasClip() && !isHidden()) { pd = m_clipboard->clip(QRect(0, 0, 0, 0), false); //Weird! Don't know how this works! if (pd) { QRect rc = pd->exactBounds(); m_brush = new KisGbrBrush(pd, rc.x(), rc.y(), rc.width(), rc.height()); m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); m_brush->setFilename(TEMPORARY_CLIPBOARD_BRUSH_FILENAME); m_brush->setName(TEMPORARY_CLIPBOARD_BRUSH_NAME); m_brush->setValid(true); preview->setPixmap(QPixmap::fromImage(m_brush->image())); } } else { preview->setText(i18n("Nothing copied\n to Clipboard")); } if(m_brush == 0) { buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - } else { + } else { buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + colorAsmask->setChecked(true); // initializing this has to happen here since we need a valid brush for it to work } } void KisClipboardBrushWidget::slotSpacingChanged() { if (m_brush) { m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); } } void KisClipboardBrushWidget::showEvent(QShowEvent *) { slotCreateBrush(); } void KisClipboardBrushWidget::slotUpdateUseColorAsMask(bool useColorAsMask) { if (m_brush) { static_cast(m_brush.data())->setUseColorAsMask(useColorAsMask); preview->setPixmap(QPixmap::fromImage(m_brush->brushTipImage())); } } void KisClipboardBrushWidget::slotAddPredefined() { if(!m_brush) return; QString dir = KoResourcePaths::saveLocation("data", "brushes"); QString extension = ".gbr"; QString name = nameEdit->text(); QString tempFileName; QFileInfo fileInfo; fileInfo.setFile(dir + name + extension); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(dir + name + QString("%1").arg(i) + extension); i++; } tempFileName = fileInfo.filePath(); if (m_rServerAdapter) { KisGbrBrush *resource = dynamic_cast(m_brush->clone()); resource->setFilename(tempFileName); if (nameEdit->text().isEmpty()) { resource->setName(QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm")); } else { resource->setName(name); } if (colorAsmask->isChecked()) { resource->makeMaskImage(); } m_rServerAdapter->addResource(resource); emit sigNewPredefinedBrush(resource); } close(); } #include "moc_kis_clipboard_brush_widget.cpp" diff --git a/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp b/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp index 65ead643ee..6f6b2a8002 100644 --- a/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp +++ b/plugins/paintops/libpaintop/kis_custom_brush_widget.cpp @@ -1,251 +1,253 @@ /* * Copyright (c) 2005 Bart Coppens * Copyright (c) 2010 Lukáš Tvrdý * * 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_custom_brush_widget.h" #include #include #include #include #include #include #include #include #include #include #include "kis_image.h" #include "kis_layer.h" #include "kis_paint_device.h" #include "kis_gbr_brush.h" #include "kis_imagepipe_brush.h" #include #include "kis_brush_server.h" #include "kis_paint_layer.h" #include "kis_group_layer.h" #include #include #include "kis_iterator_ng.h" KisCustomBrushWidget::KisCustomBrushWidget(QWidget *parent, const QString& caption, KisImageWSP image) : KisWdgCustomBrush(parent) , m_image(image) { setWindowTitle(caption); preview->setScaledContents(true); preview->setFixedSize(preview->size()); preview->setStyleSheet("border: 2px solid #222; border-radius: 4px; padding: 5px; font: normal 10px;"); KisBrushResourceServer* rServer = KisBrushServer::instance()->brushServer(); m_rServerAdapter = QSharedPointer(new KisBrushResourceServerAdapter(rServer)); m_brush = 0; connect(this, SIGNAL(accepted()), SLOT(slotAddPredefined())); connect(brushStyle, SIGNAL(activated(int)), this, SLOT(slotUpdateCurrentBrush(int))); - connect(colorAsMask, SIGNAL(toggled(bool)), this, SLOT(slotUpdateUseColorAsMask(bool))); + connect(colorAsMask, SIGNAL(toggled(bool)), this, SLOT(slotUpdateUscColorAsMask(bool))); + + colorAsMask->setChecked(true); // use color as mask by default. This is by far the most common way to make tip. spacingWidget->setSpacing(true, 1.0); connect(spacingWidget, SIGNAL(sigSpacingChanged()), SLOT(slotSpacingChanged())); } KisCustomBrushWidget::~KisCustomBrushWidget() { } KisBrushSP KisCustomBrushWidget::brush() { return m_brush; } void KisCustomBrushWidget::showEvent(QShowEvent *) { slotUpdateCurrentBrush(0); } void KisCustomBrushWidget::slotUpdateCurrentBrush(int) { if (brushStyle->currentIndex() == 0) { comboBox2->setEnabled(false); } else { comboBox2->setEnabled(true); } if (m_image) { createBrush(); if (m_brush) { preview->setPixmap(QPixmap::fromImage(m_brush->brushTipImage())); } } } void KisCustomBrushWidget::slotSpacingChanged() { if (m_brush) { m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); } } void KisCustomBrushWidget::slotUpdateUseColorAsMask(bool useColorAsMask) { if (m_brush) { static_cast(m_brush.data())->setUseColorAsMask(useColorAsMask); preview->setPixmap(QPixmap::fromImage(m_brush->brushTipImage())); } } void KisCustomBrushWidget::slotAddPredefined() { QString dir = KoResourcePaths::saveLocation("data", "brushes"); QString extension; if (brushStyle->currentIndex() == 0) { extension = ".gbr"; } else { extension = ".gih"; } QString name = nameLineEdit->text(); QString tempFileName; { QFileInfo fileInfo; fileInfo.setFile(dir + name + extension); int i = 1; while (fileInfo.exists()) { fileInfo.setFile(dir + name + QString("%1").arg(i) + extension); i++; } tempFileName = fileInfo.filePath(); } // Add it to the brush server, so that it automatically gets to the mediators, and // so to the other brush choosers can pick it up, if they want to if (m_rServerAdapter && m_brush) { qDebug() << "m_brush" << m_brush; KisGbrBrush *resource = dynamic_cast(m_brush->clone()); resource->setFilename(tempFileName); if (nameLineEdit->text().isEmpty()) { resource->setName(QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm")); } else { resource->setName(name); } if (colorAsMask->isChecked()) { resource->makeMaskImage(); } m_rServerAdapter->addResource(resource); emit sigNewPredefinedBrush(resource); } close(); } void KisCustomBrushWidget::createBrush() { if (!m_image) return; if (brushStyle->currentIndex() == 0) { KisSelectionSP selection = m_image->globalSelection(); // create copy of the data m_image->lock(); KisPaintDeviceSP dev = new KisPaintDevice(*m_image->projection()); m_image->unlock(); if (!selection) { m_brush = new KisGbrBrush(dev, 0, 0, m_image->width(), m_image->height()); } else { // apply selection mask QRect r = selection->selectedExactRect(); dev->crop(r); KisHLineIteratorSP pixelIt = dev->createHLineIteratorNG(r.x(), r.top(), r.width()); KisHLineConstIteratorSP maskIt = selection->projection()->createHLineIteratorNG(r.x(), r.top(), r.width()); for (qint32 y = r.top(); y <= r.bottom(); ++y) { do { dev->colorSpace()->applyAlphaU8Mask(pixelIt->rawData(), maskIt->oldRawData(), 1); } while (pixelIt->nextPixel() && maskIt->nextPixel()); pixelIt->nextRow(); maskIt->nextRow(); } QRect rc = dev->exactBounds(); m_brush = new KisGbrBrush(dev, rc.x(), rc.y(), rc.width(), rc.height()); } } else { // For each layer in the current image, create a new image, and add it to the list QVector< QVector > devices; devices.push_back(QVector()); int w = m_image->width(); int h = m_image->height(); m_image->lock(); // We only loop over the rootLayer. Since we actually should have a layer selection // list, no need to elaborate on that here and now KoProperties properties; properties.setProperty("visible", true); QList layers = m_image->root()->childNodes(QStringList("KisLayer"), properties); KisNodeSP node; Q_FOREACH (KisNodeSP node, layers) { devices[0].push_back(node->projection().data()); } QVector modes; switch (comboBox2->currentIndex()) { case 0: modes.push_back(KisParasite::Constant); break; case 1: modes.push_back(KisParasite::Random); break; case 2: modes.push_back(KisParasite::Incremental); break; case 3: modes.push_back(KisParasite::Pressure); break; case 4: modes.push_back(KisParasite::Angular); break; default: modes.push_back(KisParasite::Incremental); } m_brush = new KisImagePipeBrush(m_image->objectName(), w, h, devices, modes); m_image->unlock(); } static_cast(m_brush.data())->setUseColorAsMask(colorAsMask->isChecked()); m_brush->setSpacing(spacingWidget->spacing()); m_brush->setAutoSpacing(spacingWidget->autoSpacingActive(), spacingWidget->autoSpacingCoeff()); m_brush->setFilename(TEMPORARY_FILENAME); m_brush->setName(TEMPORARY_BRUSH_NAME); m_brush->setValid(true); } diff --git a/plugins/tools/defaulttool/defaulttool/ShapeMoveStrategy.h b/plugins/tools/defaulttool/defaulttool/ShapeMoveStrategy.h index 4cfc4479ab..4e6678682c 100644 --- a/plugins/tools/defaulttool/defaulttool/ShapeMoveStrategy.h +++ b/plugins/tools/defaulttool/defaulttool/ShapeMoveStrategy.h @@ -1,63 +1,65 @@ /* This file is part of the KDE project Copyright (C) 2006 Thorsten Zachmann Copyright (C) 2006-2007 Thomas Zander 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. */ #ifndef SHAPEMOVESTRATEGY_H #define SHAPEMOVESTRATEGY_H #include +#include #include #include -class KoCanvasBase; +#include + class KoToolBase; class KoShape; /** * Implements the Move action on an object or selected objects. */ class ShapeMoveStrategy : public KoInteractionStrategy { public: /** * Constructor that starts to move the objects. * @param tool the parent tool which controls this strategy * @param canvas the canvas interface which will supply things like a selection object * @param clicked the initial point that the user depressed (in pt). */ ShapeMoveStrategy(KoToolBase *tool, const QPointF &clicked); virtual ~ShapeMoveStrategy() {} void handleMouseMove(const QPointF &mouseLocation, Qt::KeyboardModifiers modifiers); KUndo2Command *createCommand(); void finishInteraction(Qt::KeyboardModifiers modifiers); virtual void paint(QPainter &painter, const KoViewConverter &converter); virtual void handleCustomEvent(KoPointerEvent *event); private: void moveSelection(); QList m_previousPositions; QList m_newPositions; QPointF m_start, m_diff, m_initialSelectionPosition, m_initialOffset; QList m_selectedShapes; - KoCanvasBase *m_canvas; + QPointer m_canvas; }; #endif diff --git a/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.h b/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.h index c5428462bd..6293b6082a 100644 --- a/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.h +++ b/plugins/tools/karbonplugins/tools/filterEffectTool/FilterEffectEditWidget.h @@ -1,69 +1,71 @@ /* This file is part of the KDE project * Copyright (c) 2009 Jan Hambrecht * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 Lesser 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. */ #ifndef FILTEREFFECTEDITWIDGET_H #define FILTEREFFECTEDITWIDGET_H #include "ui_FilterEffectEditWidget.h" #include "FilterEffectScene.h" #include +#include + +#include class KoShape; -class KoCanvasBase; class KoFilterEffect; class KoFilterEffectStack; class FilterEffectEditWidget : public QWidget, Ui::FilterEffectEditWidget { Q_OBJECT public: explicit FilterEffectEditWidget(QWidget *parent = 0); ~FilterEffectEditWidget(); /// Edits effects of given shape void editShape(KoShape *shape, KoCanvasBase *canvas); protected: /// reimplemented from QWidget virtual void resizeEvent(QResizeEvent *event); /// reimplemented from QWidget virtual void showEvent(QShowEvent *event); private Q_SLOTS: void addSelectedEffect(); void removeSelectedItem(); void connectionCreated(ConnectionSource source, ConnectionTarget target); void addToPresets(); void removeFromPresets(); void presetSelected(KoResource *resource); void filterChanged(); void sceneSelectionChanged(); void defaultSourceChanged(int); private: void fitScene(); void addWidgetForItem(ConnectionSource item); FilterEffectScene *m_scene; KoShape *m_shape; - KoCanvasBase *m_canvas; + QPointer m_canvas; KoFilterEffectStack *m_effects; ConnectionSource m_currentItem; KComboBox *m_defaultSourceSelector; }; #endif // FILTEREFFECTEDITWIDGET_H diff --git a/plugins/tools/tool_transform2/kis_tool_transform.h b/plugins/tools/tool_transform2/kis_tool_transform.h index 407889374e..0bee4ec5ae 100644 --- a/plugins/tools/tool_transform2/kis_tool_transform.h +++ b/plugins/tools/tool_transform2/kis_tool_transform.h @@ -1,335 +1,333 @@ /* * kis_tool_transform.h - part of Krita * * Copyright (c) 2004 Boudewijn Rempt * Copyright (c) 2005 C. Boemann * Copyright (c) 2010 Marc Pegon * * 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_TOOL_TRANSFORM_H_ #define KIS_TOOL_TRANSFORM_H_ #include #include #include #include #include #include +#include #include #include #include #include #include #include #include +#include #include "tool_transform_args.h" #include "tool_transform_changes_tracker.h" #include "kis_tool_transform_config_widget.h" #include "transform_transaction_properties.h" - - -class KisCanvas2; - class QTouchEvent; class KisTransformStrategyBase; class KisWarpTransformStrategy; class KisCageTransformStrategy; class KisLiquifyTransformStrategy; class KisFreeTransformStrategy; class KisPerspectiveTransformStrategy; /** * Transform tool * This tool offers several modes. * - Free Transform mode allows the user to translate, scale, shear, rotate and * apply a perspective transformation to a selection or the whole canvas. * - Warp mode allows the user to warp the selection of the canvas by grabbing * and moving control points placed on the image. The user can either work * with default control points, like a grid whose density can be modified, or * place the control points manually. The modifications made on the selected * pixels are applied only when the user clicks the Apply button : the * semi-transparent image displayed until the user click that button is only a * preview. * - Cage transform is similar to warp transform with control points exactly * placed on the outer boundary. The user draws a boundary polygon, the * vertices of which become control points. * - Perspective transform applies a two-point perspective transformation. The * user can manipulate the corners of the selection. If the vanishing points * of the resulting quadrilateral are on screen, the user can manipulate those * as well. * - Liquify transform transforms the selection by painting motions, as if the * user were fingerpainting. */ class KisToolTransform : public KisTool { Q_OBJECT Q_PROPERTY(TransformToolMode transformMode READ transformMode WRITE setTransformMode NOTIFY transformModeChanged) Q_PROPERTY(double translateX READ translateX WRITE setTranslateX NOTIFY freeTransformChanged) Q_PROPERTY(double translateY READ translateY WRITE setTranslateY NOTIFY freeTransformChanged) Q_PROPERTY(double rotateX READ rotateX WRITE setRotateX NOTIFY freeTransformChanged) Q_PROPERTY(double rotateY READ rotateY WRITE setRotateY NOTIFY freeTransformChanged) Q_PROPERTY(double rotateZ READ rotateZ WRITE setRotateZ NOTIFY freeTransformChanged) Q_PROPERTY(double scaleX READ scaleX WRITE setScaleX NOTIFY freeTransformChanged) Q_PROPERTY(double scaleY READ scaleY WRITE setScaleY NOTIFY freeTransformChanged) Q_PROPERTY(double shearX READ shearX WRITE setShearX NOTIFY freeTransformChanged) Q_PROPERTY(double shearY READ shearY WRITE setShearY NOTIFY freeTransformChanged) Q_PROPERTY(WarpType warpType READ warpType WRITE setWarpType NOTIFY warpTransformChanged) Q_PROPERTY(double warpFlexibility READ warpFlexibility WRITE setWarpFlexibility NOTIFY warpTransformChanged) Q_PROPERTY(int warpPointDensity READ warpPointDensity WRITE setWarpPointDensity NOTIFY warpTransformChanged) public: enum TransformToolMode { FreeTransformMode, WarpTransformMode, CageTransformMode, LiquifyTransformMode, PerspectiveTransformMode }; Q_ENUMS(TransformToolMode) enum WarpType { RigidWarpType, AffineWarpType, SimilitudeWarpType }; Q_ENUMS(WarpType) KisToolTransform(KoCanvasBase * canvas); virtual ~KisToolTransform(); virtual QWidget* createOptionWidget(); virtual void mousePressEvent(KoPointerEvent *e); virtual void mouseMoveEvent(KoPointerEvent *e); virtual void mouseReleaseEvent(KoPointerEvent *e); virtual void touchEvent(QTouchEvent *event); void beginActionImpl(KoPointerEvent *event, bool usePrimaryAction, KisTool::AlternateAction action); void continueActionImpl(KoPointerEvent *event, bool usePrimaryAction, KisTool::AlternateAction action); void endActionImpl(KoPointerEvent *event, bool usePrimaryAction, KisTool::AlternateAction action); void activatePrimaryAction(); void deactivatePrimaryAction(); void beginPrimaryAction(KoPointerEvent *event); void continuePrimaryAction(KoPointerEvent *event); void endPrimaryAction(KoPointerEvent *event); void activateAlternateAction(AlternateAction action); void deactivateAlternateAction(AlternateAction action); void beginAlternateAction(KoPointerEvent *event, AlternateAction action); void continueAlternateAction(KoPointerEvent *event, AlternateAction action); void endAlternateAction(KoPointerEvent *event, AlternateAction action); void paint(QPainter& gc, const KoViewConverter &converter); TransformToolMode transformMode() const; double translateX() const; double translateY() const; double rotateX() const; double rotateY() const; double rotateZ() const; double scaleX() const; double scaleY() const; double shearX() const; double shearY() const; WarpType warpType() const; double warpFlexibility() const; int warpPointDensity() const; bool wantsTouch() const { return true; } public Q_SLOTS: virtual void activate(ToolActivation toolActivation, const QSet &shapes); virtual void deactivate(); // Applies the current transformation to the original paint device and commits it to the undo stack void applyTransform(); void setTransformMode( KisToolTransform::TransformToolMode newMode ); void setTranslateX(double translateX); void setTranslateY(double translateY); void setRotateX(double rotation); void setRotateY(double rotation); void setRotateZ(double rotation); void setScaleX(double scaleX); void setScaleY(double scaleY); void setShearX(double shearX); void setShearY(double shearY); void setWarpType(WarpType type); void setWarpFlexibility(double flexibility); void setWarpPointDensity(int density); protected Q_SLOTS: virtual void resetCursorStyle(); Q_SIGNALS: void transformModeChanged(); void freeTransformChanged(); void warpTransformChanged(); public Q_SLOTS: void requestUndoDuringStroke(); void requestStrokeEnd(); void requestStrokeCancellation(); void canvasUpdateRequested(); void cursorOutlineUpdateRequested(const QPointF &imagePos); // Update the widget according to m_currentArgs void updateOptionWidget(); void resetRotationCenterButtonsRequested(); void imageTooBigRequested(bool value); private: bool clearDevices(KisNodeSP node, bool recursive); void transformDevices(KisNodeSP node, bool recursive); void startStroke(ToolTransformArgs::TransformMode mode, bool forceReset); void endStroke(); void cancelStroke(); private: void outlineChanged(); // Sets the cursor according to mouse position (doesn't take shearing into account well yet) void setFunctionalCursor(); // Sets m_function according to mouse position and modifier void setTransformFunction(QPointF mousePos, Qt::KeyboardModifiers modifiers); void commitChanges(); bool tryInitTransformModeFromNode(KisNodeSP node); bool tryFetchArgsFromCommandAndUndo(ToolTransformArgs *args, ToolTransformArgs::TransformMode mode, KisNodeSP currentNode); void initTransformMode(ToolTransformArgs::TransformMode mode); void initGuiAfterTransformMode(); void initThumbnailImage(KisPaintDeviceSP previewDevice); void updateSelectionPath(); void updateApplyResetAvailability(); private: ToolTransformArgs m_currentArgs; bool m_actuallyMoveWhileSelected; // true <=> selection has been moved while clicked KisPaintDeviceSP m_selectedPortionCache; struct StrokeData { StrokeData() {} StrokeData(KisStrokeId strokeId) : m_strokeId(strokeId) {} void clear() { m_strokeId.clear(); m_clearedNodes.clear(); } const KisStrokeId strokeId() const { return m_strokeId; } void addClearedNode(KisNodeSP node) { m_clearedNodes.append(node); } const QVector& clearedNodes() const { return m_clearedNodes; } private: KisStrokeId m_strokeId; QVector m_clearedNodes; }; StrokeData m_strokeData; bool m_workRecursively; QPainterPath m_selectionPath; // original (unscaled) selection outline, used for painting decorations KisToolTransformConfigWidget *m_optionsWidget; - KisCanvas2 *m_canvas; + QPointer m_canvas; TransformTransactionProperties m_transaction; TransformChangesTracker m_changesTracker; /** * This artificial rect is used to store the image to flake * transformation. We check against this rect to get to know * whether zoom has changed. */ QRectF m_refRect; QScopedPointer m_warpStrategy; QScopedPointer m_cageStrategy; QScopedPointer m_liquifyStrategy; QScopedPointer m_freeStrategy; QScopedPointer m_perspectiveStrategy; KisTransformStrategyBase* currentStrategy() const; QPainterPath m_cursorOutline; private Q_SLOTS: void slotTrackerChangedConfig(); void slotUiChangedConfig(); void slotApplyTransform(); void slotResetTransform(); void slotRestartTransform(); void slotEditingFinished(); }; class KisToolTransformFactory : public KoToolFactoryBase { public: KisToolTransformFactory() : KoToolFactoryBase("KisToolTransform") { setToolTip(i18n("Transform a layer or a selection")); setSection(TOOL_TYPE_TRANSFORM); setIconName(koIconNameCStr("krita_tool_transform")); setShortcut(QKeySequence(Qt::CTRL + Qt::Key_T)); setPriority(2); setActivationShapeId(KRITA_TOOL_ACTIVATION_ID); } virtual ~KisToolTransformFactory() {} virtual KoToolBase * createTool(KoCanvasBase *canvas) { return new KisToolTransform(canvas); } }; #endif // KIS_TOOL_TRANSFORM_H_