diff --git a/libs/libkis/Document.cpp b/libs/libkis/Document.cpp index 93433df852..e3e076ce8f 100644 --- a/libs/libkis/Document.cpp +++ b/libs/libkis/Document.cpp @@ -1,832 +1,838 @@ /* * 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 #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 struct Document::Private { Private() {} QPointer document; }; Document::Document(KisDocument *document, QObject *parent) : QObject(parent) , d(new Private) { d->document = document; } Document::~Document() { delete d; } bool Document::operator==(const Document &other) const { return (d->document == other.d->document); } bool Document::operator!=(const Document &other) const { return !(operator==(other)); } 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) { QList nodes = LibKisUtils::createNodeList(activeNodes, d->document->image()); return nodes.first(); } return 0; } void Document::setActiveNode(Node* value) { if (!value->node()) return; KisMainWindow *mainWin = KisPart::instance()->currentMainwindow(); if (!mainWin) return; KisViewManager *viewManager = mainWin->viewManager(); if (!viewManager) return; if (viewManager->document() != d->document) return; KisNodeManager *nodeManager = viewManager->nodeManager(); if (!nodeManager) return; KisNodeSelectionAdapter *selectionAdapter = nodeManager->nodeSelectionAdapter(); if (!selectionAdapter) return; selectionAdapter->setActiveNode(value->node()); } QList Document::topLevelNodes() const { if (!d->document) return QList(); Node n(d->document->image(), d->document->image()->rootLayer()); return n.childNodes(); } Node *Document::nodeByName(const QString &name) const { if (!d->document) return 0; KisNodeSP node = d->document->image()->rootLayer()->findChildByName(name); return new Node(d->document->image(), 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; bool retval = d->document->image()->assignImageProfile(profile); 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()->convertImageColorSpace(colorSpace, KoColorConversionTransformation::IntentPerceptual, KoColorConversionTransformation::HighQuality | KoColorConversionTransformation::NoOptimization); d->document->image()->setModified(); d->document->image()->initialRefreshGraph(); return true; } QColor Document::backgroundColor() { if (!d->document) return QColor(); if (!d->document->image()) return QColor(); const KoColor color = d->document->image()->defaultProjectionColor(); return color.toQColor(); } bool Document::setBackgroundColor(const QColor &color) { if (!d->document) return false; if (!d->document->image()) return false; KoColor background = KoColor(color, d->document->image()->colorSpace()); d->document->image()->setDefaultProjectionColor(background); d->document->image()->setModified(); d->document->image()->initialRefreshGraph(); return true; } QString Document::documentInfo() const { QDomDocument doc = KisDocument::createDomDocument("document-info" /*DTD name*/, "document-info" /*tag name*/, "1.1"); doc = d->document->documentInfo()->save(doc); return doc.toString(); } void Document::setDocumentInfo(const QString &document) { KoXmlDocument doc; QString errorMsg; int errorLine, errorColumn; doc.setContent(document, &errorMsg, &errorLine, &errorColumn); d->document->documentInfo()->load(doc); } QString Document::fileName() const { if (!d->document) return QString(); return d->document->url().toLocalFile(); } void Document::setFileName(QString value) { if (!d->document) return; QString mimeType = KisMimeDatabase::mimeTypeForFile(value, false); d->document->setMimeType(mimeType.toLatin1()); d->document->setUrl(QUrl::fromLocalFile(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; if (!d->document->image()) return; resizeImage(d->document->image()->bounds().x(), d->document->image()->bounds().y(), d->document->image()->width(), value); } QString Document::name() const { if (!d->document) return ""; return d->document->documentInfo()->aboutInfo("title"); } void Document::setName(QString value) { if (!d->document) return; d->document->documentInfo()->setAboutInfo("title", 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 { if (!d->document) return 0; if (!d->document->image()) return 0; if (!d->document->image()->globalSelection()) return 0; return new Selection(d->document->image()->globalSelection()); } void Document::setSelection(Selection* value) { if (!d->document) return; if (!d->document->image()) return; if (value) { d->document->image()->setGlobalSelection(value->selection()); } else { d->document->image()->setGlobalSelection(0); } } 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; if (!d->document->image()) return; resizeImage(d->document->image()->bounds().x(), d->document->image()->bounds().y(), value, d->document->image()->height()); } int Document::xOffset() const { if (!d->document) return 0; KisImageSP image = d->document->image(); if (!image) return 0; return image->bounds().x(); } void Document::setXOffset(int x) { if (!d->document) return; if (!d->document->image()) return; resizeImage(x, d->document->image()->bounds().y(), d->document->image()->width(), d->document->image()->height()); } int Document::yOffset() const { if (!d->document) return 0; KisImageSP image = d->document->image(); if (!image) return 0; return image->bounds().y(); } void Document::setYOffset(int y) { if (!d->document) return; if (!d->document->image()) return; resizeImage(d->document->image()->bounds().x(), y, d->document->image()->width(), d->document->image()->height()); } double Document::xRes() const { if (!d->document) return 0.0; if (!d->document->image()) return 0.0; return d->document->image()->xRes()*72.0; } void Document::setXRes(double xRes) const { if (!d->document) return; if (!d->document->image()) return; d->document->image()->setResolution(xRes/72.0, 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()*72.0; } void Document::setYRes(double yRes) const { if (!d->document) return; if (!d->document->image()) return; d->document->image()->setResolution(d->document->image()->xRes(), yRes/72.0); } QByteArray Document::pixelData(int x, int y, int w, int h) const { QByteArray ba; if (!d->document) return ba; KisImageSP image = d->document->image(); if (!image) return ba; KisPaintDeviceSP dev = image->projection(); ba.resize(w * h * dev->pixelSize()); dev->readBytes(reinterpret_cast(ba.data()), x, y, w, h); return ba; } bool Document::close() { bool retval = d->document->closeUrl(false); Q_FOREACH(KisView *view, KisPart::instance()->views()) { if (view->document() == d->document) { view->close(); view->closeView(); view->deleteLater(); } } KisPart::instance()->removeDocument(d->document); d->document = 0; return retval; } 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; const QString outputFormatString = KisMimeDatabase::mimeTypeForFile(filename, false); const QByteArray outputFormat = outputFormatString.toLatin1(); return d->document->exportDocumentSync(QUrl::fromLocalFile(filename), outputFormat, exportConfiguration.configuration()); } void Document::flatten() { if (!d->document) return; if (!d->document->image()) return; d->document->image()->flatten(0); } void Document::resizeImage(int x, int y, int w, int h) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; QRect rc; rc.setX(x); rc.setY(y); rc.setWidth(w); rc.setHeight(h); image->resizeImage(rc); } void Document::scaleImage(int w, int h, int xres, int yres, QString strategy) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; QRect rc = image->bounds(); rc.setWidth(w); rc.setHeight(h); KisFilterStrategy *actualStrategy = KisFilterStrategyRegistry::instance()->get(strategy); if (!actualStrategy) actualStrategy = KisFilterStrategyRegistry::instance()->get("Bicubic"); image->scaleImage(rc.size(), xres/72, yres/72, actualStrategy); } void Document::rotateImage(double radians) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; image->rotateImage(radians); } void Document::shearImage(double angleX, double angleY) { if (!d->document) return; KisImageSP image = d->document->image(); if (!image) return; image->shear(angleX, angleY); } bool Document::save() { if (!d->document) return false; if (d->document->url().isEmpty()) return false; bool retval = d->document->save(true, 0); d->document->waitForSavingToComplete(); return retval; } bool Document::saveAs(const QString &filename) { if (!d->document) return false; const QString outputFormatString = KisMimeDatabase::mimeTypeForFile(filename, false); const QByteArray outputFormat = outputFormatString.toLatin1(); QUrl oldUrl = d->document->url(); d->document->setUrl(QUrl::fromLocalFile(filename)); bool retval = d->document->saveAs(QUrl::fromLocalFile(filename), outputFormat, true); d->document->waitForSavingToComplete(); d->document->setUrl(oldUrl); return retval; } Node* Document::createNode(const QString &name, const QString &nodeType) { if (!d->document) return 0; if (!d->document->image()) return 0; KisImageSP image = d->document->image(); Node *node = 0; if (nodeType.toLower()== "paintlayer") { node = new Node(image, new KisPaintLayer(image, name, OPACITY_OPAQUE_U8)); } else if (nodeType.toLower() == "grouplayer") { node = new Node(image, new KisGroupLayer(image, name, OPACITY_OPAQUE_U8)); } else if (nodeType.toLower() == "filelayer") { node = new Node(image, new KisFileLayer(image, name, OPACITY_OPAQUE_U8)); } else if (nodeType.toLower() == "filterlayer") { node = new Node(image, new KisAdjustmentLayer(image, name, 0, 0)); } else if (nodeType.toLower() == "filllayer") { node = new Node(image, new KisGeneratorLayer(image, name, 0, 0)); } else if (nodeType.toLower() == "clonelayer") { node = new Node(image, new KisCloneLayer(0, image, name, OPACITY_OPAQUE_U8)); } else if (nodeType.toLower() == "vectorlayer") { node = new Node(image, new KisShapeLayer(d->document->shapeController(), image, name, OPACITY_OPAQUE_U8)); } else if (nodeType.toLower() == "transparencymask") { node = new Node(image, new KisTransparencyMask()); } else if (nodeType.toLower() == "filtermask") { node = new Node(image, new KisFilterMask()); } else if (nodeType.toLower() == "transformmask") { node = new Node(image, new KisTransformMask()); } else if (nodeType.toLower() == "selectionmask") { node = new Node(image, new KisSelectionMask(image)); } return node; } GroupLayer *Document::createGroupLayer(const QString &name) { if (!d->document) return 0; if (!d->document->image()) return 0; KisImageSP image = d->document->image(); return new GroupLayer(image, name); } FileLayer *Document::createFileLayer(const QString &name, const QString fileName, const QString scalingMethod) { if (!d->document) return 0; if (!d->document->image()) return 0; KisImageSP image = d->document->image(); return new FileLayer(image, name, this->fileName(), fileName, scalingMethod); } FilterLayer *Document::createFilterLayer(const QString &name, Filter &filter, Selection &selection) { if (!d->document) return 0; if (!d->document->image()) return 0; KisImageSP image = d->document->image(); return new FilterLayer(image, name, filter, selection); } FillLayer *Document::createFillLayer(const QString &name, const QString generatorName, InfoObject &configuration, Selection &selection) { if (!d->document) return 0; if (!d->document->image()) return 0; KisImageSP image = d->document->image(); KisGeneratorSP generator = KisGeneratorRegistry::instance()->value(generatorName); if (generator) { KisFilterConfigurationSP config = generator->defaultConfiguration(); Q_FOREACH(const QString property, configuration.properties().keys()) { config->setProperty(property, configuration.property(property)); } return new FillLayer(image, name, config, selection); } return 0; } CloneLayer *Document::createCloneLayer(const QString &name, const Node *source) { if (!d->document) return 0; if (!d->document->image()) return 0; KisImageSP image = d->document->image(); KisLayerSP layer = qobject_cast(source->node().data()); return new CloneLayer(image, name, layer); } VectorLayer *Document::createVectorLayer(const QString &name) { if (!d->document) return 0; if (!d->document->image()) return 0; KisImageSP image = d->document->image(); return new VectorLayer(d->document->shapeController(), image, name); } FilterMask *Document::createFilterMask(const QString &name, Filter &filter) { if (!d->document) return 0; if (!d->document->image()) return 0; KisImageSP image = d->document->image(); return new FilterMask(image, name, filter); } SelectionMask *Document::createSelectionMask(const QString &name) { if (!d->document) return 0; if (!d->document->image()) return 0; KisImageSP image = d->document->image(); return new SelectionMask(image, name); } QImage Document::projection(int x, int y, int w, int h) const { if (!d->document || !d->document->image()) return QImage(); return d->document->image()->convertToQImage(x, y, w, h, 0); } QImage Document::thumbnail(int w, int h) const { if (!d->document || !d->document->image()) return QImage(); return d->document->generatePreview(QSize(w, h)).toImage(); } void Document::lock() { if (!d->document || !d->document->image()) return; d->document->image()->barrierLock(); } void Document::unlock() { if (!d->document || !d->document->image()) return; d->document->image()->unlock(); } void Document::waitForDone() { if (!d->document || !d->document->image()) return; d->document->image()->waitForDone(); } bool Document::tryBarrierLock() { if (!d->document || !d->document->image()) return false; return d->document->image()->tryBarrierLock(); } bool Document::isIdle() { if (!d->document || !d->document->image()) return false; return d->document->image()->isIdle(); } void Document::refreshProjection() { if (!d->document || !d->document->image()) return; d->document->image()->refreshGraph(); } QList Document::horizontalGuides() const { QList lines; if (!d->document || !d->document->image()) return lines; KisCoordinatesConverter converter; converter.setImage(d->document->image()); QTransform transform = converter.imageToDocumentTransform().inverted(); QList untransformedLines = d->document->guidesConfig().horizontalGuideLines(); for (int i = 0; i< untransformedLines.size(); i++) { qreal line = untransformedLines[i]; lines.append(transform.map(QPointF(line, line)).x()); } return lines; } QList Document::verticalGuides() const { QList lines; if (!d->document || !d->document->image()) return lines; KisCoordinatesConverter converter; converter.setImage(d->document->image()); QTransform transform = converter.imageToDocumentTransform().inverted(); QList untransformedLines = d->document->guidesConfig().verticalGuideLines(); for (int i = 0; i< untransformedLines.size(); i++) { qreal line = untransformedLines[i]; lines.append(transform.map(QPointF(line, line)).y()); } return lines; } bool Document::guidesVisible() const { return d->document->guidesConfig().lockGuides(); } bool Document::guidesLocked() const { return d->document->guidesConfig().showGuides(); } Document *Document::clone() const { if (!d->document) return 0; QPointer clone = d->document->clone(); Document * d = new Document(clone); clone->setParent(d); // It's owned by the document, not KisPart return d; } void Document::setHorizontalGuides(const QList &lines) { if (!d->document) return; KisGuidesConfig config = d->document->guidesConfig(); KisCoordinatesConverter converter; converter.setImage(d->document->image()); QTransform transform = converter.imageToDocumentTransform(); QList transformedLines; for (int i = 0; i< lines.size(); i++) { qreal line = lines[i]; transformedLines.append(transform.map(QPointF(line, line)).x()); } config.setHorizontalGuideLines(transformedLines); d->document->setGuidesConfig(config); } void Document::setVerticalGuides(const QList &lines) { if (!d->document) return; KisGuidesConfig config = d->document->guidesConfig(); KisCoordinatesConverter converter; converter.setImage(d->document->image()); QTransform transform = converter.imageToDocumentTransform(); QList transformedLines; for (int i = 0; i< lines.size(); i++) { qreal line = lines[i]; transformedLines.append(transform.map(QPointF(line, line)).y()); } config.setVerticalGuideLines(transformedLines); d->document->setGuidesConfig(config); } void Document::setGuidesVisible(bool visible) { if (!d->document) return; KisGuidesConfig config = d->document->guidesConfig(); config.setShowGuides(visible); d->document->setGuidesConfig(config); } void Document::setGuidesLocked(bool locked) { if (!d->document) return; KisGuidesConfig config = d->document->guidesConfig(); config.setLockGuides(locked); d->document->setGuidesConfig(config); } bool Document::modified() const { if (!d->document) return false; return d->document->isModified(); } +QRect Document::bounds() const +{ + if (!d->document) return QRect(); + return d->document->image()->bounds(); +} + QPointer Document::document() const { return d->document; } diff --git a/libs/libkis/Document.h b/libs/libkis/Document.h index 2bb15c0c0e..d50905afc2 100644 --- a/libs/libkis/Document.h +++ b/libs/libkis/Document.h @@ -1,757 +1,763 @@ /* * 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_DOCUMENT_H #define LIBKIS_DOCUMENT_H #include #include "kritalibkis_export.h" #include "libkis.h" #include "GroupLayer.h" #include "CloneLayer.h" #include "FileLayer.h" #include "FilterLayer.h" #include "FillLayer.h" #include "VectorLayer.h" #include "FilterMask.h" #include "SelectionMask.h" class KisDocument; /** * The Document class encapsulates a Krita Document/Image. A Krita document is an Image with * a filename. Libkis does not differentiate between a document and an image, like Krita does * internally. */ class KRITALIBKIS_EXPORT Document : public QObject { Q_OBJECT Q_DISABLE_COPY(Document) public: explicit Document(KisDocument *document, QObject *parent = 0); ~Document() override; bool operator==(const Document &other) const; bool operator!=(const Document &other) const; /** * @brief horizontalGuides * The horizontal guides. * @return a list of the horizontal positions of guides. */ QList horizontalGuides() const; /** * @brief verticalGuides * The vertical guide lines. * @return a list of vertical guides. */ QList verticalGuides() const; /** * @brief guidesVisible * Returns guide visiiblity. * @return whether the guides are visible. */ bool guidesVisible() const; /** * @brief guidesLocked * Returns guide lockedness. * @return whether the guides are locked. */ bool guidesLocked() const; public Q_SLOTS: /** * @brief clone create a shallow clone of this document. * @return a new Document that should be identical to this one in every respect. */ Document *clone() const; /** * Batchmode means that no actions on the document should show dialogs or popups. * @return true if the document is in batchmode. */ bool batchmode() const; /** * Set batchmode to @param value. If batchmode is true, then there should be no popups * or dialogs shown to the user. */ void setBatchmode(bool value); /** * @brief activeNode retrieve the node that is currently active in the currently active window * @return the active node. If there is no active window, the first child node is returned. */ Node* activeNode() const; /** * @brief setActiveNode make the given node active in the currently active view and window * @param value the node to make active. */ void setActiveNode(Node* value); /** * @brief toplevelNodes return a list with all top level nodes in the image graph */ QList topLevelNodes() const; /** * @brief nodeByName searches the node tree for a node with the given name and returns it * @param name the name of the node * @return the first node with the given name or 0 if no node is found */ Node *nodeByName(const QString &name) const; /** * colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @return the color depth. */ QString colorDepth() const; /** * @brief colorModel retrieve the current color model of this document: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @return the internal color model string. */ QString colorModel() const; /** * @return the name of the current color profile */ QString colorProfile() const; /** * @brief setColorProfile set the color profile of the image to the given profile. The profile has to * be registered with krita and be compatible with the current color model and depth; the image data * is not converted. * @param colorProfile * @return false if the colorProfile name does not correspond to to a registered profile or if assigning * the profile failed. */ bool setColorProfile(const QString &colorProfile); /** * @brief setColorSpace convert the nodes and the image to the given colorspace. The conversion is * done with Perceptual as intent, High Quality and No LCMS Optimizations as flags and no blackpoint * compensation. * * @param colorModel A string describing the color model of the image: *
    *
  • A: Alpha mask
  • *
  • RGBA: RGB with alpha channel (The actual order of channels is most often BGR!)
  • *
  • XYZA: XYZ with alpha channel
  • *
  • LABA: LAB with alpha channel
  • *
  • CMYKA: CMYK with alpha channel
  • *
  • GRAYA: Gray with alpha channel
  • *
  • YCbCrA: YCbCr with alpha channel
  • *
* @param colorDepth A string describing the color depth of the image: *
    *
  • U8: unsigned 8 bits integer, the most common type
  • *
  • U16: unsigned 16 bits integer
  • *
  • F16: half, 16 bits floating point. Only available if Krita was built with OpenEXR
  • *
  • F32: 32 bits floating point
  • *
* @param colorProfile a valid color profile for this color model and color depth combination. * @return false the combination of these arguments does not correspond to a colorspace. */ bool setColorSpace(const QString &colorModel, const QString &colorDepth, const QString &colorProfile); /** * @brief backgroundColor returns the current background color of the document. The color will * also include the opacity. * * @return QColor */ QColor backgroundColor(); /** * @brief setBackgroundColor sets the background color of the document. It will trigger a projection * update. * * @param color A QColor. The color will be converted from sRGB. * @return bool */ bool setBackgroundColor(const QColor &color); /** * @brief documentInfo creates and XML document representing document and author information. * @return a string containing a valid XML document with the right information about the document * and author. The DTD can be found here: * * https://phabricator.kde.org/source/krita/browse/master/krita/dtd/ * * @code * * * * * My Document * * * * * Unknown * 1 * 35 * 2017-02-27T20:15:09 * 2017-02-27T20:14:33 * * * * Boudewijn Rempt * * * * * * * * * * * * * * * @endcode * */ QString documentInfo() const; /** * @brief setDocumentInfo set the Document information to the information contained in document * @param document A string containing a valid XML document that conforms to the document-info DTD * that can be found here: * * https://phabricator.kde.org/source/krita/browse/master/krita/dtd/ */ void setDocumentInfo(const QString &document); /** * @return the full path to the document, if it has been set. */ QString fileName() const; /** * @brief setFileName set the full path of the document to @param value */ void setFileName(QString value); /** * @return the height of the image in pixels */ int height() const; /** * @brief setHeight resize the document to @param value height. This is a canvas resize, not a scale. */ void setHeight(int value); /** * @return the name of the document. This is the title field in the @see documentInfo */ QString name() const; /** * @brief setName sets the name of the document to @param value. This is the title field in the @see documentInfo */ void setName(QString value); /** * @return the resolution in pixels per inch */ int resolution() const; /** * @brief setResolution set the resolution of the image; this does not scale the image * @param value the resolution in pixels per inch */ void setResolution(int value); /** * @brief rootNode the root node is the invisible group layer that contains the entire node * hierarchy. * @return the root of the image */ Node* rootNode() const; /** * @brief selection Create a Selection object around the global selection, if there is one. * @return the global selection or None if there is no global selection. */ Selection* selection() const; /** * @brief setSelection set or replace the global selection * @param value a valid selection object. */ void setSelection(Selection* value); /** * @return the width of the image in pixels. */ int width() const; /** * @brief setWidth resize the document to @param value width. This is a canvas resize, not a scale. */ void setWidth(int value); /** * @return the left edge of the canvas in pixels. */ int xOffset() const; /** * @brief setXOffset sets the left edge of the canvas to @param x. */ void setXOffset(int x); /** * @return the top edge of the canvas in pixels. */ int yOffset() const; /** * @brief setYOffset sets the top edge of the canvas to @param y. */ void setYOffset(int y); /** * @return xRes the horizontal resolution of the image in pixels per pt (there are 72 pts to an inch) */ double xRes() const; /** * @brief setXRes set the horizontal resolution of the image to xRes in pixels per pt. (there are 72 pts to an inch) */ void setXRes(double xRes) const; /** * @return yRes the vertical resolution of the image in pixels per pt (there are 72 pts to an inch) */ double yRes() const; /** * @brief setYRes set the vertical resolution of the image to yRes in pixels per pt. (there are 72 pts to an inch) */ void setYRes(double yRes) const; /** * @brief pixelData reads the given rectangle from the image projection and returns it as a byte * array. The pixel data starts top-left, and is ordered row-first. * * The byte array can be interpreted as follows: 8 bits images have one byte per channel, * and as many bytes as there are channels. 16 bits integer images have two bytes per channel, * representing an unsigned short. 16 bits float images have two bytes per channel, representing * a half, or 16 bits float. 32 bits float images have four bytes per channel, representing a * float. * * You can read outside the image boundaries; those pixels will be transparent black. * * The order of channels is: * *
    *
  • Integer RGBA: Blue, Green, Red, Alpha *
  • Float RGBA: Red, Green, Blue, Alpha *
  • LabA: L, a, b, Alpha *
  • CMYKA: Cyan, Magenta, Yellow, Key, Alpha *
  • XYZA: X, Y, Z, A *
  • YCbCrA: Y, Cb, Cr, Alpha *
* * The byte array is a copy of the original image data. In Python, you can use bytes, bytearray * and the struct module to interpret the data and construct, for instance, a Pillow Image object. * * @param x x position from where to start reading * @param y y position from where to start reading * @param w row length to read * @param h number of rows to read * @return a QByteArray with the pixel data. The byte array may be empty. */ QByteArray pixelData(int x, int y, int w, int h) const; /** * @brief close Close the document: remove it from Krita's internal list of documents and * close all views. If the document is modified, you should save it first. There will be * no prompt for saving. * * After closing the document it becomes invalid. * * @return true if the document is closed. */ bool close(); /** * @brief crop the image to rectangle described by @param x, @param y, * @param w and @param h */ void crop(int x, int y, int w, int h); /** * @brief exportImage export the image, without changing its URL to the given path. * @param filename the full path to which the image is to be saved * @param exportConfiguration a configuration object appropriate to the file format. * An InfoObject will used to that configuration. * * The supported formats have specific configurations that must be used when in * batchmode. They are described below: * *\b png *
    *
  • alpha: bool (True or False) *
  • compression: int (1 to 9) *
  • forceSRGB: bool (True or False) *
  • indexed: bool (True or False) *
  • interlaced: bool (True or False) *
  • saveSRGBProfile: bool (True or False) *
  • transparencyFillcolor: rgb (Ex:[255,255,255]) *
* *\b jpeg *
    *
  • baseline: bool (True or False) *
  • exif: bool (True or False) *
  • filters: bool (['ToolInfo', 'Anonymizer']) *
  • forceSRGB: bool (True or False) *
  • iptc: bool (True or False) *
  • is_sRGB: bool (True or False) *
  • optimize: bool (True or False) *
  • progressive: bool (True or False) *
  • quality: int (0 to 100) *
  • saveProfile: bool (True or False) *
  • smoothing: int (0 to 100) *
  • subsampling: int (0 to 3) *
  • transparencyFillcolor: rgb (Ex:[255,255,255]) *
  • xmp: bool (True or False) *
* @return true if the export succeeded, false if it failed. */ bool exportImage(const QString &filename, const InfoObject &exportConfiguration); /** * @brief flatten all layers in the image */ void flatten(); /** * @brief resizeImage resizes the canvas to the given left edge, top edge, width and height. * Note: This doesn't scale, use scale image for that. * @param x the new left edge * @param y the new top edge * @param w the new width * @param h the new height */ void resizeImage(int x, int y, int w, int h); /** * @brief scaleImage * @param w the new width * @param h the new height * @param xres the new xres * @param yres the new yres * @param strategy the scaling strategy. There's several ones amongst these that aren't available in the regular UI. * The list of filters is extensible and can be retrieved with Krita::filter *
    *
  • Hermite
  • *
  • Bicubic - Adds pixels using the color of surrounding pixels. Produces smoother tonal gradations than Bilinear.
  • *
  • Box - Replicate pixels in the image. Preserves all the original detail, but can produce jagged effects.
  • *
  • Bilinear - Adds pixels averaging the color values of surrounding pixels. Produces medium quality results when the image is scaled from half to two times the original size.
  • *
  • Bell
  • *
  • BSpline
  • *
  • Kanczos3 - Offers similar results than Bicubic, but maybe a little bit sharper. Can produce light and dark halos along strong edges.
  • *
  • Mitchell
  • *
*/ void scaleImage(int w, int h, int xres, int yres, QString strategy); /** * @brief rotateImage * Rotate the image by the given radians. * @param radians the amount you wish to rotate the image in radians */ void rotateImage(double radians); /** * @brief shearImage shear the whole image. * @param angleX the X-angle in degrees to shear by * @param angleY the Y-angle in degrees to shear by */ void shearImage(double angleX, double angleY); /** * @brief save the image to its currently set path. The modified flag of the * document will be reset * @return true if saving succeeded, false otherwise. */ bool save(); /** * @brief saveAs save the document under the @param filename. The document's * filename will be reset to @param filename. * @param filename the new filename (full path) for the document * @return true if saving succeeded, false otherwise. */ bool saveAs(const QString &filename); /** * @brief createNode create a new node of the given type. The node is not added * to the node hierarchy; you need to do that by finding the right parent node, * getting its list of child nodes and adding the node in the right place, then * calling Node::SetChildNodes * * @param name The name of the node * * @param nodeType The type of the node. Valid types are: *
    *
  • paintlayer *
  • grouplayer *
  • filelayer *
  • filterlayer *
  • filllayer *
  • clonelayer *
  • vectorlayer *
  • transparencymask *
  • filtermask *
  • transformmask *
  • selectionmask *
* * When relevant, the new Node will have the colorspace of the image by default; * that can be changed with Node::setColorSpace. * * The settings and selections for relevant layer and mask types can also be set * after the Node has been created. * @code d = Application.createDocument(1000, 1000, "Test", "RGBA", "U8", "", 120.0) root = d.rootNode(); print(root.childNodes()) l2 = d.createNode("layer2", "paintLayer") print(l2) root.addChildNode(l2, None) print(root.childNodes()) @endcode * * * @return the new Node. */ Node* createNode(const QString &name, const QString &nodeType); /** * @brief createGroupLayer * Returns a grouplayer object. Grouplayers are nodes that can have * other layers as children and have the passthrough mode. * @param name the name of the layer. * @return a GroupLayer object. */ GroupLayer* createGroupLayer(const QString &name); /** * @brief createFileLayer returns a layer that shows an external image. * @param name name of the file layer. * @param fileName the absolute filename of the file referenced. Symlinks will be resolved. * @param scalingMethod how the dimensions of the file are interpreted * can be either "None", "ImageToSize" or "ImageToPPI" * @return a FileLayer */ FileLayer* createFileLayer(const QString &name, const QString fileName, const QString scalingMethod); /** * @brief createFilterLayer creates a filter layer, which is a layer that represents a filter * applied non-destructively. * @param name name of the filterLayer * @param filter the filter that this filter layer will us. * @param selection the selection. * @return a filter layer object. */ FilterLayer* createFilterLayer(const QString &name, Filter &filter, Selection &selection); /** * @brief createFillLayer creates a fill layer object, which is a layer * @param name * @param generatorName - name of the generation filter. * @param configuration - the configuration for the generation filter. * @param selection - the selection. * @return a filllayer object. * * @code * from krita import * * d = Krita.instance().activeDocument() * i = InfoObject(); * i.setProperty("pattern", "Cross01.pat") * s = Selection(); * s.select(0, 0, d.width(), d.height(), 255) * n = d.createFillLayer("test", "pattern", i, s) * r = d.rootNode(); * c = r.childNodes(); * r.addChildNode(n, c[0]) * d.refreshProjection() * @endcode */ FillLayer* createFillLayer(const QString &name, const QString generatorName, InfoObject &configuration, Selection &selection); /** * @brief createCloneLayer * @param name * @param source * @return */ CloneLayer* createCloneLayer(const QString &name, const Node* source); /** * @brief createVectorLayer * Creates a vector layer that can contain vector shapes. * @param name the name of this layer. * @return a VectorLayer. */ VectorLayer* createVectorLayer(const QString &name); /** * @brief createFilterMask * Creates a filter mask object that much like a filterlayer can apply a filter non-destructively. * @param name the name of the layer. * @param filter the filter assigned. * @return a FilterMask */ FilterMask* createFilterMask(const QString &name, Filter &filter); /** * @brief createSelectionMask * Creates a selection mask, which can be used to store selections. * @param name - the name of the layer. * @return a SelectionMask */ SelectionMask* createSelectionMask(const QString &name); /** * @brief projection creates a QImage from the rendered image or * a cutout rectangle. */ QImage projection(int x = 0, int y = 0, int w = 0, int h = 0) const; /** * @brief thumbnail create a thumbnail of the given dimensions. * * If the requested size is too big a null QImage is created. * * @return a QImage representing the layer contents. */ QImage thumbnail(int w, int h) const; /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ void lock(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ void unlock(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ void waitForDone(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ bool tryBarrierLock(); /** * Why this should be used, When it should be used, How it should be used, * and warnings about when not. */ bool isIdle(); /** * Starts a synchronous recomposition of the projection: everything will * wait until the image is fully recomputed. */ void refreshProjection(); /** * @brief setHorizontalGuides * replace all existing horizontal guides with the entries in the list. * @param list a list of floats containing the new guides. */ void setHorizontalGuides(const QList &lines); /** * @brief setVerticalGuides * replace all existing horizontal guides with the entries in the list. * @param list a list of floats containing the new guides. */ void setVerticalGuides(const QList &lines); /** * @brief setGuidesVisible * set guides visible on this document. * @param visible whether or not the guides are visible. */ void setGuidesVisible(bool visible); /** * @brief setGuidesLocked * set guides locked on this document * @param locked whether or not to lock the guides on this document. */ void setGuidesLocked(bool locked); /** * @brief modified returns true if the document has unsaved modifications. */ bool modified() const; + /** + * @brief bounds return the bounds of the image + * @return the bounds + */ + QRect bounds() const; + private: friend class Krita; friend class Window; friend class Filter; QPointer document() const; private: struct Private; Private *const d; }; #endif // LIBKIS_DOCUMENT_H diff --git a/libs/libkis/Window.cpp b/libs/libkis/Window.cpp index b95ae35b10..eaa7f9c5a6 100644 --- a/libs/libkis/Window.cpp +++ b/libs/libkis/Window.cpp @@ -1,153 +1,154 @@ /* * 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 #include #include #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; } bool Window::operator==(const Window &other) const { return (d->window == other.d->window); } bool Window::operator!=(const Window &other) const { return !(operator==(other)); } 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; } View *Window::addView(Document *document) { if (d->window) { KisView *view = d->window->newView(document->document()); return new View(view); } return 0; } void Window::showView(View *view) { if (views().contains(view)) { KisView *v = view->view(); d->window->showView(v); } } View *Window::activeView() const { if (d->window) { return new View(d->window->activeView()); } return 0; } void Window::activate() { if (d->window) { d->window->activateWindow(); } } void Window::close() { if (d->window) { KisPart::instance()->removeMainWindow(d->window); d->window->close(); } } QAction *Window::createAction(const QString &id, const QString &text, const QString &menuLocation) { KisAction *action = d->window->viewManager()->actionManager()->createAction(id); action->setText(text); action->setObjectName(id); if (!menuLocation.isEmpty()) { QAction *found = 0; QList candidates = d->window->menuBar()->actions(); Q_FOREACH(const QString &name, menuLocation.split("/")) { Q_FOREACH(QAction *candidate, candidates) { - if (candidate->objectName() == name) { + if (candidate->objectName().toLower() == name.toLower()) { found = candidate; candidates = candidate->menu()->actions(); break; } } if (candidates.isEmpty()) { break; } } if (found && found->menu()) { found->menu()->addAction(action); } } return action; } diff --git a/libs/pigment/compositeops/KoStreamedMath.h b/libs/pigment/compositeops/KoStreamedMath.h index eeaa2f95dd..743713b4db 100644 --- a/libs/pigment/compositeops/KoStreamedMath.h +++ b/libs/pigment/compositeops/KoStreamedMath.h @@ -1,427 +1,427 @@ /* * Copyright (c) 2012 Dmitry Kazakov * * 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 __KOSTREAMED_MATH_H #define __KOSTREAMED_MATH_H #if defined _MSC_VER // Lets shut up the "possible loss of data" and "forcing value to bool 'true' or 'false' #pragma warning ( push ) #pragma warning ( disable : 4244 ) #pragma warning ( disable : 4800 ) #endif #include #include #if defined _MSC_VER #pragma warning ( pop ) #endif #include #include #include #define BLOCKDEBUG 0 #if !defined _MSC_VER #pragma GCC diagnostic ignored "-Wcast-align" #endif template struct KoStreamedMath { using int_v = Vc::SimdArray; using uint_v = Vc::SimdArray; /** * Composes src into dst without using vector instructions */ template static void genericComposite_novector(const KoCompositeOp::ParameterInfo& params) { using namespace Arithmetic; const qint32 linearInc = pixelSize; qint32 srcLinearInc = params.srcRowStride ? pixelSize : 0; quint8* dstRowStart = params.dstRowStart; const quint8* maskRowStart = params.maskRowStart; const quint8* srcRowStart = params.srcRowStart; typename Compositor::OptionalParams optionalParams(params); for(quint32 r=params.rows; r>0; --r) { const quint8 *mask = maskRowStart; const quint8 *src = srcRowStart; quint8 *dst = dstRowStart; int blockRest = params.cols; for(int i = 0; i < blockRest; i++) { Compositor::template compositeOnePixelScalar(src, dst, mask, params.opacity, optionalParams); src += srcLinearInc; dst += linearInc; if (useMask) { mask++; } } srcRowStart += params.srcRowStride; dstRowStart += params.dstRowStride; if (useMask) { maskRowStart += params.maskRowStride; } } } template static void genericComposite32_novector(const KoCompositeOp::ParameterInfo& params) { genericComposite_novector(params); } template static void genericComposite128_novector(const KoCompositeOp::ParameterInfo& params) { genericComposite_novector(params); } static inline quint8 round_float_to_uint(float value) { return quint8(value + float(0.5)); } static inline quint8 lerp_mixed_u8_float(quint8 a, quint8 b, float alpha) { return round_float_to_uint(qint16(b - a) * alpha + a); } /** * Get a vector containing first Vc::float_v::size() values of mask. * Each source mask element is considered to be a 8-bit integer */ static inline Vc::float_v fetch_mask_8(const quint8 *data) { uint_v data_i(data); - return Vc::float_v(int_v(data_i)); + return Vc::simd_cast(int_v(data_i)); } /** * Get an alpha values from Vc::float_v::size() pixels 32-bit each * (4 channels, 8 bit per channel). The alpha value is considered * to be stored in the most significat byte of the pixel * * \p aligned controls whether the \p data is fetched using aligned * instruction or not. * 1) Fetching aligned data with unaligned instruction * degrades performance. * 2) Fetching unaligned data with aligned instruction * causes #GP (General Protection Exception) */ template static inline Vc::float_v fetch_alpha_32(const quint8 *data) { uint_v data_i; if (aligned) { data_i.load((const quint32*)data, Vc::Aligned); } else { data_i.load((const quint32*)data, Vc::Unaligned); } - return Vc::float_v(int_v(data_i >> 24)); + return Vc::simd_cast(int_v(data_i >> 24)); } /** * Get color values from Vc::float_v::size() pixels 32-bit each * (4 channels, 8 bit per channel). The color data is considered * to be stored in the 3 least significant bytes of the pixel. * * \p aligned controls whether the \p data is fetched using aligned * instruction or not. * 1) Fetching aligned data with unaligned instruction * degrades performance. * 2) Fetching unaligned data with aligned instruction * causes #GP (General Protection Exception) */ template static inline void fetch_colors_32(const quint8 *data, Vc::float_v &c1, Vc::float_v &c2, Vc::float_v &c3) { int_v data_i; if (aligned) { data_i.load((const quint32*)data, Vc::Aligned); } else { data_i.load((const quint32*)data, Vc::Unaligned); } const quint32 lowByteMask = 0xFF; uint_v mask(lowByteMask); - c1 = Vc::float_v(int_v((data_i >> 16) & mask)); - c2 = Vc::float_v(int_v((data_i >> 8) & mask)); - c3 = Vc::float_v(int_v( data_i & mask)); + c1 = Vc::simd_cast(int_v((data_i >> 16) & mask)); + c2 = Vc::simd_cast(int_v((data_i >> 8) & mask)); + c3 = Vc::simd_cast(int_v( data_i & mask)); } /** * Pack color and alpha values to Vc::float_v::size() pixels 32-bit each * (4 channels, 8 bit per channel). The color data is considered * to be stored in the 3 least significant bytes of the pixel, alpha - * in the most significant byte * * NOTE: \p data must be aligned pointer! */ static inline void write_channels_32(quint8 *data, Vc::float_v::AsArg alpha, Vc::float_v::AsArg c1, Vc::float_v::AsArg c2, Vc::float_v::AsArg c3) { /** * FIXME: make conversion float->int * use methematical rounding */ const quint32 lowByteMask = 0xFF; // FIXME: Use single-instruction rounding + conversion // The achieve that we need to implement Vc::iRound() uint_v mask(lowByteMask); uint_v v1 = uint_v(int_v(Vc::round(alpha))) << 24; uint_v v2 = (uint_v(int_v(Vc::round(c1))) & mask) << 16; uint_v v3 = (uint_v(int_v(Vc::round(c2))) & mask) << 8; uint_v v4 = uint_v(int_v(Vc::round(c3))) & mask; v1 = v1 | v2; v3 = v3 | v4; (v1 | v3).store((quint32*)data, Vc::Aligned); } /** * Composes src pixels into dst pixles. Is optimized for 32-bit-per-pixel * colorspaces. Uses \p Compositor strategy parameter for doing actual * math of the composition */ template static void genericComposite(const KoCompositeOp::ParameterInfo& params) { using namespace Arithmetic; const int vectorSize = Vc::float_v::size(); const qint32 vectorInc = pixelSize * vectorSize; const qint32 linearInc = pixelSize; qint32 srcVectorInc = vectorInc; qint32 srcLinearInc = pixelSize; quint8* dstRowStart = params.dstRowStart; const quint8* maskRowStart = params.maskRowStart; const quint8* srcRowStart = params.srcRowStart; typename Compositor::OptionalParams optionalParams(params); if (!params.srcRowStride) { if (pixelSize == 4) { quint32 *buf = Vc::malloc(vectorSize); *((uint_v*)buf) = uint_v(*((const quint32*)params.srcRowStart)); srcRowStart = reinterpret_cast(buf); srcLinearInc = 0; srcVectorInc = 0; } else { quint8 *buf = Vc::malloc(vectorInc); quint8 *ptr = buf; for (int i = 0; i < vectorSize; i++) { memcpy(ptr, params.srcRowStart, pixelSize); ptr += pixelSize; } srcRowStart = buf; srcLinearInc = 0; srcVectorInc = 0; } } #if BLOCKDEBUG int totalBlockAlign = 0; int totalBlockAlignedVector = 0; int totalBlockUnalignedVector = 0; int totalBlockRest = 0; #endif for(quint32 r=params.rows; r>0; --r) { // Hint: Mask is allowed to be unaligned const quint8 *mask = maskRowStart; const quint8 *src = srcRowStart; quint8 *dst = dstRowStart; const int pixelsAlignmentMask = vectorSize * sizeof(float) - 1; uintptr_t srcPtrValue = reinterpret_cast(src); uintptr_t dstPtrValue = reinterpret_cast(dst); uintptr_t srcAlignment = srcPtrValue & pixelsAlignmentMask; uintptr_t dstAlignment = dstPtrValue & pixelsAlignmentMask; // Uncomment if facing problems with alignment: // Q_ASSERT_X(!(dstAlignment & 3), "Compositioning", // "Pixel data must be aligned on pixels borders!"); int blockAlign = params.cols; int blockAlignedVector = 0; int blockUnalignedVector = 0; int blockRest = 0; int *vectorBlock = srcAlignment == dstAlignment || !srcVectorInc ? &blockAlignedVector : &blockUnalignedVector; if (!dstAlignment) { blockAlign = 0; *vectorBlock = params.cols / vectorSize; blockRest = params.cols % vectorSize; } else if (params.cols > 2 * vectorSize) { blockAlign = (vectorInc - dstAlignment) / pixelSize; const int restCols = params.cols - blockAlign; if (restCols > 0) { *vectorBlock = restCols / vectorSize; blockRest = restCols % vectorSize; } else { blockAlign = params.cols; *vectorBlock = 0; blockRest = 0; } } #if BLOCKDEBUG totalBlockAlign += blockAlign; totalBlockAlignedVector += blockAlignedVector; totalBlockUnalignedVector += blockUnalignedVector; totalBlockRest += blockRest; #endif for(int i = 0; i < blockAlign; i++) { Compositor::template compositeOnePixelScalar(src, dst, mask, params.opacity, optionalParams); src += srcLinearInc; dst += linearInc; if(useMask) { mask++; } } for (int i = 0; i < blockAlignedVector; i++) { Compositor::template compositeVector(src, dst, mask, params.opacity, optionalParams); src += srcVectorInc; dst += vectorInc; if (useMask) { mask += vectorSize; } } for (int i = 0; i < blockUnalignedVector; i++) { Compositor::template compositeVector(src, dst, mask, params.opacity, optionalParams); src += srcVectorInc; dst += vectorInc; if (useMask) { mask += vectorSize; } } for(int i = 0; i < blockRest; i++) { Compositor::template compositeOnePixelScalar(src, dst, mask, params.opacity, optionalParams); src += srcLinearInc; dst += linearInc; if (useMask) { mask++; } } srcRowStart += params.srcRowStride; dstRowStart += params.dstRowStride; if (useMask) { maskRowStart += params.maskRowStride; } } #if BLOCKDEBUG dbgPigment << "I" << "rows:" << params.rows << "\tpad(S):" << totalBlockAlign << "\tbav(V):" << totalBlockAlignedVector << "\tbuv(V):" << totalBlockUnalignedVector << "\tres(S)" << totalBlockRest; // << srcAlignment << dstAlignment; #endif if (!params.srcRowStride) { Vc::free(reinterpret_cast(const_cast(srcRowStart))); } } template static void genericComposite32(const KoCompositeOp::ParameterInfo& params) { genericComposite(params); } template static void genericComposite128(const KoCompositeOp::ParameterInfo& params) { genericComposite(params); } }; namespace KoStreamedMathFunctions { template ALWAYS_INLINE void clearPixel(quint8* dst); template<> ALWAYS_INLINE void clearPixel<4>(quint8* dst) { quint32 *d = reinterpret_cast(dst); *d = 0; } template<> ALWAYS_INLINE void clearPixel<16>(quint8* dst) { quint64 *d = reinterpret_cast(dst); d[0] = 0; d[1] = 0; } template ALWAYS_INLINE void copyPixel(const quint8 *src, quint8* dst); template<> ALWAYS_INLINE void copyPixel<4>(const quint8 *src, quint8* dst) { const quint32 *s = reinterpret_cast(src); quint32 *d = reinterpret_cast(dst); *d = *s; } template<> ALWAYS_INLINE void copyPixel<16>(const quint8 *src, quint8* dst) { const quint64 *s = reinterpret_cast(src); quint64 *d = reinterpret_cast(dst); d[0] = s[0]; d[1] = s[1]; } } #endif /* __KOSTREAMED_MATH_H */ diff --git a/libs/ui/canvas/kis_mirror_axis.cpp b/libs/ui/canvas/kis_mirror_axis.cpp index 47d115cde0..36070a5042 100644 --- a/libs/ui/canvas/kis_mirror_axis.cpp +++ b/libs/ui/canvas/kis_mirror_axis.cpp @@ -1,401 +1,404 @@ /* * Copyright (c) 2014 Arjen Hiemstra * * 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_mirror_axis.h" #include "KoConfig.h" #include #include #include #include #include #include #include #include "kis_canvas2.h" #include "kis_canvas_resource_provider.h" #include "KisViewManager.h" #include "KisView.h" #include "kis_image.h" #include "canvas/kis_canvas_controller.h" #include "input/kis_input_manager.h" #include "kis_algebra_2d.h" class KisMirrorAxis::Private { public: Private(KisMirrorAxis* qq) : q(qq) , resourceProvider(0) , mirrorHorizontal(false) , mirrorVertical(false) , lockHorizontal(false) , lockVertical(false) , hideVerticalDecoration(false) , hideHorizontalDecoration(false) , handleSize(32.f) , xActive(false) , yActive(false) , horizontalHandlePosition(64.f) , verticalHandlePosition(64.f) , sideMargin(10.f) , minHandlePosition(10.f + 32.f) , horizontalContainsCursor(false) , verticalContainsCursor(false) , horizontalAxis(QLineF()) , verticalAxis(QLineF()) { } void setAxisPosition(float x, float y); void recomputeVisibleAxes(QRect viewport); KisMirrorAxis* q; KisCanvasResourceProvider* resourceProvider; KisImageWSP image; bool mirrorHorizontal; bool mirrorVertical; bool lockHorizontal; bool lockVertical; bool hideVerticalDecoration; bool hideHorizontalDecoration; float handleSize; QPixmap horizontalHandleIcon; QPixmap verticalHandleIcon; QPixmap horizontalIcon; QPixmap verticalIcon; QPointF axisPosition; QRectF horizontalHandle; QRectF verticalHandle; bool xActive; bool yActive; float horizontalHandlePosition; float verticalHandlePosition; float sideMargin; float minHandlePosition; bool horizontalContainsCursor; bool verticalContainsCursor; QLineF horizontalAxis; QLineF verticalAxis; }; KisMirrorAxis::KisMirrorAxis(KisCanvasResourceProvider* provider, QPointerparent) : KisCanvasDecoration("mirror_axis", parent) , d(new Private(this)) { d->resourceProvider = provider; connect(d->resourceProvider, SIGNAL(mirrorModeChanged()), SLOT(mirrorModeChanged())); connect(d->resourceProvider, SIGNAL(moveMirrorVerticalCenter()), SLOT(moveVerticalAxisToCenter())); connect(d->resourceProvider, SIGNAL(moveMirrorHorizontalCenter()), SLOT(moveHorizontalAxisToCenter())); d->mirrorHorizontal = d->resourceProvider->mirrorHorizontal(); d->mirrorVertical = d->resourceProvider->mirrorVertical(); d->horizontalIcon = KisIconUtils::loadIcon("mirrorAxis-HorizontalMove").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->verticalIcon = KisIconUtils::loadIcon("mirrorAxis-VerticalMove").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->horizontalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->verticalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); setVisible(d->mirrorHorizontal || d->mirrorVertical); d->image = parent->canvasBase()->image(); } KisMirrorAxis::~KisMirrorAxis() { delete d; } float KisMirrorAxis::handleSize() const { return d->handleSize; } void KisMirrorAxis::setHandleSize(float newSize) { if(d->handleSize != newSize) { d->handleSize = newSize; d->horizontalIcon = KisIconUtils::loadIcon("symmetry-horyzontal").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->verticalIcon = KisIconUtils::loadIcon("symmetry-vertical").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->horizontalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->verticalHandleIcon = KisIconUtils::loadIcon("transform-move").pixmap(d->handleSize, QIcon::Normal, QIcon::On); d->minHandlePosition = d->sideMargin + newSize; emit handleSizeChanged(); } } void KisMirrorAxis::drawDecoration(QPainter& gc, const QRectF& updateArea, const KisCoordinatesConverter* converter, KisCanvas2* canvas) { Q_UNUSED(updateArea); Q_UNUSED(converter); Q_UNUSED(canvas); + gc.save(); gc.setPen(QPen(QColor(0, 0, 0, 128), 1)); gc.setBrush(Qt::white); gc.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); QOpenGLContext *ctx = QOpenGLContext::currentContext(); bool hasMultisample = ((gc.paintEngine()->type() == QPaintEngine::OpenGL2) && (ctx->hasExtension("GL_ARB_multisample"))); // QPainter cannot anti-alias the edges of circles etc. when using OpenGL // So instead, use native OpenGL anti-aliasing when available. if (hasMultisample) { gc.beginNativePainting(); ctx->functions()->glEnable(GL_MULTISAMPLE); gc.endNativePainting(); } float halfHandleSize = d->handleSize / 2; d->recomputeVisibleAxes(gc.viewport()); if(d->mirrorHorizontal && !d->hideHorizontalDecoration) { if (!d->horizontalAxis.isNull()) { // QPointF horizontalIndicatorCenter = d->horizontalAxis.unitVector().pointAt(15); // QRectF horizontalIndicator = QRectF(horizontalIndicatorCenter.x() - halfHandleSize, horizontalIndicatorCenter.y() - halfHandleSize, d->handleSize, d->handleSize); float horizontalHandlePosition = qBound(d->minHandlePosition, d->horizontalHandlePosition, d->horizontalAxis.length() - d->minHandlePosition); QPointF horizontalHandleCenter = d->horizontalAxis.unitVector().pointAt(horizontalHandlePosition); d->horizontalHandle = QRectF(horizontalHandleCenter.x() - halfHandleSize, horizontalHandleCenter.y() - halfHandleSize, d->handleSize, d->handleSize); gc.setPen(QPen(QColor(0, 0, 0, 64), 2, Qt::DashDotDotLine, Qt::RoundCap, Qt::RoundJoin)); gc.drawLine(d->horizontalAxis); // gc.drawEllipse(horizontalIndicator); // gc.drawPixmap(horizontalIndicator.adjusted(5, 5, -5, -5).toRect(), d->horizontalIcon); // don't draw the handles if we are locking the axis for movement if (!d->lockHorizontal) { gc.setPen(QPen(QColor(0, 0, 0, 128), 2)); gc.drawEllipse(d->horizontalHandle); gc.drawPixmap(d->horizontalHandle.adjusted(5, 5, -5, -5).toRect(), d->horizontalIcon); } } else { d->horizontalHandle = QRectF(); } } if(d->mirrorVertical && !d->hideVerticalDecoration) { if (!d->verticalAxis.isNull()) { gc.setPen(QPen(QColor(0, 0, 0, 64), 2, Qt::DashDotDotLine, Qt::RoundCap, Qt::RoundJoin)); gc.drawLine(d->verticalAxis); // QPointF verticalIndicatorCenter = d->verticalAxis.unitVector().pointAt(15); // QRectF verticalIndicator = QRectF(verticalIndicatorCenter.x() - halfHandleSize, verticalIndicatorCenter.y() - halfHandleSize, d->handleSize, d->handleSize); float verticalHandlePosition = qBound(d->minHandlePosition, d->verticalHandlePosition, d->verticalAxis.length() - d->minHandlePosition); QPointF verticalHandleCenter = d->verticalAxis.unitVector().pointAt(verticalHandlePosition); d->verticalHandle = QRectF(verticalHandleCenter.x() - halfHandleSize, verticalHandleCenter.y() - halfHandleSize, d->handleSize, d->handleSize); // don't draw the handles if we are locking the axis for movement if (!d->lockVertical) { gc.setPen(QPen(QColor(0, 0, 0, 128), 2)); gc.drawEllipse(d->verticalHandle); gc.drawPixmap(d->verticalHandle.adjusted(5, 5, -5, -5).toRect(), d->verticalIcon); } } else { d->verticalHandle = QRectF(); } } if (hasMultisample) { gc.beginNativePainting(); ctx->functions()->glDisable(GL_MULTISAMPLE); gc.endNativePainting(); } + gc.restore(); + } bool KisMirrorAxis::eventFilter(QObject* target, QEvent* event) { if (!visible()) return false; QObject *expectedCanvasWidget = view() ? view()->canvasBase()->canvasWidget() : 0; if (!expectedCanvasWidget || target != expectedCanvasWidget) return false; if(event->type() == QEvent::MouseButtonPress || event->type() == QEvent::TabletPress) { QMouseEvent *me = dynamic_cast(event); QTabletEvent *te = dynamic_cast(event); QPoint pos = me ? me->pos() : (te ? te->pos() : QPoint(77,77)); if(d->mirrorHorizontal && d->horizontalHandle.contains(pos) && !d->lockHorizontal && !d->hideHorizontalDecoration ) { d->xActive = true; QApplication::setOverrideCursor(Qt::ClosedHandCursor); event->accept(); return true; } if(d->mirrorVertical && d->verticalHandle.contains(pos) && !d->lockVertical && !d->hideVerticalDecoration) { d->yActive = true; QApplication::setOverrideCursor(Qt::ClosedHandCursor); event->accept(); return true; } } if(event->type() == QEvent::MouseMove || event->type() == QEvent::TabletMove) { QMouseEvent *me = dynamic_cast(event); QTabletEvent *te = dynamic_cast(event); QPoint pos = me ? me->pos() : (te ? te->pos() : QPoint(77,77)); if(d->xActive) { float axisX = view()->viewConverter()->widgetToImage(pos).x(); d->setAxisPosition(axisX, d->axisPosition.y()); d->horizontalHandlePosition = KisAlgebra2D::dotProduct(pos - d->horizontalAxis.p1(), d->horizontalAxis.unitVector().p2() - d->horizontalAxis.p1()); event->accept(); return true; } if(d->yActive) { float axisY = view()->viewConverter()->widgetToImage(pos).y(); d->setAxisPosition(d->axisPosition.x(), axisY); d->verticalHandlePosition = KisAlgebra2D::dotProduct(pos - d->verticalAxis.p1(), d->verticalAxis.unitVector().p2() - d->verticalAxis.p1()); event->accept(); return true; } if(d->mirrorHorizontal && !d->hideHorizontalDecoration) { if(d->horizontalHandle.contains(pos) && !d->lockHorizontal) { if(!d->horizontalContainsCursor) { QApplication::setOverrideCursor(Qt::OpenHandCursor); d->horizontalContainsCursor = true; } } else if(d->horizontalContainsCursor) { QApplication::restoreOverrideCursor(); d->horizontalContainsCursor = false; } } if(d->mirrorVertical && !d->hideVerticalDecoration) { if(d->verticalHandle.contains(pos) && !d->lockVertical) { if(!d->verticalContainsCursor) { QApplication::setOverrideCursor(Qt::OpenHandCursor); d->verticalContainsCursor = true; } } else if(d->verticalContainsCursor) { QApplication::restoreOverrideCursor(); d->verticalContainsCursor = false; } } } if(event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::TabletRelease) { if(d->xActive) { QApplication::restoreOverrideCursor(); d->xActive = false; event->accept(); return true; } if(d->yActive) { QApplication::restoreOverrideCursor(); d->yActive = false; event->accept(); return true; } } return QObject::eventFilter(target, event); } void KisMirrorAxis::mirrorModeChanged() { d->mirrorHorizontal = d->resourceProvider->mirrorHorizontal(); d->mirrorVertical = d->resourceProvider->mirrorVertical(); d->lockHorizontal = d->resourceProvider->mirrorHorizontalLock(); d->lockVertical = d->resourceProvider->mirrorVerticalLock(); d->hideHorizontalDecoration = d->resourceProvider->mirrorHorizontalHideDecorations(); d->hideVerticalDecoration = d->resourceProvider->mirrorVerticalHideDecorations(); setVisible(d->mirrorHorizontal || d->mirrorVertical); } void KisMirrorAxis::setVisible(bool v) { KisCanvasDecoration::setVisible(v); KisInputManager *inputManager = view() ? view()->canvasBase()->globalInputManager() : 0; if (!inputManager) return; if (v) { inputManager->attachPriorityEventFilter(this); } else { inputManager->detachPriorityEventFilter(this); } } void KisMirrorAxis::moveHorizontalAxisToCenter() { d->setAxisPosition(d->image->width()/2, d->axisPosition.y()); } void KisMirrorAxis::moveVerticalAxisToCenter() { d->setAxisPosition(d->axisPosition.x(), d->image->height()/2 ); } void KisMirrorAxis::Private::setAxisPosition(float x, float y) { QPointF newPosition = QPointF(x, y); const QPointF relativePosition = KisAlgebra2D::absoluteToRelative(newPosition, image->bounds()); image->setMirrorAxesCenter(relativePosition); q->view()->canvasBase()->updateCanvas(); } void KisMirrorAxis::Private::recomputeVisibleAxes(QRect viewport) { KisCoordinatesConverter *converter = q->view()->viewConverter(); axisPosition = KisAlgebra2D::relativeToAbsolute(image->mirrorAxesCenter(), image->bounds()); QPointF samplePt1 = converter->imageToWidget(axisPosition); QPointF samplePt2 = converter->imageToWidget(QPointF(axisPosition.x(), axisPosition.y() - 100)); horizontalAxis = QLineF(samplePt1, samplePt2); if (!KisAlgebra2D::intersectLineRect(horizontalAxis, viewport)) horizontalAxis = QLineF(); samplePt2 = converter->imageToWidget(QPointF(axisPosition.x() - 100, axisPosition.y())); verticalAxis = QLineF(samplePt1, samplePt2); if (!KisAlgebra2D::intersectLineRect(verticalAxis, viewport)) verticalAxis = QLineF(); } diff --git a/libs/widgets/KoResourceItemChooserContextMenu.cpp b/libs/widgets/KoResourceItemChooserContextMenu.cpp index d646b16547..3ec8d2b7e5 100644 --- a/libs/widgets/KoResourceItemChooserContextMenu.cpp +++ b/libs/widgets/KoResourceItemChooserContextMenu.cpp @@ -1,213 +1,216 @@ /* This file is part of the KDE project * Copyright (c) 2013 Sascha Suelzer * * 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 "KoResourceItemChooserContextMenu.h" #include #include #include #include #include -#include #include KoLineEditAction::KoLineEditAction(QObject* parent) : QWidgetAction(parent) , m_closeParentOnTrigger(false) { QWidget* pWidget = new QWidget (0); QHBoxLayout* pLayout = new QHBoxLayout(); m_label = new QLabel(0); m_editBox = new QLineEdit(0); + m_editBox->setClearButtonEnabled(true); + m_AddButton = new QPushButton(); + m_AddButton->setIcon(koIcon("list-add")); pLayout->addWidget(m_label); pLayout->addWidget(m_editBox); + pLayout->addWidget(m_AddButton); pWidget->setLayout(pLayout); setDefaultWidget(pWidget); - connect (m_editBox, SIGNAL(returnPressed()), - this, SLOT(onTriggered())); + connect (m_editBox, &QLineEdit::returnPressed, this, &KoLineEditAction::onTriggered); + connect (m_AddButton, &QPushButton::clicked, this, &KoLineEditAction::onTriggered); } KoLineEditAction::~KoLineEditAction() { } void KoLineEditAction::setIcon(const QIcon &icon) { QPixmap pixmap = QPixmap(icon.pixmap(16,16)); m_label->setPixmap(pixmap); } void KoLineEditAction::closeParentOnTrigger(bool closeParent) { m_closeParentOnTrigger = closeParent; } bool KoLineEditAction::closeParentOnTrigger() { return m_closeParentOnTrigger; } void KoLineEditAction::onTriggered() { if (! m_editBox->text().isEmpty()) { emit triggered( m_editBox->text()); m_editBox->text().clear(); if (m_closeParentOnTrigger) { this->parentWidget()->close(); m_editBox->clearFocus(); } } } void KoLineEditAction::setPlaceholderText(const QString& clickMessage) { m_editBox->setPlaceholderText(clickMessage); } void KoLineEditAction::setText(const QString& text) { m_editBox->setText(text); } void KoLineEditAction::setVisible(bool showAction) { QLayout* currentLayout = defaultWidget()->layout(); this->QAction::setVisible(showAction); for(int i=0;icount();i++) { currentLayout->itemAt(i)->widget()->setVisible(showAction); } defaultWidget()->setVisible(showAction); } ContextMenuExistingTagAction::ContextMenuExistingTagAction(KoResource* resource, QString tag, QObject* parent) : QAction(parent) , m_resource(resource) , m_tag(tag) { setText(tag); connect (this, SIGNAL(triggered()), this, SLOT(onTriggered())); } ContextMenuExistingTagAction::~ContextMenuExistingTagAction() { } void ContextMenuExistingTagAction::onTriggered() { emit triggered(m_resource, m_tag); } NewTagAction::~NewTagAction() { } NewTagAction::NewTagAction(KoResource* resource, QMenu* parent) :KoLineEditAction (parent) { m_resource = resource; setIcon(koIcon("document-new")); setPlaceholderText(i18n("New tag")); closeParentOnTrigger(true); connect (this, SIGNAL(triggered(QString)), this, SLOT(onTriggered(QString))); } void NewTagAction::onTriggered(const QString & tagName) { emit triggered(m_resource,tagName); } KoResourceItemChooserContextMenu::KoResourceItemChooserContextMenu(KoResource* resource, const QStringList& resourceTags, const QString& currentlySelectedTag, const QStringList& allTags) { QImage image = resource->image(); QIcon icon(QPixmap::fromImage(image)); QAction * label = new QAction(resource->name(), this); label->setIcon(icon); addAction(label); QMenu * removableTagsMenu; QMenu * assignableTagsMenu; QStringList removables = resourceTags; QStringList assignables = allTags; removables.sort(); assignables.sort(); assignableTagsMenu = addMenu(koIcon("list-add"),i18n("Assign to tag")); if (!removables.isEmpty()) { addSeparator(); QString currentTag = currentlySelectedTag; if (removables.contains(currentTag)) { assignables.removeAll(currentTag); removables.removeAll(currentTag); ContextMenuExistingTagAction * removeTagAction = new ContextMenuExistingTagAction(resource, currentTag, this); removeTagAction->setText(i18n("Remove from this tag")); removeTagAction->setIcon(koIcon("list-remove")); connect(removeTagAction, SIGNAL(triggered(KoResource*,QString)), this, SIGNAL(resourceTagRemovalRequested(KoResource*,QString))); addAction(removeTagAction); } if (!removables.isEmpty()) { removableTagsMenu = addMenu(koIcon("list-remove"),i18n("Remove from other tag")); foreach (const QString &tag, removables) { assignables.removeAll(tag); ContextMenuExistingTagAction * removeTagAction = new ContextMenuExistingTagAction(resource, tag, this); connect(removeTagAction, SIGNAL(triggered(KoResource*,QString)), this, SIGNAL(resourceTagRemovalRequested(KoResource*,QString))); removableTagsMenu->addAction(removeTagAction); } } } foreach (const QString &tag, assignables) { ContextMenuExistingTagAction * addTagAction = new ContextMenuExistingTagAction(resource, tag, this); connect(addTagAction, SIGNAL(triggered(KoResource*,QString)), this, SIGNAL(resourceTagAdditionRequested(KoResource*,QString))); assignableTagsMenu->addAction(addTagAction); } assignableTagsMenu->addSeparator(); NewTagAction * addTagAction = new NewTagAction(resource, this); connect(addTagAction, SIGNAL(triggered(KoResource*,QString)), this, SIGNAL(resourceAssignmentToNewTagRequested(KoResource*,QString))); assignableTagsMenu->addAction(addTagAction); } KoResourceItemChooserContextMenu::~KoResourceItemChooserContextMenu() { } diff --git a/libs/widgets/KoResourceItemChooserContextMenu.h b/libs/widgets/KoResourceItemChooserContextMenu.h index 970a930a6d..fc58380c6b 100644 --- a/libs/widgets/KoResourceItemChooserContextMenu.h +++ b/libs/widgets/KoResourceItemChooserContextMenu.h @@ -1,120 +1,121 @@ /* * This file is part of the KDE project * Copyright (c) 2013 Sascha Suelzer * * 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 KORESOURCEITEMCHOOSERCONTEXTMENU_H #define KORESOURCEITEMCHOOSERCONTEXTMENU_H #include #include #include -#include +#include +#include -class QLineEdit; class KoResource; class ContextMenuExistingTagAction : public QAction { Q_OBJECT public: explicit ContextMenuExistingTagAction( KoResource * resource, QString tag, QObject* parent = 0); ~ContextMenuExistingTagAction() override; Q_SIGNALS: void triggered(KoResource * resource, QString tag); protected Q_SLOTS: void onTriggered(); private: KoResource * m_resource; QString m_tag; }; /*! * A line edit QWidgetAction. * Default behavior: Closes its parent upon triggering. */ class KoLineEditAction : public QWidgetAction { Q_OBJECT public: explicit KoLineEditAction(QObject* parent); ~KoLineEditAction() override; void setIcon(const QIcon &icon); void closeParentOnTrigger(bool closeParent); bool closeParentOnTrigger(); void setPlaceholderText(const QString& clickMessage); void setText(const QString& text); void setVisible(bool showAction); Q_SIGNALS: void triggered(const QString &tag); protected Q_SLOTS: void onTriggered(); private: bool m_closeParentOnTrigger; QLabel * m_label; QLineEdit * m_editBox; + QPushButton * m_AddButton; }; class NewTagAction : public KoLineEditAction { Q_OBJECT public: explicit NewTagAction (KoResource* resource, QMenu* parent); ~NewTagAction() override; Q_SIGNALS: void triggered(KoResource * resource, const QString &tag); protected Q_SLOTS: void onTriggered(const QString& tagName); private: KoResource * m_resource; }; class KoResourceItemChooserContextMenu : public QMenu { Q_OBJECT public: explicit KoResourceItemChooserContextMenu ( KoResource* resource, const QStringList& resourceTags, const QString& currentlySelectedTag, const QStringList& allTags ); ~KoResourceItemChooserContextMenu() override; Q_SIGNALS: /// Emitted when a resource should be added to an existing tag. void resourceTagAdditionRequested(KoResource* resource, const QString& tag); /// Emitted when a resource should be removed from an existing tag. void resourceTagRemovalRequested(KoResource* resource, const QString& tag); /// Emitted when a resource should be added to a new tag, which will need to be created. void resourceAssignmentToNewTagRequested(KoResource* resource, const QString& tag); }; #endif // KORESOURCEITEMCHOOSERCONTEXTMENU_H diff --git a/libs/widgets/kis_file_name_requester.cpp b/libs/widgets/kis_file_name_requester.cpp index 9e75aca3a0..e54080cbde 100644 --- a/libs/widgets/kis_file_name_requester.cpp +++ b/libs/widgets/kis_file_name_requester.cpp @@ -1,110 +1,108 @@ /* * 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 "kis_file_name_requester.h" #include "ui_wdg_file_name_requester.h" #include #include #include "KoIcon.h" KisFileNameRequester::KisFileNameRequester(QWidget *parent) : QWidget(parent) , m_ui(new Ui::WdgFileNameRequester) , m_mode(KoFileDialog::OpenFile) , m_name("OpenDocument") { m_ui->setupUi(this); m_ui->btnSelectFile->setIcon(kisIcon("folder")); connect(m_ui->btnSelectFile, SIGNAL(clicked()), SLOT(slotSelectFile())); connect(m_ui->txtFileName, SIGNAL(textChanged(QString)), SIGNAL(textChanged(QString))); } KisFileNameRequester::~KisFileNameRequester() { } void KisFileNameRequester::setStartDir(const QString &path) { m_basePath = path; } void KisFileNameRequester::setConfigurationName(const QString &name) { m_name = name; } void KisFileNameRequester::setFileName(const QString &path) { m_ui->txtFileName->setText(path); m_basePath = path; emit fileSelected(path); } QString KisFileNameRequester::fileName() const { return m_ui->txtFileName->text(); } void KisFileNameRequester::setMode(KoFileDialog::DialogType mode) { m_mode = mode; } KoFileDialog::DialogType KisFileNameRequester::mode() const { return m_mode; } -void KisFileNameRequester::setMimeTypeFilters(const QStringList &filterList, - QString defaultFilter) +void KisFileNameRequester::setMimeTypeFilters(const QStringList &filterList, QString defaultFilter) { m_mime_filter_list = filterList; m_mime_default_filter = defaultFilter; } void KisFileNameRequester::slotSelectFile() { KoFileDialog dialog(this, m_mode, m_name); if (m_mode == KoFileDialog::OpenFile) { dialog.setCaption(i18n("Select a file to load...")); } else if (m_mode == KoFileDialog::OpenDirectory) { dialog.setCaption(i18n("Select a directory to load...")); } if (m_basePath.isEmpty()) { dialog.setDefaultDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)); } else { dialog.setDefaultDir(m_basePath); } - Q_ASSERT(!m_mime_filter_list.isEmpty()); dialog.setMimeTypeFilters(m_mime_filter_list, m_mime_default_filter); QString newFileName = dialog.filename(); if (!newFileName.isEmpty()) { setFileName(newFileName); } } diff --git a/plugins/dockers/touchdocker/TouchDockerDock.cpp b/plugins/dockers/touchdocker/TouchDockerDock.cpp index 616fc17872..a0e2757956 100644 --- a/plugins/dockers/touchdocker/TouchDockerDock.cpp +++ b/plugins/dockers/touchdocker/TouchDockerDock.cpp @@ -1,401 +1,411 @@ /* * Copyright (c) 2017 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. */ #include "TouchDockerDock.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 namespace { bool shouldSetAcceptTouchEvents() { // See https://bugreports.qt.io/browse/QTBUG-66718 static QVersionNumber qtVersion = QVersionNumber::fromString(qVersion()); static bool retval = qtVersion > QVersionNumber(5, 9, 3) && qtVersion.normalized() != QVersionNumber(5, 10); return retval; } } // namespace class TouchDockerDock::Private { public: Private() { } TouchDockerDock *q; bool allowClose {true}; KisSketchView *sketchView {0}; QString currentSketchPage; KoDialog *openDialog {0}; KoDialog *saveAsDialog {0}; QMap buttonMapping; bool shiftOn {false}; bool ctrlOn {false}; bool altOn {false}; }; TouchDockerDock::TouchDockerDock() : QDockWidget(i18n("Touch Docker")) , d(new Private()) { QStringList defaultMapping = QStringList() << "decrease_opacity" << "increase_opacity" << "make_brush_color_lighter" << "make_brush_color_darker" << "decrease_brush_size" << "increase_brush_size" << "previous_preset" << "clear"; QStringList mapping = KisConfig(true).readEntry("touchdockermapping", defaultMapping.join(',')).split(','); for (int i = 0; i < 8; ++i) { if (i < mapping.size()) { d->buttonMapping[QString("button%1").arg(i + 1)] = mapping[i]; } else if (i < defaultMapping.size()) { d->buttonMapping[QString("button%1").arg(i + 1)] = defaultMapping[i]; } } m_quickWidget = new QQuickWidget(this); if (shouldSetAcceptTouchEvents()) { m_quickWidget->setAttribute(Qt::WA_AcceptTouchEvents); } setWidget(m_quickWidget); setEnabled(true); m_quickWidget->engine()->rootContext()->setContextProperty("mainWindow", this); m_quickWidget->engine()->addImportPath(KoResourcePaths::getApplicationRoot() + "/lib/qml/"); m_quickWidget->engine()->addImportPath(KoResourcePaths::getApplicationRoot() + "/lib64/qml/"); m_quickWidget->engine()->addPluginPath(KoResourcePaths::getApplicationRoot() + "/lib/qml/"); m_quickWidget->engine()->addPluginPath(KoResourcePaths::getApplicationRoot() + "/lib64/qml/"); Settings *settings = new Settings(this); DocumentManager::instance()->setSettingsManager(settings); m_quickWidget->engine()->rootContext()->setContextProperty("Settings", settings); Theme *theme = Theme::load(KSharedConfig::openConfig()->group("General").readEntry("theme", "default"), m_quickWidget->engine()); if (theme) { settings->setTheme(theme); } m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); m_quickWidget->setSource(QUrl("qrc:/touchstrip.qml")); } TouchDockerDock::~TouchDockerDock() { } bool TouchDockerDock::allowClose() const { return d->allowClose; } void TouchDockerDock::setAllowClose(bool allow) { d->allowClose = allow; } QString TouchDockerDock::currentSketchPage() const { return d->currentSketchPage; } void TouchDockerDock::setCurrentSketchPage(QString newPage) { d->currentSketchPage = newPage; emit currentSketchPageChanged(); } void TouchDockerDock::closeEvent(QCloseEvent* event) { if (!d->allowClose) { event->ignore(); emit closeRequested(); } else { event->accept(); } } void TouchDockerDock::slotButtonPressed(const QString &id) { if (id == "fileOpenButton") { showFileOpenDialog(); } else if (id == "fileSaveButton" && m_canvas && m_canvas->viewManager() && m_canvas->viewManager()->document()) { bool batchMode = m_canvas->viewManager()->document()->fileBatchMode(); m_canvas->viewManager()->document()->setFileBatchMode(true); m_canvas->viewManager()->document()->save(true, 0); m_canvas->viewManager()->document()->setFileBatchMode(batchMode); } else if (id == "fileSaveAsButton" && m_canvas && m_canvas->viewManager() && m_canvas->viewManager()->document()) { showFileSaveAsDialog(); } else { QAction *a = action(id); if (a) { if (a->isCheckable()) { a->toggle(); } else { a->trigger(); } } else if (id == "shift") { // set shift state for the next pointer event, somehow QKeyEvent event(d->shiftOn ? QEvent::KeyRelease : QEvent::KeyPress, 0, Qt::ShiftModifier); QApplication::sendEvent(KisPart::instance()->currentMainwindow(), &event); d->shiftOn = !d->shiftOn; } else if (id == "ctrl") { // set ctrl state for the next pointer event, somehow QKeyEvent event(d->ctrlOn ? QEvent::KeyRelease : QEvent::KeyPress, 0, Qt::ControlModifier); QApplication::sendEvent(KisPart::instance()->currentMainwindow(), &event); d->ctrlOn = !d->ctrlOn; } else if (id == "alt") { // set alt state for the next pointer event, somehow QKeyEvent event(d->altOn ? QEvent::KeyRelease : QEvent::KeyPress, 0, Qt::AltModifier); QApplication::sendEvent(KisPart::instance()->currentMainwindow(), &event); d->altOn = !d->altOn; } } } void TouchDockerDock::slotOpenImage(QString path) { if (d->openDialog) { d->openDialog->accept(); } KisPart::instance()->currentMainwindow()->openDocument(QUrl::fromLocalFile(path), KisMainWindow::None); } void TouchDockerDock::slotSaveAs(QString path, QString mime) { if (d->saveAsDialog) { d->saveAsDialog->accept(); } m_canvas->viewManager()->document()->saveAs(QUrl::fromLocalFile(path), mime.toLatin1(), true); m_canvas->viewManager()->document()->waitForSavingToComplete(); } void TouchDockerDock::hideFileOpenDialog() { if (d->openDialog) { d->openDialog->accept(); } } void TouchDockerDock::hideFileSaveAsDialog() { if (d->saveAsDialog) { d->saveAsDialog->accept(); } } QString TouchDockerDock::imageForButton(QString id) { if (d->buttonMapping.contains(id)) { id = d->buttonMapping[id]; } if (KisActionRegistry::instance()->hasAction(id)) { QString a = KisActionRegistry::instance()->getActionProperty(id, "icon"); if (!a.isEmpty()) { return "image://icon/" + a; } } return QString(); } QString TouchDockerDock::textForButton(QString id) { if (d->buttonMapping.contains(id)) { id = d->buttonMapping[id]; } if (KisActionRegistry::instance()->hasAction(id)) { QString a = KisActionRegistry::instance()->getActionProperty(id, "iconText"); if (a.isEmpty()) { a = KisActionRegistry::instance()->getActionProperty(id, "text"); } return a; } return id; } QAction *TouchDockerDock::action(QString id) const { if (m_canvas && m_canvas->viewManager()) { if (d->buttonMapping.contains(id)) { id = d->buttonMapping[id]; } return m_canvas->viewManager()->actionManager()->actionByName(id); } return 0; } void TouchDockerDock::showFileOpenDialog() { if (!d->openDialog) { d->openDialog = createDialog("qrc:/opendialog.qml"); } d->openDialog->exec(); } void TouchDockerDock::showFileSaveAsDialog() { if (!d->openDialog) { d->openDialog = createDialog("qrc:/saveasdialog.qml"); } d->openDialog->exec(); } +void TouchDockerDock::changeEvent(QEvent *event) +{ + if (event->type() == QEvent::PaletteChange) { + m_quickWidget->setSource(QUrl("qrc:/touchstrip.qml")); + event->accept(); + } else { + event->ignore(); + } +} + KoDialog *TouchDockerDock::createDialog(const QString qml) { KoDialog *dlg = new KoDialog(this); dlg->setButtons(KoDialog::None); QQuickWidget *quickWidget = new QQuickWidget(this); if (shouldSetAcceptTouchEvents()) { quickWidget->setAttribute(Qt::WA_AcceptTouchEvents); } dlg->setMainWidget(quickWidget); setEnabled(true); quickWidget->engine()->rootContext()->setContextProperty("mainWindow", this); quickWidget->engine()->addImportPath(KoResourcePaths::getApplicationRoot() + "/lib/qml/"); quickWidget->engine()->addImportPath(KoResourcePaths::getApplicationRoot() + "/lib64/qml/"); quickWidget->engine()->addPluginPath(KoResourcePaths::getApplicationRoot() + "/lib/qml/"); quickWidget->engine()->addPluginPath(KoResourcePaths::getApplicationRoot() + "/lib64/qml/"); Settings *settings = new Settings(this); DocumentManager::instance()->setSettingsManager(settings); quickWidget->engine()->rootContext()->setContextProperty("Settings", settings); Theme *theme = Theme::load(KSharedConfig::openConfig()->group("General").readEntry("theme", "default"), quickWidget->engine()); settings->setTheme(theme); quickWidget->setSource(QUrl(qml)); quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); dlg->setMinimumSize(1280, 768); return dlg; } QObject *TouchDockerDock::sketchKisView() const { return d->sketchView; } void TouchDockerDock::setSketchKisView(QObject* newView) { if (d->sketchView) { d->sketchView->disconnect(this); } if (d->sketchView != newView) { d->sketchView = qobject_cast(newView); emit sketchKisViewChanged(); } } void TouchDockerDock::setCanvas(KoCanvasBase *canvas) { setEnabled(true); if (m_canvas == canvas) { return; } if (m_canvas) { m_canvas->disconnectCanvasObserver(this); } if (!canvas) { m_canvas = 0; return; } m_canvas = dynamic_cast(canvas); } void TouchDockerDock::unsetCanvas() { setEnabled(true); m_canvas = 0; } diff --git a/plugins/dockers/touchdocker/TouchDockerDock.h b/plugins/dockers/touchdocker/TouchDockerDock.h index 6678daaa3c..16e2fb5a9f 100644 --- a/plugins/dockers/touchdocker/TouchDockerDock.h +++ b/plugins/dockers/touchdocker/TouchDockerDock.h @@ -1,90 +1,91 @@ /* * Copyright (c) 2017 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 TOUCHDOCKER_DOCK_H #define TOUCHDOCKER_DOCK_H #include #include #include #include #include class KoDialog; class QQuickWidget; class TouchDockerDock : public QDockWidget, public KoCanvasObserverBase { Q_OBJECT Q_PROPERTY(bool allowClose READ allowClose WRITE setAllowClose) Q_PROPERTY(QString currentSketchPage READ currentSketchPage WRITE setCurrentSketchPage NOTIFY currentSketchPageChanged) Q_PROPERTY(QObject* sketchKisView READ sketchKisView WRITE setSketchKisView NOTIFY sketchKisViewChanged) public: TouchDockerDock(); ~TouchDockerDock() override; QString observerName() override { return "TouchDockerDock"; } void setCanvas(KoCanvasBase *canvas) override; void unsetCanvas() override; bool allowClose() const; void setAllowClose(bool allow); QString currentSketchPage() const; void setCurrentSketchPage(QString newPage); QObject *sketchKisView() const; void setSketchKisView(QObject *newView); virtual void closeEvent(QCloseEvent *event); Q_SIGNALS: void closeRequested(); void currentSketchPageChanged(); void sketchKisViewChanged(); public Q_SLOTS: void slotButtonPressed(const QString &id); void slotOpenImage(QString path); void slotSaveAs(QString path, QString mime); void hideFileOpenDialog(); void hideFileSaveAsDialog(); QString imageForButton(QString id); QString textForButton(QString id); QAction *action(QString id) const; private: void showFileOpenDialog(); void showFileSaveAsDialog(); + void changeEvent(QEvent* event) override; KoDialog *createDialog(const QString qml); QPointer m_canvas; QQuickWidget *m_quickWidget {0}; class Private; const QScopedPointer d; }; #endif diff --git a/plugins/dockers/touchdocker/qml/touchstrip.qml b/plugins/dockers/touchdocker/qml/touchstrip.qml index e2bb2cc8a2..2ebd46952a 100644 --- a/plugins/dockers/touchdocker/qml/touchstrip.qml +++ b/plugins/dockers/touchdocker/qml/touchstrip.qml @@ -1,287 +1,137 @@ import QtQuick 2.3 import org.krita.sketch 1.0 import org.krita.sketch.components 1.0 Rectangle { - id: base - color: "#545454" + id: root + SystemPalette { + id: palette; + colorGroup: SystemPalette.Active } + property int rowHeight: height/13; + color: palette.base; - Button { - id: fileOpenButton - color: "grey" - radius: 8 - width: base.width / 3 - height: base.height / 13 - anchors.left: base.left - anchors.top: base.top - image: Settings.theme.icon("fileopen"); - onClicked: { - mainWindow.slotButtonPressed("fileOpenButton") + Column { + width: root.width + Row { + height: root.rowHeight; + Repeater { + model: ["fileOpen", "fileSave", "fileSaveAs"] + + Button { + color: palette.button + highlightColor: palette.highlight + textColor: palette.buttonText + radius: 8; + width: root.width / 3 + height: parent.height; + onClicked: { + mainWindow.slotButtonPressed(modelData+"Button") + } + image: Settings.theme.icon(modelData.toLowerCase()); + } + } + } + Row { + width: parent.width; + height: root.rowHeight; + Button { + color: palette.button + highlightColor: palette.highlight + textColor: palette.buttonText + radius: 8; + id: undoButton + width: root.width / 2 + height: parent.height; + image: Settings.theme.icon("undo"); + onClicked: { + mainWindow.slotButtonPressed("edit_undo") + } + } + + Button { + color: palette.button + highlightColor: palette.highlight + textColor: palette.buttonText + radius: 8; + width: root.width / 2 + height: parent.height; + image: Settings.theme.icon("redo"); + onClicked: { + mainWindow.slotButtonPressed("edit_redo") + } + } + } + + Repeater { + width: parent.width; + height: childrenRect.height; + model: [1, 2, 3, 4] + Button { + color: palette.button + highlightColor: palette.highlight + textColor: palette.buttonText + radius: 8; + width: parent.width; + height: root.rowHeight + text: mainWindow.imageForButton("button" + modelData) === "" ? mainWindow.textForButton("button" + modelData) : "" + checkable: text === "shift" || text == "ctrl" || text == "alt" ? true : false; + onClicked: { + mainWindow.slotButtonPressed("button" + modelData) + } + image: mainWindow.imageForButton("button" + modelData); + + } + } + + Grid { + columns: 3 + rows: 3 + Repeater { + model: ["", "view_zoom_in", "", "rotate_canvas_left", "reset_canvas_rotation", "rotate_canvas_right", "", "view_zoom_out", ""] + Item { + height: root.rowHeight + width: root.width/3 + Button { + id: rockerSwitch + color: palette.button + highlightColor: palette.highlight + textColor: palette.buttonText + radius: 8; + anchors.fill: parent; + visible: modelData !== ""; + image: mainWindow.imageForButton(modelData); + onClicked: { + mainWindow.slotButtonPressed(modelData) + if (modelData === "reset_canvas_rotation") { + mainWindow.slotButtonPressed("zoom_to_100pct") + } + } + } + } + } + } + + + + Repeater { + width: parent.width; + height: childrenRect.height; + model: [5, 6, 7, 8] + Button { + color: palette.button + highlightColor: palette.highlight + textColor: palette.buttonText + radius: 8; + width: parent.width; + height: root.rowHeight + text: mainWindow.imageForButton("button" + modelData) === "" ? mainWindow.textForButton("button" + modelData) : "" + checkable: text === "shift" || text == "ctrl" || text == "alt" ? true : false; + onClicked: { + mainWindow.slotButtonPressed("button" + modelData) + } + image: mainWindow.imageForButton("button" + modelData); + + } } } - - Button { - id: fileSaveButton - color: "grey" - radius: 8 - width: base.width / 3 - height: base.height / 13 - anchors.top: base.top - anchors.left: fileOpenButton.right - image: Settings.theme.icon("filesave"); - onClicked: { - mainWindow.slotButtonPressed("fileSaveButton") - } - } - - Button { - id: fileSaveAsButton - color: "grey" - radius: 8 - width: base.width / 3 - height: base.height / 13 - anchors.top: base.top - anchors.left: fileSaveButton.right - image: Settings.theme.icon("filesaveas"); - onClicked: { - mainWindow.slotButtonPressed("fileSaveAsButton") - } - } - - Button { - id: undoButton - color: "grey" - radius: 8 - width: base.width / 2 - height: base.height / 13 - anchors.left: base.left - anchors.top: fileOpenButton.bottom - image: Settings.theme.icon("undo"); - onClicked: { - mainWindow.slotButtonPressed("edit_undo") - } - } - - Button { - id: redoButton - color: "grey" - radius: 8 - width: base.width / 2 - height: base.height / 13 - anchors.left: undoButton.right - anchors.top: undoButton.top - image: Settings.theme.icon("redo"); - onClicked: { - mainWindow.slotButtonPressed("edit_redo") - } - } - - Button { - id: button1 - color: "grey" - width: base.width - height: base.height / 13 - anchors.left: base.left - anchors.top: undoButton.bottom - radius: 3 - text: mainWindow.imageForButton("button1") === "" ? mainWindow.textForButton("button1") : "" - checkable: text === "shift" || text == "ctrl" || text == "alt" ? true : false; - image: mainWindow.imageForButton("button1") - onClicked: { - mainWindow.slotButtonPressed("button1") - } - } - - Button { - id: button2 - color: "grey" - width: base.width - height: base.height / 13 - anchors.left: base.left - anchors.top: button1.bottom - radius: 3 - text: mainWindow.imageForButton("button2") === "" ? mainWindow.textForButton("button2") : "" - checkable: text === "shift" || text == "ctrl" || text == "alt" ? true : false; - image: mainWindow.imageForButton("button2") - onClicked: { - mainWindow.slotButtonPressed("button2") - } - } - - Button { - id: button3 - color: "grey" - width: base.width - height: base.height / 13 - anchors.left: base.left - anchors.top: button2.bottom - radius: 3 - text: mainWindow.imageForButton("button3") === "" ? mainWindow.textForButton("button3") : "" - checkable: text === "shift" || text == "ctrl" || text == "alt" ? true : false; - image: mainWindow.imageForButton("button3") - onClicked: { - mainWindow.slotButtonPressed("button3") - } - } - - Button { - id: button4 - color: "grey" - width: base.width - height: base.height / 13 - anchors.left: base.left - anchors.top: button3.bottom - radius: 3 - text: mainWindow.imageForButton("button4") === "" ? mainWindow.textForButton("button4") : "" - checkable: text === "shift" || text == "ctrl" || text == "alt" ? true : false; - image: mainWindow.imageForButton("button4") - onClicked: { - mainWindow.slotButtonPressed("button4") - } - } - - Button { - id: rockerSwitchTop - color: "grey" - radius: 8 - width: base.width / 3 - height: base.height / 13 - anchors.left: fileSaveButton.left - anchors.top: button4.bottom - - anchors.right: rockerSwitchCenter.Left - image: mainWindow.imageForButton("view_zoom_in") - onClicked: { - mainWindow.slotButtonPressed("view_zoom_in") - } - } - - - Button { - id: rockerSwitchLeft - color: "grey" - radius: 8 - width: base.width / 3 - height: base.height / 13 - anchors.left: base.left - anchors.top: rockerSwitchTop.bottom - - image: mainWindow.imageForButton("rotate_canvas_left") - onClicked: { - mainWindow.slotButtonPressed("rotate_canvas_left") - } - } - - Button { - id: rockerSwitchCenter - color: "grey" - radius: 8 - width: base.width / 3 - height: base.height / 13 - anchors.left: rockerSwitchLeft.right - anchors.top: rockerSwitchTop.bottom - - image: mainWindow.imageForButton("reset_canvas_rotation") - onClicked: { - mainWindow.slotButtonPressed("reset_canvas_rotation") - mainWindow.slotButtonPressed("zoom_to_100pct") - } - } - - Button { - id: rockerSwitchRight - color: "grey" - radius: 8 - width: base.width / 3 - height: base.height / 13 - anchors.left: rockerSwitchCenter.right - anchors.top: rockerSwitchTop.bottom - - image: mainWindow.imageForButton("rotate_canvas_right") - onClicked: { - mainWindow.slotButtonPressed("rotate_canvas_right") - } - } - - Button { - id: rockerSwitchBottom - color: "grey" - radius: 8 - width: base.width / 3 - height: base.height / 13 - anchors.left: rockerSwitchCenter.left - anchors.top: rockerSwitchCenter.bottom - - anchors.right: rockerSwitchCenter.Left - image: mainWindow.imageForButton("view_zoom_out") - onClicked: { - mainWindow.slotButtonPressed("view_zoom_out") - } - } - - Button { - id: button5 - color: "grey" - width: base.width - height: base.height / 13 - anchors.left: base.left - anchors.top: rockerSwitchBottom.bottom - radius: 3 - text: mainWindow.imageForButton("button5") === "" ? mainWindow.textForButton("button5") : "" - checkable: text === "shift" || text == "ctrl" || text == "alt" ? true : false; - image: mainWindow.imageForButton("button5") - onClicked: { - mainWindow.slotButtonPressed("button5") - } - } - - Button { - id: button6 - color: "grey" - width: base.width - height: base.height / 13 - anchors.left: base.left - anchors.top: button5.bottom - radius: 3 - text: mainWindow.imageForButton("button6") === "" ? mainWindow.textForButton("button6") : "" - checkable: text === "shift" || text == "ctrl" || text == "alt" ? true : false; - image: mainWindow.imageForButton("button6") - onClicked: { - mainWindow.slotButtonPressed("button6") - } - } - - Button { - id: button7 - color: "grey" - width: base.width - height: base.height / 13 - anchors.left: base.left - anchors.top: button6.bottom - radius: 3 - text: mainWindow.imageForButton("button7") === "" ? mainWindow.textForButton("button7") : "" - checkable: text === "shift" || text == "ctrl" || text == "alt" ? true : false; - image: mainWindow.imageForButton("button7") - onClicked: { - mainWindow.slotButtonPressed("button7") - } - } - - Button { - id: button8 - color: "grey" - width: base.width - height: base.height / 13 - anchors.left: base.left - anchors.top: button7.bottom - radius: 3 - text: mainWindow.imageForButton("button8") === "" ? mainWindow.textForButton("button8") : "" - checkable: text === "shift" || text == "ctrl" || text == "alt" ? true : false; - image: mainWindow.imageForButton("button8") - onClicked: { - mainWindow.slotButtonPressed("button8") - } - } - - } diff --git a/plugins/extensions/pykrita/sip/krita/Document.sip b/plugins/extensions/pykrita/sip/krita/Document.sip index d56cebc266..9424ed3a32 100644 --- a/plugins/extensions/pykrita/sip/krita/Document.sip +++ b/plugins/extensions/pykrita/sip/krita/Document.sip @@ -1,88 +1,89 @@ class Document : QObject /NoDefaultCtors/ { %TypeHeaderCode #include "Document.h" %End Document(const Document & __0); public: bool operator==(const Document &other) const; bool operator!=(const Document &other) const; QList horizontalGuides() const; QList verticalGuides() const; bool guidesVisible() const; bool guidesLocked() const; public Q_SLOTS: Document *clone() const /Factory/; Node * activeNode() const /Factory/; void setActiveNode(Node* value); QList topLevelNodes() const /Factory/; Node *nodeByName(const QString &node) const /Factory/; bool batchmode() const; void setBatchmode(bool value); QString colorDepth() const; QString colorModel() const; QString colorProfile() const; bool setColorProfile(const QString &colorProfile); bool setColorSpace(const QString &value, const QString &colorDepth, const QString &colorProfile); QColor backgroundColor(); bool setBackgroundColor(const QColor &color); QString documentInfo() const; void setDocumentInfo(const QString &document); QString fileName() const; void setFileName(QString value); int height() const; void setHeight(int value); QString name() const; void setName(QString value); int resolution() const; void setResolution(int value); Node * rootNode() const /Factory/; Selection * selection() const /Factory/; void setSelection(Selection* value); int width() const; void setWidth(int value); int xOffset() const; void setXOffset(int x); int yOffset() const; void setYOffset(int y); double xRes() const; void setXRes(double xRes) const; double yRes() const; void setYRes(double yRes) const; QByteArray pixelData(int x, int y, int w, int h) const; bool close(); void crop(int x, int y, int w, int h); bool exportImage(const QString &filename, const InfoObject & exportConfiguration); void flatten(); void resizeImage(int x, int y, int w, int h); void scaleImage(int w, int h, int xres, int yres, QString strategy); void rotateImage(double radians); void shearImage(double angleX, double angleY); bool save(); bool saveAs(const QString & filename); Node *createNode(const QString & name, const QString & nodeType) /Factory/; GroupLayer *createGroupLayer(const QString &name) /Factory/; CloneLayer *createCloneLayer(const QString &name, const Node *source) /Factory/; FilterLayer *createFilterLayer(const QString &name, Filter &filter, Selection &selection) /Factory/; FillLayer *createFillLayer(const QString &name, const QString filterName, InfoObject &configuration, Selection &selection) /Factory/; VectorLayer *createVectorLayer(const QString &name) /Factory/; FilterMask *createFilterMask(const QString &name, Filter &filter) /Factory/; SelectionMask *createSelectionMask(const QString &name) /Factory/; QImage projection(int x = 0, int y = 0, int w = 0, int h = 0) const; QImage thumbnail(int w, int h) const; void lock(); void unlock(); void waitForDone(); bool tryBarrierLock(); bool isIdle(); void refreshProjection(); void setHorizontalGuides(const QList &lines); void setVerticalGuides(const QList &lines); void setGuidesVisible(bool visible); void setGuidesLocked(bool locked); bool modified() const; + QRect bounds() const; private: }; diff --git a/plugins/flake/textshape/kotext/styles/KoTableStyle.cpp b/plugins/flake/textshape/kotext/styles/KoTableStyle.cpp index 27791a5395..fb94ef9967 100644 --- a/plugins/flake/textshape/kotext/styles/KoTableStyle.cpp +++ b/plugins/flake/textshape/kotext/styles/KoTableStyle.cpp @@ -1,665 +1,663 @@ /* This file is part of the KDE project * Copyright (C) 2006-2009 Thomas Zander * Copyright (C) 2008 Thorsten Zachmann * Copyright (C) 2008 Roopesh Chander * Copyright (C) 2008 Girish Ramakrishnan * Copyright (C) 2009 KO GmbH * Copyright (C) 2011 Pierre Ducroquet * * 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 "KoTableStyle.h" #include #include "Styles_p.h" #include #include #include #include #include #include #include #include #include "TextDebug.h" class Q_DECL_HIDDEN KoTableStyle::Private { public: Private() : parentStyle(0), next(0) {} ~Private() { } void setProperty(int key, const QVariant &value) { stylesPrivate.add(key, value); } QString name; KoTableStyle *parentStyle; int next; StylePrivate stylesPrivate; }; KoTableStyle::KoTableStyle(QObject *parent) : QObject(parent), d(new Private()) { } KoTableStyle::KoTableStyle(const QTextTableFormat &tableFormat, QObject *parent) : QObject(parent), d(new Private()) { d->stylesPrivate = tableFormat.properties(); } KoTableStyle *KoTableStyle::fromTable(const QTextTable &table, QObject *parent) { QTextTableFormat tableFormat = table.format(); return new KoTableStyle(tableFormat, parent); } KoTableStyle::~KoTableStyle() { delete d; } void KoTableStyle::setParentStyle(KoTableStyle *parent) { d->parentStyle = parent; } void KoTableStyle::setProperty(int key, const QVariant &value) { if (d->parentStyle) { QVariant var = d->parentStyle->value(key); if (!var.isNull() && var == value) { // same as parent, so its actually a reset. d->stylesPrivate.remove(key); return; } } d->stylesPrivate.add(key, value); } void KoTableStyle::remove(int key) { d->stylesPrivate.remove(key); } QVariant KoTableStyle::value(int key) const { QVariant var = d->stylesPrivate.value(key); if (var.isNull() && d->parentStyle) return d->parentStyle->value(key); return var; } bool KoTableStyle::hasProperty(int key) const { return d->stylesPrivate.contains(key); } qreal KoTableStyle::propertyDouble(int key) const { QVariant variant = value(key); if (variant.isNull()) return 0.0; return variant.toDouble(); } QTextLength KoTableStyle::propertyLength(int key) const { QVariant variant = value(key); if (variant.isNull()) return QTextLength(QTextLength::FixedLength, 0.0); if (!variant.canConvert()) { // Fake support, for compatibility sake if (variant.canConvert()) { return QTextLength(QTextLength::FixedLength, variant.toReal()); } warnText << "This should never happen : requested property can't be converted to QTextLength"; return QTextLength(QTextLength::FixedLength, 0.0); } return variant.value(); } int KoTableStyle::propertyInt(int key) const { QVariant variant = value(key); if (variant.isNull()) return 0; return variant.toInt(); } bool KoTableStyle::propertyBoolean(int key) const { QVariant variant = value(key); if (variant.isNull()) return false; return variant.toBool(); } QColor KoTableStyle::propertyColor(int key) const { QVariant variant = value(key); if (variant.isNull()) { return QColor(); } return qvariant_cast(variant); } void KoTableStyle::applyStyle(QTextTableFormat &format) const {/* if (d->parentStyle) { d->parentStyle->applyStyle(format); }*/ QList keys = d->stylesPrivate.keys(); for (int i = 0; i < keys.count(); i++) { QVariant variant = d->stylesPrivate.value(keys[i]); int key = keys[i]; switch(key) { // Qt expects qreal's for the Frame*Margin's unlike the Block*Margin's case QTextFormat::FrameTopMargin: case QTextFormat::FrameBottomMargin: case QTextFormat::FrameLeftMargin: case QTextFormat::FrameRightMargin: variant = propertyLength(key).rawValue(); break; default: break; } format.setProperty(key, variant); } } void KoTableStyle::setWidth(const QTextLength &width) { d->setProperty(QTextFormat::FrameWidth, width); } void KoTableStyle::setKeepWithNext(bool keep) { d->setProperty(KeepWithNext, keep); } bool KoTableStyle::keepWithNext() const { return propertyBoolean(KeepWithNext); } void KoTableStyle::setShadow(const KoShadowStyle &shadow) { d->setProperty(Shadow, QVariant::fromValue(shadow)); } KoShadowStyle KoTableStyle::shadow() const { if (hasProperty(Shadow)) return value(Shadow).value(); return KoShadowStyle(); } void KoTableStyle::setMayBreakBetweenRows(bool allow) { d->setProperty(MayBreakBetweenRows, allow); } void KoTableStyle::setBackground(const QBrush &brush) { d->setProperty(QTextFormat::BackgroundBrush, brush); } void KoTableStyle::clearBackground() { d->stylesPrivate.remove(QTextCharFormat::BackgroundBrush); } QBrush KoTableStyle::background() const { QVariant variant = d->stylesPrivate.value(QTextFormat::BackgroundBrush); if (variant.isNull()) { return QBrush(); } return qvariant_cast(variant); } void KoTableStyle::setBreakBefore(KoText::KoTextBreakProperty state) { setProperty(BreakBefore, state); } KoText::KoTextBreakProperty KoTableStyle::breakBefore() const { return (KoText::KoTextBreakProperty) propertyInt(BreakBefore); } void KoTableStyle::setBreakAfter(KoText::KoTextBreakProperty state) { setProperty(BreakAfter, state); } KoText::KoTextBreakProperty KoTableStyle::breakAfter() const { return (KoText::KoTextBreakProperty) propertyInt(BreakAfter); } void KoTableStyle::setCollapsingBorderModel(bool on) { setProperty(CollapsingBorders, on); } bool KoTableStyle::collapsingBorderModel() const { return propertyBoolean(CollapsingBorders); } void KoTableStyle::setTopMargin(QTextLength topMargin) { setProperty(QTextFormat::FrameTopMargin, topMargin); } qreal KoTableStyle::topMargin() const { if (parentStyle()) return propertyLength(QTextFormat::FrameTopMargin).value(parentStyle()->topMargin()); else return propertyLength(QTextFormat::FrameTopMargin).value(0); } void KoTableStyle::setBottomMargin(QTextLength margin) { setProperty(QTextFormat::FrameBottomMargin, margin); } qreal KoTableStyle::bottomMargin() const { if (parentStyle()) return propertyLength(QTextFormat::FrameBottomMargin).value(parentStyle()->bottomMargin()); else return propertyLength(QTextFormat::FrameBottomMargin).value(0); } void KoTableStyle::setLeftMargin(QTextLength margin) { setProperty(QTextFormat::FrameLeftMargin, margin); } qreal KoTableStyle::leftMargin() const { if (parentStyle()) return propertyLength(QTextFormat::FrameLeftMargin).value(parentStyle()->leftMargin()); else return propertyLength(QTextFormat::FrameLeftMargin).value(0); } void KoTableStyle::setRightMargin(QTextLength margin) { setProperty(QTextFormat::FrameRightMargin, margin); } qreal KoTableStyle::rightMargin() const { if (parentStyle()) return propertyLength(QTextFormat::FrameRightMargin).value(parentStyle()->rightMargin()); else return propertyLength(QTextFormat::FrameRightMargin).value(0); } void KoTableStyle::setMargin(QTextLength margin) { setTopMargin(margin); setBottomMargin(margin); setLeftMargin(margin); setRightMargin(margin); } void KoTableStyle::setAlignment(Qt::Alignment alignment) { setProperty(QTextFormat::BlockAlignment, (int) alignment); } Qt::Alignment KoTableStyle::alignment() const { return static_cast(propertyInt(QTextFormat::BlockAlignment)); } KoTableStyle *KoTableStyle::parentStyle() const { return d->parentStyle; } QString KoTableStyle::name() const { return d->name; } void KoTableStyle::setName(const QString &name) { if (name == d->name) return; d->name = name; emit nameChanged(name); } int KoTableStyle::styleId() const { return propertyInt(StyleId); } void KoTableStyle::setStyleId(int id) { setProperty(StyleId, id); if (d->next == 0) d->next = id; } QString KoTableStyle::masterPageName() const { return value(MasterPageName).toString(); } void KoTableStyle::setMasterPageName(const QString &name) { setProperty(MasterPageName, name); } Qt::Alignment KoTableStyle::alignmentFromString(const QString &align) { Qt::Alignment alignment = Qt::AlignLeft; if (align == "left") alignment = Qt::AlignLeft; else if (align == "right") alignment = Qt::AlignRight; else if (align == "center") alignment = Qt::AlignHCenter; else if (align == "margins") // in tables this is effectively the same as justify alignment = Qt::AlignJustify; return alignment; } QString KoTableStyle::alignmentToString(Qt::Alignment alignment) { QString align; if (alignment == Qt::AlignLeft) align = "left"; else if (alignment == Qt::AlignRight) align = "right"; else if (alignment == Qt::AlignHCenter) align = "center"; else if (alignment == Qt::AlignJustify) align = "margins"; return align; } bool KoTableStyle::mayBreakBetweenRows() const { return propertyBoolean(MayBreakBetweenRows); } void KoTableStyle::setPageNumber(int page) { if (page >= 0) setProperty(PageNumber, page); } int KoTableStyle::pageNumber() const { return propertyInt(PageNumber); } bool KoTableStyle::visible() const { if (hasProperty(Visible)) return propertyBoolean(Visible); return true; } void KoTableStyle::setVisible(bool on) { setProperty(Visible, on); } KoText::Direction KoTableStyle::textDirection() const { return (KoText::Direction) propertyInt(TextProgressionDirection); } void KoTableStyle::setTextDirection(KoText::Direction direction) { setProperty(TextProgressionDirection, direction); } void KoTableStyle::loadOdf(const KoXmlElement *element, KoOdfLoadingContext &context) { if (element->hasAttributeNS(KoXmlNS::style, "display-name")) d->name = element->attributeNS(KoXmlNS::style, "display-name", QString()); if (d->name.isEmpty()) // if no style:display-name is given us the style:name d->name = element->attributeNS(KoXmlNS::style, "name", QString()); QString masterPage = element->attributeNS(KoXmlNS::style, "master-page-name", QString()); if (! masterPage.isEmpty()) { setMasterPageName(masterPage); } context.styleStack().save(); QString family = element->attributeNS(KoXmlNS::style, "family", "table"); context.addStyles(element, family.toLocal8Bit().constData()); // Load all parents - only because we don't support inheritance. context.styleStack().setTypeProperties("table"); // load all style attributes from "style:table-properties" loadOdfProperties(context.styleStack()); // load the KoTableStyle from the stylestack context.styleStack().restore(); } void KoTableStyle::loadOdfProperties(KoStyleStack &styleStack) { if (styleStack.hasProperty(KoXmlNS::style, "writing-mode")) { // http://www.w3.org/TR/2004/WD-xsl11-20041216/#writing-mode setTextDirection(KoText::directionFromString(styleStack.property(KoXmlNS::style, "writing-mode"))); } if (styleStack.hasProperty(KoXmlNS::table, "display")) { setVisible(styleStack.property(KoXmlNS::table, "display") == "true"); } // Width if (styleStack.hasProperty(KoXmlNS::style, "width")) { setWidth(QTextLength(QTextLength::FixedLength, KoUnit::parseValue(styleStack.property(KoXmlNS::style, "width")))); } if (styleStack.hasProperty(KoXmlNS::style, "rel-width")) { setWidth(QTextLength(QTextLength::PercentageLength, styleStack.property(KoXmlNS::style, "rel-width").remove('%').remove('*').toDouble())); } // Alignment if (styleStack.hasProperty(KoXmlNS::table, "align")) { setAlignment(alignmentFromString(styleStack.property(KoXmlNS::table, "align"))); } // Margin bool hasMarginLeft = styleStack.hasProperty(KoXmlNS::fo, "margin-left"); bool hasMarginRight = styleStack.hasProperty(KoXmlNS::fo, "margin-right"); if (hasMarginLeft) setLeftMargin(KoText::parseLength(styleStack.property(KoXmlNS::fo, "margin-left"))); if (hasMarginRight) setRightMargin(KoText::parseLength(styleStack.property(KoXmlNS::fo, "margin-right"))); if (styleStack.hasProperty(KoXmlNS::fo, "margin-top")) setTopMargin(KoText::parseLength(styleStack.property(KoXmlNS::fo, "margin-top"))); if (styleStack.hasProperty(KoXmlNS::fo, "margin-bottom")) setBottomMargin(KoText::parseLength(styleStack.property(KoXmlNS::fo, "margin-bottom"))); if (styleStack.hasProperty(KoXmlNS::fo, "margin")) { setMargin(KoText::parseLength(styleStack.property(KoXmlNS::fo, "margin"))); - hasMarginLeft = true; - hasMarginRight = true; } // keep table with next paragraph? if (styleStack.hasProperty(KoXmlNS::fo, "keep-with-next")) { // OASIS spec says it's "auto"/"always", not a boolean. QString val = styleStack.property(KoXmlNS::fo, "keep-with-next"); setKeepWithNext(val == "true" || val == "always"); } // The fo:break-before and fo:break-after attributes insert a page or column break before or after a table. if (styleStack.hasProperty(KoXmlNS::fo, "break-before")) { setBreakBefore(KoText::textBreakFromString(styleStack.property(KoXmlNS::fo, "break-before"))); } if (styleStack.hasProperty(KoXmlNS::fo, "break-after")) { setBreakAfter(KoText::textBreakFromString(styleStack.property(KoXmlNS::fo, "break-after"))); } if (styleStack.hasProperty(KoXmlNS::style, "may-break-between-rows")) { setMayBreakBetweenRows(styleStack.property(KoXmlNS::style, "may-break-between-rows") == "true"); } if (styleStack.hasProperty(KoXmlNS::style, "page-number")) { setPageNumber(styleStack.property(KoXmlNS::style, "page-number").toInt()); } if (styleStack.hasProperty(KoXmlNS::style, "shadow")) { KoShadowStyle shadow; if (shadow.loadOdf(styleStack.property(KoXmlNS::style, "shadow"))) setShadow(shadow); } // The fo:background-color attribute specifies the background color of a paragraph. if (styleStack.hasProperty(KoXmlNS::fo, "background-color")) { const QString bgcolor = styleStack.property(KoXmlNS::fo, "background-color"); QBrush brush = background(); if (bgcolor == "transparent") brush.setStyle(Qt::NoBrush); else { if (brush.style() == Qt::NoBrush) brush.setStyle(Qt::SolidPattern); brush.setColor(bgcolor); // #rrggbb format } setBackground(brush); } // border-model if (styleStack.hasProperty(KoXmlNS::table, "border-model")) { QString val = styleStack.property(KoXmlNS::table, "border-model"); setCollapsingBorderModel(val == "collapsing"); } } void KoTableStyle::copyProperties(const KoTableStyle *style) { d->stylesPrivate = style->d->stylesPrivate; setName(style->name()); // make sure we emit property change d->next = style->d->next; d->parentStyle = style->d->parentStyle; } KoTableStyle *KoTableStyle::clone(QObject *parent) { KoTableStyle *newStyle = new KoTableStyle(parent); newStyle->copyProperties(this); return newStyle; } bool KoTableStyle::operator==(const KoTableStyle &other) const { return other.d->stylesPrivate == d->stylesPrivate; } void KoTableStyle::removeDuplicates(const KoTableStyle &other) { d->stylesPrivate.removeDuplicates(other.d->stylesPrivate); } bool KoTableStyle::isEmpty() const { return d->stylesPrivate.isEmpty(); } void KoTableStyle::saveOdf(KoGenStyle &style) { QList keys = d->stylesPrivate.keys(); if ((hasProperty(QTextFormat::FrameLeftMargin)) && (hasProperty(QTextFormat::FrameRightMargin)) && (hasProperty(QTextFormat::FrameTopMargin)) && (hasProperty(QTextFormat::FrameBottomMargin)) && (rightMargin() == leftMargin()) && (leftMargin() == topMargin()) && (topMargin() == bottomMargin())) { style.addPropertyLength("fo:margin", propertyLength(QTextFormat::FrameBottomMargin), KoGenStyle::TableType); keys.removeAll(QTextFormat::FrameBottomMargin); keys.removeAll(QTextFormat::FrameTopMargin); keys.removeAll(QTextFormat::FrameRightMargin); keys.removeAll(QTextFormat::FrameLeftMargin); } Q_FOREACH (int key, keys) { if (key == QTextFormat::FrameWidth) { QTextLength width = propertyLength(QTextFormat::FrameWidth); if (width.type() == QTextLength::PercentageLength) { style.addPropertyLength("style:rel-width", width, KoGenStyle::TableType); } else if (width.type() == QTextLength::FixedLength) { style.addPropertyLength("style:width", width, KoGenStyle::TableType); } } else if (key == QTextFormat::BlockAlignment) { bool ok = false; int alignValue = value(QTextFormat::BlockAlignment).toInt(&ok); if (ok) { QString alignment = alignmentToString((Qt::Alignment) alignValue); if (!alignment.isEmpty()) style.addProperty("table:align", alignment, KoGenStyle::TableType); } } else if (key == KoTableStyle::BreakBefore) { style.addProperty("fo:break-before", KoText::textBreakToString(breakBefore()), KoGenStyle::TableType); } else if (key == KoTableStyle::BreakAfter) { style.addProperty("fo:break-after", KoText::textBreakToString(breakAfter()), KoGenStyle::TableType); } else if (key == KoTableStyle::MayBreakBetweenRows) { style.addProperty("style:may-break-between-rows", mayBreakBetweenRows(), KoGenStyle::TableType); } else if (key == QTextFormat::BackgroundBrush) { QBrush backBrush = background(); if (backBrush.style() != Qt::NoBrush) style.addProperty("fo:background-color", backBrush.color().name(), KoGenStyle::TableType); else style.addProperty("fo:background-color", "transparent", KoGenStyle::TableType); } else if (key == QTextFormat::FrameLeftMargin) { style.addPropertyLength("fo:margin-left", propertyLength(QTextFormat::FrameLeftMargin), KoGenStyle::TableType); } else if (key == QTextFormat::FrameRightMargin) { style.addPropertyLength("fo:margin-right", propertyLength(QTextFormat::FrameRightMargin), KoGenStyle::TableType); } else if (key == QTextFormat::FrameTopMargin) { style.addPropertyLength("fo:margin-top", propertyLength(QTextFormat::FrameTopMargin), KoGenStyle::TableType); } else if (key == QTextFormat::FrameBottomMargin) { style.addPropertyLength("fo:margin-bottom", propertyLength(QTextFormat::FrameBottomMargin), KoGenStyle::TableType); } else if (key == KoTableStyle::CollapsingBorders) { if (collapsingBorderModel()) style.addProperty("table:border-model", "collapsing", KoGenStyle::TableType); else style.addProperty("table:border-model", "separating", KoGenStyle::TableType); } else if (key == KoTableStyle::KeepWithNext) { if (keepWithNext()) style.addProperty("fo:keep-with-next", "always", KoGenStyle::TableType); else style.addProperty("fo:keep-with-next", "auto", KoGenStyle::TableType); } else if (key == KoTableStyle::Visible) { style.addProperty("table:display", visible(), KoGenStyle::TableType); } else if (key == KoTableStyle::PageNumber) { if (pageNumber() > 0) style.addProperty("style:page-number", pageNumber(), KoGenStyle::TableType); else style.addProperty("style:page-number", "auto", KoGenStyle::TableType); } else if (key == TextProgressionDirection) { style.addProperty("style:writing-mode", KoText::directionToString(textDirection()), KoGenStyle::TableType); } else if (key == KoTableStyle::Shadow) { style.addProperty("style:shadow", shadow().saveOdf()); } } } diff --git a/plugins/python/CMakeLists.txt b/plugins/python/CMakeLists.txt index 9a4753d314..f666e0e91b 100644 --- a/plugins/python/CMakeLists.txt +++ b/plugins/python/CMakeLists.txt @@ -1,119 +1,113 @@ # 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 "*.txt" PATTERN "*.csv" PATTERN "*.html" 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(assignprofiledialog) install_pykrita_plugin(scripter) install_pykrita_plugin(colorspace) install_pykrita_plugin(documenttools) install_pykrita_plugin(filtermanager) install_pykrita_plugin(exportlayers) #install_pykrita_plugin(highpass) install_pykrita_plugin(tenbrushes) install_pykrita_plugin(tenscripts) install_pykrita_plugin(palette_docker) install_pykrita_plugin(quick_settings_docker) install_pykrita_plugin(lastdocumentsdocker) # install_pykrita_plugin(scriptdocker) install_pykrita_plugin(comics_project_management_tools) install_pykrita_plugin(krita_script_starter) # 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( FILES - hello/hello.xmlgui -DESTINATION ${DATA_INSTALL_DIR}/kritaplugins/) - - - install( FILES hello/hello.action tenbrushes/tenbrushes.action tenscripts/tenscripts.action DESTINATION ${DATA_INSTALL_DIR}/krita/actions) install( DIRECTORY libkritapykrita DESTINATION ${DATA_INSTALL_DIR}/krita/pykrita FILES_MATCHING PATTERN "*.py" PATTERN "__pycache__*" EXCLUDE ) diff --git a/plugins/python/example_scripts/resize_to_all_layers.py b/plugins/python/example_scripts/resize_to_all_layers.py new file mode 100644 index 0000000000..e854763086 --- /dev/null +++ b/plugins/python/example_scripts/resize_to_all_layers.py @@ -0,0 +1,34 @@ +''' +This script is licensed CC 0 1.0, so that you can learn from it. + +------ CC 0 1.0 --------------- + +The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law. + +You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. + +https://creativecommons.org/publicdomain/zero/1.0/legalcode +''' +# +# This script will iterate over all toplevel nodes, create +# keeping track of the layer boundaries and then resize +# the image to the unity of all boundaries. +# +from krita import * +d = Krita.instance().activeDocument() +w = d.width() +h = d.height() +x = d.xOffset() +y = d.yOffset() + +print(x, y, w, h) +r = QRect(x, y, w, h) +print(r) +for n in d.topLevelNodes(): + print (n, n.bounds()) + b = n.bounds() + r = r.united(b) + +print (r) + +d.resizeImage(r.x(), r.y(), r.width(), r.height()) diff --git a/plugins/python/hello/hello.xmlgui b/plugins/python/hello/hello.xmlgui deleted file mode 100644 index 90bac2ae7a..0000000000 --- a/plugins/python/hello/hello.xmlgui +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - diff --git a/plugins/tools/defaulttool/defaulttool/ShapeResizeStrategy.cpp b/plugins/tools/defaulttool/defaulttool/ShapeResizeStrategy.cpp index e219519291..f247c6213c 100644 --- a/plugins/tools/defaulttool/defaulttool/ShapeResizeStrategy.cpp +++ b/plugins/tools/defaulttool/defaulttool/ShapeResizeStrategy.cpp @@ -1,246 +1,254 @@ /* This file is part of the KDE project * Copyright (C) 2006-2007 Thomas Zander * Copyright (C) 2007,2011 Jan Hambrecht * Copyright (C) 2017 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 "ShapeResizeStrategy.h" #include "SelectionDecorator.h" #include #include #include #include #include #include #include #include #include #include #include #include ShapeResizeStrategy::ShapeResizeStrategy(KoToolBase *tool, KoSelection *selection, const QPointF &clicked, KoFlake::SelectionHandle direction, bool forceUniformScalingMode) : KoInteractionStrategy(tool), m_forceUniformScalingMode(forceUniformScalingMode) { KIS_SAFE_ASSERT_RECOVER_RETURN(selection && selection->count() > 0); m_selectedShapes = selection->selectedEditableShapes(); m_start = clicked; KoShape *shape = 0; if (m_selectedShapes.size() > 1) { shape = selection; } else if (m_selectedShapes.size() == 1) { shape = m_selectedShapes.first(); } if (shape) { const qreal w = shape->size().width(); const qreal h = shape->size().height(); switch (direction) { case KoFlake::TopMiddleHandle: m_start = 0.5 * (shape->absolutePosition(KoFlake::TopLeft) + shape->absolutePosition(KoFlake::TopRight)); m_top = true; m_bottom = false; m_left = false; m_right = false; m_globalStillPoint = QPointF(0.5 * w, h); break; case KoFlake::TopRightHandle: m_start = shape->absolutePosition(KoFlake::TopRight); m_top = true; m_bottom = false; m_left = false; m_right = true; m_globalStillPoint = QPointF(0, h); break; case KoFlake::RightMiddleHandle: m_start = 0.5 * (shape->absolutePosition(KoFlake::TopRight) + shape->absolutePosition(KoFlake::BottomRight)); m_top = false; m_bottom = false; m_left = false; m_right = true; m_globalStillPoint = QPointF(0, 0.5 * h); break; case KoFlake::BottomRightHandle: m_start = shape->absolutePosition(KoFlake::BottomRight); m_top = false; m_bottom = true; m_left = false; m_right = true; m_globalStillPoint = QPointF(0, 0); break; case KoFlake::BottomMiddleHandle: m_start = 0.5 * (shape->absolutePosition(KoFlake::BottomRight) + shape->absolutePosition(KoFlake::BottomLeft)); m_top = false; m_bottom = true; m_left = false; m_right = false; m_globalStillPoint = QPointF(0.5 * w, 0); break; case KoFlake::BottomLeftHandle: m_start = shape->absolutePosition(KoFlake::BottomLeft); m_top = false; m_bottom = true; m_left = true; m_right = false; m_globalStillPoint = QPointF(w, 0); break; case KoFlake::LeftMiddleHandle: m_start = 0.5 * (shape->absolutePosition(KoFlake::BottomLeft) + shape->absolutePosition(KoFlake::TopLeft)); m_top = false; m_bottom = false; m_left = true; m_right = false; m_globalStillPoint = QPointF(w, 0.5 * h); break; case KoFlake::TopLeftHandle: m_start = shape->absolutePosition(KoFlake::TopLeft); m_top = true; m_bottom = false; m_left = true; m_right = false; m_globalStillPoint = QPointF(w, h); break; default: Q_ASSERT(0); // illegal 'corner' } const QPointF p0 = shape->outlineRect().topLeft(); m_globalStillPoint = shape->absoluteTransformation(0).map(p0 + m_globalStillPoint); m_globalCenterPoint = shape->absolutePosition(KoFlake::Center); m_unwindMatrix = shape->absoluteTransformation(0).inverted(); m_initialSelectionSize = shape->size(); m_postScalingCoveringTransform = shape->transformation(); } tool->setStatusText(i18n("Press CTRL to resize from center.")); tool->canvas()->snapGuide()->setIgnoredShapes(KoShape::linearizeSubtree(m_selectedShapes)); } ShapeResizeStrategy::~ShapeResizeStrategy() { } void ShapeResizeStrategy::handleMouseMove(const QPointF &point, Qt::KeyboardModifiers modifiers) { tool()->canvas()->updateCanvas(tool()->canvas()->snapGuide()->boundingRect()); QPointF newPos = tool()->canvas()->snapGuide()->snap(point, modifiers); tool()->canvas()->updateCanvas(tool()->canvas()->snapGuide()->boundingRect()); bool keepAspect = modifiers & Qt::ShiftModifier; Q_FOREACH (KoShape *shape, m_selectedShapes) { keepAspect = keepAspect || shape->keepAspectRatio(); } qreal startWidth = m_initialSelectionSize.width(); if (startWidth < std::numeric_limits::epsilon()) { startWidth = std::numeric_limits::epsilon(); } qreal startHeight = m_initialSelectionSize.height(); if (startHeight < std::numeric_limits::epsilon()) { startHeight = std::numeric_limits::epsilon(); } QPointF distance = m_unwindMatrix.map(newPos) - m_unwindMatrix.map(m_start); // guard against resizing zero width shapes, which would result in huge zoom factors if (m_initialSelectionSize.width() < std::numeric_limits::epsilon()) { distance.rx() = 0.0; } // guard against resizing zero height shapes, which would result in huge zoom factors if (m_initialSelectionSize.height() < std::numeric_limits::epsilon()) { distance.ry() = 0.0; } const bool scaleFromCenter = modifiers & Qt::ControlModifier; if (scaleFromCenter) { distance *= 2.0; } qreal newWidth = startWidth; qreal newHeight = startHeight; if (m_left) { newWidth = startWidth - distance.x(); } else if (m_right) { newWidth = startWidth + distance.x(); } if (m_top) { newHeight = startHeight - distance.y(); } else if (m_bottom) { newHeight = startHeight + distance.y(); } /** * Do not let a shape be less than 1px in size in current view * coordinates. If the user wants it to be smaller, he can just * zoom-in a bit. */ QSizeF minViewSize(1.0, 1.0); QSizeF minDocSize = tool()->canvas()->viewConverter()->viewToDocument(minViewSize); if (qAbs(newWidth) < minDocSize.width()) { int sign = newWidth >= 0.0 ? 1 : -1; // zero -> '1' newWidth = sign * minDocSize.width(); } if (qAbs(newHeight) < minDocSize.height()) { int sign = newHeight >= 0.0 ? 1 : -1; // zero -> '1' newHeight = sign * minDocSize.height(); } qreal zoomX = newWidth / startWidth; qreal zoomY = newHeight / startHeight; if (keepAspect) { const bool cornerUsed = ((m_bottom ? 1 : 0) + (m_top ? 1 : 0) + (m_left ? 1 : 0) + (m_right ? 1 : 0)) == 2; - if ((cornerUsed && startWidth < startHeight) || m_left || m_right) { - zoomY = zoomX; + if (cornerUsed) { + if (startWidth < startHeight) { + zoomY = zoomX; + } else { + zoomX = zoomY; + } } else { - zoomX = zoomY; + if (m_left || m_right) { + zoomY = qAbs(zoomX); + } else { + zoomX = qAbs(zoomY); + } } } resizeBy(scaleFromCenter ? m_globalCenterPoint : m_globalStillPoint, zoomX, zoomY); } void ShapeResizeStrategy::resizeBy(const QPointF &stillPoint, qreal zoomX, qreal zoomY) { if (m_executedCommand) { m_executedCommand->undo(); m_executedCommand.reset(); } const bool usePostScaling = m_selectedShapes.size() > 1 || m_forceUniformScalingMode; m_executedCommand.reset( new KoShapeResizeCommand( m_selectedShapes, zoomX, zoomY, stillPoint, false, usePostScaling, m_postScalingCoveringTransform)); m_executedCommand->redo(); } KUndo2Command *ShapeResizeStrategy::createCommand() { tool()->canvas()->snapGuide()->reset(); if (m_executedCommand) { m_executedCommand->setSkipOneRedo(true); } return m_executedCommand.take(); } void ShapeResizeStrategy::finishInteraction(Qt::KeyboardModifiers modifiers) { Q_UNUSED(modifiers); tool()->canvas()->updateCanvas(tool()->canvas()->snapGuide()->boundingRect()); } void ShapeResizeStrategy::paint(QPainter &painter, const KoViewConverter &converter) { Q_UNUSED(painter); Q_UNUSED(converter); } diff --git a/plugins/tools/svgtexttool/SvgTextEditor.h b/plugins/tools/svgtexttool/SvgTextEditor.h index ee95d62e78..24330d488a 100644 --- a/plugins/tools/svgtexttool/SvgTextEditor.h +++ b/plugins/tools/svgtexttool/SvgTextEditor.h @@ -1,160 +1,159 @@ /* This file is part of the KDE project * * Copyright 2017 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. */ #ifndef TEXTNGSHAPECONFIGWIDGET_H #define TEXTNGSHAPECONFIGWIDGET_H #include #include #include #include #include //for the enums #include #include "ui_WdgSvgTextEditor.h" #include "ui_WdgSvgTextSettings.h" class KoSvgTextShape; -class KisFileNameRequester; class KoDialog; class SvgTextEditor : public KXmlGuiWindow { Q_OBJECT public: SvgTextEditor(QWidget *parent = 0, Qt::WindowFlags flags = 0); ~SvgTextEditor(); //tiny enum to keep track of the tab on which editor something happens while keeping the code readable. enum Editor { Richtext, // 0 SVGsource // 1 }; // enum to store which tabs are visible in the configuration enum EditorMode { RichText, SvgSource, Both }; void setShape(KoSvgTextShape *shape); private Q_SLOTS: /** * switch the text editor tab. */ void switchTextEditorTab(bool convertData = true); /** * in rich text, check the current format, and toggle the given buttons. */ void checkFormat(); void save(); void undo(); void redo(); void cut(); void copy(); void paste(); void selectAll(); void deselect(); void find(); void findNext(); void findPrev(); void replace(); void zoomOut(); void zoomIn(); #ifndef Q_OS_WIN void showInsertSpecialCharacterDialog(); void insertCharacter(const QChar &c); #endif void setTextBold(QFont::Weight weight = QFont::Bold); void setTextWeightLight(); void setTextWeightNormal(); void setTextWeightDemi(); void setTextWeightBlack(); void setTextItalic(QFont::Style style = QFont::StyleOblique); void setTextDecoration(KoSvgText::TextDecoration decor); void setTextUnderline(); void setTextOverline(); void setTextStrikethrough(); void setTextSubscript(); void setTextSuperScript(); void increaseTextSize(); void decreaseTextSize(); void setLineHeight(double lineHeightPercentage); void alignLeft(); void alignRight(); void alignCenter(); void alignJustified(); void setFont(const QString &fontName); void setFontSize(qreal size); void setBaseline(KoSvgText::BaselineShiftMode baseline); void setSettings(); void slotToolbarToggled(bool); void setFontColor(const KoColor &c); void setBackgroundColor(const KoColor &c); void setModified(bool modified); void dialogButtonClicked(QAbstractButton *button); Q_SIGNALS: void textUpdated(KoSvgTextShape *shape, const QString &svg, const QString &defs, bool richTextPreferred); protected: void wheelEvent(QWheelEvent *event) override; private: void applySettings(); QAction *createAction(const QString &name, const char *member); void createActions(); void enableRichTextActions(bool enable); Ui_WdgSvgTextEditor m_textEditorWidget; QTextEdit *m_currentEditor {0}; QWidget *m_page {0}; QList m_richTextActions; KoSvgTextShape *m_shape {0}; #ifndef Q_OS_WIN KoDialog *m_charSelectDialog {0}; #endif BasicXMLSyntaxHighlighter *m_syntaxHighlighter; QString m_searchKey; }; #endif //TEXTNGSHAPECONFIGWIDGET_H