diff --git a/toonz/sources/toonz/cellselection.cpp b/toonz/sources/toonz/cellselection.cpp index f4b3225..4ae8039 100644 --- a/toonz/sources/toonz/cellselection.cpp +++ b/toonz/sources/toonz/cellselection.cpp @@ -1408,6 +1408,10 @@ void TCellSelection::enableCommands() { enableCommand(this, MI_CloneLevel, &TCellSelection::cloneLevel); enableCommand(this, MI_SetKeyframes, &TCellSelection::setKeyframes); + enableCommand(this, MI_ShiftKeyframesDown, + &TCellSelection::shiftKeyframesDown); + enableCommand(this, MI_ShiftKeyframesUp, &TCellSelection::shiftKeyframesUp); + enableCommand(this, MI_Copy, &TCellSelection::copyCells); enableCommand(this, MI_Paste, &TCellSelection::pasteCells); @@ -1462,6 +1466,8 @@ bool TCellSelection::isEnabledCommand( MI_TimeStretch, MI_CloneLevel, MI_SetKeyframes, + MI_ShiftKeyframesDown, + MI_ShiftKeyframesUp, MI_Copy, MI_Paste, MI_PasteInto, diff --git a/toonz/sources/toonz/cellselection.h b/toonz/sources/toonz/cellselection.h index 0c7c5ee..f0597a5 100644 --- a/toonz/sources/toonz/cellselection.h +++ b/toonz/sources/toonz/cellselection.h @@ -92,6 +92,10 @@ public: void setKeyframes(); void pasteKeyframesInto(); + void shiftKeyframes(int direction); + void shiftKeyframesUp() { shiftKeyframes(-1); } + void shiftKeyframesDown() { shiftKeyframes(1); } + void cloneLevel(); void insertCells(); diff --git a/toonz/sources/toonz/cellselectioncommand.cpp b/toonz/sources/toonz/cellselectioncommand.cpp index 7a94a49..f22f16a 100644 --- a/toonz/sources/toonz/cellselectioncommand.cpp +++ b/toonz/sources/toonz/cellselectioncommand.cpp @@ -1,6 +1,9 @@ #include #include "cellselection.h" +#include "cellkeyframeselection.h" +#include "keyframeselection.h" +#include "keyframedata.h" // Tnz6 includes #include "tapp.h" @@ -1676,3 +1679,47 @@ void TCellSelection::cloneLevel() { if (undo->redo(), undo->m_ok) TUndoManager::manager()->add(undo.release()); } + +//============================================================================= + +void TCellSelection::shiftKeyframes(int direction) { + if (isEmpty() || areAllColSelectedLocked()) return; + + int shift = m_range.getRowCount() * direction; + if (!shift) return; + + TXsheetHandle *xsheet = TApp::instance()->getCurrentXsheet(); + TXsheet *xsh = xsheet->getXsheet(); + TCellKeyframeSelection *cellKeyframeSelection = new TCellKeyframeSelection( + new TCellSelection(), new TKeyframeSelection()); + + cellKeyframeSelection->setXsheetHandle(xsheet); + + TUndoManager::manager()->beginBlock(); + for (int col = m_range.m_c0; col <= m_range.m_c1; col++) { + TXshColumn *column = xsh->getColumn(col); + if (!column || column->isLocked()) continue; + + TStageObjectId colId = + col < 0 ? TStageObjectId::ColumnId(xsh->getCameraColumnIndex()) + : TStageObjectId::ColumnId(col); + TStageObject *colObj = xsh->getStageObject(colId); + TStageObject::KeyframeMap keyframes; + colObj->getKeyframes(keyframes); + if (!keyframes.size()) continue; + int row = m_range.m_r0; + for (TStageObject::KeyframeMap::iterator it = keyframes.begin(); + it != keyframes.end(); it++) { + if (it->first < m_range.m_r0) continue; + row = it->first; + cellKeyframeSelection->selectCellsKeyframes(row, col, + xsh->getFrameCount(), col); + cellKeyframeSelection->getKeyframeSelection()->shiftKeyframes( + row, row + shift, col, col); + break; + } + } + TUndoManager::manager()->endBlock(); + + delete cellKeyframeSelection; +} diff --git a/toonz/sources/toonz/keyframeselection.cpp b/toonz/sources/toonz/keyframeselection.cpp index 1b35b1e..e8bdac8 100644 --- a/toonz/sources/toonz/keyframeselection.cpp +++ b/toonz/sources/toonz/keyframeselection.cpp @@ -7,6 +7,7 @@ #include "cellkeyframedata.h" #include "tapp.h" #include "menubarcommandids.h" +#include "xsheetviewer.h" // TnzQt includes #include "toonzqt/menubarcommand.h" @@ -40,7 +41,8 @@ struct PegbarArgument { //----------------------------------------------------------------------------- -bool shiftKeyframesWithoutUndo(int r0, int r1, int c0, int c1, bool cut) { +bool shiftKeyframesWithoutUndo(int r0, int r1, int c0, int c1, bool cut, + bool shiftFollowing) { int delta = cut ? -(r1 - r0 + 1) : r1 - r0 + 1; if (delta == 0) return false; TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); @@ -55,7 +57,10 @@ bool shiftKeyframesWithoutUndo(int r0, int r1, int c0, int c1, bool cut) { stObj->getKeyframeRange(kr0, kr1); int i = r0; while (i <= kr1) { - if (stObj->isKeyframe(i)) keyToShift.insert(i); + if (stObj->isKeyframe(i)) { + keyToShift.insert(i); + if (!shiftFollowing) break; + } i++; } isShifted = stObj->moveKeyframes(keyToShift, delta); @@ -156,13 +161,13 @@ public: new TKeyframeSelection(m_selection->getSelection()); deleteKeyframesWithoutUndo(&selection->getSelection()); if (-(m_r1 - m_r0 + 1) != 0) - shiftKeyframesWithoutUndo(m_r0, m_r1, m_c0, m_c1, true); + shiftKeyframesWithoutUndo(m_r0, m_r1, m_c0, m_c1, true, true); if (m_oldData) setXshFromData(m_oldData); TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); } void redo() const override { if (m_r1 - m_r0 + 1 != 0) - shiftKeyframesWithoutUndo(m_r0, m_r1, m_c0, m_c1, false); + shiftKeyframesWithoutUndo(m_r0, m_r1, m_c0, m_c1, false, true); // Delete merged data setXshFromData(m_newData); TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); @@ -201,7 +206,7 @@ public: void undo() const override { const TKeyframeData *keyframeData = dynamic_cast(m_data); if (m_r1 - m_r0 + 1 != 0) - shiftKeyframesWithoutUndo(m_r0, m_r1, m_c0, m_c1, false); + shiftKeyframesWithoutUndo(m_r0, m_r1, m_c0, m_c1, false, true); if (keyframeData) pasteKeyframesWithoutUndo(keyframeData, &m_selection->getSelection()); TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); @@ -212,7 +217,7 @@ public: new TKeyframeSelection(m_selection->getSelection()); deleteKeyframesWithoutUndo(&tempSelection->getSelection()); if (m_r1 - m_r0 + 1 != 0) - shiftKeyframesWithoutUndo(m_r0, m_r1, m_c0, m_c1, true); + shiftKeyframesWithoutUndo(m_r0, m_r1, m_c0, m_c1, true, true); TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); } @@ -223,6 +228,51 @@ public: } }; +//============================================================================= +// ShiftKeyframesUndo +//----------------------------------------------------------------------------- + +class ShiftKeyframesUndo final : public TUndo { + int m_r0, m_r1, m_c0, m_c1; + bool m_shiftFollowing; + +public: + ShiftKeyframesUndo(int r0, int r1, int c0, int c1, bool shiftFollowing) + : m_r0(r0) + , m_r1(r1) + , m_c0(c0) + , m_c1(c1) + , m_shiftFollowing(shiftFollowing) {} + + ~ShiftKeyframesUndo() {} + void undo() const override { + if (m_r0 != m_r1) { + int r1adj = m_r0 < m_r1 ? m_r1 - 1 : m_r0 + (m_r0 - m_r1) - 1; + int rshift = m_r0 < m_r1 ? 0 : -(r1adj - m_r0 + 1); + bool cut = m_r0 < m_r1 ? true : false; + + shiftKeyframesWithoutUndo(m_r0 + rshift, r1adj + rshift, m_c0, m_c1, cut, + m_shiftFollowing); + } + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); + } + void redo() const override { + if (m_r0 != m_r1) { + int r1adj = m_r0 < m_r1 ? m_r1 - 1 : m_r0 + (m_r0 - m_r1) - 1; + bool cut = m_r0 < m_r1 ? false : true; + + shiftKeyframesWithoutUndo(m_r0, r1adj, m_c0, m_c1, cut, m_shiftFollowing); + } + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); + } + int getSize() const override { return sizeof(*this); } + + QString getHistoryString() override { + if (m_r0 < m_r1) return QObject::tr("Shift Key Frames Down"); + return QObject::tr("Shift Key Frames Up"); + } +}; + //----------------------------------------------------------------------------- } // namespace //----------------------------------------------------------------------------- @@ -236,6 +286,10 @@ void TKeyframeSelection::enableCommands() { enableCommand(this, MI_Paste, &TKeyframeSelection::pasteKeyframes); enableCommand(this, MI_Cut, &TKeyframeSelection::cutKeyframes); enableCommand(this, MI_Clear, &TKeyframeSelection::deleteKeyframes); + enableCommand(this, MI_ShiftKeyframesDown, + &TKeyframeSelection::shiftKeyframesDown); + enableCommand(this, MI_ShiftKeyframesUp, + &TKeyframeSelection::shiftKeyframesUp); } //----------------------------------------------------------------------------- @@ -335,6 +389,43 @@ void TKeyframeSelection::cutKeyframes() { //----------------------------------------------------------------------------- +void TKeyframeSelection::shiftKeyframes(int direction) { + copyKeyframes(); + if (isEmpty()) return; + + std::set positions = m_positions; + + int r0 = positions.begin()->first; + int c0 = positions.begin()->second; + + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + TKeyframeData *data = new TKeyframeData(); + data->setKeyframes(positions, xsh); + + TUndoManager::manager()->beginBlock(); + + XsheetViewer *viewer = TApp::instance()->getCurrentXsheetViewer(); + TKeyframeSelection *selection = viewer->getKeyframeSelection(); + selection->selectNone(); + + std::set::iterator it = positions.begin(), itEnd = positions.end(); + for(; it != itEnd; ++it) { + Position position = *it; + int r = position.first; + int c = position.second; + + TXshColumn *column = xsh->getColumn(c); + if (!column || column->isLocked()) continue; + + shiftKeyframes(r, r + direction, c, c, false); + selection->select(r + direction, c); + } + + TUndoManager::manager()->endBlock(); +} + +//----------------------------------------------------------------------------- + void TKeyframeSelection::pasteKeyframesWithShift(int r0, int r1, int c0, int c1) { unselectLockedColumn(); @@ -358,7 +449,7 @@ void TKeyframeSelection::pasteKeyframesWithShift(int r0, int r1, int c0, TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); oldData->setKeyframes(positions, xsh); - bool isShift = shiftKeyframesWithoutUndo(r0, r1, c0, c1, false); + bool isShift = shiftKeyframesWithoutUndo(r0, r1, c0, c1, false, true); bool isPaste = pasteKeyframesWithoutUndo(data, &m_positions); if (!isPaste && !isShift) { delete oldData; @@ -389,7 +480,7 @@ void TKeyframeSelection::deleteKeyframesWithShift(int r0, int r1, int c0, } TKeyframeSelection *selection = new TKeyframeSelection(m_positions); bool deleteKeyFrame = deleteKeyframesWithoutUndo(&m_positions); - bool isShift = shiftKeyframesWithoutUndo(r0, r1, c0, c1, true); + bool isShift = shiftKeyframesWithoutUndo(r0, r1, c0, c1, true, true); if (!deleteKeyFrame && !isShift) { delete selection; delete data; @@ -400,3 +491,22 @@ void TKeyframeSelection::deleteKeyframesWithShift(int r0, int r1, int c0, TApp::instance()->getCurrentScene()->setDirtyFlag(true); TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); } + +//----------------------------------------------------------------------------- + +void TKeyframeSelection::shiftKeyframes(int r0, int r1, int c0, int c1, + bool shiftFollowing) { + unselectLockedColumn(); + + int r1adj = r0 < r1 ? r1 - 1 : r0 + (r0 - r1) - 1; + bool cut = r0 < r1 ? false : true; + + bool isShift = + shiftKeyframesWithoutUndo(r0, r1adj, c0, c1, cut, shiftFollowing); + if (!isShift) return; + + TUndoManager::manager()->add( + new ShiftKeyframesUndo(r0, r1, c0, c1, shiftFollowing)); + TApp::instance()->getCurrentScene()->setDirtyFlag(true); + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); +} diff --git a/toonz/sources/toonz/keyframeselection.h b/toonz/sources/toonz/keyframeselection.h index ca5dfe6..63ed47d 100644 --- a/toonz/sources/toonz/keyframeselection.h +++ b/toonz/sources/toonz/keyframeselection.h @@ -68,9 +68,14 @@ public: void pasteKeyframes(); void deleteKeyframes(); void cutKeyframes(); + void shiftKeyframes(int direction); + void shiftKeyframesDown() { shiftKeyframes(1); } + void shiftKeyframesUp() { shiftKeyframes(-1); } void pasteKeyframesWithShift(int r0, int r1, int c0, int c1); void deleteKeyframesWithShift(int r0, int r1, int c0, int c1); + void shiftKeyframes(int r0, int r1, int c0, int c1, + bool shiftFollowing = true); }; #endif // TKEYFRAMESELECTION_H diff --git a/toonz/sources/toonz/mainwindow.cpp b/toonz/sources/toonz/mainwindow.cpp index f0219d8..1f8ee89 100644 --- a/toonz/sources/toonz/mainwindow.cpp +++ b/toonz/sources/toonz/mainwindow.cpp @@ -1834,6 +1834,9 @@ void MainWindow::defineActions() { createMenuCellsAction(MI_FillEmptyCell, tr("&Fill In Empty Cells"), ""); createRightClickMenuAction(MI_SetKeyframes, tr("&Set Key"), "Z"); + createRightClickMenuAction(MI_ShiftKeyframesDown, tr("&Shift Keys Down"), ""); + createRightClickMenuAction(MI_ShiftKeyframesUp, tr("&Shift Keys Up"), ""); + createRightClickMenuAction(MI_PasteNumbers, tr("&Paste Numbers"), ""); createToggle(MI_ViewCamera, tr("&Camera Box"), "", diff --git a/toonz/sources/toonz/menubarcommandids.h b/toonz/sources/toonz/menubarcommandids.h index ab12989..489a2f9 100644 --- a/toonz/sources/toonz/menubarcommandids.h +++ b/toonz/sources/toonz/menubarcommandids.h @@ -275,6 +275,9 @@ #define MI_SelectFollowingKeysInRow "MI_SelectFollowingKeysInRow" #define MI_InvertKeyframeSelection "MI_InvertKeyframeSelection" +#define MI_ShiftKeyframesDown "MI_ShiftKeyframesDown" +#define MI_ShiftKeyframesUp "MI_ShiftKeyframesUp" + #define MI_SetAcceleration "MI_SetAcceleration" #define MI_SetDeceleration "MI_SetDeceleration" #define MI_SetConstantSpeed "MI_SetConstantSpeed" diff --git a/toonz/sources/toonz/xshcellviewer.cpp b/toonz/sources/toonz/xshcellviewer.cpp index e9cc51a..6a1e374 100644 --- a/toonz/sources/toonz/xshcellviewer.cpp +++ b/toonz/sources/toonz/xshcellviewer.cpp @@ -3325,6 +3325,8 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell) { replaceLevelMenu->addAction( cmdManager->getAction(MI_RevertToLastSaved)); menu.addAction(cmdManager->getAction(MI_SetKeyframes)); + menu.addAction(cmdManager->getAction(MI_ShiftKeyframesDown)); + menu.addAction(cmdManager->getAction(MI_ShiftKeyframesUp)); } menu.addSeparator(); } @@ -3389,6 +3391,8 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell) { if (cameraCellsSelected) { menu.addSeparator(); menu.addAction(cmdManager->getAction(MI_SetKeyframes)); + menu.addAction(cmdManager->getAction(MI_ShiftKeyframesDown)); + menu.addAction(cmdManager->getAction(MI_ShiftKeyframesUp)); } } menu.addSeparator(); @@ -3460,6 +3464,9 @@ void CellArea::createKeyMenu(QMenu &menu) { menu.addAction(cmdManager->getAction(MI_Paste)); menu.addAction(cmdManager->getAction(MI_Clear)); menu.addSeparator(); + menu.addAction(cmdManager->getAction(MI_ShiftKeyframesDown)); + menu.addAction(cmdManager->getAction(MI_ShiftKeyframesUp)); + menu.addSeparator(); menu.addAction(cmdManager->getAction(MI_OpenFunctionEditor)); } @@ -3511,6 +3518,8 @@ void CellArea::createKeyLineMenu(QMenu &menu, int row, int col) { if (col < 0) { menu.addSeparator(); menu.addAction(cmdManager->getAction(MI_SetKeyframes)); + menu.addAction(cmdManager->getAction(MI_ShiftKeyframesDown)); + menu.addAction(cmdManager->getAction(MI_ShiftKeyframesUp)); } #ifdef LINETEST