diff --git a/toonz/sources/toonz/cellselection.cpp b/toonz/sources/toonz/cellselection.cpp index 77f3109..381e800 100644 --- a/toonz/sources/toonz/cellselection.cpp +++ b/toonz/sources/toonz/cellselection.cpp @@ -1210,6 +1210,47 @@ public: }; //----------------------------------------------------------------------------- + +class FillEmptyCellUndo final : public TUndo { + TCellSelection *m_selection; + TXshCell m_cell; + +public: + FillEmptyCellUndo(int r0, int r1, int c, TXshCell &cell) : m_cell(cell) { + m_selection = new TCellSelection(); + m_selection->selectCells(r0, c, r1, c); + } + + ~FillEmptyCellUndo() { delete m_selection; } + + void undo() const override { + int r0, c0, r1, c1; + m_selection->getSelectedCells(r0, c0, r1, c1); + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + for (int c = c0; c <= c1; c++) { + xsh->clearCells(r0, c, r1 - r0 + 1); + } + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); + } + + void redo() const override { + int r0, c0, r1, c1; + m_selection->getSelectedCells(r0, c0, r1, c1); + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + for (int i = r0; i <= r1; i++) xsh->setCell(i, c0, m_cell); + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); + } + + int getSize() const override { return sizeof(*this); } + + QString getHistoryString() override { + return QObject::tr("Fill In Empty Cells"); + } + + int getHistoryType() override { return HistoryType::Xsheet; } + //----------------------------------------------------------------------------- +}; + } // namespace //----------------------------------------------------------------------------- @@ -1281,6 +1322,7 @@ void TCellSelection::enableCommands() { enableCommand(this, MI_PasteInto, &TCellSelection::overWritePasteCells); + enableCommand(this, MI_FillEmptyCell, &TCellSelection::fillEmptyCell); enableCommand(this, MI_Reframe1, &TCellSelection::reframe1Cells); enableCommand(this, MI_Reframe2, &TCellSelection::reframe2Cells); enableCommand(this, MI_Reframe3, &TCellSelection::reframe3Cells); @@ -1333,7 +1375,8 @@ bool TCellSelection::isEnabledCommand( MI_Redo, MI_PasteNumbers, MI_ConvertToToonzRaster, - MI_ConvertVectorToVector}; + MI_ConvertVectorToVector, + MI_FillEmptyCell}; return commands.contains(commandId); } @@ -2785,4 +2828,65 @@ void TCellSelection::convertVectortoVector() { app->getCurrentTool()->onImageChanged( (TImage::Type)app->getCurrentImageType()); +} + +void TCellSelection::fillEmptyCell() { + if (isEmpty()) return; + + // set up basics + bool initUndo = false; + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + int r, r0, c0, c, r1, c1; + + getSelectedCells(r0, c0, r1, c1); + + for (c = c0; c <= c1; c++) { + TXshColumn *column = xsh->getColumn(c); + if (!column || column->isEmpty() || column->isLocked() || + column->getSoundColumn()) + continue; + + for (r = r1; r >= r0; r--) { + int fillCount = 0; + TXshCell cell = xsh->getCell(r, c); + + if (cell.isEmpty()) fillCount++; + + int prevR = r - 1; + while (prevR >= 0) { + cell = xsh->getCell(prevR, c); + if (!cell.isEmpty()) break; + + prevR--; + fillCount++; + } + + // We've gone past the beginning of timeline without finding a cell. + // Do nothing, and end current column processing immediately. + if (prevR < 0) break; + + // Adjacent cell is filled. Move to next one. + if (!fillCount) continue; + + // Ok, time fill + int startR = prevR + 1; + int endR = startR + fillCount - 1; + + if (!initUndo) { + initUndo = true; + TUndoManager::manager()->beginBlock(); + } + + FillEmptyCellUndo *undo = new FillEmptyCellUndo(startR, endR, c, cell); + TUndoManager::manager()->add(undo); + undo->redo(); + + // Let's skip cells we just filled + r = prevR; + } + } + + if (initUndo) TUndoManager::manager()->endBlock(); + + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); } \ No newline at end of file diff --git a/toonz/sources/toonz/cellselection.h b/toonz/sources/toonz/cellselection.h index dad866c..6adf8d2 100644 --- a/toonz/sources/toonz/cellselection.h +++ b/toonz/sources/toonz/cellselection.h @@ -115,6 +115,8 @@ public: void renameMultiCells(QList &cells); static bool isEnabledCommand(std::string commandId); + + void fillEmptyCell(); }; #endif // TCELLSELECTION_H diff --git a/toonz/sources/toonz/mainwindow.cpp b/toonz/sources/toonz/mainwindow.cpp index 46a04d3..ac6f2cb 100644 --- a/toonz/sources/toonz/mainwindow.cpp +++ b/toonz/sources/toonz/mainwindow.cpp @@ -1899,6 +1899,7 @@ void MainWindow::defineActions() { tr("Reframe with Empty Inbetweens..."), ""); createMenuCellsAction(MI_AutoInputCellNumber, tr("Auto Input Cell Number..."), ""); + createMenuCellsAction(MI_FillEmptyCell, tr("&Fill In Empty Cells"), ""); createRightClickMenuAction(MI_SetKeyframes, tr("&Set Key"), "Z"); createRightClickMenuAction(MI_PasteNumbers, tr("&Paste Numbers"), ""); diff --git a/toonz/sources/toonz/menubar.cpp b/toonz/sources/toonz/menubar.cpp index 2de2024..a353626 100644 --- a/toonz/sources/toonz/menubar.cpp +++ b/toonz/sources/toonz/menubar.cpp @@ -1285,6 +1285,7 @@ QMenuBar *StackedMenuBar::createFullMenuBar() { addMenuItem(cellsMenu, MI_Rollup); addMenuItem(cellsMenu, MI_Rolldown); addMenuItem(cellsMenu, MI_TimeStretch); + addMenuItem(cellsMenu, MI_FillEmptyCell); cellsMenu->addSeparator(); addMenuItem(cellsMenu, MI_DrawingSubForward); addMenuItem(cellsMenu, MI_DrawingSubBackward); diff --git a/toonz/sources/toonz/menubarcommandids.h b/toonz/sources/toonz/menubarcommandids.h index 92e4dc4..9b2bf5d 100644 --- a/toonz/sources/toonz/menubarcommandids.h +++ b/toonz/sources/toonz/menubarcommandids.h @@ -146,6 +146,7 @@ #define MI_PasteNew "MI_PasteNew" #define MI_Autorenumber "MI_Autorenumber" +#define MI_FillEmptyCell "MI_FillEmptyCell" #define MI_MergeFrames "MI_MergeFrames" #define MI_Reverse "MI_Reverse" diff --git a/toonz/sources/toonz/xshcellviewer.cpp b/toonz/sources/toonz/xshcellviewer.cpp index 1abe4a9..5508a4a 100644 --- a/toonz/sources/toonz/xshcellviewer.cpp +++ b/toonz/sources/toonz/xshcellviewer.cpp @@ -3033,6 +3033,7 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected) { cmdManager->getAction(MI_AutoInputCellNumber)); } menu.addMenu(editCellNumbersMenu); + menu.addAction(cmdManager->getAction(MI_FillEmptyCell)); menu.addSeparator(); menu.addAction(cmdManager->getAction(MI_Autorenumber)); @@ -3130,6 +3131,8 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected) { (TApp::instance()->getCurrentLevel()->getLevel() && TApp::instance()->getCurrentLevel()->getLevel()->getChildLevel())) menu.addAction(cmdManager->getAction(MI_LipSyncPopup)); + } else { + menu.addAction(cmdManager->getAction(MI_FillEmptyCell)); } menu.addSeparator(); if (!soundCellsSelected)