File indexing completed on 2024-12-22 04:10:02

0001 /*
0002  *  SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
0003  *  SPDX-FileCopyrightText: 2005 C. Boemann <cbo@boemann.dk>
0004  *
0005  *  SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include <klocalizedstring.h>
0009 #include "kis_node.h"
0010 #include "commands/kis_node_opacity_command.h"
0011 #include "kis_command_ids.h"
0012 #include "kis_command_utils.h"
0013 #include "kis_keyframe_channel.h"
0014 #include "kis_image.h"
0015 #include "kis_image_animation_interface.h"
0016 #include "kis_scalar_keyframe_channel.h"
0017 
0018 using namespace KisCommandUtils;
0019 
0020 KisNodeOpacityCommand::KisNodeOpacityCommand(KisNodeSP node, quint8 newOpacity) :
0021         KisNodeCommand(kundo2_i18n("Opacity Change"), node)
0022 {
0023     m_newOpacity = newOpacity;
0024 
0025     KIS_SAFE_ASSERT_RECOVER_RETURN(node->image());
0026 
0027     const int time = node->image()->animationInterface()->currentTime();
0028 
0029     KisKeyframeChannel* channel = m_node->getKeyframeChannel(KisKeyframeChannel::Opacity.id());
0030     if (channel && !channel->keyframeAt(time)) {
0031         KisScalarKeyframeChannel* scalarChannel = dynamic_cast<KisScalarKeyframeChannel*>(channel);
0032         KIS_ASSERT(scalarChannel);
0033         m_autokey.reset(new SkipFirstRedoWrapper());
0034         scalarChannel->addScalarKeyframe(time, newOpacity, m_autokey.data());
0035     }
0036 }
0037 
0038 void KisNodeOpacityCommand::redo()
0039 {
0040     if (!m_oldOpacity) {
0041         m_oldOpacity = m_node->opacity();
0042     }
0043 
0044     if (m_autokey) {
0045         m_autokey->redo();
0046     }
0047 
0048     m_node->setOpacity(m_newOpacity);
0049     m_node->setDirty();
0050 }
0051 
0052 void KisNodeOpacityCommand::undo()
0053 {
0054     KIS_SAFE_ASSERT_RECOVER_RETURN(m_oldOpacity);
0055 
0056     m_node->setOpacity(*m_oldOpacity);
0057     m_node->setDirty();
0058 
0059     if (m_autokey) {
0060         m_autokey->undo();
0061     }
0062 }
0063 
0064 int KisNodeOpacityCommand::id() const
0065 {
0066     return KisCommandUtils::ChangeNodeOpacityId;
0067 }
0068 
0069 bool KisNodeOpacityCommand::mergeWith(const KUndo2Command *command)
0070 {
0071     const KisNodeOpacityCommand *other =
0072         dynamic_cast<const KisNodeOpacityCommand*>(command);
0073 
0074     if (other && other->m_node == m_node) {
0075         // verify both commands have been executed and they are consecutive
0076         KIS_SAFE_ASSERT_RECOVER_NOOP(m_oldOpacity);
0077         KIS_SAFE_ASSERT_RECOVER_NOOP(other->m_oldOpacity);
0078         KIS_SAFE_ASSERT_RECOVER_NOOP(other->m_oldOpacity && m_newOpacity == *other->m_oldOpacity);
0079 
0080         m_newOpacity = other->m_newOpacity;
0081         return true;
0082     }
0083 
0084     return false;
0085 }
0086 
0087 bool KisNodeOpacityCommand::canMergeWith(const KUndo2Command *command) const
0088 {
0089     const KisNodeOpacityCommand *other =
0090         dynamic_cast<const KisNodeOpacityCommand*>(command);
0091     if (!other) return false;
0092 
0093 
0094     bool otherCreatedKeyframe = other->m_autokey;
0095     bool weCreatedKeyframe = m_autokey;
0096     bool canMergeKeyframe = ((otherCreatedKeyframe ^ weCreatedKeyframe) == true) || (!otherCreatedKeyframe && !weCreatedKeyframe);
0097 
0098     return other->m_node == m_node && canMergeKeyframe;
0099 }
0100 
0101 bool KisNodeOpacityCommand::canAnnihilateWith(const KUndo2Command *command) const
0102 {
0103     const KisNodeOpacityCommand *other =
0104         dynamic_cast<const KisNodeOpacityCommand*>(command);
0105 
0106     if (!other || other->m_node != m_node) {
0107         return false;
0108     }
0109 
0110     if (m_autokey || other->m_autokey) {
0111         return false;
0112     }
0113 
0114     KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(m_oldOpacity, false);
0115     return *m_oldOpacity == other->m_newOpacity;
0116 }