diff --git a/libs/libkis/Document.cpp b/libs/libkis/Document.cpp index 6287751394..0a6e3673be 100644 --- a/libs/libkis/Document.cpp +++ b/libs/libkis/Document.cpp @@ -1,371 +1,373 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program 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 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 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 "Document.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct Document::Private { Private() {} QPointer document; bool ownsDocument {false}; }; Document::Document(KisDocument *document, bool ownsDocument, QObject *parent) : QObject(parent) , d(new Private) { d->document = document; d->ownsDocument = ownsDocument; } Document::~Document() { qDebug() << "Document" << this << "deleted"; delete d; } bool Document::batchmode() const { if (!d->document) return false; return d->document->fileBatchMode(); } void Document::setBatchmode(bool value) { if (!d->document) return; d->document->setFileBatchMode(value); } Node *Document::activeNode() const { QList activeNodes; Q_FOREACH(QPointer view, KisPart::instance()->views()) { if (view && view->document() == d->document) { activeNodes << view->currentNode(); } } if (activeNodes.size() > 0) { return new Node(d->document->image(), activeNodes.first()); } return new Node(d->document->image(), d->document->image()->root()->firstChild()); } void Document::setActiveNode(Node* value) { if (!value->node()) return; KisMainWindow *mainWin = KisPart::instance()->currentMainwindow(); if (!mainWin) return; KisViewManager *viewManager = mainWin->viewManager(); if (!viewManager) return; KisNodeManager *nodeManager = viewManager->nodeManager(); if (!nodeManager) return; KisNodeSelectionAdapter *selectionAdapter = nodeManager->nodeSelectionAdapter(); if (!selectionAdapter) return; selectionAdapter->setActiveNode(value->node()); } QString Document::colorDepth() const { if (!d->document) return ""; return d->document->image()->colorSpace()->colorDepthId().id(); } QString Document::colorModel() const { if (!d->document) return ""; return d->document->image()->colorSpace()->colorModelId().id(); } QString Document::colorProfile() const { if (!d->document) return ""; return d->document->image()->colorSpace()->profile()->name(); } bool Document::setColorProfile(const QString &value) { if (!d->document) return false; if (!d->document->image()) return false; const KoColorProfile *profile = KoColorSpaceRegistry::instance()->profileByName(value); if (!profile) return false; d->document->image()->lock(); bool retval = d->document->image()->assignImageProfile(profile); d->document->image()->unlock(); + d->document->image()->setModified(); d->document->image()->initialRefreshGraph(); return retval; } bool Document::setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile) { if (!d->document) return false; if (!d->document->image()) return false; const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth, colorProfile); if (!colorSpace) return false; d->document->image()->lock(); d->document->image()->convertImageColorSpace(colorSpace, KoColorConversionTransformation::IntentPerceptual, KoColorConversionTransformation::HighQuality | KoColorConversionTransformation::NoOptimization); d->document->image()->unlock(); + d->document->image()->setModified(); d->document->image()->initialRefreshGraph(); return true; } InfoObject* Document::documentInfo() const { return 0; } void Document::setDocumentInfo(InfoObject* value) { } QString Document::fileName() const { if (!d->document) return QString::null; return d->document->url().toLocalFile(); } void Document::setFileName(QString value) { } int Document::height() const { if (!d->document) return 0; KisImageSP image = d->document->image(); if (!image) return 0; return image->height(); } void Document::setHeight(int value) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; QRect rc = image->bounds(); rc.setHeight(value); image->resizeImage(rc); } InfoObject* Document::metaData() const { return 0; } void Document::setMetaData(InfoObject* value) { } QString Document::name() const { return QString(); } void Document::setName(QString value) { } int Document::resolution() const { if (!d->document) return 0; KisImageSP image = d->document->image(); if (!image) return 0; return qRound(d->document->image()->xRes() * 72); } void Document::setResolution(int value) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; d->document->image()->setResolution(value / 72.0, value / 72.0); } Node *Document::rootNode() const { if (!d->document) return 0; KisImageSP image = d->document->image(); if (!image) return 0; return new Node(image, image->root()); } Selection *Document::selection() const { return 0; } void Document::setSelection(Selection* value) { } int Document::width() const { if (!d->document) return 0; KisImageSP image = d->document->image(); if (!image) return 0; return image->width(); } void Document::setWidth(int value) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; QRect rc = image->bounds(); rc.setWidth(value); image->resizeImage(rc); } double Document::xRes() const { if (!d->document) return 0.0; if (!d->document->image()) return 0.0; return d->document->image()->xRes(); } void Document::setXRes(double xRes) const { if (!d->document) return; if (!d->document->image()) return; d->document->image()->setResolution(xRes, d->document->image()->yRes()); } double Document::yRes() const { if (!d->document) return 0.0; if (!d->document->image()) return 0.0; return d->document->image()->yRes(); } void Document::setyRes(double yRes) const { if (!d->document) return; if (!d->document->image()) return; d->document->image()->setResolution(d->document->image()->xRes(), yRes); } QByteArray Document::pixelData() const { QByteArray ba; if (!d->document) return ba; KisImageSP image = d->document->image(); if (!image) return ba; KisPaintDeviceSP dev = image->projection(); quint8 *data = new quint8[image->width() * image->height() * dev->pixelSize()]; dev->readBytes(data, 0, 0, image->width(), image->height()); ba = QByteArray((const char*)data, (int)(image->width() * image->height() * dev->pixelSize())); delete[] data; return ba; } bool Document::close() { if (d->ownsDocument) { KisPart::instance()->removeDocument(d->document); } return d->document->closeUrl(false); } void Document::crop(int x, int y, int w, int h) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; QRect rc(x, y, w, h); image->cropImage(rc); } bool Document::exportImage(const QString &filename, const InfoObject &exportConfiguration) { if (!d->document) return false; return d->document->exportDocument(QUrl::fromLocalFile(filename)); } void Document::flatten() { } void Document::resizeImage(int w, int h) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; QRect rc = image->bounds(); rc.setWidth(w); rc.setHeight(h); image->resizeImage(rc); } bool Document::save() { if (!d->document) return false; return d->document->save(); } bool Document::saveAs(const QString &filename) { if (!d->document) return false; return d->document->saveAs(QUrl::fromLocalFile(filename)); } void Document::openView() { } Node* Document::createNode(const QString &name, const QString &nodeType) { return 0; } QPointer Document::document() const { return d->document; } diff --git a/libs/libkis/View.h b/libs/libkis/View.h index cc4ae654e0..4b41424a6f 100644 --- a/libs/libkis/View.h +++ b/libs/libkis/View.h @@ -1,65 +1,62 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program 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 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 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 LIBKIS_VIEW_H #define LIBKIS_VIEW_H #include #include "kritalibkis_export.h" #include "libkis.h" class KisView; /** * View */ class KRITALIBKIS_EXPORT View : public QObject { Q_OBJECT Q_DISABLE_COPY(View) public: explicit View(KisView *view, QObject *parent = 0); virtual ~View(); public Q_SLOTS: Window* window() const; Document* document() const; bool visible() const; void setVisible(); Canvas* canvas() const; - - - void close(bool confirm); private: friend class Window; KisView *view(); struct Private; Private *const d; }; #endif // LIBKIS_VIEW_H diff --git a/libs/libkis/Window.cpp b/libs/libkis/Window.cpp index d6d89155eb..795422490b 100644 --- a/libs/libkis/Window.cpp +++ b/libs/libkis/Window.cpp @@ -1,96 +1,101 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program 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 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 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 "Window.h" #include #include #include #include #include struct Window::Private { Private() {} QPointer window; }; Window::Window(KisMainWindow *window, QObject *parent) : QObject(parent) , d(new Private) { d->window = window; connect(window, SIGNAL(destroyed(QObject*)), SIGNAL(windowClosed())); } Window::~Window() { delete d; } +QMainWindow *Window::qwindow() const +{ + return d->window; +} + QList Window::views() const { QList ret; if (d->window) { foreach(QPointer view, KisPart::instance()->views()) { if (view->mainWindow() == d->window) { ret << new View(view); } } } return ret; } void Window::addView(Document *document) { if (d->window) { KisView *view = KisPart::instance()->createView(document->document(), d->window->resourceManager(), d->window->actionCollection(), d->window); d->window->addView(view); } } void Window::showView(View *view) { if (views().contains(view)) { KisView *v = view->view(); d->window->showView(v); } } void Window::activate() { if (d->window) { d->window->activateWindow(); } } void Window::close() { if (d->window) { d->window->close(); } } diff --git a/libs/libkis/Window.h b/libs/libkis/Window.h index ec13a40661..39bcc68e0a 100644 --- a/libs/libkis/Window.h +++ b/libs/libkis/Window.h @@ -1,67 +1,73 @@ /* * Copyright (c) 2016 Boudewijn Rempt * * This program 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 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 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 LIBKIS_WINDOW_H #define LIBKIS_WINDOW_H #include +#include #include "kritalibkis_export.h" #include "libkis.h" #include /** * Window */ class KRITALIBKIS_EXPORT Window : public QObject { Q_OBJECT public: explicit Window(KisMainWindow *window, QObject *parent = 0); virtual ~Window(); public Q_SLOTS: + /** + * Return a handle to the QMainWindow widget. This is useful + * to e.g. parent dialog boxes and message box. + */ + QMainWindow *qwindow() const; + QList views() const; void addView(Document *document); void showView(View *view); - /** * @brief activate activates this Window. */ void activate(); /** * @brief close the active window and all its Views. If there * are no Views left for a given Document, that Document will * also be closed. */ void close(); Q_SIGNALS: /// Emitted when the window is closed. void windowClosed(); private: struct Private; Private *const d; }; #endif // LIBKIS_WINDOW_H diff --git a/plugins/extensions/pykrita/plugin/plugins/CMakeLists.txt b/plugins/extensions/pykrita/plugin/plugins/CMakeLists.txt index 1d69771c61..18de88fc76 100644 --- a/plugins/extensions/pykrita/plugin/plugins/CMakeLists.txt +++ b/plugins/extensions/pykrita/plugin/plugins/CMakeLists.txt @@ -1,91 +1,91 @@ # Copyright (C) 2012, 2013 Shaheed Haque # Copyright (C) 2013 Alex Turbov # Copyright (C) 2014-2016 Boudewijn Rempt # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES # OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT # NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. include(CMakeParseArguments) # # Simple helper function to install plugin and related files # having only a name of the plugin... # (just to reduce syntactic noise when a lot of plugins get installed) # function(install_pykrita_plugin name) set(_options) set(_one_value_args) set(_multi_value_args PATTERNS FILE) cmake_parse_arguments(install_pykrita_plugin "${_options}" "${_one_value_args}" "${_multi_value_args}" ${ARGN}) if(NOT name) message(FATAL_ERROR "Plugin filename is not given") endif() if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${name}.py) install(FILES kritapykrita_${name}.desktop DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita) foreach(_f ${name}.py ${name}.ui ${install_pykrita_plugin_FILE}) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_f}) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${_f} DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita) endif() endforeach() elseif(IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${name}) install(FILES ${name}/kritapykrita_${name}.desktop DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita) install( DIRECTORY ${name} DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita FILES_MATCHING PATTERN "*.py" PATTERN "*.ui" PATTERN "__pycache__*" EXCLUDE ) # TODO Is there any way to form a long PATTERN options string # and use it in a single install() call? # NOTE Install specified patterns one-by-one... foreach(_pattern ${install_pykrita_plugin_PATTERNS}) install( DIRECTORY ${name} DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita FILES_MATCHING PATTERN "${_pattern}" PATTERN "__pycache__*" EXCLUDE ) endforeach() else() message(FATAL_ERROR "Do not know what to do with ${name}") endif() endfunction() install_pykrita_plugin(hello) -install_pykrita_plugin(selectionsbagdocker) +install_pykrita_plugin(assignprofiledialog) install_pykrita_plugin(scripter) # if(PYTHON_VERSION_MAJOR VERSION_EQUAL 3) # install_pykrita_plugin(cmake_utils) # install_pykrita_plugin(js_utils PATTERNS "*.json") # install_pykrita_plugin(expand PATTERNS "*.expand" "templates/*.tpl") # endif() install( DIRECTORY libkritapykrita DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita FILES_MATCHING PATTERN "*.py" PATTERN "__pycache__*" EXCLUDE ) diff --git a/plugins/extensions/pykrita/plugin/plugins/assignprofiledialog/__init__.py b/plugins/extensions/pykrita/plugin/plugins/assignprofiledialog/__init__.py new file mode 100644 index 0000000000..68c3ce8b95 --- /dev/null +++ b/plugins/extensions/pykrita/plugin/plugins/assignprofiledialog/__init__.py @@ -0,0 +1,2 @@ +# let's make a module +from .assignprofiledialog import * diff --git a/plugins/extensions/pykrita/plugin/plugins/assignprofiledialog/assignprofiledialog.py b/plugins/extensions/pykrita/plugin/plugins/assignprofiledialog/assignprofiledialog.py new file mode 100644 index 0000000000..512f7a49cb --- /dev/null +++ b/plugins/extensions/pykrita/plugin/plugins/assignprofiledialog/assignprofiledialog.py @@ -0,0 +1,46 @@ +import sys +from PyQt5.QtGui import * +from PyQt5.QtWidgets import * +from krita import * + +class AssignProfileDialog(ViewExtension): + + def __init__(self, parent): + super().__init__(parent) + + def assignProfile(self): + doc = Application.activeDocument() + if doc == None: + QMessageBox.information(Application.activeWindow().qwindow(), "Assign Profile", "There is no active document.") + return + + self.dialog = QDialog(Application.activeWindow().qwindow()) + self.dialog.setWindowModality(Qt.NonModal) + + self.cmbProfile = QComboBox(self.dialog) + + for profile in sorted(Application.profiles(doc.colorModel(), doc.colorDepth())): + self.cmbProfile.addItem(profile) + + vbox = QVBoxLayout(self.dialog) + vbox.addWidget(self.cmbProfile) + self.buttonBox = QDialogButtonBox(self.dialog) + self.buttonBox.setOrientation(QtCore.Qt.Horizontal) + self.buttonBox.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.buttonBox.accepted.connect(self.dialog.accept) + self.buttonBox.accepted.connect(self.accept) + self.buttonBox.rejected.connect(self.dialog.reject) + vbox.addWidget(self.buttonBox) + self.dialog.show() + self.dialog.activateWindow() + self.dialog.exec() + + def accept(self): + doc = Application.activeDocument() + doc.setColorProfile(self.cmbProfile.currentText()) + + def setup(self): + action = Application.createAction("Assign Profile to Image") + action.triggered.connect(self.assignProfile) + +Scripter.addViewExtension(AssignProfileDialog(Application)) diff --git a/plugins/extensions/pykrita/plugin/plugins/assignprofiledialog/kritapykrita_assignprofiledialog.desktop b/plugins/extensions/pykrita/plugin/plugins/assignprofiledialog/kritapykrita_assignprofiledialog.desktop new file mode 100644 index 0000000000..70ded3cd5c --- /dev/null +++ b/plugins/extensions/pykrita/plugin/plugins/assignprofiledialog/kritapykrita_assignprofiledialog.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Service +ServiceTypes=Krita/PythonPlugin +X-KDE-Library=assignprofiledialog +X-Python-2-Compatible=false +Name=Assign Profile to Image +Comment=Assign a profile to an image without converting it. diff --git a/plugins/extensions/pykrita/sip/krita/CubicCurve.sip b/plugins/extensions/pykrita/sip/krita/KisCubicCurve.sip similarity index 100% rename from plugins/extensions/pykrita/sip/krita/CubicCurve.sip rename to plugins/extensions/pykrita/sip/krita/KisCubicCurve.sip diff --git a/plugins/extensions/pykrita/sip/krita/Window.sip b/plugins/extensions/pykrita/sip/krita/Window.sip index 40965d2c5e..31175bd600 100644 --- a/plugins/extensions/pykrita/sip/krita/Window.sip +++ b/plugins/extensions/pykrita/sip/krita/Window.sip @@ -1,16 +1,17 @@ class Window : QObject { %TypeHeaderCode #include "Window.h" %End Window(const Window & __0); public Q_SLOTS: + QMainWindow *qwindow() const; QList views() const /Factory/; void addView(Document *document); void showView(View *view); void activate(); void close(); Q_SIGNALS: void windowClosed(); private: }; diff --git a/plugins/extensions/pykrita/sip/krita/kritamod.sip b/plugins/extensions/pykrita/sip/krita/kritamod.sip index b77588620b..d12920e145 100644 --- a/plugins/extensions/pykrita/sip/krita/kritamod.sip +++ b/plugins/extensions/pykrita/sip/krita/kritamod.sip @@ -1,31 +1,32 @@ %Module PyKrita.krita %ModuleHeaderCode #pragma GCC visibility push(default) %End %Import QtCore/QtCoremod.sip %Import QtGui/QtGuimod.sip %Import QtXml/QtXmlmod.sip %Import QtWidgets/QtWidgetsmod.sip %Include Action.sip %Include Canvas.sip %Include Channel.sip %Include DockWidgetFactoryBase.sip %Include DockWidget.sip %Include Document.sip %Include Filter.sip %Include Generator.sip %Include InfoObject.sip %Include ViewExtension.sip %Include View.sip %Include Window.sip %Include Krita.sip %Include Node.sip %Include Notifier.sip %Include Resource.sip %Include Selection.sip %Include Transformation.sip %Include ViewExtension.sip -%Include CubicCurve.sip + +%Include KisCubicCurve.sip