File indexing completed on 2024-05-12 15:58:44
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com> 0003 * 0004 * SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kis_switch_time_stroke_strategy.h" 0008 0009 #include <QMutex> 0010 0011 #include "kis_image_animation_interface.h" 0012 #include "kis_post_execution_undo_adapter.h" 0013 #include "commands_new/kis_switch_current_time_command.h" 0014 0015 0016 struct KisSwitchTimeStrokeStrategy::Private 0017 { 0018 Private(int frameId, bool needsRegeneration) 0019 : token(new SharedToken(frameId, needsRegeneration)) 0020 { 0021 } 0022 0023 KisImageAnimationInterface *interface {nullptr}; 0024 KisPostExecutionUndoAdapter *undoAdapter {nullptr}; 0025 SharedTokenSP token; 0026 }; 0027 0028 KisSwitchTimeStrokeStrategy::KisSwitchTimeStrokeStrategy(int frameId, 0029 bool needsRegeneration, 0030 KisImageAnimationInterface *interface, 0031 KisPostExecutionUndoAdapter *undoAdapter) 0032 : KisSimpleStrokeStrategy(QLatin1String("switch_current_frame_stroke"), kundo2_i18n("Switch Frames")), 0033 m_d(new Private(frameId, needsRegeneration)) 0034 { 0035 m_d->interface = interface; 0036 m_d->undoAdapter = undoAdapter; 0037 0038 0039 enableJob(JOB_INIT, true, KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::EXCLUSIVE); 0040 0041 // switching frames is a distinct user action, so it should 0042 // cancel the playback or any action easily 0043 setRequestsOtherStrokesToEnd(true); 0044 setClearsRedoOnStart(false); 0045 } 0046 0047 KisSwitchTimeStrokeStrategy::~KisSwitchTimeStrokeStrategy() 0048 { 0049 } 0050 void KisSwitchTimeStrokeStrategy::initStrokeCallback() 0051 { 0052 const int frameId = m_d->token->fetchTime(); 0053 0054 if (frameId == m_d->interface->currentTime()) return; 0055 0056 const int oldTime = m_d->interface->currentTime(); 0057 m_d->interface->explicitlySetCurrentTime(frameId); 0058 0059 if (m_d->undoAdapter) { 0060 KUndo2CommandSP cmd( 0061 new KisSwitchCurrentTimeCommand(m_d->interface, 0062 oldTime, 0063 frameId)); 0064 m_d->undoAdapter->addCommand(cmd); 0065 } 0066 } 0067 KisStrokeStrategy* KisSwitchTimeStrokeStrategy::createLodClone(int levelOfDetail) 0068 { 0069 Q_UNUSED(levelOfDetail); 0070 0071 // This stroke is explicitly made LEGACY, so that it could create a barrier for 0072 // time switch. Theoretically, we can have separate time ids for Lod0 and LodN, 0073 // but currently this idea doesn't wotk for some reason. The consequences of 0074 // making this stroke a barrier: 0075 // 0076 // * LodSync stroke is started after every time switch (not slow, but still...) 0077 // * The frame switches only *after* all the pending strokes are finished 0078 // * LodSync stroke is started even when the image is not changed (not regeneration needed)! 0079 0080 return 0; 0081 } 0082 0083 KisSwitchTimeStrokeStrategy::SharedTokenSP KisSwitchTimeStrokeStrategy::token() const 0084 { 0085 return m_d->token; 0086 } 0087 0088 0089 /*****************************************************************/ 0090 /* KisSwitchTimeStrokeStrategy::SharedToken */ 0091 /*****************************************************************/ 0092 0093 struct KisSwitchTimeStrokeStrategy::SharedToken::Private { 0094 Private(int _time, bool _needsRegeneration) 0095 : time(_time), 0096 needsRegeneration(_needsRegeneration), 0097 isCompleted(false) 0098 { 0099 } 0100 0101 QMutex mutex; 0102 int time; 0103 bool needsRegeneration; 0104 bool isCompleted; 0105 }; 0106 0107 KisSwitchTimeStrokeStrategy::SharedToken::SharedToken(int initialTime, bool needsRegeneration) 0108 : m_d(new Private(initialTime, needsRegeneration)) 0109 { 0110 } 0111 0112 KisSwitchTimeStrokeStrategy::SharedToken::~SharedToken() 0113 { 0114 } 0115 0116 bool KisSwitchTimeStrokeStrategy::SharedToken::tryResetDestinationTime(int time, bool needsRegeneration) 0117 { 0118 QMutexLocker l(&m_d->mutex); 0119 0120 const bool result = 0121 !m_d->isCompleted && 0122 (m_d->needsRegeneration || !needsRegeneration); 0123 0124 if (result) { 0125 m_d->time = time; 0126 } 0127 0128 return result; 0129 } 0130 0131 int KisSwitchTimeStrokeStrategy::SharedToken::fetchTime() const 0132 { 0133 QMutexLocker l(&m_d->mutex); 0134 KIS_SAFE_ASSERT_RECOVER_NOOP(!m_d->isCompleted); 0135 0136 m_d->isCompleted = true; 0137 return m_d->time; 0138 }