diff --git a/libs/image/kis_base_node.cpp b/libs/image/kis_base_node.cpp index bd9a8600df..dfc54a2842 100644 --- a/libs/image/kis_base_node.cpp +++ b/libs/image/kis_base_node.cpp @@ -1,471 +1,491 @@ /* * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kis_base_node.h" #include #include #include #include #include #include #include "kis_paint_device.h" #include "kis_layer_properties_icons.h" #include "kis_scalar_keyframe_channel.h" struct Q_DECL_HIDDEN KisBaseNode::Private { QString compositeOp; KoProperties properties; KisBaseNode::Property hack_visible; //HACK QUuid id; QMap keyframeChannels; QScopedPointer opacityChannel; bool systemLocked; bool collapsed; bool supportsLodMoves; bool animated; bool useInTimeline; KisImageWSP image; Private(KisImageWSP image) : id(QUuid::createUuid()) , systemLocked(false) , collapsed(false) , supportsLodMoves(false) , animated(false) , useInTimeline(true) , image(image) { } Private(const Private &rhs) : compositeOp(rhs.compositeOp), id(QUuid::createUuid()), systemLocked(false), collapsed(rhs.collapsed), supportsLodMoves(rhs.supportsLodMoves), animated(rhs.animated), useInTimeline(rhs.useInTimeline), image(rhs.image) { QMapIterator iter = rhs.properties.propertyIterator(); while (iter.hasNext()) { iter.next(); properties.setProperty(iter.key(), iter.value()); } } }; KisBaseNode::KisBaseNode(KisImageWSP image) : m_d(new Private(image)) { /** * Be cautious! These two calls are vital to warm-up KoProperties. * We use it and its QMap in a threaded environment. This is not * officially supported by Qt, but our environment guarantees, that * there will be the only writer and several readers. Whilst the * value of the QMap is boolean and there are no implicit-sharing * calls provocated, it is safe to work with it in such an * environment. */ setVisible(true, true); setUserLocked(false); setCollapsed(false); setSupportsLodMoves(true); m_d->compositeOp = COMPOSITE_OVER; } KisBaseNode::KisBaseNode(const KisBaseNode & rhs) : QObject() , KisShared() , m_d(new Private(*rhs.m_d)) { if (rhs.m_d->keyframeChannels.size() > 0) { Q_FOREACH(QString key, rhs.m_d->keyframeChannels.keys()) { KisKeyframeChannel* channel = rhs.m_d->keyframeChannels.value(key); if (!channel) { continue; } if (channel->inherits("KisScalarKeyframeChannel")) { KisScalarKeyframeChannel* pchannel = qobject_cast(channel); KIS_ASSERT_RECOVER(pchannel) { continue; } KisScalarKeyframeChannel* channelNew = new KisScalarKeyframeChannel(*pchannel, 0); KIS_ASSERT(channelNew); m_d->keyframeChannels.insert(channelNew->id(), channelNew); if (KoID(key) == KisKeyframeChannel::Opacity) { m_d->opacityChannel.reset(channelNew); } } } } } KisBaseNode::~KisBaseNode() { delete m_d; } KisPaintDeviceSP KisBaseNode::colorPickSourceDevice() const { return projection(); } quint8 KisBaseNode::opacity() const { if (m_d->opacityChannel) { qreal value = m_d->opacityChannel->currentValue(); if (!qIsNaN(value)) { return value; } } return nodeProperties().intProperty("opacity", OPACITY_OPAQUE_U8); } void KisBaseNode::setOpacity(quint8 val) { if (m_d->opacityChannel) { KisKeyframeSP activeKeyframe = m_d->opacityChannel->currentlyActiveKeyframe(); if (activeKeyframe) { m_d->opacityChannel->setScalarValue(activeKeyframe, val); } } if (opacity() == val) return; setNodeProperty("opacity", val); baseNodeInvalidateAllFramesCallback(); } quint8 KisBaseNode::percentOpacity() const { return int(float(opacity() * 100) / 255 + 0.5); } void KisBaseNode::setPercentOpacity(quint8 val) { setOpacity(int(float(val * 255) / 100 + 0.5)); } const QString& KisBaseNode::compositeOpId() const { return m_d->compositeOp; } void KisBaseNode::setCompositeOpId(const QString& compositeOp) { if (m_d->compositeOp == compositeOp) return; m_d->compositeOp = compositeOp; baseNodeChangedCallback(); baseNodeInvalidateAllFramesCallback(); } KisBaseNode::PropertyList KisBaseNode::sectionModelProperties() const { KisBaseNode::PropertyList l; l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::visible, visible(), m_d->hack_visible.isInStasis, m_d->hack_visible.stateInStasis); l << KisLayerPropertiesIcons::getProperty(KisLayerPropertiesIcons::locked, userLocked()); return l; } void KisBaseNode::setSectionModelProperties(const KisBaseNode::PropertyList &properties) { setVisible(properties.at(0).state.toBool()); m_d->hack_visible = properties.at(0); setUserLocked(properties.at(1).state.toBool()); } const KoProperties & KisBaseNode::nodeProperties() const { return m_d->properties; } void KisBaseNode::setNodeProperty(const QString & name, const QVariant & value) { m_d->properties.setProperty(name, value); baseNodeChangedCallback(); } void KisBaseNode::mergeNodeProperties(const KoProperties & properties) { QMapIterator iter = properties.propertyIterator(); while (iter.hasNext()) { iter.next(); m_d->properties.setProperty(iter.key(), iter.value()); } baseNodeChangedCallback(); baseNodeInvalidateAllFramesCallback(); } bool KisBaseNode::check(const KoProperties & properties) const { QMapIterator iter = properties.propertyIterator(); while (iter.hasNext()) { iter.next(); if (m_d->properties.contains(iter.key())) { if (m_d->properties.value(iter.key()) != iter.value()) return false; } } return true; } QImage KisBaseNode::createThumbnail(qint32 w, qint32 h) { try { QImage image(w, h, QImage::Format_ARGB32); image.fill(0); return image; } catch (const std::bad_alloc&) { return QImage(); } } QImage KisBaseNode::createThumbnailForFrame(qint32 w, qint32 h, int time) { Q_UNUSED(time) return createThumbnail(w, h); } bool KisBaseNode::visible(bool recursive) const { bool isVisible = m_d->properties.boolProperty(KisLayerPropertiesIcons::visible.id(), true); KisBaseNodeSP parentNode = parentCallback(); return recursive && isVisible && parentNode ? parentNode->visible(recursive) : isVisible; } void KisBaseNode::setVisible(bool visible, bool loading) { const bool isVisible = m_d->properties.boolProperty(KisLayerPropertiesIcons::visible.id(), true); if (!loading && isVisible == visible) return; m_d->properties.setProperty(KisLayerPropertiesIcons::visible.id(), visible); notifyParentVisibilityChanged(visible); if (!loading) { baseNodeChangedCallback(); baseNodeInvalidateAllFramesCallback(); } } bool KisBaseNode::userLocked() const { return m_d->properties.boolProperty(KisLayerPropertiesIcons::locked.id(), false); } +bool KisBaseNode::belongsToIsolatedGroup() const +{ + if (!m_d->image) { + return false; + } + + const KisBaseNode* isolatedRoot = m_d->image->isolatedModeRoot().data(); + const KisBaseNode* element = this; + + while (element) { + if (element == isolatedRoot) { + return true; + } else { + element = element->parentCallback().data(); + } + } + + return false; +} + void KisBaseNode::setUserLocked(bool locked) { const bool isLocked = m_d->properties.boolProperty(KisLayerPropertiesIcons::locked.id(), true); if (isLocked == locked) return; m_d->properties.setProperty(KisLayerPropertiesIcons::locked.id(), locked); baseNodeChangedCallback(); } bool KisBaseNode::isEditable(bool checkVisibility) const { bool editable = true; if (checkVisibility) { - editable = (visible(false) && !userLocked()); + editable = ((visible(false) || belongsToIsolatedGroup()) && !userLocked()); } else { editable = (!userLocked()); } if (editable) { KisBaseNodeSP parentNode = parentCallback(); if (parentNode && parentNode != this) { editable = parentNode->isEditable(checkVisibility); } } return editable; } bool KisBaseNode::hasEditablePaintDevice() const { return paintDevice() && isEditable(); } void KisBaseNode::setCollapsed(bool collapsed) { const bool oldCollapsed = m_d->collapsed; m_d->collapsed = collapsed; if (oldCollapsed != collapsed) { baseNodeCollapsedChangedCallback(); } } bool KisBaseNode::collapsed() const { return m_d->collapsed; } void KisBaseNode::setColorLabelIndex(int index) { const int currentLabel = colorLabelIndex(); if (currentLabel == index) return; m_d->properties.setProperty(KisLayerPropertiesIcons::colorLabelIndex.id(), index); baseNodeChangedCallback(); } int KisBaseNode::colorLabelIndex() const { return m_d->properties.intProperty(KisLayerPropertiesIcons::colorLabelIndex.id(), 0); } QUuid KisBaseNode::uuid() const { return m_d->id; } void KisBaseNode::setUuid(const QUuid& id) { m_d->id = id; baseNodeChangedCallback(); } bool KisBaseNode::supportsLodMoves() const { return m_d->supportsLodMoves; } void KisBaseNode::setImage(KisImageWSP image) { m_d->image = image; } KisImageWSP KisBaseNode::image() const { return m_d->image; } bool KisBaseNode::isFakeNode() const { return false; } void KisBaseNode::setSupportsLodMoves(bool value) { m_d->supportsLodMoves = value; } QMap KisBaseNode::keyframeChannels() const { return m_d->keyframeChannels; } KisKeyframeChannel * KisBaseNode::getKeyframeChannel(const QString &id) const { QMap::const_iterator i = m_d->keyframeChannels.constFind(id); if (i == m_d->keyframeChannels.constEnd()) { return 0; } return i.value(); } KisKeyframeChannel * KisBaseNode::getKeyframeChannel(const QString &id, bool create) { KisKeyframeChannel *channel = getKeyframeChannel(id); if (!channel && create) { channel = requestKeyframeChannel(id); if (channel) { addKeyframeChannel(channel); } } return channel; } bool KisBaseNode::isAnimated() const { return m_d->animated; } void KisBaseNode::enableAnimation() { m_d->animated = true; baseNodeChangedCallback(); } bool KisBaseNode::useInTimeline() const { return m_d->useInTimeline; } void KisBaseNode::setUseInTimeline(bool value) { if (value == m_d->useInTimeline) return; m_d->useInTimeline = value; baseNodeChangedCallback(); } void KisBaseNode::addKeyframeChannel(KisKeyframeChannel *channel) { m_d->keyframeChannels.insert(channel->id(), channel); emit keyframeChannelAdded(channel); } KisKeyframeChannel *KisBaseNode::requestKeyframeChannel(const QString &id) { if (id == KisKeyframeChannel::Opacity.id()) { Q_ASSERT(m_d->opacityChannel.isNull()); KisPaintDeviceSP device = original(); if (device) { KisScalarKeyframeChannel * channel = new KisScalarKeyframeChannel( KisKeyframeChannel::Opacity, 0, 255, device->defaultBounds(), KisKeyframe::Linear ); m_d->opacityChannel.reset(channel); return channel; } } return 0; } diff --git a/libs/image/kis_base_node.h b/libs/image/kis_base_node.h index ba828b44c6..bd2d83baa9 100644 --- a/libs/image/kis_base_node.h +++ b/libs/image/kis_base_node.h @@ -1,590 +1,595 @@ /* * Copyright (c) 2007 Boudewijn Rempt * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef _KIS_BASE_NODE_H #define _KIS_BASE_NODE_H #include #include #include #include #include #include "kis_shared.h" #include "kis_paint_device.h" #include "kis_processing_visitor.h" // included, not forward declared for msvc class KoProperties; class KoColorSpace; class KoCompositeOp; class KisNodeVisitor; class KisUndoAdapter; class KisKeyframeChannel; #include "kritaimage_export.h" /** * A KisBaseNode is the base class for all components of an image: * nodes, layers masks, selections. A node has a number of properties, * can be represented as a thumbnail and knows what to do when it gets * a certain paint device to process. A KisBaseNode does not know * anything about its peers. You should not directly inherit from a * KisBaseNode; inherit from KisNode instead. */ class KRITAIMAGE_EXPORT KisBaseNode : public QObject, public KisShared { Q_OBJECT public: /** * Describes a property of a document section. * * FIXME: using a QList instead of QMap and not having an untranslated identifier, * either enum or string, forces applications to rely on the order of properties * or to compare the translated strings. This makes it hard to robustly extend the * properties of document section items. */ struct Property { QString id; /** i18n-ed name, suitable for displaying */ QString name; /** Whether the property is a boolean (e.g. locked, visible) which can be toggled directly from the widget itself. */ bool isMutable; /** Provide these if the property isMutable. */ QIcon onIcon; QIcon offIcon; /** If the property isMutable, provide a boolean. Otherwise, a string suitable for displaying. */ QVariant state; /** If the property is mutable, specifies whether it can be put into stasis. When a property is in stasis, a new state is created, and the old one is stored in stateInStasis. When stasis ends, the old value is restored and the new one discarded */ bool canHaveStasis; /** If the property isMutable and canHaveStasis, indicate whether it is in stasis or not */ bool isInStasis; /** If the property isMutable and canHaveStasis, provide this value to store the property's state while in stasis */ bool stateInStasis; bool operator==(const Property &rhs) const { return rhs.name == name && rhs.state == state && isInStasis == rhs.isInStasis; } Property(): isMutable( false ), isInStasis(false) { } /// Constructor for a mutable property. Property( const KoID &n, const QIcon &on, const QIcon &off, bool isOn ) : id(n.id()), name( n.name() ), isMutable( true ), onIcon( on ), offIcon( off ), state( isOn ), canHaveStasis( false ), isInStasis(false) { } /** Constructor for a mutable property accepting stasis */ Property( const KoID &n, const QIcon &on, const QIcon &off, bool isOn, bool _isInStasis, bool _stateInStasis = false ) : id(n.id()), name(n.name()), isMutable( true ), onIcon( on ), offIcon( off ), state( isOn ), canHaveStasis( true ), isInStasis( _isInStasis ), stateInStasis( _stateInStasis ) { } /// Constructor for a nonmutable property. Property( const KoID &n, const QString &s ) : id(n.id()), name(n.name()), isMutable( false ), state( s ), isInStasis(false) { } }; /** Return this type for PropertiesRole. */ typedef QList PropertyList; public: /** * Create a new, empty base node. The node is unnamed, unlocked * visible and unlinked. */ KisBaseNode(KisImageWSP image); /** * Create a copy of this node. */ KisBaseNode(const KisBaseNode & rhs); /** * Delete this node */ ~KisBaseNode() override; /** * Return the paintdevice you can use to change pixels on. For a * paint layer these will be paint pixels, for an adjustment layer or a mask * the selection paint device. * * @return the paint device to paint on. Can be 0 if the actual * node type does not support painting. */ virtual KisPaintDeviceSP paintDevice() const = 0; /** * @return the rendered representation of a node * before the effect masks have had their go at it. Can be 0. */ virtual KisPaintDeviceSP original() const = 0; /** * @return the fully rendered representation of this layer: its * rendered original and its effect masks. Can be 0. */ virtual KisPaintDeviceSP projection() const = 0; /** * @return a special device from where the color picker tool should pick * color when in layer-only mode. For most of the nodes just shortcuts * to projection() device. TODO: can it be null? */ virtual KisPaintDeviceSP colorPickSourceDevice() const; virtual const KoColorSpace *colorSpace() const = 0; /** * Return the opacity of this layer, scaled to a range between 0 * and 255. * XXX: Allow true float opacity */ quint8 opacity() const; //0-255 /** * Set the opacity for this layer. The range is between 0 and 255. * The layer will be marked dirty. * * XXX: Allow true float opacity */ void setOpacity(quint8 val); //0-255 /** * return the 8-bit opacity of this layer scaled to the range * 0-100 * * XXX: Allow true float opacity */ quint8 percentOpacity() const; //0-100 /** * Set the opacity of this layer with a number between 0 and 100; * the number will be scaled to between 0 and 255. * XXX: Allow true float opacity */ void setPercentOpacity(quint8 val); //0-100 /** * Return the composite op associated with this layer. */ virtual const KoCompositeOp *compositeOp() const = 0; const QString& compositeOpId() const; /** * Set a new composite op for this layer. The layer will be marked * dirty. */ void setCompositeOpId(const QString& compositeOpId); /** * @return unique id, which is now used by clone layers. */ QUuid uuid() const; /** * Set the uuid of node. This should only be used when loading * existing node and in constructor. */ void setUuid(const QUuid& id); /** * return the name of this node. This is the same as the * QObject::objectName. */ QString name() const { return objectName(); } /** * set the QObject::objectName. This is also the user-visible name * of the layer. The reason for this is that we want to see the * layer name also when debugging. */ void setName(const QString& name) { setObjectName(name); baseNodeChangedCallback(); } /** * @return the icon used to represent the node type, for instance * in the layerbox and in the menu. */ virtual QIcon icon() const { return QIcon(); } /** * Return a the properties of this base node (locked, visible etc, * with the right icons for their representation and their state. * * Subclasses can extend this list with new properties, like * opacity for layers or visualized for masks. * * The order of properties is, unfortunately, for now, important, * so take care which properties superclasses of your class * define. * * KisBaseNode defines visible = 0, locked = 1 * KisLayer defines opacity = 2, compositeOp = 3 * KisMask defines active = 2 (KisMask does not inherit kislayer) */ virtual PropertyList sectionModelProperties() const; /** * Change the section model properties. */ virtual void setSectionModelProperties(const PropertyList &properties); /** * Return all the properties of this layer as a KoProperties-based * serializable key-value list. */ const KoProperties & nodeProperties() const; /** * Set a node property. * @param name name of the property to be set. * @param value value to set the property to. */ void setNodeProperty(const QString & name, const QVariant & value); /** * Merge the specified properties with the properties of this * layer. Wherever these properties overlap, the value of the * node properties is changed. No properties on the node are * deleted. If there are new properties in this list, they will be * added on the node. */ void mergeNodeProperties(const KoProperties & properties); /** * Compare the given properties list with the properties of this * node. * * @return false only if the same property exists in both lists * but with a different value. Properties that are not in both * lists are disregarded. */ bool check(const KoProperties & properties) const; /** * Accept the KisNodeVisitor (for the Visitor design pattern), * should call the correct function on the KisNodeVisitor for this * node type, so you need to override it for all leaf classes in * the node inheritance hierarchy. * * return false if the visitor could not successfully act on this * node instance. */ virtual bool accept(KisNodeVisitor &) { return false; } /** * Accept the KisNodeVisitor (for the Visitor design pattern), * should call the correct function on the KisProcessingVisitor * for this node type, so you need to override it for all leaf * classes in the node inheritance hierarchy. * * The processing visitor differs from node visitor in the way * that it accepts undo adapter, that allows the processing to * be multithreaded */ virtual void accept(KisProcessingVisitor &visitor, KisUndoAdapter *undoAdapter) { Q_UNUSED(visitor); Q_UNUSED(undoAdapter); } /** * @return a thumbnail in requested size. The thumbnail is a rgba * QImage and may have transparent parts. Returns a fully * transparent QImage of the requested size if the current node * type cannot generate a thumbnail. If the requested size is too * big, return a null QImage. */ virtual QImage createThumbnail(qint32 w, qint32 h); /** * @return a thumbnail in requested size for the defined timestamp. * The thumbnail is a rgba Image and may have transparent parts. * Returns a fully transparent QImage of the requested size if the * current node type cannot generate a thumbnail. If the requested * size is too big, return a null QImage. */ virtual QImage createThumbnailForFrame(qint32 w, qint32 h, int time); /** * Ask this node to re-read the pertinent settings from the krita * configuration. */ virtual void updateSettings() { } /** * @return true if this node is visible (i.e, active (except for * selection masks where visible and active properties are * different)) in the graph * * @param bool recursive if true, check whether all parents of * this node are visible as well. */ virtual bool visible(bool recursive = false) const; /** * Set the visible status of this node. Visible nodes are active * in the graph (except for selections masks which can be active * while hidden), that is to say, they are taken into account * when merging. Invisible nodes play no role in the final image *, but will be modified when modifying all layers, for instance * when cropping. * * Toggling the visibility of a node will not automatically lead * to recomposition. * * @param visible the new visibility state * @param isLoading if true, the property is set during loading. */ virtual void setVisible(bool visible, bool loading = false); /** * Return the locked status of this node. Locked nodes cannot be * edited. */ bool userLocked() const; + /** + * Return whether or not the given node is isolated. + */ + bool belongsToIsolatedGroup() const; + /** * Set the locked status of this node. Locked nodes cannot be * edited. */ virtual void setUserLocked(bool l); /** * @return true if the node can be edited: * * if checkVisibility is true, then the node is only editable if it is visible and not locked. * if checkVisibility is false, then the node is editable if it's not locked. */ bool isEditable(bool checkVisibility = true) const; /** * @return true if the node is editable and has a paintDevice() * which which can be used for accessing pixels. It is an * equivalent to (isEditable() && paintDevice()) */ bool hasEditablePaintDevice() const; /** * @return the x-offset of this layer in the image plane. */ virtual qint32 x() const { return 0; } /** * Set the x offset of this layer in the image place. * Re-implement this where it makes sense, by default it does * nothing. It should not move child nodes. */ virtual void setX(qint32) { } /** * @return the y-offset of this layer in the image plane. */ virtual qint32 y() const { return 0; } /** * Set the y offset of this layer in the image place. * Re-implement this where it makes sense, by default it does * nothing. It should not move child nodes. */ virtual void setY(qint32) { } /** * Returns an approximation of where the bounds on actual data are * in this node. */ virtual QRect extent() const { return QRect(); } /** * Returns the exact bounds of where the actual data resides in * this node. */ virtual QRect exactBounds() const { return QRect(); } /** * Sets the state of the node to the value of @param collapsed */ void setCollapsed(bool collapsed); /** * returns the collapsed state of this node */ bool collapsed() const; /** * Sets a color label index associated to the layer. The actual * color of the label and the number of available colors is * defined by Krita GUI configuration. */ void setColorLabelIndex(int index); /** * \see setColorLabelIndex */ int colorLabelIndex() const; /** * Returns true if the offset of the node can be changed in a LodN * stroke. Currently, all the nodes except shape layers support that. */ bool supportsLodMoves() const; /** * Return the keyframe channels associated with this node * @return list of keyframe channels */ QMap keyframeChannels() const; /** * Get the keyframe channel with given id. * If the channel does not yet exist and the node supports the requested * channel, it will be created if create is true. * @param id internal name for channel * @param create attempt to create the channel if it does not exist yet * @return keyframe channel with the id, or null if not found */ KisKeyframeChannel *getKeyframeChannel(const QString &id, bool create); KisKeyframeChannel *getKeyframeChannel(const QString &id) const; bool useInTimeline() const; void setUseInTimeline(bool value); bool isAnimated() const; void enableAnimation(); virtual void setImage(KisImageWSP image); KisImageWSP image() const; /** * Fake node is not present in the layer stack and is not used * for normal projection rendering algorithms. */ virtual bool isFakeNode() const; protected: void setSupportsLodMoves(bool value); /** * FIXME: This method is a workaround for getting parent node * on a level of KisBaseNode. In fact, KisBaseNode should inherit * KisNode (in terms of current Krita) to be able to traverse * the node stack */ virtual KisBaseNodeSP parentCallback() const { return KisBaseNodeSP(); } virtual void notifyParentVisibilityChanged(bool value) { Q_UNUSED(value); } /** * This callback is called when some meta state of the base node * that can be interesting to the UI has changed. E.g. visibility, * lockness, opacity, compositeOp and etc. This signal is * forwarded by the KisNode and KisNodeGraphListener to the model * in KisLayerBox, so it can update its controls when information * changes. */ virtual void baseNodeChangedCallback() { } /** * This callback is called when collapsed state of the base node * has changed. This signal is forwarded by the KisNode and * KisNodeGraphListener to the model in KisLayerBox, so it can * update its controls when information changes. */ virtual void baseNodeCollapsedChangedCallback() { } virtual void baseNodeInvalidateAllFramesCallback() { } /** * Add a keyframe channel for this node. The channel will be added * to the common hash table which will be available to the UI. * * WARNING: the \p channel object *NOT* become owned by the node! * The caller must ensure manually that the lifetime of * the object coincide with the lifetime of the node. */ virtual void addKeyframeChannel(KisKeyframeChannel* channel); /** * Attempt to create the requested channel. Used internally by getKeyframeChannel. * Subclasses should implement this method to catch any new channel types they support. * @param id channel to create * @return newly created channel or null */ virtual KisKeyframeChannel * requestKeyframeChannel(const QString &id); Q_SIGNALS: void keyframeChannelAdded(KisKeyframeChannel *channel); private: struct Private; Private * const m_d; }; Q_DECLARE_METATYPE( KisBaseNode::PropertyList ) #endif