fix scene cast to update on pasting

This commit is contained in:
shun-iwasawa 2021-03-04 16:57:24 +09:00 committed by manongjohn
parent 8714c53942
commit 39b7fccea7
13 changed files with 313 additions and 1 deletions

View file

@ -156,6 +156,7 @@ signals:
void doCollapse(const QList<TFxP> &);
void doExplodeChild(const QList<TFxP> &);
void doDelete();
void columnPasted(const QList<TXshColumnP> &);
};
#endif

View file

@ -5,6 +5,7 @@
// TnzLib includes
#include "toonz/tstageobjectid.h"
#include "toonz/txshcolumn.h"
// TnzBase includes
#include "tfx.h"
@ -571,6 +572,7 @@ signals:
void doDeleteFxs(const FxSelection *);
void doDeleteStageObjects(const StageObjectSelection *);
void columnPasted(const QList<TXshColumnP> &);
protected slots:
void onSceneChanged();

View file

@ -174,6 +174,7 @@ set(HEADERS
../include/orientation.h
../include/saveloadqsettings.h
xdtsio.h
levelcommand.h
# Tracker file
ObjectTracker.h
dummyprocessor.h

View file

@ -13,6 +13,7 @@
#include "timestretchpopup.h"
#include "tapp.h"
#include "xsheetviewer.h"
#include "levelcommand.h"
// TnzTools includes
#include "tools/toolutils.h"
@ -1512,6 +1513,26 @@ public:
//-----------------------------------------------------------------------------
};
//-----------------------------------------------------------------------------
// obtain level set contained in the cellData
// it is used for checking and updating the scene cast when pasting
void getLevelSetFromData(const TCellData *cellData,
std::set<TXshLevel *> &levelSet) {
for (int c = 0; c < cellData->getCellCount(); c++) {
TXshCell cell = cellData->getCell(c);
if (cell.isEmpty()) continue;
TXshLevelP tmpLevel = cell.m_level;
if (levelSet.count(tmpLevel.getPointer()) == 0) {
// gather levels in subxsheet
if (tmpLevel->getChildLevel()) {
TXsheet *childXsh = tmpLevel->getChildLevel()->getXsheet();
childXsh->getUsedLevels(levelSet);
}
levelSet.insert(tmpLevel.getPointer());
}
}
}
} // namespace
//-----------------------------------------------------------------------------
@ -1886,8 +1907,16 @@ void TCellSelection::pasteCells() {
(newCr0 == r0 && newCr1 == r1));
}
if (!isPaste) return;
initUndo = true;
TUndoManager::manager()->beginBlock();
// make sure that the pasting levels are registered in the scene cast
// it may rename the level if there is another level with the same name
std::set<TXshLevel *> pastedLevels;
getLevelSetFromData(cellData, pastedLevels);
LevelCmd::addMissingLevelsToCast(pastedLevels);
TUndoManager::manager()->add(new PasteCellsUndo(
r0, c0, r1, c1, oldR0, oldC0, oldR1, oldC1, areColumnsEmpty));
TApp::instance()->getCurrentScene()->setDirtyFlag(true);
@ -2490,6 +2519,12 @@ void TCellSelection::pasteDuplicateCells() {
return;
}
// make sure that the pasting levels are registered in the scene cast
// it may rename the level if there is another level with the same name
std::set<TXshLevel *> pastedLevels;
getLevelSetFromData(newCellData, pastedLevels);
LevelCmd::addMissingLevelsToCast(pastedLevels);
TUndoManager::manager()->add(new PasteCellsUndo(
r0, c0, r1, c1, oldR0, oldC0, oldR1, oldC1, areColumnsEmpty));
TApp::instance()->getCurrentScene()->setDirtyFlag(true);
@ -3353,10 +3388,19 @@ void TCellSelection::overWritePasteCells() {
areColumnsEmpty.push_back(!column || column->isEmpty() ||
(newCr0 == r0 && newCr1 == r1));
}
TUndoManager::manager()->beginBlock();
// make sure that the pasting levels are registered in the scene cast
// it may rename the level if there is another level with the same name
std::set<TXshLevel *> pastedLevels;
getLevelSetFromData(cellData, pastedLevels);
LevelCmd::addMissingLevelsToCast(pastedLevels);
/*-- r0,c0,r1,c1はペーストされた範囲 old付きはペースト前の選択範囲 --*/
TUndoManager::manager()->add(
new OverwritePasteCellsUndo(r0, c0, r1, c1, oldR0, oldC0, oldR1, oldC1,
areColumnsEmpty, beforeData));
TUndoManager::manager()->endBlock();
TApp::instance()->getCurrentScene()->setDirtyFlag(true);
delete beforeData;

View file

@ -7,6 +7,7 @@
#include "menubarcommandids.h"
#include "columncommand.h"
#include "tapp.h"
#include "levelcommand.h"
// TnzLib includes
#include "toonz/txsheethandle.h"
@ -19,10 +20,48 @@
#include "toonz/levelproperties.h"
#include "orientation.h"
#include "toonz/preferences.h"
#include "toonz/txshchildlevel.h"
// TnzCore includes
#include "tvectorimage.h"
#include "ttoonzimage.h"
#include "tundo.h"
namespace {
// obtain level set contained in the column specified by indices
// it is used for checking and updating the scene cast when pasting
// based on TXsheet::getUsedLevels
void getLevelSetFromColumnIndices(const std::set<int>& indices,
std::set<TXshLevel*>& levelSet) {
TXsheet* xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
for (auto c : indices) {
TXshColumnP column = const_cast<TXsheet*>(xsh)->getColumn(c);
if (!column) continue;
TXshCellColumn* cellColumn = column->getCellColumn();
if (!cellColumn) continue;
int r0, r1;
if (!cellColumn->getRange(r0, r1)) continue;
TXshLevel* level = 0;
for (int r = r0; r <= r1; r++) {
TXshCell cell = cellColumn->getCell(r);
if (cell.isEmpty() || !cell.m_level) continue;
if (level != cell.m_level.getPointer()) {
level = cell.m_level.getPointer();
levelSet.insert(level);
if (level->getChildLevel()) {
TXsheet* childXsh = level->getChildLevel()->getXsheet();
childXsh->getUsedLevels(levelSet);
}
}
}
}
}
} // namespace
//=============================================================================
// TColumnSelection
@ -78,7 +117,21 @@ void TColumnSelection::pasteColumnsBelow() {
return;
else
indices.insert(*m_indices.begin());
TUndoManager::manager()->beginBlock();
ColumnCmd::pasteColumns(indices);
if (!indices.empty()) {
// make sure that the levels contained in the pasted columns are registered
// in the scene cast it may rename the level if there is another level with
// the same name
std::set<TXshLevel*> pastedLevels;
getLevelSetFromColumnIndices(indices, pastedLevels);
LevelCmd::addMissingLevelsToCast(pastedLevels);
}
TUndoManager::manager()->endBlock();
}
//-----------------------------------------------------------------------------
@ -90,7 +143,21 @@ void TColumnSelection::pasteColumns() {
indices.insert(xsh->getFirstFreeColumnIndex());
} else
indices.insert(*m_indices.rbegin() + 1);
TUndoManager::manager()->beginBlock();
ColumnCmd::pasteColumns(indices);
if (!indices.empty()) {
// make sure that the levels contained in the pasted columns are registered
// in the scene cast it may rename the level if there is another level with
// the same name
std::set<TXshLevel*> pastedLevels;
getLevelSetFromColumnIndices(indices, pastedLevels);
LevelCmd::addMissingLevelsToCast(pastedLevels);
}
TUndoManager::manager()->endBlock();
}
//-----------------------------------------------------------------------------

View file

@ -1,5 +1,6 @@
#include "levelcommand.h"
#include "toonzqt/menubarcommand.h"
#include "menubarcommandids.h"
#include "tapp.h"
@ -19,6 +20,7 @@
#include "toonz/levelset.h"
#include "toonz/txshcell.h"
#include "toonz/childstack.h"
#include "toonz/txshchildlevel.h"
#include "toonzqt/dvdialog.h"
#include "toonzqt/icongenerator.h"
@ -30,6 +32,7 @@
#include "tsystem.h"
#include "toonzqt/gutil.h"
#include "toonz/namebuilder.h"
namespace {
@ -426,3 +429,119 @@ public:
void execute() override { revertTo(false); }
} revertToLastSaveCommand;
//-----------------------------------------------------------------------------
namespace {
class addLevelToCastUndo final : public TUndo {
TXshLevelP m_xl;
std::wstring m_newName, m_oldName;
public:
addLevelToCastUndo(TXshLevel *xl, const std::wstring newName = L"",
const std::wstring oldName = L"")
: m_xl(xl), m_newName(newName), m_oldName(oldName) {}
void undo() const override {
TLevelSet *levelSet =
TApp::instance()->getCurrentScene()->getScene()->getLevelSet();
levelSet->removeLevel(m_xl.getPointer());
if (m_oldName != L"") m_xl->setName(m_oldName);
if (m_isLastInBlock)
TApp::instance()->getCurrentScene()->notifyCastChange();
}
void redo() const override {
TLevelSet *levelSet =
TApp::instance()->getCurrentScene()->getScene()->getLevelSet();
if (m_newName != L"") m_xl->setName(m_newName);
levelSet->insertLevel(m_xl.getPointer());
if (m_isLastInRedoBlock)
TApp::instance()->getCurrentScene()->notifyCastChange();
}
int getSize() const override { return sizeof *this + 100; }
QString getHistoryString() override {
return QObject::tr("Add Level to Scene Cast : %1")
.arg(QString::fromStdWString(m_xl->getName()));
}
};
}; // namespace
void LevelCmd::addMissingLevelsToCast(const QList<TXshColumnP> &columns) {
// make sure that the levels contained in the pasted columns are registered in
// the scene cast it may rename the level if there is another level with the
// same name
std::set<TXshLevel *> levels;
// obtain level set contained in the specified columns
// it is used for checking and updating the scene cast when pasting
// based on TXsheet::getUsedLevels
for (auto column : columns) {
if (!column) continue;
TXshCellColumn *cellColumn = column->getCellColumn();
if (!cellColumn) continue;
int r0, r1;
if (!cellColumn->getRange(r0, r1)) continue;
TXshLevel *level = 0;
for (int r = r0; r <= r1; r++) {
TXshCell cell = cellColumn->getCell(r);
if (cell.isEmpty() || !cell.m_level) continue;
if (level != cell.m_level.getPointer()) {
level = cell.m_level.getPointer();
levels.insert(level);
if (level->getChildLevel()) {
TXsheet *childXsh = level->getChildLevel()->getXsheet();
childXsh->getUsedLevels(levels);
}
}
}
}
LevelCmd::addMissingLevelsToCast(levels);
}
void LevelCmd::addMissingLevelsToCast(std::set<TXshLevel *> &levels) {
if (levels.empty()) return;
TUndoManager::manager()->beginBlock();
TLevelSet *levelSet =
TApp::instance()->getCurrentScene()->getScene()->getLevelSet();
bool castChanged = false;
// for each level
for (auto level : levels) {
std::wstring levelName = level->getName();
// search by level name
if (TXshLevel *levelInCast = levelSet->getLevel(levelName)) {
// continue if it is the same level. This should be in most cases
if (level == levelInCast) continue;
// if the the name is occupied by another level, then rename and register
// it
std::wstring oldName = levelName;
NameModifier nm(levelName);
levelName = nm.getNext();
while (levelSet->hasLevel(levelName)) levelName = nm.getNext();
addLevelToCastUndo *undo =
new addLevelToCastUndo(level, levelName, oldName);
undo->m_isLastInRedoBlock = false; // prevent to emit signal
undo->redo();
TUndoManager::manager()->add(undo);
castChanged = true;
}
// if not found
else {
// register the level
addLevelToCastUndo *undo = new addLevelToCastUndo(level);
undo->redo();
TUndoManager::manager()->add(undo);
castChanged = true;
}
}
TUndoManager::manager()->endBlock();
if (castChanged) TApp::instance()->getCurrentScene()->notifyCastChange();
}

View file

@ -0,0 +1,18 @@
#pragma once
#ifndef LEVELCOMMAND_H
#define LEVELCOMMAND_H
#include "toonz/txshcolumn.h"
#include <set>
#include <QList>
class TXshLevel;
namespace LevelCmd {
void addMissingLevelsToCast(const QList<TXshColumnP>& columns);
void addMissingLevelsToCast(std::set<TXshLevel*>& levels);
} // namespace LevelCmd
#endif

View file

@ -37,6 +37,7 @@
#include "tapp.h"
#include "mainwindow.h"
#include "columncommand.h"
#include "levelcommand.h"
// TnzTools includes
#include "tools/tooloptions.h"
@ -262,6 +263,12 @@ void SchematicScenePanel::onDeleteStageObjects(
//-----------------------------------------------------------------------------
void SchematicScenePanel::onColumnPaste(const QList<TXshColumnP> &columns) {
LevelCmd::addMissingLevelsToCast(columns);
}
//-----------------------------------------------------------------------------
void SchematicScenePanel::showEvent(QShowEvent *e) {
if (m_schematicViewer->isStageSchematicViewed())
setWindowTitle(QObject::tr("Stage Schematic"));
@ -295,6 +302,8 @@ void SchematicScenePanel::showEvent(QShowEvent *e) {
SLOT(updateSchematic()));
connect(app->getCurrentScene(), SIGNAL(sceneSwitched()), m_schematicViewer,
SLOT(onSceneSwitched()));
connect(m_schematicViewer, SIGNAL(columnPasted(const QList<TXshColumnP> &)),
this, SLOT(onColumnPaste(const QList<TXshColumnP> &)));
m_schematicViewer->updateSchematic();
}
@ -324,6 +333,9 @@ void SchematicScenePanel::hideEvent(QHideEvent *e) {
m_schematicViewer, SLOT(updateSchematic()));
disconnect(app->getCurrentScene(), SIGNAL(sceneSwitched()), m_schematicViewer,
SLOT(onSceneSwitched()));
disconnect(m_schematicViewer,
SIGNAL(columnPasted(const QList<TXshColumnP> &)), this,
SLOT(onColumnPaste(const QList<TXshColumnP> &)));
}
//=============================================================================

View file

@ -191,6 +191,7 @@ protected slots:
void onEditObject();
void onDeleteFxs(const FxSelection *);
void onDeleteStageObjects(const StageObjectSelection *);
void onColumnPaste(const QList<TXshColumnP> &);
};
//=========================================================

View file

@ -211,10 +211,22 @@ void FxSelection::pasteSelection() {
TPointD(ssv->getOldScenePos().x(), ssv->getOldScenePos().y());
}
if (!columns.isEmpty()) {
// make sure that the levels contained in the pasted column nodes are
// registered in the scene cast it may rename the level if there is
// another level with the same name
TUndoManager::manager()->beginBlock();
emit columnPasted(columns);
}
TFxCommand::pasteFxs(fxs.toStdList(), zeraryFxColumnSize.toStdMap(),
columns.toStdList(), m_pastePosition, m_xshHandle,
m_fxHandle);
if (!columns.isEmpty()) {
TUndoManager::manager()->endBlock();
}
if (m_schematicScene) {
selectNone();
for (int i = 0; i < (int)fxs.size(); i++) select(fxs[i]);
@ -263,6 +275,10 @@ bool FxSelection::insertPasteSelection() {
if (!auto_.m_destruct) {
auto_.m_destruct = true;
TUndoManager::manager()->beginBlock();
// make sure that the levels contained in the pasted column nodes are
// registered in the scene cast it may rename the level if there is
// another level with the same name
emit columnPasted(columns);
}
TFxCommand::insertPasteFxs(selectedLinks[i], fxs.toStdList(),
@ -349,8 +365,13 @@ bool FxSelection::replacePasteSelection() {
if (fxs.empty() && columns.empty()) return true;
// auto ends the undo block in its destructor
if (!auto_.m_destruct)
if (!auto_.m_destruct) {
auto_.m_destruct = true, TUndoManager::manager()->beginBlock();
// make sure that the levels contained in the pasted column nodes are
// registered in the scene cast it may rename the level if there is
// another level with the same name
emit columnPasted(columns);
}
TFx *inFx = m_selectedFxs[i].getPointer();
TFxCommand::replacePasteFxs(inFx, fxs.toStdList(),

View file

@ -800,6 +800,13 @@ SchematicViewer::SchematicViewer(QWidget *parent)
connect(m_stageScene->getStageSelection(), SIGNAL(doDelete()), this,
SLOT(deleteStageObjects()));
connect(m_fxScene->getFxSelection(),
SIGNAL(columnPasted(const QList<TXshColumnP> &)), this,
SIGNAL(columnPasted(const QList<TXshColumnP> &)));
connect(m_stageScene->getStageSelection(),
SIGNAL(columnPasted(const QList<TXshColumnP> &)), this,
SIGNAL(columnPasted(const QList<TXshColumnP> &)));
m_viewer->setScene(m_stageScene);
m_fxToolbar->hide();

View file

@ -365,6 +365,21 @@ void StageObjectSelection::pasteSelection() {
std::vector<TStageObjectId> ids = objData->restoreObjects(
indexes, restoredSplineIds, m_xshHandle->getXsheet(),
StageObjectsData::eDoClone, m_pastePosition);
// make sure that the levels contained in the pasted column nodes are
// registered in the scene cast it may rename the level if there is another
// level with the same name
QList<TXshColumnP> pastedColumns;
for (auto c : indexes) {
TXshColumnP column = m_xshHandle->getXsheet()->getColumn(c);
if (!column || column->isEmpty()) continue;
pastedColumns.append(column);
}
if (!pastedColumns.isEmpty()) {
TUndoManager::manager()->beginBlock();
emit columnPasted(pastedColumns);
}
StageObjectsData *undoData = new StageObjectsData();
undoData->storeObjects(ids, m_xshHandle->getXsheet(), 0);
undoData->storeColumnFxs(indexes, m_xshHandle->getXsheet(), 0);
@ -374,6 +389,8 @@ void StageObjectSelection::pasteSelection() {
m_objHandle, m_fxHandle));
m_xshHandle->notifyXsheetChanged();
m_pastePosition = TConst::nowhere;
if (!pastedColumns.isEmpty()) TUndoManager::manager()->endBlock();
}
//-------------------------------------------------------

View file

@ -5,6 +5,7 @@
#include "toonzqt/selection.h"
#include "toonz/tstageobjectid.h"
#include "toonz/txshcolumn.h"
#include "tgeometry.h"
#include <QList>
#include <QPair>
@ -98,6 +99,7 @@ signals:
void doCollapse(QList<TStageObjectId>);
void doExplodeChild(QList<TStageObjectId>);
void doDelete();
void columnPasted(const QList<TXshColumnP> &);
};
#endif