Merge pull request #2953 from manongjohn/fix_numbering_duplicate_frame
Fix Duplicate Frame numbering in Scene Edit mode
This commit is contained in:
commit
a9637a463d
4 changed files with 183 additions and 80 deletions
|
@ -1254,6 +1254,45 @@ public:
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class DuplicateDrawingUndo final : public ToolUtils::TToolUndo {
|
||||
TFrameId origFrameId;
|
||||
TFrameId dupFrameId;
|
||||
|
||||
public:
|
||||
DuplicateDrawingUndo(TXshSimpleLevel *level, const TFrameId &srcFrameId,
|
||||
const TFrameId &tgtFrameId)
|
||||
: TToolUndo(level, tgtFrameId, true) {
|
||||
origFrameId = srcFrameId;
|
||||
dupFrameId = tgtFrameId;
|
||||
}
|
||||
|
||||
~DuplicateDrawingUndo() {}
|
||||
|
||||
void undo() const override {
|
||||
removeLevelAndFrameIfNeeded();
|
||||
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
|
||||
notifyImageChanged();
|
||||
}
|
||||
|
||||
void redo() const override {
|
||||
insertLevelAndFrameIfNeeded();
|
||||
|
||||
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
|
||||
notifyImageChanged();
|
||||
}
|
||||
|
||||
int getSize() const override { return sizeof(*this); }
|
||||
|
||||
QString getHistoryString() override {
|
||||
return QObject::tr("Duplicate Drawing");
|
||||
}
|
||||
|
||||
int getHistoryType() override { return HistoryType::Xsheet; }
|
||||
//-----------------------------------------------------------------------------
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class FillEmptyCellUndo final : public TUndo {
|
||||
TCellSelection *m_selection;
|
||||
TXshCell m_cell;
|
||||
|
@ -1440,7 +1479,7 @@ void TCellSelection::enableCommands() {
|
|||
enableCommand(this, MI_PasteNumbers, &TCellSelection::overwritePasteNumbers);
|
||||
enableCommand(this, MI_CreateBlankDrawing,
|
||||
&TCellSelection::createBlankDrawings);
|
||||
enableCommand(this, MI_Duplicate, &TCellSelection::duplicateFrame);
|
||||
enableCommand(this, MI_Duplicate, &TCellSelection::duplicateFrames);
|
||||
}
|
||||
//-----------------------------------------------------------------------------
|
||||
// Used in RenameCellField::eventFilter()
|
||||
|
@ -1726,7 +1765,7 @@ void TCellSelection::pasteCells() {
|
|||
}
|
||||
TKeyframeSelection selection;
|
||||
if (isEmpty() && TApp::instance()->getCurrentObject()->getObjectId() ==
|
||||
TStageObjectId::CameraId(xsh->getCameraColumnIndex()))
|
||||
TStageObjectId::CameraId(xsh->getCameraColumnIndex()))
|
||||
// Se la selezione e' vuota e l'objectId e' quello della camera sono nella
|
||||
// colonna di camera quindi devo selezionare la row corrente e -1.
|
||||
{
|
||||
|
@ -1938,7 +1977,7 @@ void TCellSelection::pasteKeyframesInto() {
|
|||
|
||||
TKeyframeSelection selection;
|
||||
if (isEmpty() && TApp::instance()->getCurrentObject()->getObjectId() ==
|
||||
TStageObjectId::CameraId(xsh->getCameraColumnIndex()))
|
||||
TStageObjectId::CameraId(xsh->getCameraColumnIndex()))
|
||||
// Se la selezione e' vuota e l'objectId e' quello della camera sono nella
|
||||
// colonna di camera quindi devo selezionare la row corrente e -1.
|
||||
{
|
||||
|
@ -2079,99 +2118,139 @@ void TCellSelection::createBlankDrawings() {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void TCellSelection::duplicateFrame() {
|
||||
if (!Preferences::instance()->isSyncLevelRenumberWithXsheetEnabled()) {
|
||||
DVGui::warning(
|
||||
QObject::tr("Please enable \"Sync Level Strip Drawing Number Changes "
|
||||
"with the XSheet\" preference option\nto use the duplicate "
|
||||
"command in the xsheet / timeline."));
|
||||
return;
|
||||
}
|
||||
|
||||
void TCellSelection::duplicateFrame(int row, int col, bool multiple) {
|
||||
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
|
||||
// TApp::instance()->getCurrentScene()->getScene()->g
|
||||
int r0, c0, r1, c1;
|
||||
getSelectedCells(r0, c0, r1, c1);
|
||||
// check for cases that won't work
|
||||
if (c1 > c0) {
|
||||
DVGui::error(
|
||||
QObject::tr("Please select only one layer to duplicate a frame."));
|
||||
return;
|
||||
}
|
||||
if (r1 > r0) {
|
||||
DVGui::error(QObject::tr("Please select only one frame to duplicate."));
|
||||
|
||||
if (col < 0) {
|
||||
if (!multiple)
|
||||
DVGui::warning(QObject::tr(
|
||||
"There are no drawings in the camera column to duplicate"));
|
||||
return;
|
||||
}
|
||||
|
||||
r0 = TTool::getApplication()->getCurrentFrame()->getFrame();
|
||||
c0 = TTool::getApplication()->getCurrentColumn()->getColumnIndex();
|
||||
TXshColumn *column = xsh->getColumn(col);
|
||||
if (column && column->isLocked()) {
|
||||
if (!multiple) DVGui::warning(QObject::tr("The current column is locked"));
|
||||
return;
|
||||
}
|
||||
|
||||
TXshCell cell = xsh->getCell(r0, c0);
|
||||
TXshCell prevCell = xsh->getCell(r0 - 1, c0);
|
||||
TXshCell nextCell = xsh->getCell(r0 + 1, c0);
|
||||
TFrameId selectedFrameId = cell.getFrameId();
|
||||
TXshSimpleLevel *sl = cell.getSimpleLevel();
|
||||
bool usePreviousCell = false;
|
||||
bool goForward = false;
|
||||
TApp::instance()->getCurrentColumn()->setColumnIndex(col);
|
||||
TApp::instance()->getCurrentFrame()->setCurrentFrame(row + 1);
|
||||
|
||||
// check if we use the current cell to duplicate or the previous cell
|
||||
if (cell.isEmpty()) {
|
||||
if (prevCell.isEmpty() || !(prevCell.m_level->getSimpleLevel())) {
|
||||
TXshLevel *level = TApp::instance()->getCurrentLevel()->getLevel();
|
||||
if (!level && Preferences::instance()->isAutoCreateEnabled() &&
|
||||
Preferences::instance()->isAnimationSheetEnabled()) {
|
||||
int r0, r1;
|
||||
xsh->getCellRange(col, r0, r1);
|
||||
for (int r = std::min(r1, row); r > r0; r--) {
|
||||
TXshCell cell = xsh->getCell(r, col);
|
||||
if (cell.isEmpty()) continue;
|
||||
level = cell.m_level.getPointer();
|
||||
if (!level) continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (level) {
|
||||
int levelType = level->getType();
|
||||
if (levelType == ZERARYFX_XSHLEVEL || levelType == PLT_XSHLEVEL ||
|
||||
levelType == SND_XSHLEVEL || levelType == SND_TXT_XSHLEVEL ||
|
||||
levelType == MESH_XSHLEVEL) {
|
||||
if (!multiple)
|
||||
DVGui::warning(
|
||||
QObject::tr("Cannot duplicate a drawing in the current column"));
|
||||
return;
|
||||
} else if (level->getSimpleLevel() &&
|
||||
level->getSimpleLevel()->isReadOnly()) {
|
||||
if (!multiple)
|
||||
DVGui::warning(QObject::tr("The current level is not editable"));
|
||||
return;
|
||||
}
|
||||
usePreviousCell = true;
|
||||
selectedFrameId = prevCell.getFrameId();
|
||||
sl = prevCell.getSimpleLevel();
|
||||
}
|
||||
|
||||
TXshCell targetCell = xsh->getCell(row, col);
|
||||
TXshCell prevCell = xsh->getCell(row - 1, col);
|
||||
;
|
||||
|
||||
// check if we use the current cell to duplicate or the previous cell
|
||||
if (!targetCell.isEmpty() && targetCell != prevCell) {
|
||||
// Current cell has a drawing to duplicate and it's not a hold shift focus
|
||||
// to next cell as if they selected that one to duplicate into
|
||||
prevCell = targetCell;
|
||||
TApp::instance()->getCurrentFrame()->setCurrentFrame(row + 2);
|
||||
row++;
|
||||
}
|
||||
|
||||
if (prevCell.isEmpty() || !(prevCell.m_level->getSimpleLevel())) return;
|
||||
|
||||
TXshSimpleLevel *sl = prevCell.getSimpleLevel();
|
||||
if (!sl || sl->isSubsequence() || sl->isReadOnly()) return;
|
||||
|
||||
// check whether to change the next cell or replace the current cell if it is
|
||||
// a hold from a previous frame
|
||||
if (!usePreviousCell) {
|
||||
// use the current cell
|
||||
if (prevCell.m_level == cell.m_level &&
|
||||
prevCell.m_frameId == cell.m_frameId) {
|
||||
// the current frame is a hold from a previous frame
|
||||
// change this frame and any sequential frames part of the same hold
|
||||
bool hold = true;
|
||||
r1 = r0 + 1;
|
||||
while (hold) {
|
||||
TXshCell testCell = xsh->getCell(r1, c0);
|
||||
if (testCell.m_frameId == cell.m_frameId &&
|
||||
testCell.m_level == cell.m_level) {
|
||||
r1 += 1;
|
||||
} else {
|
||||
r1 -= 1;
|
||||
hold = false;
|
||||
}
|
||||
}
|
||||
ToolHandle *toolHandle = TApp::instance()->getCurrentTool();
|
||||
|
||||
} else {
|
||||
// This is not part of a hold, use the next cell.
|
||||
// make sure we are not going to overwrite a non-empty cell
|
||||
if (nextCell.isEmpty()) {
|
||||
r0 += 1;
|
||||
cell = nextCell;
|
||||
goForward = true;
|
||||
} else
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// cell = prevCell;
|
||||
// If autocreate disabled, let's turn it on temporarily
|
||||
bool isAutoCreateEnabled = Preferences::instance()->isAutoCreateEnabled();
|
||||
if (!isAutoCreateEnabled)
|
||||
Preferences::instance()->setValue(AutocreationType, 1, false);
|
||||
|
||||
TImage *img = toolHandle->getTool()->touchImage();
|
||||
if (!img) {
|
||||
if (!isAutoCreateEnabled)
|
||||
Preferences::instance()->setValue(AutocreationType, 0, false);
|
||||
if (!multiple)
|
||||
DVGui::warning(
|
||||
QObject::tr("Unable to duplicate a drawing on the current column"));
|
||||
return;
|
||||
}
|
||||
|
||||
bool frameCreated = toolHandle->getTool()->m_isFrameCreated;
|
||||
if (!frameCreated) {
|
||||
if (!multiple)
|
||||
DVGui::warning(QObject::tr(
|
||||
"Unable to replace the current or next drawing with a duplicate drawing"));
|
||||
return;
|
||||
}
|
||||
|
||||
targetCell = xsh->getCell(row, col);
|
||||
TPalette *palette = sl->getPalette();
|
||||
TFrameId srcFrame = prevCell.getFrameId();
|
||||
TFrameId targetFrame = targetCell.getFrameId();
|
||||
std::set<TFrameId> frames;
|
||||
frames.insert(selectedFrameId);
|
||||
TUndoManager::manager()->beginBlock();
|
||||
FilmstripCmd::duplicate(sl, frames, true);
|
||||
TXshCell newCell;
|
||||
newCell.m_level = sl;
|
||||
newCell.m_frameId = selectedFrameId + 1;
|
||||
DuplicateInXSheetUndo *undo =
|
||||
new DuplicateInXSheetUndo(r0, r1, c0, cell, newCell, goForward);
|
||||
|
||||
FilmstripCmd::duplicateFrameWithoutUndo(sl, srcFrame, targetFrame);
|
||||
|
||||
TApp::instance()->getCurrentLevel()->notifyLevelChange();
|
||||
|
||||
DuplicateDrawingUndo *undo =
|
||||
new DuplicateDrawingUndo(sl, srcFrame, targetFrame);
|
||||
TUndoManager::manager()->add(undo);
|
||||
|
||||
if (!isAutoCreateEnabled)
|
||||
Preferences::instance()->setValue(AutocreationType, 0, false);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void TCellSelection::duplicateFrames() {
|
||||
int col = TApp::instance()->getCurrentColumn()->getColumnIndex();
|
||||
int row = TApp::instance()->getCurrentFrame()->getFrameIndex();
|
||||
|
||||
int r0, c0, r1, c1;
|
||||
getSelectedCells(r0, c0, r1, c1);
|
||||
|
||||
bool multiple = (r1 - r0 > 1) || (c1 - c0 > 1);
|
||||
|
||||
TUndoManager::manager()->beginBlock();
|
||||
for (int c = c0; c <= c1; c++) {
|
||||
for (int r = r0; r <= r1; r++) {
|
||||
duplicateFrame(r, c, multiple);
|
||||
}
|
||||
}
|
||||
TUndoManager::manager()->endBlock();
|
||||
undo->redo();
|
||||
|
||||
if (multiple) {
|
||||
TApp::instance()->getCurrentColumn()->setColumnIndex(col);
|
||||
TApp::instance()->getCurrentFrame()->setCurrentFrame(row + 1);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -113,7 +113,8 @@ public:
|
|||
void convertVectortoVector();
|
||||
|
||||
void reframeWithEmptyInbetweens();
|
||||
void duplicateFrame();
|
||||
void duplicateFrame(int row, int col, bool multiple);
|
||||
void duplicateFrames();
|
||||
|
||||
void renameCells(TXshCell &cell);
|
||||
// rename cells for each columns with correspondent item in the list
|
||||
|
|
|
@ -2226,6 +2226,27 @@ public:
|
|||
// duplicate
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void FilmstripCmd::duplicateFrameWithoutUndo(TXshSimpleLevel *sl,
|
||||
TFrameId srcFrame,
|
||||
TFrameId targetFrame) {
|
||||
if (srcFrame.isNoFrame() || targetFrame.isNoFrame()) return;
|
||||
if (srcFrame.isEmptyFrame()) return;
|
||||
|
||||
std::set<TFrameId> frames;
|
||||
|
||||
frames.insert(srcFrame);
|
||||
DrawingData *data = new DrawingData();
|
||||
data->setLevelFrames(sl, frames);
|
||||
|
||||
frames.clear();
|
||||
frames.insert(targetFrame);
|
||||
|
||||
bool keepOriginalPalette = true;
|
||||
|
||||
pasteFramesWithoutUndo(data, sl, frames, DrawingData::OVER_SELECTION, true,
|
||||
keepOriginalPalette);
|
||||
}
|
||||
|
||||
void FilmstripCmd::duplicate(TXshSimpleLevel *sl, std::set<TFrameId> &frames,
|
||||
bool withUndo) {
|
||||
if (frames.empty() || !sl || sl->isSubsequence() || sl->isReadOnly()) return;
|
||||
|
|
|
@ -40,6 +40,8 @@ void swing(TXshSimpleLevel *sl, std::set<TFrameId> &frames);
|
|||
void step(TXshSimpleLevel *sl, std::set<TFrameId> &frames, int step);
|
||||
void each(TXshSimpleLevel *sl, std::set<TFrameId> &frames, int each);
|
||||
|
||||
void duplicateFrameWithoutUndo(TXshSimpleLevel *sl, TFrameId srcFrame,
|
||||
TFrameId targetFrame);
|
||||
void duplicate(TXshSimpleLevel *sl, std::set<TFrameId> &frames, bool withUndo);
|
||||
|
||||
// TODO vanno spostati in un altro posto
|
||||
|
|
Loading…
Reference in a new issue