Krita Source Code Documentation
Loading...
Searching...
No Matches
StoryboardModel Class Reference

The main storyboard model. This class manages a StoryboardItemList which is a list of StoryboardItem objects. It provides the interface to manipulate and access the data. More...

#include <StoryboardModel.h>

+ Inheritance diagram for StoryboardModel:

Classes

class  KeyframeReorderLock
 

Public Types

enum  AdditionalRoles { TotalSceneDurationInFrames = Qt::UserRole + 1 , TotalSceneDurationInSeconds = Qt::UserRole + 2 }
 

Public Slots

void slotSetActiveNode (KisNodeSP)
 

Signals

void sigStoryboardItemListChanged ()
 This signal is emitted whenever m_items is changed. it is used to keep the StoryboardItemList in KisDocument in sync with m_items.
 

Public Member Functions

QModelIndexList affectedIndexes (KisTimeSpan range) const
 Returns a list of index of items that have frame in between argument range.
 
bool changeSceneHoldLength (int oldDuration, QModelIndex itemIndex)
 moves all keyframes in all layers after the frame of the parent of durationIndex Keyframes are moved to the left or right based on the difference (newDuration-oldDuration)
 
int columnCount (const QModelIndex &parent=QModelIndex()) const override
 
void createBlankKeyframes (const QModelIndex &index, KUndo2Command *cmd=nullptr)
 
void createDuplicateKeyframes (const QModelIndex &index, KUndo2Command *cmd=nullptr)
 
QVariant data (const QModelIndex &index, int role=Qt::DisplayRole) const override
 
bool dropMimeData (const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
 
Qt::ItemFlags flags (const QModelIndex &index) const override
 
StoryboardComment getComment (int row) const
 
StoryboardItemList getData ()
 
int getFramesPerSecond () const
 
QModelIndex index (int row, int column, const QModelIndex &parent=QModelIndex()) const override
 
QModelIndex indexFromFrame (int frame, bool framePerfect=true) const
 Returns the index of the item corresponding the frame, if there is an item with that frame.
 
void insertChildRows (int position, KUndo2Command *cmd=nullptr)
 must be called after a first level index is inserted. Adds child nodes to the first level indices
 
void insertChildRows (int position, StoryboardItemSP item)
 Adds child nodes from the item provided.
 
bool insertItem (QModelIndex index, bool after)
 inserts item after or before index based on after parameter
 
bool insertRows (int position, int rows, const QModelIndex &index=QModelIndex()) override
 
bool isFrozen () const
 
bool isLocked () const
 
QModelIndex lastIndexBeforeFrame (int frame) const
 Returns the index of the item with largest frame smaller than argument frame.
 
int lastKeyframeGlobal () const
 
int lastKeyframeWithin (QModelIndex index)
 Gets the last keyframe that exists within an index's duration. Used to prevent duration from overwriting keyframes that exist internal to an existing scene.
 
QMimeData * mimeData (const QModelIndexList &indexes) const override
 
QStringList mimeTypes () const override
 
bool moveRows (const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override
 
int nextKeyframeGlobal (int keyframeTime) const
 the next time at which there is a keyframe in any layer after keyframeTime
 
QModelIndex parent (const QModelIndex &index) const override
 
void pushUndoCommand (KUndo2Command *command)
 
bool removeItem (QModelIndex index, KUndo2Command *command=nullptr)
 removes item, deletes keyframes within and shifts keyframe after the scene to fill in the gap
 
bool removeRows (int position, int rows, const QModelIndex &index=QModelIndex()) override
 
void reorderKeyframes ()
 reorders all keyframes to reflect storyboard docker's arrangement. typically used after drag and drop to keep storyboard timing accurate to timeline timing.
 
void resetData (StoryboardItemList list)
 resets m_items to list
 
int rowCount (const QModelIndex &parent=QModelIndex()) const override
 
void setCommentModel (StoryboardCommentModel *commentModel)
 Sets the commentModel in StoryboardModel and creates connections to keep the local copy of comments in sync with the commentModel's.
 
bool setCommentScrollData (const QModelIndex &index, const QVariant &value)
 Sets the scrollValue of the CommentBox object.
 
bool setData (const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
 
void setFreeze (bool)
 
void setImage (KisImageWSP image)
 
void setLocked (bool)
 
bool setThumbnailPixmapData (const QModelIndex &parentIndex, const KisPaintDeviceSP &dev)
 Sets the Pixmap data.
 
void setView (StoryboardView *view)
 
void shiftKeyframes (KisTimeSpan affected, int offset, KUndo2Command *cmd=nullptr)
 
void slotUpdateThumbnailsForItems (QModelIndexList indices)
 
 StoryboardModel (QObject *parent)
 
Qt::DropActions supportedDragActions () const override
 
Qt::DropActions supportedDropActions () const override
 
int totalCommentCount ()
 Get total number of comments.
 
bool updateDurationData (const QModelIndex &parentIndex)
 updates the duration data of item at parentIndex to the number of frame to the next keyframe in any layer.
 
int visibleCommentCount () const
 Used in StoryboardDelegate and StoryboardView to get size of one storyboard item.
 
int visibleCommentsUpto (QModelIndex index) const
 Used in StoryboardView to design the layout of storyboard item.
 
void visualizeScene (const QModelIndex &index, bool useUndo=true)
 
 ~StoryboardModel () override
 

Private Slots

void slotCommentDataChanged ()
 
void slotCommentRowInserted (const QModelIndex, int, int)
 
void slotCommentRowMoved (const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)
 
void slotCommentRowRemoved (const QModelIndex, int, int)
 
void slotCurrentFrameChanged (int frameId)
 called when currentUiTime changes
 
void slotFramerateChanged ()
 
void slotFrameRenderCancelled (int frame)
 called KisStoryboardThumbnailRenderScheduler when frame render is cancelled.
 
void slotFrameRenderCompleted (int frame, KisPaintDeviceSP dev)
 called KisStoryboardThumbnailRenderScheduler when frame render is complete
 
void slotKeyframeAdded (const KisKeyframeChannel *channel, int time)
 
void slotKeyframeRemoved (const KisKeyframeChannel *channel, int time)
 
void slotNodeRemoved (KisNodeSP node)
 
void slotUpdateThumbnailForFrame (int frame, bool delay=true)
 calls regeneration of frame in the background i.e. in another thread.
 
void slotUpdateThumbnails ()
 calls regeneration of the currentUiTime() and all frames in affectedIndexes(KisTimeSpan)
 

Private Member Functions

bool isValidBoard (const QModelIndex &index) const
 
bool moveRowsImpl (const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild, KUndo2Command *parentCMD=nullptr)
 

Private Attributes

KisNodeWSP m_activeNode
 
QVector< StoryboardCommentm_commentList
 
StoryboardCommentModelm_commentModel {0}
 
bool m_freezeKeyframePositions {false}
 
KisImageWSP m_image
 
KisIdleWatcher m_imageIdleWatcher
 
StoryboardItemList m_items
 
int m_lastScene {0}
 
bool m_lockBoards {false}
 
KisStoryboardThumbnailRenderSchedulerm_renderScheduler {0}
 
KisSignalCompressor m_renderSchedulingCompressor
 
bool m_reorderingKeyframes {false}
 
StoryboardViewm_view {0}
 

Friends

class KisMoveStoryboardCommand
 

Detailed Description

The main storyboard model. This class manages a StoryboardItemList which is a list of StoryboardItem objects. It provides the interface to manipulate and access the data.

Definition at line 32 of file StoryboardModel.h.

Member Enumeration Documentation

◆ AdditionalRoles

Enumerator
TotalSceneDurationInFrames 
TotalSceneDurationInSeconds 

Definition at line 37 of file StoryboardModel.h.

37 {
38 TotalSceneDurationInFrames = Qt::UserRole + 1,
39 TotalSceneDurationInSeconds = Qt::UserRole + 2,
40 };

Constructor & Destructor Documentation

◆ StoryboardModel()

StoryboardModel::StoryboardModel ( QObject * parent)

Definition at line 30 of file StoryboardModel.cpp.

31 : QAbstractItemModel(parent)
33 , m_lockBoards(false)
38{
39 connect(m_renderScheduler, SIGNAL(sigFrameCompleted(int, KisPaintDeviceSP)), this, SLOT(slotFrameRenderCompleted(int, KisPaintDeviceSP)));
40 connect(m_renderScheduler, SIGNAL(sigFrameCancelled(int)), this, SLOT(slotFrameRenderCancelled(int)));
41 connect(&m_renderSchedulingCompressor, SIGNAL(timeout()), this, SLOT(slotUpdateThumbnails()));
42 connect(&m_imageIdleWatcher, SIGNAL(startedIdleMode()), m_renderScheduler, SLOT(slotStartFrameRendering()));
43}
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
This class maintains queues of dirty frames sorted in the order of proximity to the last changed fram...
KisStoryboardThumbnailRenderScheduler * m_renderScheduler
KisIdleWatcher m_imageIdleWatcher
void slotFrameRenderCompleted(int frame, KisPaintDeviceSP dev)
called KisStoryboardThumbnailRenderScheduler when frame render is complete
QModelIndex parent(const QModelIndex &index) const override
void slotUpdateThumbnails()
calls regeneration of the currentUiTime() and all frames in affectedIndexes(KisTimeSpan)
KisSignalCompressor m_renderSchedulingCompressor
void slotFrameRenderCancelled(int frame)
called KisStoryboardThumbnailRenderScheduler when frame render is cancelled.

References connect(), m_imageIdleWatcher, m_renderScheduler, m_renderSchedulingCompressor, slotFrameRenderCancelled(), slotFrameRenderCompleted(), and slotUpdateThumbnails().

◆ ~StoryboardModel()

StoryboardModel::~StoryboardModel ( )
override

Definition at line 45 of file StoryboardModel.cpp.

46{
47 delete m_renderScheduler;
48}

References m_renderScheduler.

Member Function Documentation

◆ affectedIndexes()

QModelIndexList StoryboardModel::affectedIndexes ( KisTimeSpan range) const

Returns a list of index of items that have frame in between argument range.

Parameters
rangeThe range of frames
Returns
The list of index corresponding to the range.

Definition at line 667 of file StoryboardModel.cpp.

668{
669 QModelIndex firstIndex = index(0,0);
670
671 if (!firstIndex.isValid())
672 return QModelIndexList();
673
674 if ( range.start() > index(StoryboardItem::FrameNumber, 0, firstIndex).data().toInt()) {
675 firstIndex = indexFromFrame(range.start(), false);
676 }
677
678 QModelIndex lastIndex = index(rowCount() - 1, 0);
679
680 if (!range.isInfinite() && range.isValid()) {
681 lastIndex = indexFromFrame(range.end(), false);
682 }
683
684 QItemSelectionRange indexRange(firstIndex, lastIndex);
685 return indexRange.indexes();
686}
QList< QModelIndex > QModelIndexList
Definition LayerBox.h:41
int start() const
bool isInfinite() const
int end() const
bool isValid() const
@ FrameNumber
Store the frame number at index 0. Data type stored here should be ThumbnailData.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QModelIndex indexFromFrame(int frame, bool framePerfect=true) const
Returns the index of the item corresponding the frame, if there is an item with that frame.
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
int toInt(const QString &str, bool *ok=nullptr)

References data(), KisTimeSpan::end(), StoryboardItem::FrameNumber, index(), indexFromFrame(), KisTimeSpan::isInfinite(), KisTimeSpan::isValid(), rowCount(), and KisTimeSpan::start().

◆ changeSceneHoldLength()

bool StoryboardModel::changeSceneHoldLength ( int oldDuration,
QModelIndex itemIndex )

moves all keyframes in all layers after the frame of the parent of durationIndex Keyframes are moved to the left or right based on the difference (newDuration-oldDuration)

Parameters
oldDurationThe old duration in frames assigned to item
itemIndexThe storyboard item index.
Returns
True if keyframes were moved, otherwise False

Definition at line 854 of file StoryboardModel.cpp.

855{
856 if (!itemIndex.isValid()) {
857 return false;
858 }
859
860 const int origSceneFrameLength = data(itemIndex, TotalSceneDurationInFrames).toInt();
861 const int lastFrameOfScene = lastKeyframeWithin(itemIndex);
862
863 int durationChange = newDuration - origSceneFrameLength;
864 if (durationChange == 0) {
865 return false;
866 }
867
868 if (origSceneFrameLength != 0) {
869 shiftKeyframes(KisTimeSpan::infinite(lastFrameOfScene + 1), durationChange);
870 }
871
872 return true;
873}
static KisTimeSpan infinite(int start)
int lastKeyframeWithin(QModelIndex index)
Gets the last keyframe that exists within an index's duration. Used to prevent duration from overwrit...
void shiftKeyframes(KisTimeSpan affected, int offset, KUndo2Command *cmd=nullptr)

References data(), KisTimeSpan::infinite(), lastKeyframeWithin(), shiftKeyframes(), and TotalSceneDurationInFrames.

◆ columnCount()

int StoryboardModel::columnCount ( const QModelIndex & parent = QModelIndex()) const
override

Definition at line 107 of file StoryboardModel.cpp.

108{
109 if (!parent.isValid()) {
110 return 1;
111 }
112 //1st level nodes have 1 column
113 if (!parent.parent().isValid()) {
114 return 1;
115 }
116 //end level nodes have no child
117 return 0;
118}

References parent().

◆ createBlankKeyframes()

void StoryboardModel::createBlankKeyframes ( const QModelIndex & index,
KUndo2Command * cmd = nullptr )

Definition at line 1321 of file StoryboardModel.cpp.

1322{
1324 const int targetFrame = index(StoryboardItem::FrameNumber, 0, pIndex).data().toInt();
1325
1326 KisLayerUtils::recursiveApplyNodes(m_image->root(), [targetFrame, cmd](KisNodeSP node){
1327 if (node->supportsKeyframeChannel(KisKeyframeChannel::Raster.id())
1328 && node->isEditable(true)) {
1329
1330 KisKeyframeChannel* chan = node->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true);
1331 chan->addKeyframe(targetFrame, cmd);
1332 }
1333 });
1334 }
1335}
KisImageWSP m_image
void recursiveApplyNodes(NodePointer node, Functor func)

References StoryboardItem::FrameNumber, index(), m_freezeKeyframePositions, m_image, KisLayerUtils::recursiveApplyNodes(), and KisNodeFacade::root.

◆ createDuplicateKeyframes()

void StoryboardModel::createDuplicateKeyframes ( const QModelIndex & index,
KUndo2Command * cmd = nullptr )

Definition at line 1304 of file StoryboardModel.cpp.

1305{
1307 const int targetFrame = index(StoryboardItem::FrameNumber, 0, pIndex).data().toInt();
1308
1309 KisLayerUtils::recursiveApplyNodes(m_image->root(), [targetFrame, cmd](KisNodeSP node){
1310 if (node->supportsKeyframeChannel(KisKeyframeChannel::Raster.id())
1311 && node->isEditable(true)) {
1312
1313 KisKeyframeChannel* chan = node->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true);
1314 const int activeFrameTime = chan->activeKeyframeTime(targetFrame);
1315 chan->copyKeyframe(activeFrameTime, targetFrame, cmd);
1316 }
1317 });
1318 }
1319}

References StoryboardItem::FrameNumber, index(), m_freezeKeyframePositions, m_image, KisLayerUtils::recursiveApplyNodes(), and KisNodeFacade::root.

◆ data()

QVariant StoryboardModel::data ( const QModelIndex & index,
int role = Qt::DisplayRole ) const
override

Definition at line 120 of file StoryboardModel.cpp.

121{
122 if (!index.isValid()) {
123 return QVariant();
124 }
125
126 //return data only for the storyboardChild i.e. 2nd level nodes
127 if (isValidBoard(index)) {
128 if (role == TotalSceneDurationInFrames) {
129 int duration = this->index(StoryboardItem::DurationFrame, 0, index).data().toInt()
130 + this->index(StoryboardItem::DurationSecond, 0, index).data().toInt() * getFramesPerSecond();
131 return duration;
132 }
133 else if (role == TotalSceneDurationInSeconds) {
134 qreal duration = this->index(StoryboardItem::DurationSecond, 0, index).data().toInt()
135 + this->index(StoryboardItem::DurationFrame, 0, index).data().toInt()
137 return duration;
138 }
139 return QVariant();
140 }
141
142 if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::UserRole) {
143 QSharedPointer<StoryboardChild> child = m_items.at(index.parent().row())->child(index.row());
144 if (index.row() == StoryboardItem::FrameNumber) {
145 ThumbnailData thumbnailData = qvariant_cast<ThumbnailData>(child->data());
146 if (role == Qt::UserRole) {
147 return thumbnailData.pixmap;
148 }
149 else {
150 return thumbnailData.frameNum;
151 }
152 }
153 else if (index.row() >= StoryboardItem::Comments) {
154 CommentBox commentBox = qvariant_cast<CommentBox>(child->data());
155 if (role == Qt::UserRole) { //scroll bar position
156 return commentBox.scrollValue;
157 }
158 else {
159 return commentBox.content;
160 }
161 }
162 return child->data();
163 }
164 return QVariant();
165}
This class is a simple combination of two QVariants. It can be converted to and from QVariant type an...
QVariant scrollValue
the value of the scroll bar of the comment scrollbar
QVariant content
the text content of the Comment
@ DurationFrame
Store the duration in frame at index 3. Data type stored here should be int.
@ DurationSecond
Store the duration in second at index 2. Data type stored here should be int.
@ Comments
Store the comments at indices greater_than_or_equal_to to index 4. Data type stored here should be Co...
bool isValidBoard(const QModelIndex &index) const
int getFramesPerSecond() const
StoryboardItemList m_items
This class is a simple combination of two QVariants. It can be converted to and from QVariant type an...
QVariant frameNum
the frame number corresponding to this item in the timeline docker
QVariant pixmap
a scaled down thumbnail version of the frame

References StoryboardItem::Comments, CommentBox::content, StoryboardItem::DurationFrame, StoryboardItem::DurationSecond, ThumbnailData::frameNum, StoryboardItem::FrameNumber, getFramesPerSecond(), index(), isValidBoard(), m_items, ThumbnailData::pixmap, CommentBox::scrollValue, TotalSceneDurationInFrames, and TotalSceneDurationInSeconds.

◆ dropMimeData()

bool StoryboardModel::dropMimeData ( const QMimeData * data,
Qt::DropAction action,
int row,
int column,
const QModelIndex & parent )
override

Definition at line 468 of file StoryboardModel.cpp.

470{
471 Q_UNUSED(column);
472 if (action == Qt::IgnoreAction) {
473 return false;
474 }
475
476 if (action == Qt::MoveAction && data->hasFormat("application/x-krita-storyboard")) {
477 QByteArray bytes = data->data("application/x-krita-storyboard");
478 QDataStream stream(&bytes, QIODevice::ReadOnly);
479
480 if (parent.isValid()) {
481 return false;
482 }
483
484 if (isLocked()) {
485 return false;
486 }
487
488 int sourceRow;
489 QModelIndexList moveRowIndexes;
490 while (!stream.atEnd()) {
491 stream >> sourceRow;
492 QModelIndex index = this->index(sourceRow, 0);
493 moveRowIndexes.append(index);
494 }
495
496 moveRows(QModelIndex(), moveRowIndexes.at(0).row(), moveRowIndexes.count(), parent, row);
497 //returning true deletes the source row
498 return false;
499 }
500 return false;
501}
bool isLocked() const
bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) override

References data(), index(), isLocked(), moveRows(), and parent().

◆ flags()

Qt::ItemFlags StoryboardModel::flags ( const QModelIndex & index) const
override

Definition at line 320 of file StoryboardModel.cpp.

321{
322 if(!index.isValid()) {
323 return Qt::ItemIsDropEnabled;
324 }
325
326 //1st level nodes
327 if (isValidBoard(index)) {
328 return Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled;
329 }
330
331 //2nd level nodes
332 return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren;
333}

References index(), and isValidBoard().

◆ getComment()

StoryboardComment StoryboardModel::getComment ( int row) const
Parameters
rowThe row of the comment.
Returns
The Comment object at row in comment's list.
Note
The Comment object contains the name of the comment. Not to be confused with CommentBox.
See also
Comment

Definition at line 556 of file StoryboardModel.cpp.

557{
558 return m_commentList.at(row);
559}
QVector< StoryboardComment > m_commentList

References m_commentList.

◆ getData()

StoryboardItemList StoryboardModel::getData ( )
Returns
The list of StoryboardItem* stored in the model.

Definition at line 1030 of file StoryboardModel.cpp.

1031{
1032 return m_items;
1033}

References m_items.

◆ getFramesPerSecond()

int StoryboardModel::getFramesPerSecond ( ) const

Definition at line 581 of file StoryboardModel.cpp.

582{
583 return m_image.isValid() ? m_image->animationInterface()->framerate() : 24;
584}
KisImageAnimationInterface * animationInterface() const
bool isValid() const

References KisImage::animationInterface(), KisImageAnimationInterface::framerate(), KisWeakSharedPtr< T >::isValid(), and m_image.

◆ index()

QModelIndex StoryboardModel::index ( int row,
int column,
const QModelIndex & parent = QModelIndex() ) const
override

Definition at line 50 of file StoryboardModel.cpp.

51{
52 if (!hasIndex(row, column, parent)) {
53 return QModelIndex();
54 }
55 if (row < 0 || row >= rowCount(parent)) {
56 return QModelIndex();
57 }
58 if (column != 0) {
59 return QModelIndex();
60 }
61
62 if (isValidBoard(parent)) {
63 StoryboardItemSP parentItem = m_items.at(parent.row());
64 QSharedPointer<StoryboardChild> childItem = parentItem->child(row);
65
66 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(childItem, QModelIndex());
67 return createIndex(row, column, childItem.data());
68 } else {
69 return createIndex(row, column, m_items.at(row).data());
70 }
71}
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129

References isValidBoard(), KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_items, parent(), and rowCount().

◆ indexFromFrame()

QModelIndex StoryboardModel::indexFromFrame ( int frame,
bool framePerfect = true ) const

Returns the index of the item corresponding the frame, if there is an item with that frame.

Parameters
frameThe frame whose index is needed.
framePerfectWhether query will return a valid scene even when a scene contains the frame, not just if it starts on said frame. Default == true
Returns
The index corresponding to frame, if exists.

Definition at line 637 of file StoryboardModel.cpp.

638{
639 int end = rowCount(), begin = 0;
640 while (end >= begin) {
641 const int row = begin + (end - begin) / 2;
642 const int nextRow = row + 1;
643 QModelIndex parentIndex = index(row, 0);
644 QModelIndex frameNumIndex = index(StoryboardItem::FrameNumber, 0, parentIndex);
645 QModelIndex nextParentIndex = index(nextRow, 0);
646 QModelIndex nextFrameNumIndex = index(StoryboardItem::FrameNumber, 0, nextParentIndex);
647
648 if (framePerfect && frame == frameNumIndex.data().toInt()) {
649 return parentIndex;
650 } else if (frame >= frameNumIndex.data().toInt() && (!nextParentIndex.isValid() || frame < nextFrameNumIndex.data().toInt())) {
651 return parentIndex;
652 } else if (frame < frameNumIndex.data().toInt()) {
653 end = row - 1;
654 } else if (frame > frameNumIndex.data().toInt()) {
655 begin = row + 1;
656 }
657 }
658
659 return QModelIndex();
660}

References StoryboardItem::FrameNumber, index(), and rowCount().

◆ insertChildRows() [1/2]

void StoryboardModel::insertChildRows ( int position,
KUndo2Command * cmd = nullptr )

must be called after a first level index is inserted. Adds child nodes to the first level indices

Parameters
positionIndex of the first level node.

Definition at line 1245 of file StoryboardModel.cpp.

1246{
1247 if (position + 1 < rowCount()) {
1248 const int frame = index(StoryboardItem::FrameNumber, 0, index(position + 1, 0)).data().toInt();
1250 }
1251
1252 for (int row = position + 1; row < rowCount(); ++row) {
1253 const int frame = index(StoryboardItem::FrameNumber, 0, index(row, 0)).data().toInt();
1254 setData(index(StoryboardItem::FrameNumber, 0, index(row, 0)), frame + 1);
1255 }
1256
1257 QModelIndex parentIndex = index(position, 0);
1258 insertRows(0, 4 + m_commentList.count(), parentIndex);
1259
1260 m_lastScene++;
1261 QString sceneName = i18nc("default name for storyboard item", "scene ") + QString::number(m_lastScene);
1262 setData(index(StoryboardItem::ItemName, 0, parentIndex), sceneName);
1263
1264 const bool firstEntry = rowCount() == 1;
1265
1266 if (position == 0) {
1267 setData(index(StoryboardItem::FrameNumber, 0, index(position, 0)), 0);
1269 } else {
1270 const int targetFrame = index(StoryboardItem::FrameNumber, 0, index(position - 1,0)).data().toInt()
1271 + data(index(position - 1, 0), TotalSceneDurationInFrames).toInt();
1272
1273 setData(index(StoryboardItem::FrameNumber, 0, index(position, 0)), targetFrame);
1274 setData(index(StoryboardItem::DurationFrame, 0, parentIndex), 1);
1275 setData(index(StoryboardItem::DurationSecond, 0, parentIndex), 0);
1276 }
1277
1278 if (firstEntry) {
1279 createDuplicateKeyframes(index(position, 0), cmd);
1280 } else {
1281 createBlankKeyframes(index(position, 0), cmd);
1282 }
1283
1284 const int frameToSwitch = index(StoryboardItem::FrameNumber, 0, index(position, 0)).data().toInt();
1285 if (m_image) {
1287 switchFrameCmd->redo();
1288 }
1289}
@ ItemName
Store the item name at index 1. Data type stored here should be string.
void createBlankKeyframes(const QModelIndex &index, KUndo2Command *cmd=nullptr)
int lastKeyframeGlobal() const
bool insertRows(int position, int rows, const QModelIndex &index=QModelIndex()) override
void createDuplicateKeyframes(const QModelIndex &index, KUndo2Command *cmd=nullptr)
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override

References KisImage::animationInterface(), createBlankKeyframes(), createDuplicateKeyframes(), KisImageAnimationInterface::currentTime(), data(), StoryboardItem::DurationFrame, StoryboardItem::DurationSecond, StoryboardItem::FrameNumber, index(), KisTimeSpan::infinite(), insertRows(), StoryboardItem::ItemName, lastKeyframeGlobal(), m_commentList, m_image, m_lastScene, KisSwitchCurrentTimeCommand::redo(), rowCount(), setData(), shiftKeyframes(), and TotalSceneDurationInFrames.

◆ insertChildRows() [2/2]

void StoryboardModel::insertChildRows ( int position,
StoryboardItemSP item )

Adds child nodes from the item provided.

Parameters
positionIndex of the first level node.

Definition at line 1415 of file StoryboardModel.cpp.

1416{
1417 QModelIndex parentIndex = index(position, 0);
1418 insertRows(0, 4 + m_commentList.count(), parentIndex);
1419
1420 setFreeze(true);
1421 for (int i = 0; i < item->childCount(); i++) {
1422 QVariant data = item->child(i)->data();
1423 setData(index(i, 0, index(position, 0)), data);
1424 }
1425 setFreeze(false);
1428}

References data(), index(), insertRows(), m_commentList, m_renderScheduler, setData(), setFreeze(), KisStoryboardThumbnailRenderScheduler::slotStartFrameRendering(), and slotUpdateThumbnails().

◆ insertItem()

bool StoryboardModel::insertItem ( QModelIndex index,
bool after )

inserts item after or before index based on after parameter

Parameters
indexThe index at which right click was clicked or the plus button belonged to.
afterIf True item is added after index, otherwise before
Returns
True if item was inserted, otherwise false

Definition at line 926 of file StoryboardModel.cpp.

927{
928 //index is the index at which context menu was created, or the + button belongs to
929 //after is whether we want the item before or after index
930
931 //disable for vector layers
932 if (!m_activeNode->paintDevice()) {
933 return false;
934 }
935
936 int desiredIndex;
937 if (!index.isValid()) {
938 desiredIndex = rowCount();
939 } else {
940 desiredIndex = after ? index.row() + 1 : index.row();
941 }
942
943 insertRow(desiredIndex);
944 KisAddStoryboardCommand *command = new KisAddStoryboardCommand(desiredIndex, m_items.at(desiredIndex), this);
945 insertChildRows(desiredIndex, command);
946 const int currentTime = m_image->animationInterface()->currentTime();
947 const int desiredTime = this->index(StoryboardItem::FrameNumber, 0, this->index(desiredIndex, 0)).data().toInt();
948
949 if (m_image && currentTime != desiredTime) {
951 currentTime,
952 desiredTime,
953 command);
954 switchTimeCmd->redo();
955 } else {
956 m_view->setCurrentItem(currentTime);
957 }
958
959 pushUndoCommand(command);
960
961 // Let's start rendering after adding new storyboard items.
964
965 return true;
966}
void insertChildRows(int position, KUndo2Command *cmd=nullptr)
must be called after a first level index is inserted. Adds child nodes to the first level indices
KisNodeWSP m_activeNode
StoryboardView * m_view
void pushUndoCommand(KUndo2Command *command)
void setCurrentItem(int frame)
changes the currentIndex and selectedIndex to frame
virtual KisPaintDeviceSP paintDevice() const =0

References KisImage::animationInterface(), KisImageAnimationInterface::currentTime(), StoryboardItem::FrameNumber, index(), insertChildRows(), m_activeNode, m_image, m_items, m_renderScheduler, m_view, KisBaseNode::paintDevice(), pushUndoCommand(), KisSwitchCurrentTimeCommand::redo(), rowCount(), StoryboardView::setCurrentItem(), KisStoryboardThumbnailRenderScheduler::slotStartFrameRendering(), and slotUpdateThumbnails().

◆ insertRows()

bool StoryboardModel::insertRows ( int position,
int rows,
const QModelIndex & index = QModelIndex() )
override

Definition at line 335 of file StoryboardModel.cpp.

336{
337 if (!parent.isValid()) {
338 if (position < 0 || position > m_items.count()) {
339 return false;
340 }
341
342 if (isLocked()) {
343 return false;
344 }
345
346 beginInsertRows(QModelIndex(), position, position+rows-1);
347 for (int row = 0; row < rows; ++row) {
349 m_items.insert(position + row, newItem);
350 }
351 endInsertRows();
353 return true;
354 }
355 else if (!parent.parent().isValid()) { //insert 2nd level nodes
356 StoryboardItemSP item = m_items.at(parent.row());
357
358 if (position < 0 || position > item->childCount()) {
359 return false;
360 }
361 beginInsertRows(parent, position, position+rows-1);
362 for (int row = 0; row < rows; ++row) {
363 item->insertChild(position, QVariant());
364 }
365 endInsertRows();
367 return true;
368 }
369 //we can't insert to 2nd level nodes as they are leaf nodes
370 return false;
371}
This class stores a list of StoryboardChild objects and provides functionality to manipulate the list...
void sigStoryboardItemListChanged()
This signal is emitted whenever m_items is changed. it is used to keep the StoryboardItemList in KisD...
QSharedPointer< T > toQShared(T *ptr)

References isLocked(), m_items, parent(), sigStoryboardItemListChanged(), and toQShared().

◆ isFrozen()

bool StoryboardModel::isFrozen ( ) const

Definition at line 566 of file StoryboardModel.cpp.

567{
569}

References m_freezeKeyframePositions.

◆ isLocked()

bool StoryboardModel::isLocked ( ) const

Definition at line 576 of file StoryboardModel.cpp.

577{
578 return m_lockBoards;
579}

References m_lockBoards.

◆ isValidBoard()

bool StoryboardModel::isValidBoard ( const QModelIndex & index) const
inlineprivate

Definition at line 275 of file StoryboardModel.h.

275{return index.isValid() && !index.parent().isValid();}

◆ lastIndexBeforeFrame()

QModelIndex StoryboardModel::lastIndexBeforeFrame ( int frame) const

Returns the index of the item with largest frame smaller than argument frame.

Parameters
frame
Returns
The index with largest frame less than argument frame.

Definition at line 662 of file StoryboardModel.cpp.

663{
664 return indexFromFrame(frame, false);
665}

References indexFromFrame().

◆ lastKeyframeGlobal()

int StoryboardModel::lastKeyframeGlobal ( ) const

Definition at line 717 of file StoryboardModel.cpp.

718{
719 if (!m_image)
720 return 0;
721
722 KisNodeSP node = m_image->rootLayer();
723 int lastKeyframeTime = 0;
724 if (node) {
725 KisLayerUtils::recursiveApplyNodes (node, [&lastKeyframeTime] (KisNodeSP node)
726 {
728 KisKeyframeChannel* channel = node->getKeyframeChannel(KisKeyframeChannel::Raster.id(), false);
729
730 if (!channel) {
731 return;
732 }
733
734 lastKeyframeTime = qMax(channel->lastKeyframeTime(), lastKeyframeTime);
735 }
736 });
737 }
738
739 return lastKeyframeTime;
740}
KisGroupLayerSP rootLayer() const
static const KoID Raster
QString id() const
Definition KoID.cpp:63
bool isAnimated() const
virtual bool supportsKeyframeChannel(const QString &id)

References KoID::id(), KisBaseNode::isAnimated(), m_image, KisKeyframeChannel::Raster, KisLayerUtils::recursiveApplyNodes(), KisImage::rootLayer(), and KisBaseNode::supportsKeyframeChannel().

◆ lastKeyframeWithin()

int StoryboardModel::lastKeyframeWithin ( QModelIndex index)

Gets the last keyframe that exists within an index's duration. Used to prevent duration from overwriting keyframes that exist internal to an existing scene.

Definition at line 742 of file StoryboardModel.cpp.

743{
744 KIS_ASSERT(sceneIndex.isValid());
745 const int sceneFrame = index(StoryboardItem::FrameNumber, 0, sceneIndex).data().toInt();
746
747 if (!m_image)
748 return sceneFrame;
749
750 QModelIndex nextScene = index(sceneIndex.row() + 1, 0);
751 int nextSceneFrame;
752 if (nextScene.isValid()) {
753 nextSceneFrame = data(index(StoryboardItem::FrameNumber, 0, nextScene)).toInt();
754 }
755 else {
756 nextSceneFrame = sceneFrame + data(sceneIndex, TotalSceneDurationInFrames).toInt();
757 }
758
759 int lastFrameOfScene = sceneFrame;
760 for (int frame = sceneFrame; frame < nextSceneFrame; frame = nextKeyframeGlobal(frame)) {
761 lastFrameOfScene = frame;
762 }
763
764 return lastFrameOfScene;
765}
int nextKeyframeGlobal(int keyframeTime) const
the next time at which there is a keyframe in any layer after keyframeTime
#define KIS_ASSERT(cond)
Definition kis_assert.h:33

References data(), StoryboardItem::FrameNumber, index(), KIS_ASSERT, m_image, nextKeyframeGlobal(), and TotalSceneDurationInFrames.

◆ mimeData()

QMimeData * StoryboardModel::mimeData ( const QModelIndexList & indexes) const
override

Definition at line 449 of file StoryboardModel.cpp.

450{
451 QMimeData *mimeData = new QMimeData();
452 QByteArray encodeData;
453
454 QDataStream stream(&encodeData, QIODevice::WriteOnly);
455
456 //take the row number of the index where drag started
457 foreach (QModelIndex index, indexes) {
458 if (index.isValid()) {
459 int row = index.row();
460 stream << row;
461 }
462 }
463
464 mimeData->setData("application/x-krita-storyboard", encodeData); //default mimetype
465 return mimeData;
466}
QMimeData * mimeData(const QModelIndexList &indexes) const override
void encodeData(Imf::OutputFile &file, const QList< ExrPaintLayerSaveInfo > &informationObjects, int width, int height)

References encodeData(), index(), and mimeData().

◆ mimeTypes()

QStringList StoryboardModel::mimeTypes ( ) const
override

Definition at line 442 of file StoryboardModel.cpp.

443{
444 QStringList types;
445 types << QLatin1String("application/x-krita-storyboard");
446 return types;
447}

◆ moveRows()

bool StoryboardModel::moveRows ( const QModelIndex & sourceParent,
int sourceRow,
int count,
const QModelIndex & destinationParent,
int destinationChild )
override

Definition at line 421 of file StoryboardModel.cpp.

422{
423 KisMoveStoryboardCommand *command = new KisMoveStoryboardCommand(sourceRow, count, destinationChild, this);
424
425 if (moveRowsImpl(sourceParent, sourceRow, count, destinationParent, destinationChild, command)) {
426 if (!sourceParent.isValid()) {
427 const int sceneIndex = sourceRow < destinationChild ? destinationChild - 1 : destinationChild;
429 sceneIndex,
430 this,
431 m_image,
432 command);
433 }
434
436 return true;
437 }
438
439 return false;
440}
static void runSingleCommandStroke(KisImageSP image, KUndo2Command *cmd, KisStrokeJobData::Sequentiality sequentiality=KisStrokeJobData::SEQUENTIAL, KisStrokeJobData::Exclusivity exclusivity=KisStrokeJobData::NORMAL)
runSingleCommandStroke creates a stroke and runs cmd in it. The text() field of cmd is used as a titl...
friend class KisMoveStoryboardCommand
bool moveRowsImpl(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild, KUndo2Command *parentCMD=nullptr)

References KisImage::animationInterface(), KisStrokeJobData::BARRIER, KisImageAnimationInterface::currentTime(), KisStrokeJobData::EXCLUSIVE, KisMoveStoryboardCommand, m_image, moveRowsImpl(), and KisProcessingApplicator::runSingleCommandStroke().

◆ moveRowsImpl()

bool StoryboardModel::moveRowsImpl ( const QModelIndex & sourceParent,
int sourceRow,
int count,
const QModelIndex & destinationParent,
int destinationChild,
KUndo2Command * parentCMD = nullptr )
private

Definition at line 1337 of file StoryboardModel.cpp.

1339{
1340 if (sourceParent != destinationParent) {
1341 return false;
1342 }
1343 if (destinationChild == sourceRow || destinationChild == sourceRow + 1) {
1344 return false;
1345 }
1346
1347 if (isLocked()) {
1348 return false;
1349 }
1350
1351 //We want to test-run an action when nullptrs are present.
1352 bool dryrun = (parentCMD != nullptr);
1353
1354 if (destinationChild > sourceRow + count - 1) {
1355 //we adjust for the upward shift, see qt doc for why this is needed
1356 beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild + count - 1);
1357 destinationChild = destinationChild - count;
1358 }
1359 else {
1360 beginMoveRows(sourceParent, sourceRow, sourceRow + count - 1, destinationParent, destinationChild);
1361 }
1362 //for moves within the 1st level nodes for comment nodes
1363 if (sourceParent == destinationParent && sourceParent.isValid() && !sourceParent.parent().isValid()) {
1364 const QModelIndex parent = sourceParent;
1365 for (int row = 0; row < count; row++) {
1366 if (sourceRow < StoryboardItem::Comments || sourceRow >= rowCount(parent)) {
1367 return false;
1368 }
1369 if (destinationChild + row < StoryboardItem::Comments || destinationChild + row >= rowCount(parent)) {
1370 return false;
1371 }
1372
1373 StoryboardItemSP item = m_items.at(parent.row());
1374
1375 if (!dryrun) {
1376 item->moveChild(sourceRow, destinationChild + row);
1377 }
1378 }
1379 endMoveRows();
1380
1381 if (!dryrun) {
1384 }
1385
1386 return true;
1387 }
1388 else if (!sourceParent.isValid()) { //for moves of 1st level nodes
1389 for (int row = 0; row < count; row++) {
1390 if (sourceRow < 0 || sourceRow >= rowCount()) {
1391 return false;
1392 }
1393 if (destinationChild + row < 0 || destinationChild + row >= rowCount()) {
1394 return false;
1395 }
1396
1397 if (!dryrun) {
1398 m_items.move(sourceRow, destinationChild + row);
1399 }
1400 }
1401 endMoveRows();
1402
1403 if (!dryrun) {
1406 }
1407
1408 return true;
1409 }
1410 else {
1411 return false;
1412 }
1413}
void reorderKeyframes()
reorders all keyframes to reflect storyboard docker's arrangement. typically used after drag and drop...

References isLocked(), m_items, parent(), reorderKeyframes(), rowCount(), and sigStoryboardItemListChanged().

◆ nextKeyframeGlobal()

int StoryboardModel::nextKeyframeGlobal ( int keyframeTime) const

the next time at which there is a keyframe in any layer after keyframeTime

Parameters
keyframeTimeThe time after which keyframe is wanted.
Returns
The time of the next keyframe in any layer.

Definition at line 688 of file StoryboardModel.cpp.

689{
690 KisNodeSP node = m_image->rootLayer();
691 int nextKeyframeTime = INT_MAX;
692 if (node) {
693 KisLayerUtils::recursiveApplyNodes (node, [keyframeTime, &nextKeyframeTime] (KisNodeSP node)
694 {
696 KisKeyframeChannel* channel = node->getKeyframeChannel(KisKeyframeChannel::Raster.id(), false);
697
698 if (!channel) {
699 return;
700 }
701
702 int nextKeyframeTimeQuery = channel->nextKeyframeTime(keyframeTime);
703 if (channel->keyframeAt(nextKeyframeTimeQuery)) {
704 if (nextKeyframeTime == INT_MAX) {
705 nextKeyframeTime = nextKeyframeTimeQuery;
706 } else {
707 nextKeyframeTime = qMin(nextKeyframeTime, nextKeyframeTimeQuery);
708 }
709 }
710 }
711 });
712 }
713
714 return nextKeyframeTime;
715}

References KoID::id(), KisBaseNode::isAnimated(), m_image, KisKeyframeChannel::Raster, KisLayerUtils::recursiveApplyNodes(), KisImage::rootLayer(), and KisBaseNode::supportsKeyframeChannel().

◆ parent()

QModelIndex StoryboardModel::parent ( const QModelIndex & index) const
override

Definition at line 73 of file StoryboardModel.cpp.

74{
75 if (!index.isValid()) {
76 return QModelIndex();
77 }
78
79 //no parent for 1st level node
80 StoryboardItem *childItemFirstLevel = static_cast<StoryboardItem*>(index.internalPointer());
81
82 Q_FOREACH( StoryboardItemSP item, m_items) {
83 if (item.data() == childItemFirstLevel) {
84 return QModelIndex();
85 }
86 }
87
88 //return parent only for 2nd level nodes
89 StoryboardChild *childItem = static_cast<StoryboardChild*>(index.internalPointer());
90 QSharedPointer<StoryboardItem> parentItem = childItem->parent();
91 int indexOfParent = m_items.indexOf(parentItem);
92 return createIndex(indexOfParent, 0, parentItem.data());
93}
This class makes up the StoryboardItem class. It consists of pointer to its parent item and the data ...
StoryboardItemSP parent()

References index(), m_items, and StoryboardChild::parent().

◆ pushUndoCommand()

void StoryboardModel::pushUndoCommand ( KUndo2Command * command)

Definition at line 1035 of file StoryboardModel.cpp.

1036{
1038}
KisPostExecutionUndoAdapter * postExecutionUndoAdapter() const override

References KisPostExecutionUndoAdapter::addCommand(), m_image, KisImage::postExecutionUndoAdapter(), and toQShared().

◆ removeItem()

bool StoryboardModel::removeItem ( QModelIndex index,
KUndo2Command * command = nullptr )

removes item, deletes keyframes within and shifts keyframe after the scene to fill in the gap

Parameters
indexThe index of the item to be removed
Returns
true if item was removed

Definition at line 968 of file StoryboardModel.cpp.

969 {
970 const int row = index.row();
971 const int durationDeletedScene = data(index, TotalSceneDurationInFrames).toInt();
972
973 //remove all keyframes within the scene with command as parent
974 KisNodeSP node = m_image->rootLayer();
975 const int firstFrameOfScene = data(this->index(StoryboardItem::FrameNumber, 0, index)).toInt();
976 const int timeOfNextScene = firstFrameOfScene + durationDeletedScene;
977 if (command) {
978 if (node) {
979 KisLayerUtils::recursiveApplyNodes (node, [firstFrameOfScene, timeOfNextScene, command] (KisNodeSP node){
980 if (node->isAnimated() && node->isEditable(true)) {
981 Q_FOREACH(KisKeyframeChannel* keyframeChannel, node->keyframeChannels()) {
982 int timeIter = keyframeChannel->keyframeAt(firstFrameOfScene)
983 ? firstFrameOfScene
984 : keyframeChannel->nextKeyframeTime(firstFrameOfScene);
985
986 while (keyframeChannel->keyframeAt(timeIter) && timeIter < timeOfNextScene) {
987 keyframeChannel->removeKeyframe(timeIter, command);
988 timeIter = keyframeChannel->nextKeyframeTime(timeIter);
989 }
990 }
991 }
992 });
993 }
994 shiftKeyframes(KisTimeSpan::infinite(timeOfNextScene), -durationDeletedScene, command);
995
996 //If we're viewing the scene we're about the remove, let's jump back to the last valid scene.
997 if (row > 0 && row <= rowCount()) {
998 QModelIndex currentSceneFN = this->index(StoryboardItem::FrameNumber, 0, this->index(row, 0));
999 if (m_image && m_image->animationInterface()->currentTime() == currentSceneFN.data().toInt()) {
1001 currentSceneFN.data().toInt(),
1002 this->index(StoryboardItem::FrameNumber, 0, this->index(row-1, 0)).data().toInt(),
1003 command);
1004 switchTimeCmd->redo();
1005 }
1006 }
1007 }
1008
1009 removeRows(row, 1);
1010 for (int i = row; i < rowCount(); i++) {
1011 QModelIndex frameNumIndex = this->index(StoryboardItem::FrameNumber, 0, this->index(i, 0));
1012 setData(frameNumIndex, data(frameNumIndex).toInt() - durationDeletedScene);
1013 }
1014
1015 //do we also need to make the 'change frame' command a child??
1016 // Render after removing
1019
1020 return true;
1021}
bool removeRows(int position, int rows, const QModelIndex &index=QModelIndex()) override
bool isEditable(bool checkVisibility=true) const

References KisImage::animationInterface(), KisImageAnimationInterface::currentTime(), data(), StoryboardItem::FrameNumber, index(), KisTimeSpan::infinite(), KisBaseNode::isAnimated(), KisBaseNode::isEditable(), m_image, KisLayerUtils::recursiveApplyNodes(), KisSwitchCurrentTimeCommand::redo(), KisImage::rootLayer(), rowCount(), shiftKeyframes(), and TotalSceneDurationInFrames.

◆ removeRows()

bool StoryboardModel::removeRows ( int position,
int rows,
const QModelIndex & index = QModelIndex() )
override

Definition at line 373 of file StoryboardModel.cpp.

374{
375 if (rows <= 0) {
376 return false;
377 }
378 //remove 1st level nodes
379 if (!parent.isValid()) {
380
381 if (position < 0 || position >= m_items.count()) {
382 return false;
383 }
384
385 if (isLocked()) {
386 return false;
387 }
388
389 beginRemoveRows(QModelIndex(), position, position+rows-1);
390
391 for (int row = position + rows - 1; row >= position; row--) {
392 m_items.removeAt(row);
393 if (m_items.count() == 0) {
394 break;
395 }
396 }
397 endRemoveRows();
399 return true;
400 }
401 else if (!parent.parent().isValid()) { //remove 2nd level nodes
402 StoryboardItemSP item = m_items.at(parent.row());
403
404 if (position < 0 || position >= item->childCount()) {
405 return false;
406 }
407 if (m_items.contains(item)) {
408 beginRemoveRows(parent, position, position+rows-1);
409 for (int row = 0; row < rows; ++row) {
410 item->removeChild(position);
411 }
412 endRemoveRows();
414 return true;
415 }
416 }
417 //2nd level node has no child
418 return false;
419}

References isLocked(), m_items, parent(), and sigStoryboardItemListChanged().

◆ reorderKeyframes()

void StoryboardModel::reorderKeyframes ( )

reorders all keyframes to reflect storyboard docker's arrangement. typically used after drag and drop to keep storyboard timing accurate to timeline timing.

Definition at line 767 of file StoryboardModel.cpp.

768{
769 //Get the earliest frame number in the storyboard list
770 int earliestFrame = INT_MAX;
771
772 if (!m_image) {
773 return;
774 }
775
776 typedef int AssociateFrameOffset;
777
778 QMultiHash<QModelIndex, AssociateFrameOffset> frameAssociates;
779
780 for (int i = 0; i < rowCount(); i++) {
781 QModelIndex sceneIndex = index(i, 0);
782 int sceneFrame = index(StoryboardItem::FrameNumber, 0, sceneIndex).data().toInt();
783 earliestFrame = sceneFrame < earliestFrame ? sceneFrame : earliestFrame;
784
785 const int lastFrameOfScene = index(StoryboardItem::FrameNumber, 0, sceneIndex).data().toInt()
786 + data(sceneIndex, TotalSceneDurationInFrames).toInt();
787
788 for( int i = sceneFrame; i < lastFrameOfScene; i++) {
789 frameAssociates.insert(sceneIndex, i - sceneFrame);
790 }
791 }
792
793 if (earliestFrame == INT_MAX) {
794 return;
795 }
796
797 //We want to temporarily lock responding to keyframe removal / addition.
798 //Will unlock when scope exits.
799 QScopedPointer<KeyframeReorderLock> lock(new KeyframeReorderLock(this));
800
801 //Let's cancel all frame rendering for the time being.
803
804 KisNodeSP root = m_image->root();
805 if (root && !m_freezeKeyframePositions) {
806 KisLayerUtils::recursiveApplyNodes(root, [this, earliestFrame, frameAssociates](KisNodeSP node) {
807 if (!node->isAnimated() || !node->paintDevice())
808 return;
809
811
812 if (!rasterChan)
813 return;
814
815 // Gather all original keyframes and their associated time values.
816 QHash<int, KisKeyframeSP> originalKeyframes;
817 Q_FOREACH( const int& time, rasterChan->allKeyframeTimes()) {
818 if (time >= earliestFrame && rasterChan->keyframeAt(time)) {
819 originalKeyframes.insert(time, rasterChan->keyframeAt(time));
820 rasterChan->removeKeyframe(time);
821 }
822 }
823
824 //Now lets re-sort the raster channels...
825 int intendedSceneFrameTime = earliestFrame;
826 for (int i = 0; i < rowCount(); i++) {
827 QModelIndex sceneIndex = index(i, 0);
828 const int srcFrame = index(StoryboardItem::FrameNumber, 0, sceneIndex).data().toInt();
829 Q_FOREACH( const int& associateFrameOffset, frameAssociates.values(sceneIndex) ) {
830 if (!originalKeyframes.contains(srcFrame + associateFrameOffset))
831 continue;
832
833 rasterChan->insertKeyframe(intendedSceneFrameTime + associateFrameOffset,
834 originalKeyframes.value(srcFrame + associateFrameOffset));
835 }
836
837 intendedSceneFrameTime += data(sceneIndex, TotalSceneDurationInFrames).toInt();
838 }
839 });
840 }
841
842 //Lastly, let's update all of the frame values.
843 int intendedFrameValue = earliestFrame;
844 for (int i = 0; i < rowCount(); i++) {
845 QModelIndex sceneIndex = index(i, 0);
846 setData(index(StoryboardItem::FrameNumber, 0, sceneIndex), intendedFrameValue);
847 slotUpdateThumbnailForFrame(intendedFrameValue);
848 intendedFrameValue += data(sceneIndex, TotalSceneDurationInFrames).toInt();
849 }
850
852}
QSet< int > allKeyframeTimes() const
Get a set of all integer times that map to a keyframe.
KisKeyframeSP keyframeAt(int time) const
Get a keyframe at specified time. Used primarily when the value of a given keyframe is needed.
KisRasterKeyframeChannel * keyframeChannel() const
The KisRasterKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisRas...
virtual void insertKeyframe(int time, KisKeyframeSP keyframe, KUndo2Command *parentUndoCmd=nullptr) override
Insert an existing keyframe into the channel at the specified time.
virtual void removeKeyframe(int time, KUndo2Command *parentUndoCmd=nullptr) override
Remove a keyframe from the channel at the specified time.
void cancelAllFrameRendering()
Cancels all frame rendering. Empties all queues and cancels the current rendering,...
void slotUpdateThumbnailForFrame(int frame, bool delay=true)
calls regeneration of frame in the background i.e. in another thread.

References KisKeyframeChannel::allKeyframeTimes(), KisStoryboardThumbnailRenderScheduler::cancelAllFrameRendering(), data(), StoryboardItem::FrameNumber, index(), KisRasterKeyframeChannel::insertKeyframe(), KisBaseNode::isAnimated(), KisKeyframeChannel::keyframeAt(), KisPaintDevice::keyframeChannel(), m_freezeKeyframePositions, m_image, m_renderScheduler, KisBaseNode::paintDevice(), KisLayerUtils::recursiveApplyNodes(), KisRasterKeyframeChannel::removeKeyframe(), KisNodeFacade::root, rowCount(), setData(), KisStoryboardThumbnailRenderScheduler::slotStartFrameRendering(), slotUpdateThumbnailForFrame(), and TotalSceneDurationInFrames.

◆ resetData()

void StoryboardModel::resetData ( StoryboardItemList list)

resets m_items to list

Parameters
listThe new list of StoryboardItem*

Definition at line 1023 of file StoryboardModel.cpp.

1024{
1025 beginResetModel();
1026 m_items = list;
1027 endResetModel();
1028}

References m_items.

◆ rowCount()

int StoryboardModel::rowCount ( const QModelIndex & parent = QModelIndex()) const
override

Definition at line 95 of file StoryboardModel.cpp.

96{
97 if (!parent.isValid()) {
98 return m_items.count();
99 }
100 else if (!parent.parent().isValid()) {
101 QSharedPointer<StoryboardItem> parentItem = m_items.at(parent.row());
102 return parentItem->childCount();
103 }
104 return 0; //2nd level nodes have no child
105}

References m_items, and parent().

◆ setCommentModel()

void StoryboardModel::setCommentModel ( StoryboardCommentModel * commentModel)

Sets the commentModel in StoryboardModel and creates connections to keep the local copy of comments in sync with the commentModel's.

See also
slotCommentDataChanged();
slotCommentRowInserted(QModelIndex,int,int)
slotCommentRowRemoved(QModelIndex,int,int)
slotCommentRowMoved();

Definition at line 543 of file StoryboardModel.cpp.

544{
545 m_commentModel = commentModel;
546 connect(m_commentModel, SIGNAL(dataChanged(const QModelIndex ,const QModelIndex)),
547 this, SLOT(slotCommentDataChanged()));
548 connect(m_commentModel, SIGNAL(rowsRemoved(const QModelIndex ,int, int)),
549 this, SLOT(slotCommentRowRemoved(const QModelIndex ,int, int)));
550 connect(m_commentModel, SIGNAL(rowsInserted(const QModelIndex, int, int)),
551 this, SLOT(slotCommentRowInserted(const QModelIndex, int, int)));
552 connect(m_commentModel, SIGNAL(rowsMoved(const QModelIndex, int, int, const QModelIndex, int)),
553 this, SLOT(slotCommentRowMoved(const QModelIndex, int, int, const QModelIndex, int)));
554}
void slotCommentRowInserted(const QModelIndex, int, int)
StoryboardCommentModel * m_commentModel
void slotCommentRowRemoved(const QModelIndex, int, int)
void slotCommentRowMoved(const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild)

References connect(), m_commentModel, slotCommentDataChanged(), slotCommentRowInserted(), slotCommentRowMoved(), and slotCommentRowRemoved().

◆ setCommentScrollData()

bool StoryboardModel::setCommentScrollData ( const QModelIndex & index,
const QVariant & value )

Sets the scrollValue of the CommentBox object.

Parameters
indexThe index of the CommentBox object whose scrollValue is changed
valueThe new scrollValue
Returns
True if data was set
See also
CommentBox

Definition at line 258 of file StoryboardModel.cpp.

259{
260 QSharedPointer<StoryboardChild> child = m_items.at(index.parent().row())->child(index.row());
261 if (child) {
262 CommentBox commentBox = qvariant_cast<CommentBox>(child->data());
263 commentBox.scrollValue = value.toInt();
264 child->setData(QVariant::fromValue<CommentBox>(commentBox));
266 return true;
267 }
268 return false;
269}
float value(const T *src, size_t ch)

References index(), m_items, CommentBox::scrollValue, sigStoryboardItemListChanged(), and value().

◆ setData()

bool StoryboardModel::setData ( const QModelIndex & index,
const QVariant & value,
int role = Qt::EditRole )
override

Definition at line 167 of file StoryboardModel.cpp.

168{
169 if (index.isValid() && !isLocked() && (role == Qt::EditRole || role == Qt::DisplayRole)) {
170 if (isValidBoard(index)) {
171 return false;
172 }
173
174 QSharedPointer<StoryboardChild> child = m_items.at(index.parent().row())->child(index.row());
175 if (child) {
176 if (index.row() == StoryboardItem::FrameNumber && !value.canConvert<ThumbnailData>()) {
177 if (value.toInt() < 0) {
178 return false;
179 }
180 ThumbnailData thumbnailData = qvariant_cast<ThumbnailData>(child->data());
181 thumbnailData.frameNum = value.toInt();
182 child->setData(QVariant::fromValue<ThumbnailData>(thumbnailData));
183 }
184 else if (index.row() == StoryboardItem::DurationSecond ||
186
189 const int sceneStartFrame = siblingAtRow(index, StoryboardItem::FrameNumber).data().toInt();
190
191 const int secondCount = index.row() == StoryboardItem::DurationSecond ? value.toInt() : secondIndex.data().toInt();
192 const int frameCount = index.row() == StoryboardItem::DurationFrame ? value.toInt() : frameIndex.data().toInt();
193
194 // Do not allow desired scene length to be shorter than keyframes within
195 // the given scene. This prevents overwriting data that exists internal
196 // to a scene.
197 const int sceneDesiredDuration = frameCount + secondCount * getFramesPerSecond();
198 const int implicitSceneDuration = qMax(
199 qMax( sceneDesiredDuration, lastKeyframeWithin(index.parent()) - sceneStartFrame + 1 ),
200 1 );
201
202 if (value.toInt() < 0 && secondIndex.data().toInt() == 0) {
203 return false;
204 }
205 if (implicitSceneDuration == data(index.parent(), TotalSceneDurationInFrames).toInt()) {
206 return false;
207 }
208 const int fps = m_image.isValid() ? m_image->animationInterface()->framerate() : 24;
209
210 QModelIndex lastScene = index.parent();
211 QModelIndex nextScene = this->index(lastScene.row() + 1, 0);
212 changeSceneHoldLength(implicitSceneDuration, index.parent());
213 while (nextScene.isValid()) {
214 const int lastSceneStartFrame = this->index(StoryboardItem::FrameNumber, 0, lastScene).data().toInt();
215 const int lastSceneDuration = lastScene == index.parent() ? implicitSceneDuration
216 : data(lastScene, TotalSceneDurationInFrames).toInt();
217 setData( this->index(StoryboardItem::FrameNumber, 0, nextScene), lastSceneStartFrame + lastSceneDuration);
218 lastScene = nextScene;
219 nextScene = this->index(lastScene.row() + 1, 0);
220 }
221
222 StoryboardItemSP scene = m_items.at(index.parent().row());
223 QSharedPointer<StoryboardChild> durationSeconds = scene->child(secondIndex.row());
224 QSharedPointer<StoryboardChild> durationFrames = scene->child(frameIndex.row());
225 durationSeconds->setData(QVariant::fromValue<int>(implicitSceneDuration / fps));
226 durationFrames->setData(QVariant::fromValue<int>(implicitSceneDuration % fps));
227
228 // Account for new durations with auto-adjust playback range option.
229 if (m_image.isValid()) {
230 KisConfig cfg(true);
231 QModelIndex lastScene = this->index(rowCount() - 1, 0);
232 if (cfg.adaptivePlaybackRange()) {
233 int frameNum = this->index(StoryboardItem::FrameNumber, 0, lastScene).data().toInt();
234 int totalDuration = data(lastScene, TotalSceneDurationInFrames).toInt();
236 playbackRange.include(frameNum+totalDuration);
238 }
239 }
240
241 }
242 else if (index.row() >= StoryboardItem::Comments && !value.canConvert<CommentBox>()) {
243 CommentBox commentBox = qvariant_cast<CommentBox>(child->data());
244 commentBox.content = value.toString();
245 child->setData(QVariant::fromValue<CommentBox>(commentBox));
246 }
247 else {
248 child->setData(value);
249 }
250 Q_EMIT dataChanged(index, index);
252 return true;
253 }
254 }
255 return false;
256}
QModelIndex siblingAtRow(const QModelIndex &index, int row)
void setDocumentRange(const KisTimeSpan range)
const KisTimeSpan & documentPlaybackRange() const
documentPlaybackRange
void include(int time)
bool changeSceneHoldLength(int oldDuration, QModelIndex itemIndex)
moves all keyframes in all layers after the frame of the parent of durationIndex Keyframes are moved ...

References KisConfig::adaptivePlaybackRange(), KisImage::animationInterface(), changeSceneHoldLength(), StoryboardItem::Comments, CommentBox::content, data(), KisImageAnimationInterface::documentPlaybackRange(), StoryboardItem::DurationFrame, StoryboardItem::DurationSecond, ThumbnailData::frameNum, StoryboardItem::FrameNumber, KisImageAnimationInterface::framerate(), getFramesPerSecond(), KisTimeSpan::include(), index(), isLocked(), KisWeakSharedPtr< T >::isValid(), isValidBoard(), lastKeyframeWithin(), m_image, m_items, rowCount(), setData(), KisImageAnimationInterface::setDocumentRange(), siblingAtRow(), sigStoryboardItemListChanged(), TotalSceneDurationInFrames, and value().

◆ setFreeze()

void StoryboardModel::setFreeze ( bool value)

Definition at line 561 of file StoryboardModel.cpp.

562{
564}

References m_freezeKeyframePositions, and value().

◆ setImage()

void StoryboardModel::setImage ( KisImageWSP image)

Definition at line 591 of file StoryboardModel.cpp.

592{
593 if (m_image) {
594 m_image->disconnect(this);
595 m_image->animationInterface()->disconnect(this);
596 }
597 m_image = image;
600
601 if (!image) {
602 return;
603 }
604
605 //setting image to a different image stops rendering of all frames previously scheduled.
606 //resetData() must be called before setImage(KisImageWSP) so that we can schedule rendering for the items in the new KisDocument
607 foreach (StoryboardItemSP item, m_items) {
608 int frame = qvariant_cast<ThumbnailData>(item->child(StoryboardItem::FrameNumber)->data()).frameNum.toInt();
610 }
611 m_lastScene = m_items.size();
612
614
615 connect(m_image, SIGNAL(sigImageUpdated(const QRect &)), &m_renderSchedulingCompressor, SLOT(start()));
616
617 connect(m_image, SIGNAL(sigRemoveNodeAsync(KisNodeSP)), this, SLOT(slotNodeRemoved(KisNodeSP)));
618
619 //for add, remove and move
620 connect(m_image->animationInterface(), SIGNAL(sigKeyframeAdded(const KisKeyframeChannel*,int)),
621 this, SLOT(slotKeyframeAdded(const KisKeyframeChannel*,int)), Qt::UniqueConnection);
622 connect(m_image->animationInterface(), SIGNAL(sigKeyframeRemoved(const KisKeyframeChannel*,int)),
623 this, SLOT(slotKeyframeRemoved(const KisKeyframeChannel*,int)), Qt::UniqueConnection);
624
625 connect(m_image->animationInterface(), SIGNAL(sigFramerateChanged()), this, SLOT(slotFramerateChanged()), Qt::UniqueConnection);
626
627 //for selection sync with timeline
629 connect(m_image->animationInterface(), SIGNAL(sigUiTimeChanged(int)), this, SLOT(slotCurrentFrameChanged(int)), Qt::UniqueConnection);
630}
void setTrackedImage(KisImageSP image)
KisKeyframeChannel stores and manages KisKeyframes. Maps units of time to virtual keyframe values....
void scheduleFrameForRegeneration(int frame, bool affected)
Adds the frame to the list of "to be regenerated" frames.
void setImage(KisImageSP image)
Sets an image, the class takes an image, clones it and calls frame regeneration on the clone so do no...
void slotKeyframeRemoved(const KisKeyframeChannel *channel, int time)
void slotCurrentFrameChanged(int frameId)
called when currentUiTime changes
void slotNodeRemoved(KisNodeSP node)
void slotKeyframeAdded(const KisKeyframeChannel *channel, int time)

References KisImage::animationInterface(), connect(), KisImageAnimationInterface::currentUITime(), KisIdleWatcher::forceImageModified(), StoryboardItem::FrameNumber, m_image, m_imageIdleWatcher, m_items, m_lastScene, m_renderScheduler, m_renderSchedulingCompressor, KisStoryboardThumbnailRenderScheduler::scheduleFrameForRegeneration(), KisStoryboardThumbnailRenderScheduler::setImage(), KisIdleWatcher::setTrackedImage(), slotCurrentFrameChanged(), slotFramerateChanged(), slotKeyframeAdded(), slotKeyframeRemoved(), and slotNodeRemoved().

◆ setLocked()

void StoryboardModel::setLocked ( bool value)

Definition at line 571 of file StoryboardModel.cpp.

572{
574}

References m_lockBoards, and value().

◆ setThumbnailPixmapData()

bool StoryboardModel::setThumbnailPixmapData ( const QModelIndex & parentIndex,
const KisPaintDeviceSP & dev )

Sets the Pixmap data.

Parameters
parentIndexThe index of item whose thumbnail changed.
devProjection of the new pixmap.
Returns
True if data was set
See also
ThumbnailData

Definition at line 271 of file StoryboardModel.cpp.

272{
273 QModelIndex index = this->index(0, 0, parentIndex);
274 QRect thumbnailRect = m_view->visualRect(parentIndex);
275 float scale = qMin(thumbnailRect.height() / (float)m_image->height(), (float)thumbnailRect.width() / m_image->width());
276
277 QImage image = dev->convertToQImage(KoColorSpaceRegistry::instance()->rgb8()->profile(), m_image->bounds());
278 QPixmap pxmap = QPixmap::fromImage(image);
279 pxmap = pxmap.scaled((1.5)*scale*m_image->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
280
281 if (isValidBoard(index))
282 return false;
283
284 QSharedPointer<StoryboardChild> child = m_items.at(index.parent().row())->child(index.row());
285 if (child) {
286 ThumbnailData thumbnailData = qvariant_cast<ThumbnailData>(child->data());
287 thumbnailData.pixmap = pxmap;
288 child->setData(QVariant::fromValue<ThumbnailData>(thumbnailData));
289 Q_EMIT dataChanged(index, index);
290 return true;
291 }
292 return false;
293}
qint32 width() const
QSize size() const
Definition kis_image.h:547
qint32 height() const
QRect bounds() const override
QImage convertToQImage(const KoColorProfile *dstProfile, qint32 x, qint32 y, qint32 w, qint32 h, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags()) const
QRect visualRect(const QModelIndex &index) const override
static KoColorSpaceRegistry * instance()

References KisImage::bounds(), KisPaintDevice::convertToQImage(), KisImage::height(), index(), KoColorSpaceRegistry::instance(), isValidBoard(), m_image, m_items, m_view, ThumbnailData::pixmap, KisImage::size(), StoryboardView::visualRect(), and KisImage::width().

◆ setView()

void StoryboardModel::setView ( StoryboardView * view)

Definition at line 586 of file StoryboardModel.cpp.

587{
588 m_view = view;
589}

References m_view.

◆ shiftKeyframes()

void StoryboardModel::shiftKeyframes ( KisTimeSpan affected,
int offset,
KUndo2Command * cmd = nullptr )

Definition at line 875 of file StoryboardModel.cpp.

875 {
876 if (!m_image)
877 return;
878
879 KisNodeSP node = m_image->rootLayer();
880
881 if (offset == 0)
882 return;
883
884 //We want to temporarily lock respondance to keyframe removal / addition.
885 //Will unlock when scope exits.
886 QScopedPointer<KeyframeReorderLock> lock(new KeyframeReorderLock(this));
887
888 if (node && !m_freezeKeyframePositions) {
889 KisLayerUtils::recursiveApplyNodes (node, [affected, offset, cmd] (KisNodeSP node) {
890 const int startFrame = affected.start();
891 if (node->isAnimated()) {
892 Q_FOREACH(KisKeyframeChannel* keyframeChannel, node->keyframeChannels()) {
893 if (keyframeChannel) {
894 if (offset > 0) {
895 int timeIter = affected.isInfinite() ?
896 keyframeChannel->lastKeyframeTime()
897 : keyframeChannel->activeKeyframeTime(affected.end());
898
899 KisKeyframeSP iterEnd = keyframeChannel->keyframeAt(keyframeChannel->previousKeyframeTime(startFrame));
900
901 while (keyframeChannel->keyframeAt(timeIter) &&
902 keyframeChannel->keyframeAt(timeIter) != iterEnd) {
903 keyframeChannel->moveKeyframe(timeIter, timeIter + offset, cmd);
904 timeIter = keyframeChannel->previousKeyframeTime(timeIter);
905 }
906
907 } else {
908 int timeIter = keyframeChannel->keyframeAt(startFrame) ? startFrame : keyframeChannel->nextKeyframeTime(startFrame);
909
910 KisKeyframeSP iterEnd = affected.isInfinite() ?
911 nullptr
912 : keyframeChannel->keyframeAt(keyframeChannel->nextKeyframeTime(affected.end()));
913
914 while (keyframeChannel->keyframeAt(timeIter) != iterEnd) {
915 keyframeChannel->moveKeyframe(timeIter, timeIter + offset, cmd);
916 timeIter = keyframeChannel->nextKeyframeTime(timeIter);
917 }
918 }
919 }
920 }
921 }
922 });
923 }
924}

References KisBaseNode::isAnimated(), m_freezeKeyframePositions, m_image, KisLayerUtils::recursiveApplyNodes(), KisImage::rootLayer(), and KisTimeSpan::start().

◆ sigStoryboardItemListChanged

void StoryboardModel::sigStoryboardItemListChanged ( )
signal

This signal is emitted whenever m_items is changed. it is used to keep the StoryboardItemList in KisDocument in sync with m_items.

◆ slotCommentDataChanged

void StoryboardModel::slotCommentDataChanged ( )
privateslot

Definition at line 1204 of file StoryboardModel.cpp.

1205{
1207 emit(layoutChanged());
1208}
QVector< StoryboardComment > m_commentList

References StoryboardCommentModel::m_commentList, m_commentList, and m_commentModel.

◆ slotCommentRowInserted

void StoryboardModel::slotCommentRowInserted ( const QModelIndex parent,
int first,
int last )
privateslot

Definition at line 1210 of file StoryboardModel.cpp.

1211{
1212 Q_UNUSED(parent);
1213 int numItems = rowCount();
1214 for(int row = 0; row < numItems; row++) {
1215 QModelIndex parentIndex = index(row, 0);
1216 insertRows(4 + first, last - first + 1, parentIndex); //four indices are already there
1217 }
1219}

References index(), insertRows(), parent(), rowCount(), and slotCommentDataChanged().

◆ slotCommentRowMoved

void StoryboardModel::slotCommentRowMoved ( const QModelIndex & sourceParent,
int sourceRow,
int count,
const QModelIndex & destinationParent,
int destinationChild )
privateslot

Definition at line 1232 of file StoryboardModel.cpp.

1234{
1235 Q_UNUSED(sourceParent);
1236 Q_UNUSED(destinationParent);
1237 int numItems = rowCount();
1238 for(int row = 0; row < numItems; row++) {
1239 QModelIndex parentIndex = index(row, 0);
1240 moveRowsImpl(parentIndex, start + 4, end - start + 1, parentIndex, destinationRow + 4);
1241 }
1243}

References index(), moveRowsImpl(), rowCount(), and slotCommentDataChanged().

◆ slotCommentRowRemoved

void StoryboardModel::slotCommentRowRemoved ( const QModelIndex parent,
int first,
int last )
privateslot

Definition at line 1221 of file StoryboardModel.cpp.

1222{
1223 Q_UNUSED(parent);
1224 int numItems = rowCount();
1225 for(int row = 0; row < numItems; row++) {
1226 QModelIndex parentIndex = index(row, 0);
1227 removeRows(4 + first, last - first + 1, parentIndex);
1228 }
1230}

References index(), parent(), removeRows(), rowCount(), and slotCommentDataChanged().

◆ slotCurrentFrameChanged

void StoryboardModel::slotCurrentFrameChanged ( int frameId)
privateslot

called when currentUiTime changes

See also
KisImageAnimationInterface::sigUiTimeChanged(int)

Definition at line 1040 of file StoryboardModel.cpp.

1041{
1042 m_view->setCurrentItem(frameId);
1043}

References m_view, and StoryboardView::setCurrentItem().

◆ slotFramerateChanged

void StoryboardModel::slotFramerateChanged ( )
privateslot

Definition at line 1097 of file StoryboardModel.cpp.

1098{
1099 QModelIndex sceneIndex = index(0,0);
1100 QModelIndex nextScene = index(1,0);
1101 if (nextScene.isValid()) {
1102
1103 while (sceneIndex.isValid() && nextScene.isValid()) {
1104 StoryboardItemSP item = m_items.at(sceneIndex.row());
1105 const int nextSceneFrame = index(StoryboardItem::FrameNumber, 0, nextScene).data().toInt();
1106 const int sceneFrame = index(StoryboardItem::FrameNumber, 0, sceneIndex).data().toInt();
1107 const int duration = nextSceneFrame - sceneFrame;
1108 const int durationFrames = duration % getFramesPerSecond();
1109 const int durationSeconds = duration / getFramesPerSecond();
1110
1111 item->child(StoryboardItem::DurationFrame)->setData(QVariant::fromValue<int>(durationFrames));
1112 item->child(StoryboardItem::DurationSecond)->setData(QVariant::fromValue<int>(durationSeconds));
1113
1114 sceneIndex = nextScene;
1115 nextScene = index(sceneIndex.row() + 1, sceneIndex.column());
1116 }
1117
1118 Q_EMIT dataChanged(index(0,0), sceneIndex);
1119 } else if (sceneIndex.isValid()) {
1120
1121 StoryboardItemSP item = m_items.at(sceneIndex.row());
1122 const int lastKeyframe = lastKeyframeGlobal();
1123 const int sceneFrame = index(StoryboardItem::FrameNumber, 0, sceneIndex).data().toInt();
1124 const int duration = lastKeyframe + 1 - sceneFrame;
1125
1126 const int durationFrames = duration % getFramesPerSecond();
1127 const int durationSeconds = duration / getFramesPerSecond();
1128
1129 item->child(StoryboardItem::DurationFrame)->setData(QVariant::fromValue<int>(durationFrames));
1130 item->child(StoryboardItem::DurationSecond)->setData(QVariant::fromValue<int>(durationSeconds));
1131
1132 Q_EMIT dataChanged(sceneIndex, sceneIndex);
1133 }
1134}

References StoryboardItem::DurationFrame, StoryboardItem::DurationSecond, StoryboardItem::FrameNumber, getFramesPerSecond(), index(), lastKeyframeGlobal(), and m_items.

◆ slotFrameRenderCancelled

void StoryboardModel::slotFrameRenderCancelled ( int frame)
privateslot

called KisStoryboardThumbnailRenderScheduler when frame render is cancelled.

Definition at line 1199 of file StoryboardModel.cpp.

1200{
1201 Q_UNUSED(frame);
1202}

◆ slotFrameRenderCompleted

void StoryboardModel::slotFrameRenderCompleted ( int frame,
KisPaintDeviceSP dev )
privateslot

called KisStoryboardThumbnailRenderScheduler when frame render is complete

Parameters
frameThe frame whose regeneration was requested
devThe projection of the frame

Definition at line 1191 of file StoryboardModel.cpp.

1192{
1193 QModelIndex index = indexFromFrame(frame);
1194 if (index.isValid()) {
1196 }
1197}
bool setThumbnailPixmapData(const QModelIndex &parentIndex, const KisPaintDeviceSP &dev)
Sets the Pixmap data.

References index(), indexFromFrame(), and setThumbnailPixmapData().

◆ slotKeyframeAdded

void StoryboardModel::slotKeyframeAdded ( const KisKeyframeChannel * channel,
int time )
privateslot

Definition at line 1045 of file StoryboardModel.cpp.

1046{
1048 return;
1049
1050 const QModelIndex lastScene = lastIndexBeforeFrame(time);
1051 const QModelIndex nextScene = index( lastScene.row() + 1, 0);
1052 const bool extendsLastScene = lastScene.isValid() && !nextScene.isValid();
1053
1054 //Capture new keyframes after last scene and extend duration to include the new key.
1055 if (extendsLastScene) {
1056 const int sceneStartFrame = index(StoryboardItem::FrameNumber, 0, lastScene).data().toInt();
1057 const int desiredDuration = time - sceneStartFrame + 1;
1058 const int actualDuration = data(lastScene, TotalSceneDurationInFrames).toInt();
1059 const int duration = qMax(actualDuration, desiredDuration);
1060 KIS_ASSERT(duration > 0);
1061 const QSharedPointer<StoryboardChild> frameElement = m_items.at(lastScene.row())->child(StoryboardItem::DurationFrame);
1062 const QSharedPointer<StoryboardChild> secondElement = m_items.at(lastScene.row())->child(StoryboardItem::DurationSecond);
1063 frameElement->setData(QVariant::fromValue<int>(duration % getFramesPerSecond()));
1064 secondElement->setData(QVariant::fromValue<int>(duration / getFramesPerSecond()));
1065
1066 Q_EMIT dataChanged(lastScene, lastScene);
1067 }
1068
1071}
int nextKeyframeTime(const int time) const
static KisTimeSpan fromTimeToTime(int start, int end)
void slotUpdateThumbnailsForItems(QModelIndexList indices)
QModelIndexList affectedIndexes(KisTimeSpan range) const
Returns a list of index of items that have frame in between argument range.
QModelIndex lastIndexBeforeFrame(int frame) const
Returns the index of the item with largest frame smaller than argument frame.

References affectedIndexes(), data(), StoryboardItem::DurationFrame, StoryboardItem::DurationSecond, StoryboardItem::FrameNumber, KisTimeSpan::fromTimeToTime(), getFramesPerSecond(), index(), KIS_ASSERT, lastIndexBeforeFrame(), m_items, m_reorderingKeyframes, KisKeyframeChannel::nextKeyframeTime(), slotUpdateThumbnailsForItems(), and TotalSceneDurationInFrames.

◆ slotKeyframeRemoved

void StoryboardModel::slotKeyframeRemoved ( const KisKeyframeChannel * channel,
int time )
privateslot

Definition at line 1073 of file StoryboardModel.cpp.

1074{
1076 return;
1077
1080}
int activeKeyframeTime(int time) const
Get the time of the active keyframe. Useful for snapping any time to that of the most recent keyframe...

References KisKeyframeChannel::activeKeyframeTime(), affectedIndexes(), KisTimeSpan::fromTimeToTime(), m_reorderingKeyframes, KisKeyframeChannel::nextKeyframeTime(), and slotUpdateThumbnailsForItems().

◆ slotNodeRemoved

void StoryboardModel::slotNodeRemoved ( KisNodeSP node)
privateslot

Definition at line 1082 of file StoryboardModel.cpp.

1083{
1084 if (node->isAnimated() && node->paintDevice() && node->paintDevice()->keyframeChannel()) {
1085 KisKeyframeChannel *channel = node->paintDevice()->keyframeChannel();
1086 int keyframeTime = channel->firstKeyframeTime();
1087 while (channel->keyframeAt(keyframeTime)) {
1088 //sigKeyframeRemoved is not emitted when parent node is deleted so calling explicitly
1089 slotKeyframeRemoved(channel, keyframeTime);
1090 keyframeTime = channel->nextKeyframeTime(keyframeTime);
1091 }
1092 }
1093
1095}

References KisKeyframeChannel::firstKeyframeTime(), KisBaseNode::isAnimated(), KisKeyframeChannel::keyframeAt(), KisPaintDevice::keyframeChannel(), KisKeyframeChannel::nextKeyframeTime(), KisBaseNode::paintDevice(), slotKeyframeRemoved(), and slotUpdateThumbnails().

◆ slotSetActiveNode

void StoryboardModel::slotSetActiveNode ( KisNodeSP node)
slot

Definition at line 632 of file StoryboardModel.cpp.

633{
634 m_activeNode = node;
635}

References m_activeNode.

◆ slotUpdateThumbnailForFrame

void StoryboardModel::slotUpdateThumbnailForFrame ( int frame,
bool delay = true )
privateslot

calls regeneration of frame in the background i.e. in another thread.

Parameters
frameThe frame to be regenerated.
delayUpdate thumbnail with delay if true

Definition at line 1136 of file StoryboardModel.cpp.

1137{
1138 Q_UNUSED(delay);
1139 if (!m_image) {
1140 return;
1141 }
1142
1143 QModelIndex index = indexFromFrame(frame);
1144 bool affected = true;
1145 if (index.isValid() && !isLocked()) {
1148 }
1149}

References index(), indexFromFrame(), isLocked(), m_image, m_renderScheduler, KisStoryboardThumbnailRenderScheduler::scheduleFrameForRegeneration(), and KisStoryboardThumbnailRenderScheduler::slotStartFrameRendering().

◆ slotUpdateThumbnails

void StoryboardModel::slotUpdateThumbnails ( )
privateslot

calls regeneration of the currentUiTime() and all frames in affectedIndexes(KisTimeSpan)

Definition at line 1168 of file StoryboardModel.cpp.

1169{
1170 if (!m_image || isLocked()) {
1171 return;
1172 }
1173
1174 int currentTime = m_image->animationInterface()->currentUITime();
1175 slotUpdateThumbnailForFrame(currentTime);
1176
1177 KisTimeSpan affectedRange;
1178 if (m_activeNode) {
1179 affectedRange = KisTimeSpan::calculateAffectedFramesRecursive(m_activeNode, currentTime);
1180 QModelIndexList dirtyIndexes = affectedIndexes(affectedRange);
1181 foreach(QModelIndex index, dirtyIndexes) {
1182 int frame = this->index(StoryboardItem::FrameNumber, 0, index).data().toInt();
1184 }
1185 }
1186 else {
1187 return;
1188 }
1189}
static KisTimeSpan calculateAffectedFramesRecursive(const KisNode *node, int time)

References affectedIndexes(), KisImage::animationInterface(), KisTimeSpan::calculateAffectedFramesRecursive(), KisImageAnimationInterface::currentUITime(), StoryboardItem::FrameNumber, index(), isLocked(), m_activeNode, m_image, and slotUpdateThumbnailForFrame().

◆ slotUpdateThumbnailsForItems()

void StoryboardModel::slotUpdateThumbnailsForItems ( QModelIndexList indices)

Definition at line 1151 of file StoryboardModel.cpp.

1151 {
1152 if (isLocked())
1153 return;
1154
1155 Q_FOREACH( const QModelIndex& storyboardItemIndex, indices ) {
1156 if (!storyboardItemIndex.isValid())
1157 continue;
1158
1159 //If this isn't a storyboard item (root) we will continue
1160 if (storyboardItemIndex.parent().isValid())
1161 continue;
1162
1163 const int frame = index(StoryboardItem::FrameNumber, 0, storyboardItemIndex).data().toInt();
1164 slotUpdateThumbnailForFrame(frame, false);
1165 }
1166}

References StoryboardItem::FrameNumber, index(), isLocked(), and slotUpdateThumbnailForFrame().

◆ supportedDragActions()

Qt::DropActions StoryboardModel::supportedDragActions ( ) const
override

Definition at line 508 of file StoryboardModel.cpp.

509{
510 return Qt::CopyAction | Qt::MoveAction;
511}

◆ supportedDropActions()

Qt::DropActions StoryboardModel::supportedDropActions ( ) const
override

Definition at line 503 of file StoryboardModel.cpp.

504{
505 return Qt::CopyAction | Qt::MoveAction;
506}

◆ totalCommentCount()

int StoryboardModel::totalCommentCount ( )

Get total number of comments.

Returns
Number of total comments.

Definition at line 524 of file StoryboardModel.cpp.

525{
526 return m_commentList.count();
527}

References m_commentList.

◆ updateDurationData()

bool StoryboardModel::updateDurationData ( const QModelIndex & parentIndex)

updates the duration data of item at parentIndex to the number of frame to the next keyframe in any layer.

Parameters
parentIndexThe index whose duration is to be updated.
Returns
True if data was set
Note
If there are no keyframes after this index's frame duration is set to 0s 0f

Definition at line 295 of file StoryboardModel.cpp.

296{
297 if (!parentIndex.isValid()) {
298 return false;
299 }
300
301 QModelIndex currentScene = parentIndex;
302 QModelIndex nextScene = index(currentScene.row() + 1, 0);
303 if (nextScene.isValid()) {
304 const int currentSceneFrame = index(StoryboardItem::FrameNumber, 0, currentScene).data().toInt();
305 const int nextSceneFrame = index(StoryboardItem::FrameNumber, 0, nextScene).data().toInt();
306 const int sceneDuration = nextSceneFrame - currentSceneFrame;
307 const int fps = getFramesPerSecond();
308
309 if (index(StoryboardItem::DurationSecond, 0, parentIndex).data().toInt() != sceneDuration / fps) {
310 setData (index (StoryboardItem::DurationSecond, 0, parentIndex), sceneDuration / fps);
311 }
312 if (index(StoryboardItem::DurationFrame, 0, parentIndex).data().toInt() != sceneDuration % fps) {
313 setData (index (StoryboardItem::DurationFrame, 0, parentIndex), sceneDuration % fps);
314 }
315 }
316
317 return true;
318}

References data(), StoryboardItem::DurationFrame, StoryboardItem::DurationSecond, StoryboardItem::FrameNumber, getFramesPerSecond(), index(), and setData().

◆ visibleCommentCount()

int StoryboardModel::visibleCommentCount ( ) const

Used in StoryboardDelegate and StoryboardView to get size of one storyboard item.

Returns
Number of visible comments.
See also
StoryboardDelegate::sizeHint(QStyleOptionViewItem,QModelIndex)
StoryboardView::visualRect(QModelIndex)

Definition at line 513 of file StoryboardModel.cpp.

514{
515 int visibleComments = 0;
516 foreach(StoryboardComment comment, m_commentList) {
517 if (comment.visibility) {
518 visibleComments++;
519 }
520 }
521 return visibleComments;
522}

References m_commentList, and StoryboardComment::visibility.

◆ visibleCommentsUpto()

int StoryboardModel::visibleCommentsUpto ( QModelIndex index) const

Used in StoryboardView to design the layout of storyboard item.

Returns
Number of visible comments upto index.
See also
StoryboardView::visualRect(QModelIndex)

Definition at line 531 of file StoryboardModel.cpp.

532{
533 int commentRow = index.row() - 4;
534 int visibleComments = 0;
535 for (int row = 0; row < commentRow; row++) {
536 if (m_commentList.at(row).visibility) {
537 visibleComments++;
538 }
539 }
540 return visibleComments;
541}

References index(), and m_commentList.

◆ visualizeScene()

void StoryboardModel::visualizeScene ( const QModelIndex & index,
bool useUndo = true )

Friends And Related Symbol Documentation

◆ KisMoveStoryboardCommand

friend class KisMoveStoryboardCommand
friend

Definition at line 335 of file StoryboardModel.h.

Member Data Documentation

◆ m_activeNode

KisNodeWSP StoryboardModel::m_activeNode
private

Definition at line 347 of file StoryboardModel.h.

◆ m_commentList

QVector<StoryboardComment> StoryboardModel::m_commentList
private

Definition at line 338 of file StoryboardModel.h.

◆ m_commentModel

StoryboardCommentModel* StoryboardModel::m_commentModel {0}
private

Definition at line 339 of file StoryboardModel.h.

339{0};

◆ m_freezeKeyframePositions

bool StoryboardModel::m_freezeKeyframePositions {false}
private

Definition at line 340 of file StoryboardModel.h.

340{false};

◆ m_image

KisImageWSP StoryboardModel::m_image
private

Definition at line 345 of file StoryboardModel.h.

◆ m_imageIdleWatcher

KisIdleWatcher StoryboardModel::m_imageIdleWatcher
private

Definition at line 344 of file StoryboardModel.h.

◆ m_items

StoryboardItemList StoryboardModel::m_items
private

Definition at line 337 of file StoryboardModel.h.

◆ m_lastScene

int StoryboardModel::m_lastScene {0}
private

Definition at line 343 of file StoryboardModel.h.

343{0};

◆ m_lockBoards

bool StoryboardModel::m_lockBoards {false}
private

Definition at line 341 of file StoryboardModel.h.

341{false};

◆ m_renderScheduler

KisStoryboardThumbnailRenderScheduler* StoryboardModel::m_renderScheduler {0}
private

Definition at line 348 of file StoryboardModel.h.

348{0};

◆ m_renderSchedulingCompressor

KisSignalCompressor StoryboardModel::m_renderSchedulingCompressor
private

Definition at line 349 of file StoryboardModel.h.

◆ m_reorderingKeyframes

bool StoryboardModel::m_reorderingKeyframes {false}
private

Definition at line 342 of file StoryboardModel.h.

342{false};

◆ m_view

StoryboardView* StoryboardModel::m_view {0}
private

Definition at line 346 of file StoryboardModel.h.

346{0};

The documentation for this class was generated from the following files: