[calligra/krita-chili-kazakov] krita: [FEATURE] Implemented Pass-through mode for Group Layers!
Dmitry Kazakov
dimula73 at gmail.com
Wed May 13 11:38:24 UTC 2015
Git commit c958035b73f5ddf36789340ca5dc4ed39808352b by Dmitry Kazakov.
Committed on 13/05/2015 at 10:37.
Pushed by dkazakov into branch 'krita-chili-kazakov'.
[FEATURE] Implemented Pass-through mode for Group Layers!
Now just press an icon in the layer box and you'll get photoshop-like
behavior of the group, that is the children layers will be merged as if
they were not in the group.
Still TODO:
1) Create a proper icon for the layer properties item
2) Implement loading/saving layers into Photoshop's PSD
3) Test, test and test! :)
Ref T202
CCBUG:185448
CCMAIL:kimageshop at kde.org
M +33 -1 krita/image/kis_group_layer.cc
M +6 -0 krita/image/kis_group_layer.h
M +2 -1 krita/image/kis_layer_projection_plane.cpp
M +72 -4 krita/image/kis_projection_leaf.cpp
M +1 -0 krita/image/kis_projection_leaf.h
M +92 -0 krita/image/tests/kis_projection_leaf_test.cpp
M +1 -0 krita/image/tests/kis_projection_leaf_test.h
M +6 -4 krita/plugins/extensions/dockers/defaultdockers/kis_layer_box.cpp
M +9 -0 krita/ui/kra/kis_kra_loader.cpp
M +1 -0 krita/ui/kra/kis_kra_savexml_visitor.cpp
M +1 -0 krita/ui/kra/kis_kra_tags.h
http://commits.kde.org/calligra/c958035b73f5ddf36789340ca5dc4ed39808352b
diff --git a/krita/image/kis_group_layer.cc b/krita/image/kis_group_layer.cc
index e9eb77e..296a2b2 100644
--- a/krita/image/kis_group_layer.cc
+++ b/krita/image/kis_group_layer.cc
@@ -44,12 +44,15 @@ public:
Private()
: paintDevice(0)
, x(0)
- , y(0) {
+ , y(0)
+ , passThroughMode(false)
+ {
}
KisPaintDeviceSP paintDevice;
qint32 x;
qint32 y;
+ bool passThroughMode;
};
KisGroupLayer::KisGroupLayer(KisImageWSP image, const QString &name, quint8 opacity) :
@@ -266,6 +269,35 @@ KoColor KisGroupLayer::defaultProjectionColor() const
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("transparency-locked"), koIcon("transparency-unlocked"), 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);
diff --git a/krita/image/kis_group_layer.h b/krita/image/kis_group_layer.h
index 73bdcad..e08c198 100644
--- a/krita/image/kis_group_layer.h
+++ b/krita/image/kis_group_layer.h
@@ -47,6 +47,9 @@ public:
QIcon icon() const;
+ KisDocumentSectionModel::PropertyList sectionModelProperties() const;
+ void setSectionModelProperties(const KisDocumentSectionModel::PropertyList &properties);
+
virtual void setImage(KisImageWSP image);
virtual KisLayerSP createMergedLayer(KisLayerSP prevLayer);
@@ -92,6 +95,9 @@ public:
*/
KoColor defaultProjectionColor() const;
+ bool passThroughMode() const;
+ void setPassThroughMode(bool value);
+
protected:
KisLayer* onlyMeaningfulChild() const;
KisPaintDeviceSP tryObligeChild() const;
diff --git a/krita/image/kis_layer_projection_plane.cpp b/krita/image/kis_layer_projection_plane.cpp
index 231a9ee..dafa5b0 100644
--- a/krita/image/kis_layer_projection_plane.cpp
+++ b/krita/image/kis_layer_projection_plane.cpp
@@ -23,6 +23,7 @@
#include <KoChannelInfo.h>
#include <KoCompositeOpRegistry.h>
#include "kis_painter.h"
+#include "kis_projection_leaf.h"
struct KisLayerProjectionPlane::Private
@@ -91,7 +92,7 @@ void KisLayerProjectionPlane::apply(KisPainter *painter, const QRect &rect)
painter->setChannelFlags(channelFlags);
painter->setCompositeOp(m_d->layer->compositeOp());
- painter->setOpacity(m_d->layer->opacity());
+ painter->setOpacity(m_d->layer->projectionLeaf()->opacity());
painter->bitBlt(needRect.topLeft(), device, needRect);
}
diff --git a/krita/image/kis_projection_leaf.cpp b/krita/image/kis_projection_leaf.cpp
index 4ca0075..71602ec 100644
--- a/krita/image/kis_projection_leaf.cpp
+++ b/krita/image/kis_projection_leaf.cpp
@@ -18,6 +18,8 @@
#include "kis_projection_leaf.h"
+#include <KoColorSpaceRegistry.h>
+
#include "kis_layer.h"
#include "kis_mask.h"
#include "kis_group_layer.h"
@@ -29,6 +31,19 @@ struct KisProjectionLeaf::Private
Private(KisNode *_node) : node(_node) {}
KisNode* node;
+
+ static bool checkPassThrough(const KisNode *node) {
+ const KisGroupLayer *group = qobject_cast<const KisGroupLayer*>(node);
+ return group && group->passThroughMode();
+ }
+
+ bool checkParentPassThrough() {
+ return node->parent() && checkPassThrough(node->parent());
+ }
+
+ bool checkThisPassThrough() {
+ return checkPassThrough(node);
+ }
};
KisProjectionLeaf::KisProjectionLeaf(KisNode *node)
@@ -43,31 +58,68 @@ KisProjectionLeaf::~KisProjectionLeaf()
KisProjectionLeafSP KisProjectionLeaf::parent() const
{
KisNodeSP node = m_d->node->parent();
+
+ if (node && Private::checkPassThrough(node)) {
+ node = node->parent();
+ }
+
return node ? node->projectionLeaf() : KisProjectionLeafSP();
}
KisProjectionLeafSP KisProjectionLeaf::firstChild() const
{
- KisNodeSP node = m_d->node->firstChild();
+ KisNodeSP node;
+
+ if (!m_d->checkThisPassThrough()) {
+ node = m_d->node->firstChild();
+ }
+
return node ? node->projectionLeaf() : KisProjectionLeafSP();
}
KisProjectionLeafSP KisProjectionLeaf::lastChild() const
{
- KisNodeSP node = m_d->node->lastChild();
+ KisNodeSP node;
+
+ if (!m_d->checkThisPassThrough()) {
+ node = m_d->node->lastChild();
+ }
+
return node ? node->projectionLeaf() : KisProjectionLeafSP();
}
KisProjectionLeafSP KisProjectionLeaf::prevSibling() const
{
- KisNodeSP node = m_d->node->prevSibling();
+ KisNodeSP node;
+
+ if (m_d->checkThisPassThrough()) {
+ node = m_d->node->lastChild();
+ }
+
+ if (!node) {
+ node = m_d->node->prevSibling();
+ }
+
+ if (!node && m_d->checkParentPassThrough()) {
+ node = m_d->node->parent()->prevSibling();
+ }
+
return node ? node->projectionLeaf() : KisProjectionLeafSP();
}
KisProjectionLeafSP KisProjectionLeaf::nextSibling() const
{
KisNodeSP node = m_d->node->nextSibling();
+
+ if (node && Private::checkPassThrough(node) && node->firstChild()) {
+ node = node->firstChild();
+ }
+
+ if (!node && m_d->checkParentPassThrough()) {
+ node = m_d->node->parent();
+ }
+
return node ? node->projectionLeaf() : KisProjectionLeafSP();
}
@@ -131,7 +183,23 @@ bool KisProjectionLeaf::dependsOnLowerNodes() const
bool KisProjectionLeaf::visible() const
{
// check opacity as well!
- return m_d->node->visible();
+ return m_d->node->visible(true);
+}
+
+quint8 KisProjectionLeaf::opacity() const
+{
+ quint8 resultOpacity = m_d->node->opacity();
+ quint8 parentOpacity = 255;
+
+ if (m_d->checkParentPassThrough()) {
+ quint8 parentOpacity = m_d->node->parent()->projectionLeaf()->opacity();
+
+ if (parentOpacity != OPACITY_OPAQUE_U8) {
+ resultOpacity = (int(resultOpacity) * parentOpacity) / OPACITY_OPAQUE_U8;
+ }
+ }
+
+ return resultOpacity;
}
bool KisProjectionLeaf::isStillInGraph() const
diff --git a/krita/image/kis_projection_leaf.h b/krita/image/kis_projection_leaf.h
index 07b6fec..1a2c46f 100644
--- a/krita/image/kis_projection_leaf.h
+++ b/krita/image/kis_projection_leaf.h
@@ -56,6 +56,7 @@ public:
bool canHaveChildLayers() const;
bool dependsOnLowerNodes() const;
bool visible() const;
+ quint8 opacity() const;
bool isStillInGraph() const;
private:
diff --git a/krita/image/tests/kis_projection_leaf_test.cpp b/krita/image/tests/kis_projection_leaf_test.cpp
index 4cb101c..592a703 100644
--- a/krita/image/tests/kis_projection_leaf_test.cpp
+++ b/krita/image/tests/kis_projection_leaf_test.cpp
@@ -21,6 +21,7 @@
#include <qtest_kde.h>
#include "qimage_based_test.h"
#include "kis_projection_leaf.h"
+#include "kis_group_layer.h"
@@ -34,6 +35,18 @@ struct TestImage : TestUtil::QImageBasedTest {
KisSurrogateUndoStore *undoStore;
KisImageSP image;
+
+ KisNodeSP findBlur1() {
+ return findNode(image->root(), "blur1");
+ }
+
+ KisNodeSP findClone1() {
+ return findNode(image->root(), "clone1");
+ }
+
+ KisNodeSP findPaint1() {
+ return findNode(image->root(), "paint1");
+ }
};
bool safeCompare(KisProjectionLeafSP leaf, KisNodeSP node)
@@ -62,6 +75,50 @@ void checkNode(KisNodeSP node, const QString &prefix)
}
}
+void printNodes(KisNodeSP node, const QString &prefix = "")
+{
+ qDebug() << prefix << node->name();
+
+ KisNodeSP prevNode = node->lastChild();
+ while(prevNode) {
+ printNodes(prevNode, QString("\"\"%1").arg(prefix));
+ prevNode = prevNode->prevSibling();
+ }
+}
+
+void printLeafsBackward(KisProjectionLeafSP leaf, const QString &prefix = "")
+{
+ qDebug() << prefix << leaf->node()->name();
+
+ KisProjectionLeafSP prevLeaf = leaf->lastChild();
+ while(prevLeaf) {
+ printLeafsBackward(prevLeaf, QString("\"\"%1").arg(prefix));
+ prevLeaf = prevLeaf->prevSibling();
+ }
+}
+
+void printLeafsForward(KisProjectionLeafSP leaf, const QString &prefix = "")
+{
+ qDebug() << prefix << leaf->node()->name();
+
+ KisProjectionLeafSP prevLeaf = leaf->firstChild();
+ while(prevLeaf) {
+ printLeafsForward(prevLeaf, QString("\"\"%1").arg(prefix));
+ prevLeaf = prevLeaf->nextSibling();
+ }
+}
+
+void printParents(KisProjectionLeafSP leaf, const QString &prefix = "")
+{
+ qDebug() << prefix << leaf->node()->name();
+
+
+ leaf = leaf->parent();
+ if (leaf) {
+ printParents(leaf, QString("\"\"%1").arg(prefix));
+ }
+}
+
void KisProjectionLeafTest::test()
{
TestImage t;
@@ -69,4 +126,39 @@ void KisProjectionLeafTest::test()
checkNode(t.image->root(), "");
}
+void KisProjectionLeafTest::testPassThrough()
+{
+ TestImage t;
+
+ KisGroupLayerSP group1 = new KisGroupLayer(t.image, "group1", OPACITY_OPAQUE_U8);
+ KisPaintLayerSP paint2 = new KisPaintLayer(t.image, "paint2", OPACITY_OPAQUE_U8);
+ KisPaintLayerSP paint3 = new KisPaintLayer(t.image, "paint3", OPACITY_OPAQUE_U8);
+ KisPaintLayerSP paint4 = new KisPaintLayer(t.image, "paint4", OPACITY_OPAQUE_U8);
+
+ group1->setPassThroughMode(true);
+
+ t.image->addNode(group1, t.image->root(), t.findBlur1());
+ t.image->addNode(paint2, group1);
+ t.image->addNode(paint3, group1);
+ t.image->addNode(paint4, group1);
+
+ //checkNode(t.image->root(), "");
+
+ qDebug() << "== Nodes";
+ printNodes(t.image->root());
+ qDebug() << "== Leafs backward";
+ printLeafsBackward(t.image->root()->projectionLeaf());
+ qDebug() << "== Leafs forward";
+ printLeafsForward(t.image->root()->projectionLeaf());
+
+ qDebug() << "== Parents for paint4";
+ printParents(paint4->projectionLeaf());
+
+ qDebug() << "== Parents for paint3";
+ printParents(paint3->projectionLeaf());
+
+ qDebug() << "== Parents for group1";
+ printParents(group1->projectionLeaf());
+}
+
QTEST_KDEMAIN(KisProjectionLeafTest, GUI)
diff --git a/krita/image/tests/kis_projection_leaf_test.h b/krita/image/tests/kis_projection_leaf_test.h
index 4e9eab4..2244fd4 100644
--- a/krita/image/tests/kis_projection_leaf_test.h
+++ b/krita/image/tests/kis_projection_leaf_test.h
@@ -26,6 +26,7 @@ class KisProjectionLeafTest : public QObject
Q_OBJECT
private slots:
void test();
+ void testPassThrough();
};
#endif /* __KIS_PROJECTION_LEAF_TEST_H */
diff --git a/krita/plugins/extensions/dockers/defaultdockers/kis_layer_box.cpp b/krita/plugins/extensions/dockers/defaultdockers/kis_layer_box.cpp
index 61b94c3..08d7c4d 100644
--- a/krita/plugins/extensions/dockers/defaultdockers/kis_layer_box.cpp
+++ b/krita/plugins/extensions/dockers/defaultdockers/kis_layer_box.cpp
@@ -435,10 +435,7 @@ void KisLayerBox::updateUI()
if (activeNode->inherits("KisMask")) {
m_wdgLayerBox->cmbComposite->setEnabled(false);
m_wdgLayerBox->doubleOpacity->setEnabled(false);
- }
-
- if (activeNode->inherits("KisLayer")) {
- m_wdgLayerBox->cmbComposite->setEnabled(true);
+ } else if (activeNode->inherits("KisLayer")) {
m_wdgLayerBox->doubleOpacity->setEnabled(true);
KisLayerSP l = qobject_cast<KisLayer*>(activeNode.data());
@@ -450,6 +447,11 @@ void KisLayerBox::updateUI()
} else {
m_wdgLayerBox->cmbComposite->setEnabled(false);
}
+
+ const KisGroupLayer *group = qobject_cast<const KisGroupLayer*>(activeNode.data());
+ bool compositeSelectionActive = !(group && group->passThroughMode());
+
+ m_wdgLayerBox->cmbComposite->setEnabled(compositeSelectionActive);
}
}
}
diff --git a/krita/ui/kra/kis_kra_loader.cpp b/krita/ui/kra/kis_kra_loader.cpp
index b0122ca..35bd621 100644
--- a/krita/ui/kra/kis_kra_loader.cpp
+++ b/krita/ui/kra/kis_kra_loader.cpp
@@ -580,6 +580,15 @@ KisNodeSP KisKraLoader::loadNode(const KoXmlElement& element, KisImageWSP image,
}
}
+ if (node->inherits("KisGroupLayer")) {
+ if (element.hasAttribute(PASS_THROUGH_MODE)) {
+ bool value = element.attribute(PASS_THROUGH_MODE, "0") != "0";
+
+ KisGroupLayer *group = qobject_cast<KisGroupLayer*>(node.data());
+ group->setPassThroughMode(value);
+ }
+ }
+
if (node->inherits("KisPaintLayer")) {
KisPaintLayer* layer = qobject_cast<KisPaintLayer*>(node.data());
QBitArray channelLockFlags = stringToFlags(element.attribute(CHANNEL_LOCK_FLAGS, ""), colorSpace->channelCount());
diff --git a/krita/ui/kra/kis_kra_savexml_visitor.cpp b/krita/ui/kra/kis_kra_savexml_visitor.cpp
index 9a942b8..8980bcc 100644
--- a/krita/ui/kra/kis_kra_savexml_visitor.cpp
+++ b/krita/ui/kra/kis_kra_savexml_visitor.cpp
@@ -149,6 +149,7 @@ bool KisSaveXmlVisitor::visit(KisGroupLayer *layer)
else {
layerElement = m_doc.createElement(LAYER);
saveLayer(layerElement, GROUP_LAYER, layer);
+ layerElement.setAttribute(PASS_THROUGH_MODE, layer->passThroughMode());
m_elem.appendChild(layerElement);
}
QDomElement elem = m_doc.createElement(LAYERS);
diff --git a/krita/ui/kra/kis_kra_tags.h b/krita/ui/kra/kis_kra_tags.h
index 7eaad6b..1a9294a 100644
--- a/krita/ui/kra/kis_kra_tags.h
+++ b/krita/ui/kra/kis_kra_tags.h
@@ -104,6 +104,7 @@ const QString Y_SHEAR = "y_shear";
const QString Y_TRANSLATION = "y_translation";
const QString ACTIVE = "active";
const QString LAYER_STYLE_UUID = "layerstyle";
+const QString PASS_THROUGH_MODE = "passthrough";
}
More information about the kimageshop
mailing list