diff --git a/krita/image/kis_group_layer.cc b/krita/image/kis_group_layer.cc index 90aa2cf300b..acefd805940 100644 --- a/krita/image/kis_group_layer.cc +++ b/krita/image/kis_group_layer.cc @@ -1,383 +1,385 @@ /* * Copyright (c) 2005 C. Boemann * Copyright (c) 2007 Boudewijn Rempt * Copyright (c) 2009 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_group_layer.h" #include #include #include #include #include "kis_types.h" #include "kis_node_visitor.h" #include "kis_processing_visitor.h" #include "kis_debug.h" #include "kis_image.h" #include "kis_paint_device.h" #include "kis_default_bounds.h" #include "kis_clone_layer.h" #include "kis_selection_mask.h" #include "kis_psd_layer_style.h" struct KisGroupLayer::Private { public: Private() : paintDevice(0) , x(0) , y(0) , passThroughMode(false) { } KisPaintDeviceSP paintDevice; qint32 x; qint32 y; bool passThroughMode; }; KisGroupLayer::KisGroupLayer(KisImageWSP image, const QString &name, quint8 opacity) : KisLayer(image, name, opacity), m_d(new Private()) { resetCache(); } KisGroupLayer::KisGroupLayer(const KisGroupLayer &rhs) : KisLayer(rhs), m_d(new Private()) { m_d->paintDevice = new KisPaintDevice(*rhs.m_d->paintDevice.data()); m_d->x = rhs.m_d->x; m_d->y = rhs.m_d->y; m_d->paintDevice->setDefaultPixel(const_cast(&rhs)->m_d->paintDevice->defaultPixel()); } KisGroupLayer::~KisGroupLayer() { delete m_d; } bool KisGroupLayer::checkCloneLayer(KisCloneLayerSP clone) const { KisNodeSP source = clone->copyFrom(); if (source) { if(!allowAsChild(source)) return false; if (source->inherits("KisGroupLayer")) { KisNodeSP newParent = const_cast(this); while (newParent) { if (newParent == source) { return false; } newParent = newParent->parent(); } } } return true; } bool KisGroupLayer::checkNodeRecursively(KisNodeSP node) const { KisCloneLayerSP cloneLayer = dynamic_cast(node.data()); if(cloneLayer) { return checkCloneLayer(cloneLayer); } else if (node->inherits("KisGroupLayer")) { KisNodeSP child = node->firstChild(); while (child) { if (!checkNodeRecursively(child)) { return false; } child = child->nextSibling(); } } return true; } bool KisGroupLayer::allowAsChild(KisNodeSP node) const { return checkNodeRecursively(node) && (parent() || (node->inherits("KisSelectionMask") && !selectionMask()) || !node->inherits("KisMask")); } const KoColorSpace * KisGroupLayer::colorSpace() const { return m_d->paintDevice->colorSpace(); } QIcon KisGroupLayer::icon() const { return themedIcon("folder"); } void KisGroupLayer::setImage(KisImageWSP image) { m_d->paintDevice->setDefaultBounds(new KisDefaultBounds(image)); KisLayer::setImage(image); } KisLayerSP KisGroupLayer::createMergedLayer(KisLayerSP prevLayer) { KisGroupLayer *prevGroup = dynamic_cast(prevLayer.data()); if (prevGroup && canMergeAndKeepBlendOptions(prevLayer)) { KisSharedPtr merged(new KisGroupLayer(*prevGroup)); KisNodeSP child, cloned; for (child = firstChild(); child; child = child->nextSibling()) { cloned = child->clone(); image()->addNode(cloned, merged); } image()->refreshGraphAsync(merged); return merged; } else return KisLayer::createMergedLayer(prevLayer); } void KisGroupLayer::resetCache(const KoColorSpace *colorSpace) { if (!colorSpace) colorSpace = image()->colorSpace(); Q_ASSERT(colorSpace); if (!m_d->paintDevice) { m_d->paintDevice = new KisPaintDevice(this, colorSpace, new KisDefaultBounds(image())); m_d->paintDevice->setX(m_d->x); m_d->paintDevice->setY(m_d->y); } else if(!(*m_d->paintDevice->colorSpace() == *colorSpace)) { KisPaintDeviceSP dev = new KisPaintDevice(this, colorSpace, new KisDefaultBounds(image())); dev->setX(m_d->x); dev->setY(m_d->y); quint8* defaultPixel = new quint8[colorSpace->pixelSize()]; m_d->paintDevice->colorSpace()-> convertPixelsTo(m_d->paintDevice->defaultPixel(), defaultPixel, colorSpace, 1, KoColorConversionTransformation::InternalRenderingIntent, KoColorConversionTransformation::InternalConversionFlags); dev->setDefaultPixel(defaultPixel); delete[] defaultPixel; m_d->paintDevice = dev; } else { m_d->paintDevice->clear(); } } KisLayer* KisGroupLayer::onlyMeaningfulChild() const { KisNode *child = firstChild().data(); KisLayer *onlyLayer = 0; while (child) { KisLayer *layer = dynamic_cast(child); if (layer) { if (onlyLayer) return 0; onlyLayer = layer; } child = child->nextSibling().data(); } return onlyLayer; } KisPaintDeviceSP KisGroupLayer::tryObligeChild() const { const KisLayer *child = onlyMeaningfulChild(); if (child && child->channelFlags().isEmpty() && child->projection() && child->visible() && (child->compositeOpId() == COMPOSITE_OVER || child->compositeOpId() == COMPOSITE_ALPHA_DARKEN || child->compositeOpId() == COMPOSITE_COPY) && child->opacity() == OPACITY_OPAQUE_U8 && *child->projection()->colorSpace() == *colorSpace() && !child->layerStyle()) { quint8 defaultOpacity = m_d->paintDevice->colorSpace()->opacityU8( m_d->paintDevice->defaultPixel()); if(defaultOpacity == OPACITY_TRANSPARENT_U8) { return child->projection(); } } return 0; } KisPaintDeviceSP KisGroupLayer::original() const { /** * We are too lazy! Let's our children work for us. * Try to use children's paintDevice if it's the only * one in stack and meets some conditions */ KisPaintDeviceSP realOriginal = tryObligeChild(); if (!realOriginal) { if (!childCount() && !m_d->paintDevice->extent().isEmpty()) { m_d->paintDevice->clear(); } realOriginal = m_d->paintDevice; } return realOriginal; } void KisGroupLayer::setDefaultProjectionColor(KoColor color) { color.convertTo(m_d->paintDevice->colorSpace()); m_d->paintDevice->setDefaultPixel(color.data()); } KoColor KisGroupLayer::defaultProjectionColor() const { KoColor color(m_d->paintDevice->defaultPixel(), m_d->paintDevice->colorSpace()); return color; } bool KisGroupLayer::passThroughMode() const { return m_d->passThroughMode; } void KisGroupLayer::setPassThroughMode(bool value) { m_d->passThroughMode = value; } KisDocumentSectionModel::PropertyList KisGroupLayer::sectionModelProperties() const { KisDocumentSectionModel::PropertyList l = KisLayer::sectionModelProperties(); // XXX: get right icons l << KisDocumentSectionModel::Property(i18n("Pass Through"), koIcon("passthrough-enabled"), koIcon("passthrough-disabled"), passThroughMode()); return l; } void KisGroupLayer::setSectionModelProperties(const KisDocumentSectionModel::PropertyList &properties) { foreach (const KisDocumentSectionModel::Property &property, properties) { if (property.name == i18n("Pass Through")) { setPassThroughMode(property.state.toBool()); } } KisLayer::setSectionModelProperties(properties); } bool KisGroupLayer::accept(KisNodeVisitor &v) { return v.visit(this); } void KisGroupLayer::accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) { return visitor.visit(this, undoAdapter); } qint32 KisGroupLayer::x() const { return m_d->x; } qint32 KisGroupLayer::y() const { return m_d->y; } void KisGroupLayer::setX(qint32 x) { qint32 delta = x - m_d->x; m_d->x = x; if(m_d->paintDevice) { m_d->paintDevice->setX(m_d->paintDevice->x() + delta); Q_ASSERT(m_d->paintDevice->x() == m_d->x); } } void KisGroupLayer::setY(qint32 y) { qint32 delta = y - m_d->y; m_d->y = y; if(m_d->paintDevice) { m_d->paintDevice->setY(m_d->paintDevice->y() + delta); Q_ASSERT(m_d->paintDevice->y() == m_d->y); } } struct ExtentPolicy { inline QRect operator() (const KisNode *node) { return node->extent(); } }; struct ExactBoundsPolicy { inline QRect operator() (const KisNode *node) { return node->exactBounds(); } }; template QRect collectRects(const KisNode *node, MetricPolicy policy) { QRect accumulator; const KisNode *child = node->firstChild(); while (child) { - accumulator |= policy(child); + if (!qobject_cast(child)) { + accumulator |= policy(child); + } child = child->nextSibling(); } return accumulator; } QRect KisGroupLayer::extent() const { return m_d->passThroughMode ? collectRects(this, ExtentPolicy()) : KisLayer::extent(); } QRect KisGroupLayer::exactBounds() const { return m_d->passThroughMode ? collectRects(this, ExactBoundsPolicy()) : KisLayer::exactBounds(); } #include "kis_group_layer.moc"