Merge pull request #875 from manongjohn/implicit_hold_fixes_2

Implicit hold fixes 2
This commit is contained in:
manongjohn 2022-01-28 07:47:51 -05:00 committed by GitHub
commit d4ab9b4c7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 399 additions and 258 deletions

View file

@ -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.

View file

@ -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;

View file

@ -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;

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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;
}
}
}

View file

@ -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);

View file

@ -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<int> 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<TXshSimpleLevel *, TXshLevelP>::iterator lt =
m_insertedLevels.find(srcSl);

View file

@ -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<int, int> cellId(r, c);

View file

@ -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");

View file

@ -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();

View file

@ -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"

View file

@ -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

View file

@ -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;
}
}

View file

@ -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++;
}
}

View file

@ -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);
}
}

View file

@ -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<std::pair<int, TXshCell>> m_oldCells;
std::vector<int> m_columns;
int m_frame;
public:
SetGlobalStopframeUndo(int frame, const std::vector<int> &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<int, TXshCell> cellData = m_oldCells[i];
TXshColumn *xshColumn = xsh->getColumn(cellData.first);
if (!xshColumn) continue;
TXshCellColumn *cellColumn = xshColumn->getCellColumn();
if (!cellColumn) continue;
std::vector<TXshCell> 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<int> &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<int> 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<std::pair<int, TXshCell>> m_oldCells;
std::vector<int> m_columns;
int m_frame;
public:
RemoveGlobalStopframeUndo(int frame, const std::vector<int> &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<int, TXshCell> cellData = m_oldCells[i];
TXshColumn *xshColumn = xsh->getColumn(cellData.first);
if (!xshColumn) continue;
TXshCellColumn *cellColumn = xshColumn->getCellColumn();
if (!cellColumn) continue;
std::vector<TXshCell> 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<int> &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<int> 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;

View file

@ -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;
}

View file

@ -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();

View file

@ -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();

View file

@ -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;

View file

@ -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<double>::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();

View file

@ -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;
}

View file

@ -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, TXshCell>(
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, TXshCell>(
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;
}
}

View file

@ -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);