diff --git a/toonz/sources/include/toonz/txshcolumn.h b/toonz/sources/include/toonz/txshcolumn.h index 18bef614..562507ac 100644 --- a/toonz/sources/include/toonz/txshcolumn.h +++ b/toonz/sources/include/toonz/txshcolumn.h @@ -348,11 +348,13 @@ Return true if cell in \b row is empty. */ bool isCellEmpty(int row) const override; + bool isCellImplicit(int row) const; + /*! Return cell in \b row. \sa getCells and setCell() */ - virtual const TXshCell &getCell(int row) const; + virtual const TXshCell &getCell(int row, bool implicitLookup = true) const; /*! Set cell in \b row to \b TXshCell \b cell. \sa setCells() and getCell(); return false if cannot set cells. diff --git a/toonz/sources/include/toonz/txsheet.h b/toonz/sources/include/toonz/txsheet.h index adf1f269..4bd14766 100644 --- a/toonz/sources/include/toonz/txsheet.h +++ b/toonz/sources/include/toonz/txsheet.h @@ -192,9 +192,10 @@ public: an empty cell. \sa setCell(), getCells(), setCells() */ - const TXshCell &getCell(int row, int col) const; + const TXshCell &getCell(int row, int col, bool implicitLookup = true) const; - const TXshCell &getCell(const CellPosition &pos) const; + const TXshCell &getCell(const CellPosition &pos, + bool implicitLookup = true) const; bool isImplicitCell(int row, int col) const; diff --git a/toonz/sources/include/toonz/txshsoundcolumn.h b/toonz/sources/include/toonz/txshsoundcolumn.h index e866ae1a..cc265bad 100644 --- a/toonz/sources/include/toonz/txshsoundcolumn.h +++ b/toonz/sources/include/toonz/txshsoundcolumn.h @@ -137,7 +137,7 @@ public: /*! Return min row not empty.*/ int getFirstRow() const override; - const TXshCell &getCell(int row) const override; + const TXshCell &getCell(int row, bool implicitLookup = false) const override; TXshCell getSoundCell(int row); void getCells(int row, int rowCount, TXshCell cells[]) override; diff --git a/toonz/sources/tnztools/rasterselection.cpp b/toonz/sources/tnztools/rasterselection.cpp index 6afcb5c0..33203af5 100644 --- a/toonz/sources/tnztools/rasterselection.cpp +++ b/toonz/sources/tnztools/rasterselection.cpp @@ -1347,9 +1347,11 @@ bool RasterSelection::isEditable() { // Test for Mesh-deformed levels const TStageObjectId &parentId = obj->getParent(); if (parentId.isColumn() && obj->getParentHandle()[0] != 'H') { - TXshSimpleLevel *parentSl = - xsh->getCell(rowIndex, parentId.getIndex()).getSimpleLevel(); - if (parentSl && parentSl->getType() == MESH_XSHLEVEL) return false; + TXshCell cell = xsh->getCell(rowIndex, parentId.getIndex()); + TXshSimpleLevel *parentSl = cell.getSimpleLevel(); + if (!cell.getFrameId().isStopFrame() && parentSl && + parentSl->getType() == MESH_XSHLEVEL) + return false; } } diff --git a/toonz/sources/tnztools/strokeselection.cpp b/toonz/sources/tnztools/strokeselection.cpp index a051decc..5a08db46 100644 --- a/toonz/sources/tnztools/strokeselection.cpp +++ b/toonz/sources/tnztools/strokeselection.cpp @@ -786,9 +786,11 @@ bool StrokeSelection::isEditable() { // Test for Mesh-deformed levels const TStageObjectId &parentId = obj->getParent(); if (parentId.isColumn() && obj->getParentHandle()[0] != 'H') { - TXshSimpleLevel *parentSl = - xsh->getCell(rowIndex, parentId.getIndex()).getSimpleLevel(); - if (parentSl && parentSl->getType() == MESH_XSHLEVEL) return false; + TXshCell cell = xsh->getCell(rowIndex, parentId.getIndex()); + TXshSimpleLevel *parentSl = cell.getSimpleLevel(); + if (!cell.getFrameId().isStopFrame() && parentSl && + parentSl->getType() == MESH_XSHLEVEL) + return false; } } diff --git a/toonz/sources/tnztools/tool.cpp b/toonz/sources/tnztools/tool.cpp index b04666a7..27e9305d 100644 --- a/toonz/sources/tnztools/tool.cpp +++ b/toonz/sources/tnztools/tool.cpp @@ -385,8 +385,8 @@ TImage *TTool::touchImage() { // measure the hold length (starting from the current row) : r0-r1 int r0 = row, r1 = row; if (isAutoStretchEnabled) - while (xsh->getCell(r1 + 1, col) == cell && - !xsh->isImplicitCell(r1 + 1, col)) + while (!cell.getFrameId().isStopFrame() && + xsh->getCell(r1 + 1, col, false) == cell) r1++; // find the proper frameid (possibly addisng suffix, in order to avoid a // fid already used) @@ -465,6 +465,8 @@ TImage *TTool::touchImage() { while (a >= r0 && xsh->getCell(a, col).isEmpty()) a--; while (b <= r1 && xsh->getCell(b, col).isEmpty()) b++; + if (a >= r0 && xsh->getCell(a, col).getFrameId().isStopFrame()) a = r0 - 1; + // find the level we must attach to if (a >= r0) { // there is a not-empty cell before the current one diff --git a/toonz/sources/toonz/autoinputcellnumberpopup.cpp b/toonz/sources/toonz/autoinputcellnumberpopup.cpp index 9a7780d6..df31f0a3 100644 --- a/toonz/sources/toonz/autoinputcellnumberpopup.cpp +++ b/toonz/sources/toonz/autoinputcellnumberpopup.cpp @@ -153,9 +153,8 @@ AutoInputCellNumberUndo::AutoInputCellNumberUndo(int increment, int interval, TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); for (int c = 0; c < m_columnIndices.size(); ++c) { for (int r = m_r0; r <= rowUpTo; ++r) { - const TXshCell &cell = xsh->getCell(r, m_columnIndices.at(c)); - m_beforeCells[k++] = - xsh->isImplicitCell(r, m_columnIndices.at(c)) ? TXshCell() : cell; + const TXshCell &cell = xsh->getCell(r, m_columnIndices.at(c), false); + m_beforeCells[k++] = cell; } } } else { @@ -165,9 +164,8 @@ AutoInputCellNumberUndo::AutoInputCellNumberUndo(int increment, int interval, int k = 0; TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); for (int c = 0; c < m_columnIndices.size(); ++c) { - const TXshCell &cell = xsh->getCell(m_r0, m_columnIndices.at(c)); - m_beforeCells[k++] = - xsh->isImplicitCell(m_r0, m_columnIndices.at(c)) ? TXshCell() : cell; + const TXshCell &cell = xsh->getCell(m_r0, m_columnIndices.at(c), false); + m_beforeCells[k++] = cell; } } } diff --git a/toonz/sources/toonz/cellselection.cpp b/toonz/sources/toonz/cellselection.cpp index 145e2f6c..52b9fde8 100644 --- a/toonz/sources/toonz/cellselection.cpp +++ b/toonz/sources/toonz/cellselection.cpp @@ -2897,8 +2897,7 @@ void TCellSelection::stopFrameHold(int row, int col, bool multiple) { return; } - TXshCell cell; - if (!xsh->isImplicitCell(row, col)) cell = xsh->getCell(row, col); + TXshCell cell = xsh->getCell(row, col, false); StopFrameHoldUndo *undo = new StopFrameHoldUndo(lvl, row, col, cell); TUndoManager::manager()->add(undo); diff --git a/toonz/sources/toonz/cellselectioncommand.cpp b/toonz/sources/toonz/cellselectioncommand.cpp index 40a45780..6e92c06d 100644 --- a/toonz/sources/toonz/cellselectioncommand.cpp +++ b/toonz/sources/toonz/cellselectioncommand.cpp @@ -213,8 +213,12 @@ void IncrementUndo::undo() const { xsh->removeCells(r.x0, r.y0, size); else { xsh->insertCells(r.x0, r.y0, size); - for (int j = 0; j < size; ++j) - xsh->setCell(r.x0 + j, r.y0, m_undoCells[i].second); + for (int j = 0; j < size; ++j) { + if (j > 0 && Preferences::instance()->isImplicitHoldEnabled()) + xsh->setCell(r.x0 + j, r.y0, TXshCell(0, TFrameId::EMPTY_FRAME)); + else + xsh->setCell(r.x0 + j, r.y0, m_undoCells[i].second); + } } } @@ -391,8 +395,8 @@ StepUndo::StepUndo(int r0, int c0, int r1, int c1, int step) int k = 0; for (int r = r0; r <= r1; ++r) for (int c = c0; c <= c1; ++c) { - const TXshCell &cell = xsh->getCell(r, c); - m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell; + const TXshCell &cell = xsh->getCell(r, c, false); + m_cells[k++] = cell; } } @@ -495,8 +499,8 @@ EachUndo::EachUndo(int r0, int c0, int r1, int c1, int each) TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); for (int r = r0; r <= r1; ++r) for (int c = c0; c <= c1; ++c) { - const TXshCell &cell = xsh->getCell(r, c); - m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell; + const TXshCell &cell = xsh->getCell(r, c, false); + m_cells[k++] = cell; } } @@ -611,9 +615,8 @@ ReframeUndo::ReframeUndo(int r0, int r1, std::vector columnIndeces, TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); for (int r = r0; r <= (r1 + 1); r++) for (int c = 0; c < (int)m_columnIndeces.size(); c++) { - const TXshCell &cell = xsh->getCell(r, m_columnIndeces[c]); - m_cells[k++] = - xsh->isImplicitCell(r, m_columnIndeces[c]) ? TXshCell() : cell; + const TXshCell &cell = xsh->getCell(r, m_columnIndeces[c], false); + m_cells[k++] = cell; } m_newRows.clear(); @@ -847,7 +850,7 @@ ResetStepUndo::ResetStepUndo(int r0, int c0, int r1, int c1) TXsheetP xsh = app->getCurrentXsheet()->getXsheet(); for (int r = r0; r <= r1; ++r) { const TXshCell &cell = xsh->getCell(r, c); - m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell; + m_cells[k++] = xsh->getCell(r, c, false); if (prevCell != cell) { prevCell = cell; @@ -947,7 +950,7 @@ IncreaseStepUndo::IncreaseStepUndo(int r0, int c0, int r1, int c1) TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); for (int r = r0; r <= r1; ++r) { const TXshCell &cell = xsh->getCell(r, c); - m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell; + m_cells[k++] = xsh->getCell(r, c, false); if (prevCell != cell) { prevCell = cell; @@ -1062,11 +1065,11 @@ DecreaseStepUndo::DecreaseStepUndo(int r0, int c0, int r1, int c1) m_removedCells[c] = 0; bool removed = false; - m_cells[k++] = xsh->isImplicitCell(r0, c) ? TXshCell() : prevCell; + m_cells[k++] = xsh->getCell(r0, c, false); for (int r = r0 + 1; r <= r1; ++r) { const TXshCell &cell = xsh->getCell(r, c); - m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell; + m_cells[k++] = xsh->getCell(r, c, false); if (prevCell == cell) { if (!removed) { @@ -1610,16 +1613,9 @@ void CloneLevelUndo::insertCells() const { // Now, re-traverse the selected range, and add corresponding cells // in the destination range for (int c = m_range.m_c0; c <= m_range.m_c1; ++c) { - TXshCell prevCell; TXshLevelP lastLevel = 0; for (int r = m_range.m_r0; r <= m_range.m_r1; ++r) { - TXshCell srcCell = xsh->getCell(r, c); - if (useImplicitHold) { - if (r > m_range.m_r0 && - (prevCell == srcCell || xsh->isImplicitCell(r, c))) - srcCell = TXshCell(); - prevCell = srcCell; - } + TXshCell srcCell = xsh->getCell(r, c, false); if (TXshSimpleLevel *srcSl = srcCell.getSimpleLevel()) { std::map::iterator lt = m_insertedLevels.find(srcSl); diff --git a/toonz/sources/toonz/iocommand.cpp b/toonz/sources/toonz/iocommand.cpp index 259517af..2ea781bf 100644 --- a/toonz/sources/toonz/iocommand.cpp +++ b/toonz/sources/toonz/iocommand.cpp @@ -322,8 +322,7 @@ bool beforeCellsInsert(TXsheet *xsh, int row, int &col, int rowCount, int i = 0; TXshColumn *column = xsh->getColumn(col); - for (i = 0; i < rowCount && (xsh->getCell(row + i, col).isEmpty() || - xsh->isImplicitCell(row + i, col)); + for (i = 0; i < rowCount && (xsh->getCell(row + i, col, false).isEmpty()); i++) { } int type = (column && !column->isEmpty()) ? column->getColumnType() @@ -510,8 +509,7 @@ public: TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); for (c = m_col0; c <= m_col1; c++) for (r = m_row0; r <= m_row1; r++) { - TXshCell cell; - if (!xsh->isImplicitCell(r, c)) cell = xsh->getCell(r, c); + TXshCell cell = xsh->getCell(r, c, false); TXshSimpleLevel *oldLevel = cell.getSimpleLevel(); TFrameId fid = cell.getFrameId(); QPair cellId(r, c); diff --git a/toonz/sources/toonz/mainwindow.cpp b/toonz/sources/toonz/mainwindow.cpp index 098a7067..10eb8171 100644 --- a/toonz/sources/toonz/mainwindow.cpp +++ b/toonz/sources/toonz/mainwindow.cpp @@ -2018,6 +2018,10 @@ void MainWindow::defineActions() { createMenuXsheetAction(MI_RemoveGlobalKeyframe, QT_TR_NOOP("Remove Multiple Keys"), "", "remove_multiple_keys"); + createMenuXsheetAction(MI_SetGlobalStopframe, + QT_TR_NOOP("Set Multiple Stop Frames"), ""); + createMenuXsheetAction(MI_RemoveGlobalStopframe, + QT_TR_NOOP("Remove Multiple Stop Frames"), ""); createMenuXsheetAction(MI_RemoveEmptyColumns, QT_TR_NOOP("Remove Empty Columns"), "", "remove_empty_columns"); diff --git a/toonz/sources/toonz/menubar.cpp b/toonz/sources/toonz/menubar.cpp index a799495f..f41d5973 100644 --- a/toonz/sources/toonz/menubar.cpp +++ b/toonz/sources/toonz/menubar.cpp @@ -429,6 +429,8 @@ void TopBar::loadMenubar() { addMenuItem(sceneMenu, MI_RemoveSceneFrame); addMenuItem(sceneMenu, MI_InsertGlobalKeyframe); addMenuItem(sceneMenu, MI_RemoveGlobalKeyframe); + addMenuItem(sceneMenu, MI_SetGlobalStopframe); + addMenuItem(sceneMenu, MI_RemoveGlobalStopframe); sceneMenu->addSeparator(); addMenuItem(sceneMenu, MI_LipSyncPopup); sceneMenu->addSeparator(); diff --git a/toonz/sources/toonz/menubarcommandids.h b/toonz/sources/toonz/menubarcommandids.h index 803baabd..5e73277c 100644 --- a/toonz/sources/toonz/menubarcommandids.h +++ b/toonz/sources/toonz/menubarcommandids.h @@ -137,6 +137,8 @@ #define MI_InsertGlobalKeyframe "MI_InsertGlobalKeyframe" #define MI_RemoveGlobalKeyframe "MI_RemoveGlobalKeyframe" +#define MI_SetGlobalStopframe "MI_SetGlobalStopframe" +#define MI_RemoveGlobalStopframe "MI_RemoveGlobalStopframe" #define MI_DrawingSubForward "MI_DrawingSubForward" #define MI_DrawingSubBackward "MI_DrawingSubBackward" #define MI_DrawingSubGroupForward "MI_DrawingSubGroupForward" diff --git a/toonz/sources/toonz/sceneviewerevents.cpp b/toonz/sources/toonz/sceneviewerevents.cpp index d1949acf..ad94f27c 100644 --- a/toonz/sources/toonz/sceneviewerevents.cpp +++ b/toonz/sources/toonz/sceneviewerevents.cpp @@ -1617,15 +1617,16 @@ bool changeFrameSkippingHolds(QKeyEvent *e) { TXsheet *xsh = app->getCurrentXsheet()->getXsheet(); TXshCell cell = xsh->getCell(row, col); if (e->key() == Qt::Key_Down) { + int r0, r1; + bool range = xsh->getCellRange(col, r0, r1); if (cell.isEmpty()) { - int r0, r1; - if (xsh->getCellRange(col, r0, r1)) { + if (range) { while (row <= r1 && xsh->getCell(row, col).isEmpty()) row++; if (xsh->getCell(row, col).isEmpty()) return false; } else return false; } else { - while (xsh->getCell(row, col) == cell) row++; + while (row <= r1 && xsh->getCell(row, col) == cell) row++; } } else { // Key_Up diff --git a/toonz/sources/toonz/timestretchpopup.cpp b/toonz/sources/toonz/timestretchpopup.cpp index 488d03e9..09d2e156 100644 --- a/toonz/sources/toonz/timestretchpopup.cpp +++ b/toonz/sources/toonz/timestretchpopup.cpp @@ -68,8 +68,8 @@ public: TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); for (int c = c0; c <= c1; c++) for (int r = r0; r <= r1; r++) { - const TXshCell &cell = xsh->getCell(r, c); - m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell; + const TXshCell &cell = xsh->getCell(r, c, false); + m_cells[k++] = cell; } } diff --git a/toonz/sources/toonz/xshcellmover.cpp b/toonz/sources/toonz/xshcellmover.cpp index 27b433d2..a9fc40cc 100644 --- a/toonz/sources/toonz/xshcellmover.cpp +++ b/toonz/sources/toonz/xshcellmover.cpp @@ -248,9 +248,7 @@ bool CellsMover::canMoveCells(const TPoint &pos) { int count = 0; for (int i = 0; i < m_colCount; i++) { for (int j = 0; j < m_rowCount; j++) { - if (!xsh->getCell(r + j, c + i).isEmpty() && - !xsh->isImplicitCell(r + j, c + i)) - return false; + if (!xsh->getCell(r + j, c + i, false).isEmpty()) return false; count++; } } diff --git a/toonz/sources/toonz/xshcellviewer.cpp b/toonz/sources/toonz/xshcellviewer.cpp index c7497934..b3766f10 100644 --- a/toonz/sources/toonz/xshcellviewer.cpp +++ b/toonz/sources/toonz/xshcellviewer.cpp @@ -2272,7 +2272,8 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference, if (showLevelName && (!sameLevel || (row > 0 && xsh->isImplicitCell(row - 1, col)) || (isAfterMarkers && !isSimpleView && - Preferences::instance()->isLevelNameOnEachMarkerEnabled()))) { + Preferences::instance()->isLevelNameOnEachMarkerEnabled()) || + prevCell.getFrameId().isStopFrame())) { std::wstring levelName = cell.m_level->getName(); QString text = QString::fromStdWString(levelName); QFontMetrics fm(font); @@ -2989,7 +2990,7 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col, text, font, nameRect.width() - fm.width(numberStr) - 2, QString("~")); #endif - if (!sameLevel || isAfterMarkers) + if (!sameLevel || isAfterMarkers || prevCell.getFrameId().isStopFrame()) p.drawText(nameRect, Qt::AlignLeft | Qt::AlignBottom, elidaName); } } diff --git a/toonz/sources/toonz/xsheetcmd.cpp b/toonz/sources/toonz/xsheetcmd.cpp index 7731ad91..f633ce10 100644 --- a/toonz/sources/toonz/xsheetcmd.cpp +++ b/toonz/sources/toonz/xsheetcmd.cpp @@ -42,6 +42,7 @@ #include "toonz/tfxhandle.h" #include "toonz/scenefx.h" #include "toonz/preferences.h" +#include "toonz/txshlevelcolumn.h" // TnzQt includes #include "toonzqt/tselectionhandle.h" @@ -335,8 +336,8 @@ public: for (int c = 0; c != colsCount; ++c) { // Store cell - const TXshCell &cell = xsh->getCell(m_frame, c); - m_cells[c] = xsh->isImplicitCell(m_frame, c) ? TXshCell() : cell; + const TXshCell &cell = xsh->getCell(m_frame, c, false); + m_cells[c] = cell; // Store stage object keyframes TStageObject *obj = xsh->getStageObject(TStageObjectId::ColumnId(c)); @@ -636,6 +637,265 @@ public: } } removeGlobalKeyframeCommand; +//***************************************************************************** +// SetGlobalStopframe command +//***************************************************************************** + +class SetGlobalStopframeUndo final : public TUndo { + std::vector> m_oldCells; + std::vector m_columns; + int m_frame; + +public: + SetGlobalStopframeUndo(int frame, const std::vector &columns); + ~SetGlobalStopframeUndo() {} + + void undo() const override { + if (m_frame < 0 || !m_oldCells.size()) return; + + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + + for (int i = 0; i < m_oldCells.size(); i++) { + std::pair cellData = m_oldCells[i]; + TXshColumn *xshColumn = xsh->getColumn(cellData.first); + if (!xshColumn) continue; + + TXshCellColumn *cellColumn = xshColumn->getCellColumn(); + if (!cellColumn) continue; + + std::vector cells; + cells.push_back(cellData.second); + cellColumn->setCells(m_frame, 1, &cells[0]); + } + + TApp::instance()->getCurrentScene()->setDirtyFlag(true); + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); + } + + void redo() const override; + + int getSize() const override { return m_oldCells.size(); } + + QString getHistoryString() override { + return QObject::tr("Set Multiple Stop Frames at Frame %1") + .arg(QString::number(m_frame + 1)); + } +}; + +//----------------------------------------------------------------------------- + +SetGlobalStopframeUndo::SetGlobalStopframeUndo(int frame, + const std::vector &columns) + : m_frame(frame), m_columns(columns) { + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + + m_oldCells.clear(); + + for (int c : m_columns) { + if (c < 0) continue; + + TXshColumn *xshColumn = xsh->getColumn(c); + if (!xshColumn || xshColumn->getSoundColumn() || + xshColumn->getSoundTextColumn() || xshColumn->isLocked() || + xshColumn->isEmpty()) + continue; + + TXshCellColumn *cellColumn = xshColumn->getCellColumn(); + if (!cellColumn || cellColumn->isEmpty()) continue; + + TXshCell cell = cellColumn->getCell(m_frame, false); + if (!cell.isEmpty()) continue; + + m_oldCells.push_back(std::make_pair(c, cell)); + } +} + +//----------------------------------------------------------------------------- + +void SetGlobalStopframeUndo::redo() const { + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + + for (int c : m_columns) { + if (c < 0) continue; + + TXshColumn *xshColumn = xsh->getColumn(c); + if (!xshColumn || xshColumn->getSoundColumn() || + xshColumn->getSoundTextColumn() || xshColumn->isLocked() || + xshColumn->isEmpty()) + continue; + + TXshCellColumn *cellColumn = xshColumn->getCellColumn(); + if (!cellColumn || cellColumn->isEmpty()) continue; + + TXshCell cell = cellColumn->getCell(m_frame); + if (!cell.isEmpty() && !cellColumn->isCellImplicit(m_frame)) continue; + + if (cell.isEmpty()) { // Might have hit a stop frame + for (int r = m_frame - 1; r >= 0; r--) { + cell = cellColumn->getCell(r, false); + if (cell.isEmpty()) continue; + break; + } + if (cell.isEmpty()) continue; + } + cellColumn->setCell( + m_frame, TXshCell(cell.m_level.getPointer(), TFrameId::STOP_FRAME)); + } + + TApp::instance()->getCurrentScene()->setDirtyFlag(true); + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); +} + +//----------------------------------------------------------------------------- + +static void setGlobalStopframe(int frame) { + std::vector columns; + ::getColumns(columns); + + if (columns.empty()) return; + + TUndo *undo = new SetGlobalStopframeUndo(frame, columns); + TUndoManager::manager()->add(undo); + + undo->redo(); +} + +//============================================================================= + +class SetGlobalStopframeCommand final : public MenuItemHandler { +public: + SetGlobalStopframeCommand() : MenuItemHandler(MI_SetGlobalStopframe) {} + void execute() override { + int frame = TApp::instance()->getCurrentFrame()->getFrame(); + XshCmd::setGlobalStopframe(frame); + } +} setGlobalStopframeCommand; + +//***************************************************************************** +// RemoveGlobalStopframe command +//***************************************************************************** + +class RemoveGlobalStopframeUndo final : public TUndo { + std::vector> m_oldCells; + std::vector m_columns; + int m_frame; + +public: + RemoveGlobalStopframeUndo(int frame, const std::vector &columns); + ~RemoveGlobalStopframeUndo() {} + + void undo() const override { + if (m_frame < 0 || !m_oldCells.size()) return; + + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + + for (int i = 0; i < m_oldCells.size(); i++) { + std::pair cellData = m_oldCells[i]; + TXshColumn *xshColumn = xsh->getColumn(cellData.first); + if (!xshColumn) continue; + + TXshCellColumn *cellColumn = xshColumn->getCellColumn(); + if (!cellColumn) continue; + + std::vector cells; + cells.push_back(cellData.second); + cellColumn->setCells(m_frame, 1, &cells[0]); + } + + TApp::instance()->getCurrentScene()->setDirtyFlag(true); + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); + } + + void redo() const override; + + int getSize() const override { return m_oldCells.size(); } + + QString getHistoryString() override { + return QObject::tr("Remove Multiple Stop Frames at Frame %1") + .arg(QString::number(m_frame + 1)); + } +}; + +//----------------------------------------------------------------------------- + +RemoveGlobalStopframeUndo::RemoveGlobalStopframeUndo( + int frame, const std::vector &columns) + : m_frame(frame), m_columns(columns) { + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + + m_oldCells.clear(); + + for (int c : m_columns) { + if (c < 0) continue; + + TXshColumn *xshColumn = xsh->getColumn(c); + if (!xshColumn || xshColumn->getSoundColumn() || + xshColumn->getSoundTextColumn() || xshColumn->isLocked() || + xshColumn->isEmpty()) + continue; + + TXshCellColumn *cellColumn = xshColumn->getCellColumn(); + if (!cellColumn || cellColumn->isEmpty()) continue; + + TXshCell cell = cellColumn->getCell(m_frame, false); + if (!cell.getFrameId().isStopFrame()) continue; + + m_oldCells.push_back(std::make_pair(c, cell)); + } +} + +//----------------------------------------------------------------------------- + +void RemoveGlobalStopframeUndo::redo() const { + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + + for (int c : m_columns) { + if (c < 0) continue; + + TXshColumn *xshColumn = xsh->getColumn(c); + if (!xshColumn || xshColumn->getSoundColumn() || + xshColumn->getSoundTextColumn() || xshColumn->isLocked() || + xshColumn->isEmpty()) + continue; + + TXshCellColumn *cellColumn = xshColumn->getCellColumn(); + if (!cellColumn || cellColumn->isEmpty()) continue; + + TXshCell cell = cellColumn->getCell(m_frame, false); + if (!cell.getFrameId().isStopFrame()) continue; + + cellColumn->clearCells(m_frame, 1); + } + + TApp::instance()->getCurrentScene()->setDirtyFlag(true); + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); +} + +//----------------------------------------------------------------------------- + +static void removeGlobalStopframe(int frame) { + std::vector columns; + ::getColumns(columns); + + if (columns.empty()) return; + + TUndo *undo = new RemoveGlobalStopframeUndo(frame, columns); + TUndoManager::manager()->add(undo); + + undo->redo(); +} + +//============================================================================= + +class RemoveGlobalStopframeCommand final : public MenuItemHandler { +public: + RemoveGlobalStopframeCommand() : MenuItemHandler(MI_RemoveGlobalStopframe) {} + void execute() override { + int frame = TApp::instance()->getCurrentFrame()->getFrame(); + XshCmd::removeGlobalStopframe(frame); + } +} RemoveGlobalStopframeCommand; + //============================================================ // Drawing Substitution //============================================================ @@ -662,10 +922,8 @@ public: tempCol = c; while (r <= m_range.m_r1 + 1) { tempRow = r; - if (xsh->getCell(tempRow, tempCol).isEmpty() || - xsh->isImplicitCell(tempRow, tempCol)) { + if (xsh->getCell(tempRow, tempCol, false).isEmpty()) emptyCells.push_back(std::make_pair(tempRow, tempCol)); - } r++; } r = m_range.m_r0; diff --git a/toonz/sources/toonz/xsheetdragtool.cpp b/toonz/sources/toonz/xsheetdragtool.cpp index ea488886..f8a5ca1f 100644 --- a/toonz/sources/toonz/xsheetdragtool.cpp +++ b/toonz/sources/toonz/xsheetdragtool.cpp @@ -2063,8 +2063,7 @@ protected: getViewer()->orientation()->isVerticalTimeline()); for (c = col; c < rect.getLx() + col; c++) { for (r = row; r < rect.getLy() + row; r++) - if (!xsh->getCell(r, c).isEmpty() && !xsh->isImplicitCell(r, c)) - return false; + if (!xsh->getCell(r, c, false).isEmpty()) return false; } return true; } diff --git a/toonz/sources/toonz/xshrowviewer.cpp b/toonz/sources/toonz/xshrowviewer.cpp index 010191a7..3e001320 100644 --- a/toonz/sources/toonz/xshrowviewer.cpp +++ b/toonz/sources/toonz/xshrowviewer.cpp @@ -1255,6 +1255,8 @@ void RowArea::contextMenuEvent(QContextMenuEvent *event) { menu->addAction(cmdManager->getAction(MI_RemoveSceneFrame)); menu->addAction(cmdManager->getAction(MI_InsertGlobalKeyframe)); menu->addAction(cmdManager->getAction(MI_RemoveGlobalKeyframe)); + menu->addAction(cmdManager->getAction(MI_SetGlobalStopframe)); + menu->addAction(cmdManager->getAction(MI_RemoveGlobalStopframe)); menu->addAction(cmdManager->getAction(MI_DrawingSubForward)); menu->addAction(cmdManager->getAction(MI_DrawingSubBackward)); menu->addSeparator(); diff --git a/toonz/sources/toonzlib/plasticdeformerfx.cpp b/toonz/sources/toonzlib/plasticdeformerfx.cpp index a38a186a..cdeaeda0 100644 --- a/toonz/sources/toonzlib/plasticdeformerfx.cpp +++ b/toonz/sources/toonzlib/plasticdeformerfx.cpp @@ -196,15 +196,6 @@ bool PlasticDeformerFx::buildTextureDataSl(double frame, TRenderSettings &info, TXshLevelColumn *texColumn = lcfx->getColumn(); TXshCell texCell = texColumn->getCell(row); - if (texCell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - texColumn->getRange(r0, r1); - for (int r = std::min(r1, (int)frame); r >= r0; r--) { - texCell = texColumn->getCell(r); - if (texCell.isEmpty()) continue; - break; - } - } TXshSimpleLevel *texSl = texCell.getSimpleLevel(); const TFrameId &texFid = texCell.getFrameId(); diff --git a/toonz/sources/toonzlib/scenefx.cpp b/toonz/sources/toonzlib/scenefx.cpp index 6bac95c5..c239ffd2 100644 --- a/toonz/sources/toonzlib/scenefx.cpp +++ b/toonz/sources/toonzlib/scenefx.cpp @@ -111,15 +111,6 @@ public: if (!m_cellColumn) return m_frame; TXshCell cell = m_cellColumn->getCell(tfloor(frame)); assert(!cell.isEmpty()); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - m_cellColumn->getRange(r0, r1); - for (int r = std::min(r1, frame); r >= r0; r--) { - cell = m_cellColumn->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } return cell.m_frameId.getNumber() - 1; } @@ -813,15 +804,6 @@ PlacedFx FxBuilder::makePF(TLevelColumnFx *lcfx) { // Retrieve the corresponding xsheet cell to build up /*-- 現在のフレームのセルを取得 --*/ TXshCell cell = lcfx->getColumn()->getCell(tfloor(m_frame)); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - lcfx->getColumn()->getRange(r0, r1); - for (int r = std::min(r1, tfloor(m_frame)); r >= r0; r--) { - cell = lcfx->getColumn()->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } int levelFrame = cell.m_frameId.getNumber() - 1; /*-- ParticlesFxに繋がっておらず、空セルの場合は 中身無しを返す --*/ @@ -964,15 +946,6 @@ PlacedFx FxBuilder::makePF(TPaletteColumnFx *pcfx) { if (!pcfx->getColumn()->isPreviewVisible()) return PlacedFx(); TXshCell cell = pcfx->getColumn()->getCell(tfloor(m_frame)); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - pcfx->getColumn()->getRange(r0, r1); - for (int r = std::min(r1, tfloor(m_frame)); r >= r0; r--) { - cell = pcfx->getColumn()->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } if (cell.isEmpty() || cell.getFrameId().isStopFrame()) return PlacedFx(); @@ -1002,15 +975,6 @@ PlacedFx FxBuilder::makePF(TZeraryColumnFx *zcfx) { return PlacedFx(); TXshCell cell = zcfx->getColumn()->getCell(tfloor(m_frame)); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - zcfx->getColumn()->getRange(r0, r1); - for (int r = std::min(r1, tfloor(m_frame)); r >= r0; r--) { - cell = zcfx->getColumn()->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } // Build PlacedFx pf; diff --git a/toonz/sources/toonzlib/tcolumnfx.cpp b/toonz/sources/toonzlib/tcolumnfx.cpp index 12e532c2..179958e6 100644 --- a/toonz/sources/toonzlib/tcolumnfx.cpp +++ b/toonz/sources/toonzlib/tcolumnfx.cpp @@ -821,15 +821,6 @@ bool TLevelColumnFx::canHandle(const TRenderSettings &info, double frame) { int row = m_levelColumn->getFirstRow(); TXshCell cell = m_levelColumn->getCell(row); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - m_levelColumn->getRange(r0, r1); - for (int r = std::min(r1, row); r >= r0; r--) { - cell = m_levelColumn->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } if (cell.isEmpty()) return true; TXshSimpleLevel *sl = cell.m_level->getSimpleLevel(); @@ -847,15 +838,6 @@ TAffine TLevelColumnFx::handledAffine(const TRenderSettings &info, int row = m_levelColumn->getFirstRow(); TXshCell cell = m_levelColumn->getCell(row); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - m_levelColumn->getRange(r0, r1); - for (int r = std::min(r1, row); r >= r0; r--) { - cell = m_levelColumn->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } if (cell.isEmpty()) return TAffine(); TXshSimpleLevel *sl = cell.m_level->getSimpleLevel(); @@ -893,16 +875,6 @@ TFilePath TLevelColumnFx::getPalettePath(int frame) const { if (!m_levelColumn) return TFilePath(); TXshCell cell = m_levelColumn->getCell(frame); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - m_levelColumn->getRange(r0, r1); - for (int r = std::min(r1, frame); r >= r0; r--) { - cell = m_levelColumn->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } - if (cell.isEmpty()) return TFilePath(); TXshSimpleLevel *sl = cell.m_level->getSimpleLevel(); @@ -924,15 +896,6 @@ TPalette *TLevelColumnFx::getPalette(int frame) const { if (!m_levelColumn) return 0; TXshCell cell = m_levelColumn->getCell(frame); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - m_levelColumn->getRange(r0, r1); - for (int r = std::min(r1, frame); r >= r0; r--) { - cell = m_levelColumn->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } if (cell.isEmpty()) return 0; TXshSimpleLevel *sl = cell.m_level->getSimpleLevel(); @@ -960,15 +923,6 @@ void TLevelColumnFx::doDryCompute(TRectD &rect, double frame, int row = (int)frame; TXshCell cell = m_levelColumn->getCell(row); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - m_levelColumn->getRange(r0, r1); - for (int r = std::min(r1, row); r >= r0; r--) { - cell = m_levelColumn->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } if (cell.isEmpty()) return; TXshSimpleLevel *sl = cell.m_level->getSimpleLevel(); @@ -1019,15 +973,6 @@ void TLevelColumnFx::doCompute(TTile &tile, double frame, // Ensure that a corresponding cell and level exists int row = (int)frame; TXshCell cell = m_levelColumn->getCell(row); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - m_levelColumn->getRange(r0, r1); - for (int r = std::min(r1, row); r >= r0; r--) { - cell = m_levelColumn->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } if (cell.isEmpty()) return; TXshSimpleLevel *sl = cell.m_level->getSimpleLevel(); @@ -1446,15 +1391,6 @@ bool TLevelColumnFx::doGetBBox(double frame, TRectD &bBox, int row = (int)frame; TXshCell cell = m_levelColumn->getCell(row); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - m_levelColumn->getRange(r0, r1); - for (int r = std::min(r1, row); r >= r0; r--) { - cell = m_levelColumn->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } if (cell.isEmpty()) return false; TXshLevelP xshl = cell.m_level; @@ -1487,15 +1423,6 @@ bool TLevelColumnFx::doGetBBox(double frame, TRectD &bBox, dpi = imageInfo.m_dpix / Stage::inch; } else { TXshCell cell = m_levelColumn->getCell(row); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - m_levelColumn->getRange(r0, r1); - for (int r = std::min(r1, row); r >= r0; r--) { - cell = m_levelColumn->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } TImageP img = cell.getImage(false); if (!img) return false; bBox = img->getBBox(); @@ -1532,6 +1459,12 @@ TFxTimeRegion TLevelColumnFx::getTimeRegion() const { int first = m_levelColumn->getFirstRow(); int last = m_levelColumn->getRowCount(); + // For implicit hold, if the last frame is not a stop frame, it's held + // indefinitely + if (Preferences::instance()->isImplicitHoldEnabled() && + !m_levelColumn->getCell(last - 1).getFrameId().isStopFrame()) + return TFxTimeRegion(0, (std::numeric_limits::max)()); + return TFxTimeRegion(first, last); } @@ -1565,15 +1498,6 @@ std::string TLevelColumnFx::getAlias(double frame, if (!m_levelColumn) return std::string(); TXshCell cell = m_levelColumn->getCell((int)frame); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - m_levelColumn->getRange(r0, r1); - for (int r = std::min(r1, (int)frame); r >= r0; r--) { - cell = m_levelColumn->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } if (cell.isEmpty()) return std::string(); TFilePath fp; @@ -1635,15 +1559,6 @@ TAffine TLevelColumnFx::getDpiAff(int frame) { if (!m_levelColumn) return TAffine(); TXshCell cell = m_levelColumn->getCell(frame); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - m_levelColumn->getRange(r0, r1); - for (int r = std::min(r1, frame); r >= r0; r--) { - cell = m_levelColumn->getCell(r); - if (cell.isEmpty()) continue; - break; - } - } if (cell.isEmpty()) return TAffine(); TXshSimpleLevel *sl = cell.m_level->getSimpleLevel(); diff --git a/toonz/sources/toonzlib/txshcolumn.cpp b/toonz/sources/toonzlib/txshcolumn.cpp index 30e59918..e21210ae 100644 --- a/toonz/sources/toonzlib/txshcolumn.cpp +++ b/toonz/sources/toonzlib/txshcolumn.cpp @@ -84,11 +84,34 @@ int TXshCellColumn::getFirstRow() const { return m_first; } //----------------------------------------------------------------------------- -const TXshCell &TXshCellColumn::getCell(int row) const { +const TXshCell &TXshCellColumn::getCell(int row, bool implicitLookup) const { static TXshCell emptyCell; - if (row < 0 || row < m_first || row >= m_first + (int)m_cells.size()) - return emptyCell; - return m_cells[row - m_first]; + + if (row < 0 || row < m_first || !m_cells.size()) return emptyCell; + + bool implicitEnabled = Preferences::instance()->isImplicitHoldEnabled() && + implicitLookup && + getColumnType() != ColumnType::eSoundTextType && + getColumnType() != ColumnType::eSoundType; + + int r = row - m_first; + + if (r >= m_cells.size()) { + if (!implicitEnabled) return emptyCell; + r = m_cells.size() - 1; + if (m_cells[r].getFrameId().isStopFrame()) return emptyCell; + } + + if (m_cells[r].isEmpty() && implicitEnabled) { + for (; r >= 0; r--) { + if (m_cells[r].isEmpty()) continue; + if (m_cells[r].getFrameId().isStopFrame()) return emptyCell; + break; + } + if (r < 0) return emptyCell; + } + + return m_cells[r]; } //----------------------------------------------------------------------------- @@ -99,6 +122,21 @@ bool TXshCellColumn::isCellEmpty(int row) const { //----------------------------------------------------------------------------- +bool TXshCellColumn::isCellImplicit(int row) const { + if (!Preferences::instance()->isImplicitHoldEnabled() || + getColumnType() == ColumnType::eSoundType || + getColumnType() == ColumnType::eSoundTextType || row < 0 || + row < m_first || getCell(row).isEmpty()) + return false; + + // If we got here, the cell is technically not empty + // If it is truely empty in the array, then it is implicit + int r = row - m_first; + return r >= m_cells.size() || m_cells[r].isEmpty(); +} + +//----------------------------------------------------------------------------- + //--- debug only void TXshCellColumn::checkColumn() const { assert(m_first >= 0); @@ -422,10 +460,11 @@ bool TXshCellColumn::getLevelRange(int row, int &r0, int &r1) const { r0 = r1 = row; TXshCell cell = getCell(row); if (cell.isEmpty()) return false; - while (r0 > 0 && + while (r0 > 0 && !isCellImplicit(r0 - 1) && getCell(r0 - 1).m_level.getPointer() == cell.m_level.getPointer()) r0--; - while (getCell(r1 + 1).m_level.getPointer() == cell.m_level.getPointer()) + while (!isCellImplicit(r1 + 1) && + getCell(r1 + 1).m_level.getPointer() == cell.m_level.getPointer()) r1++; return true; } diff --git a/toonz/sources/toonzlib/txsheet.cpp b/toonz/sources/toonzlib/txsheet.cpp index 9040cfad..195aa6cc 100644 --- a/toonz/sources/toonzlib/txsheet.cpp +++ b/toonz/sources/toonzlib/txsheet.cpp @@ -230,11 +230,12 @@ int TXsheet::getFrameCount() const { return m_imp->m_frameCount; } //----------------------------------------------------------------------------- -const TXshCell &TXsheet::getCell(int row, int col) const { - return getCell(CellPosition(row, col)); +const TXshCell &TXsheet::getCell(int row, int col, bool implicitLookup) const { + return getCell(CellPosition(row, col), implicitLookup); } -const TXshCell &TXsheet::getCell(const CellPosition &pos) const { +const TXshCell &TXsheet::getCell(const CellPosition &pos, + bool implicitLookup) const { static const TXshCell emptyCell; TXshColumnP column = m_imp->m_columnSet.getColumn(pos.layer()); @@ -242,22 +243,7 @@ const TXshCell &TXsheet::getCell(const CellPosition &pos) const { TXshCellColumn *xshColumn = column->getCellColumn(); if (!xshColumn) return emptyCell; int frame = pos.frame(); - TXshCell cell = xshColumn->getCell(frame); - if (cell.isEmpty() && Preferences::instance()->isImplicitHoldEnabled()) { - int r0, r1; - xshColumn->getRange(r0, r1); - for (int r = std::min(r1, pos.frame()); r >= r0; r--) { - TXshCell tempCell = xshColumn->getCell(r); - if (tempCell.isEmpty()) continue; - if (tempCell.getSoundLevel() || tempCell.getSoundTextLevel()) - return emptyCell; - if (tempCell.getFrameId().isStopFrame() && cell.isEmpty()) - return emptyCell; - frame = r; - break; - } - } - return xshColumn->getCell(frame); + return xshColumn->getCell(frame, implicitLookup); } //----------------------------------------------------------------------------- @@ -274,17 +260,8 @@ bool TXsheet::isImplicitCell(const CellPosition &pos) const { if (!column) return false; TXshCellColumn *xshColumn = column->getCellColumn(); if (!xshColumn) return false; - TXshCell tempCell = xshColumn->getCell(pos.frame()); - if (!tempCell.isEmpty()) return false; - int r0, r1; - xshColumn->getRange(r0, r1); - for (int r = std::min(r1, pos.frame()); r >= r0; r--) { - tempCell = xshColumn->getCell(r); - if (tempCell.getFrameId().isStopFrame()) return false; - if (!tempCell.isEmpty()) return true; - } - return false; + return xshColumn->isCellImplicit(pos.frame()); } //----------------------------------------------------------------------------- @@ -294,7 +271,7 @@ bool TXsheet::setCell(int row, int col, const TXshCell &cell) { bool wasColumnEmpty = isColumnEmpty(col); TXshCellColumn *cellColumn; - if (!cell.isEmpty() && !isImplicitCell(row, col)) { + if (!cell.isEmpty()) { TXshLevel *level = cell.m_level.getPointer(); assert(level); @@ -678,12 +655,8 @@ void TXsheet::reverseCells(int r0, int c0, int r1, int c1) { for (int j = c0; j <= c1; j++) { int i1, i2; for (i1 = r0, i2 = r1; i1 < i2; i1++, i2--) { - TXshCell app1; - if (!isImplicitCell(CellPosition(i1, j))) - app1 = getCell(CellPosition(i1, j)); - TXshCell app2; - if (!isImplicitCell(CellPosition(i2, j))) - app2 = getCell(CellPosition(i2, j)); + TXshCell app1 = getCell(CellPosition(i1, j), false); + TXshCell app2 = getCell(CellPosition(i2, j), false); setCell(i1, j, app2); setCell(i2, j, app1); } @@ -700,9 +673,7 @@ void TXsheet::swingCells(int r0, int c0, int r1, int c1) { for (int j = c0; j <= c1; j++) { for (int i1 = r0Mod, i2 = r1 - 1; i2 >= r0; i1++, i2--) { - TXshCell cell; - if (!isImplicitCell(CellPosition(i2, j))) - cell = getCell(CellPosition(i2, j)); + TXshCell cell = getCell(CellPosition(i2, j), false); setCell(i1, j, cell); } } @@ -734,7 +705,7 @@ bool TXsheet::incrementCells(int r0, int c0, int r1, int c1, int frame1 = getCell(CellPosition(i, j)).getFrameId().getNumber(); if (frame1 == TFrameId::EMPTY_FRAME || frame1 == TFrameId::STOP_FRAME) break; - while (!getCell(CellPosition(i + 1, j)).isEmpty() && + while ((i + 1 <= r1) && !getCell(CellPosition(i + 1, j)).isEmpty() && !getCell(CellPosition(i + 1, j)).getFrameId().isStopFrame() && getCell(CellPosition(i + 1, j)).getFrameId().getNumber() == getCell(CellPosition(i, j)).getFrameId().getNumber()) @@ -754,9 +725,7 @@ bool TXsheet::incrementCells(int r0, int c0, int r1, int c1, forUndo.push_back(std::pair( TRect(i + 1, j, i + 1 + numCells - 1, j), cell)); for (int k = 1; k <= numCells; k++) { - TXshCell cell; - if (!isImplicitCell(CellPosition(i + k, j))) - cell = getCell(CellPosition(i, j)); + TXshCell cell = getCell(CellPosition(i, j), false); setCell(i + k, j, cell); } i += numCells; @@ -765,9 +734,7 @@ bool TXsheet::incrementCells(int r0, int c0, int r1, int c1, { int numCells = count - frame2 + frame1; i = i - numCells; - TXshCell cell; - if (!isImplicitCell(CellPosition(i + 1, j))) - cell = getCell(CellPosition(i + 1, j)); + TXshCell cell = getCell(CellPosition(i + 1, j), false); forUndo.push_back(std::pair( TRect(i + 1, j, i + 1 + numCells - 1, j), cell)); removeCells(i + 1, j, numCells); @@ -788,9 +755,7 @@ void TXsheet::duplicateCells(int r0, int c0, int r1, int c1, int upTo) { insertCells(r1 + 1, j, upTo - (r1 + 1) + 1); for (int i = r1 + 1; i <= upTo; i++) { int row = r0 + ((i - (r1 + 1)) % chunk); - TXshCell cell; - if (!isImplicitCell(CellPosition(row, j))) - cell = getCell(CellPosition(row, j)); + TXshCell cell = getCell(CellPosition(row, j), false); setCell(i, j, cell); } } @@ -809,8 +774,8 @@ void TXsheet::stepCells(int r0, int c0, int r1, int c1, int type) { int k = 0; for (int r = r0; r <= r1; r++) for (int c = c0; c <= c1; c++) { - const TXshCell &cell = getCell(CellPosition(r, c)); - cells[k++] = isImplicitCell(CellPosition(r, c)) ? TXshCell() : cell; + const TXshCell &cell = getCell(CellPosition(r, c), false); + cells[k++] = cell; } int nrows = nr * (type - 1); @@ -919,8 +884,8 @@ void TXsheet::eachCells(int r0, int c0, int r1, int c1, int type) { j += type) // in cells copio il contenuto delle celle che mi interessano { for (k = c0; k <= c1; k++, i++) { - const TXshCell &cell = getCell(CellPosition(j, k)); - cells[i] = isImplicitCell(j, k) ? TXshCell() : cell; + const TXshCell &cell = getCell(CellPosition(j, k), false); + cells[i] = cell; } } diff --git a/toonz/sources/toonzlib/txshsoundcolumn.cpp b/toonz/sources/toonzlib/txshsoundcolumn.cpp index dd639bc4..09767a01 100644 --- a/toonz/sources/toonzlib/txshsoundcolumn.cpp +++ b/toonz/sources/toonzlib/txshsoundcolumn.cpp @@ -316,7 +316,7 @@ int TXshSoundColumn::getFirstRow() const { //----------------------------------------------------------------------------- -const TXshCell &TXshSoundColumn::getCell(int row) const { +const TXshCell &TXshSoundColumn::getCell(int row, bool implicitLookup) const { static TXshCell emptyCell; ColumnLevel *l = getColumnLevelByFrame(row);