Merge pull request #847 from manongjohn/implicit_holds

Implicit Frame Hold
This commit is contained in:
manongjohn 2022-01-10 22:30:07 -05:00 committed by GitHub
commit 6f1d0fc0b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
52 changed files with 1185 additions and 265 deletions

View file

@ -2283,6 +2283,7 @@ XsheetViewer {
qproperty-LightBGColor: #d8d8d8;
qproperty-DarkBGColor: #c9c9c9;
qproperty-DarkLineColor: #7e7e7e;
qproperty-ImplicitCellAlpha: 60;
qproperty-TimelineIconLineColor: rgba(0, 0, 0, 0.4);
qproperty-XsheetColumnNameBgColor: rgba(0, 0, 0, 0);
qproperty-XsheetDragBarHighlightColor: rgba(255, 255, 255, 0.15);

View file

@ -2283,6 +2283,7 @@ XsheetViewer {
qproperty-LightBGColor: #c8c8c8;
qproperty-DarkBGColor: #b9b9b9;
qproperty-DarkLineColor: #6e6e6e;
qproperty-ImplicitCellAlpha: 60;
qproperty-TimelineIconLineColor: rgba(0, 0, 0, 0.3);
qproperty-XsheetColumnNameBgColor: rgba(0, 0, 0, 0);
qproperty-XsheetDragBarHighlightColor: rgba(255, 255, 255, 0.15);

View file

@ -2283,6 +2283,7 @@ XsheetViewer {
qproperty-LightBGColor: #ffffff;
qproperty-DarkBGColor: #ffffff;
qproperty-DarkLineColor: #ffffff;
qproperty-ImplicitCellAlpha: 115;
qproperty-TimelineIconLineColor: rgba(0, 0, 0, 0.144);
qproperty-XsheetColumnNameBgColor: rgba(0, 0, 0, 0);
qproperty-XsheetDragBarHighlightColor: rgba(255, 255, 255, 0.15);

View file

@ -2283,6 +2283,7 @@ XsheetViewer {
qproperty-LightBGColor: #f0f0f0;
qproperty-DarkBGColor: #e1e1e1;
qproperty-DarkLineColor: #969696;
qproperty-ImplicitCellAlpha: 60;
qproperty-TimelineIconLineColor: rgba(0, 0, 0, 0.3);
qproperty-XsheetColumnNameBgColor: rgba(0, 0, 0, 0);
qproperty-XsheetDragBarHighlightColor: rgba(255, 255, 255, 0.15);

View file

@ -423,6 +423,8 @@
@cellHighlightTintColor: @hl-bg-color;
@cellHighlightTintAmount: 77;
@xsheet-ImplicitCellAlpha: 60;
@xsheet-EmptyCell-color: @xsheet-OnionSkinAreaBG-color;
@xsheet-NotEmptyColumn-color: darken(@bg, 3);
@xsheet-SelectedEmptyCell-color: fade(mix(lighten(@xsheet-EmptyCell-color, 20), @cellHighlightTintColor, 80), 50);

View file

@ -153,6 +153,8 @@ XsheetViewer {
qproperty-DarkBGColor: @xsheet-DarkBG-color;
qproperty-DarkLineColor: @xsheet-DarkLine-color;
qproperty-ImplicitCellAlpha: @xsheet-ImplicitCellAlpha;
// Column Header: Vertical
qproperty-TimelineIconLineColor: @timeline-IconLine-color;
qproperty-XsheetColumnNameBgColor: @xsheet-ColumnNameBg-color;

View file

@ -191,6 +191,8 @@
@columnBorderDarkness: 15;
@cellHighlightLightness: 10;
@xsheet-ImplicitCellAlpha: 115;
@xsheet-EmptyCell-color: @xsheet-OnionSkinAreaBG-color;
@xsheet-NotEmptyColumn-color: @xsheet-bg-color;
@xsheet-SelectedEmptyCell-color: fade(mix(lighten(@xsheet-EmptyCell-color, -20), @cellHighlightTintColor, 80), 50);

View file

@ -218,6 +218,8 @@
@columnBorderDesaturation: 0;
@columnBorderDarkness: 15;
@xsheet-ImplicitCellAlpha: 75;
@xsheet-LevelColumn-color: #78a578;
@xsheet-VectorColumn-color: #a7637d;
@xsheet-ChildColumn-color: #9a759c;

View file

@ -2283,6 +2283,7 @@ XsheetViewer {
qproperty-LightBGColor: #ffffff;
qproperty-DarkBGColor: #ffffff;
qproperty-DarkLineColor: #cecece;
qproperty-ImplicitCellAlpha: 75;
qproperty-TimelineIconLineColor: rgba(0, 0, 0, 0.3);
qproperty-XsheetColumnNameBgColor: rgba(0, 0, 0, 0);
qproperty-XsheetDragBarHighlightColor: rgba(255, 255, 255, 0.15);

View file

@ -3,6 +3,7 @@
<command>MI_ToggleAutoCreate</command>
<command>MI_ToggleCreationInHoldCells</command>
<command>MI_ToggleAutoStretch</command>
<command>MI_ToggleImplicitHold</command>
<separator/>
<command>MI_NewVectorLevel</command>
<command>MI_NewToonzRasterLevel</command>

View file

@ -95,6 +95,8 @@ std::string TFrameId::expand(FrameFormat format) const {
return "";
else if (m_frame == NO_FRAME)
return "-";
else if (m_frame == STOP_FRAME)
return "x";
std::ostringstream o_buff;
if (format == FOUR_ZEROS || format == UNDERSCORE_FOUR_ZEROS) {
o_buff.fill('0');

View file

@ -36,7 +36,8 @@ class DVAPI TFrameId {
public:
enum {
EMPTY_FRAME = -1, // es. pippo..tif
NO_FRAME = -2 // es. pippo.tif
NO_FRAME = -2, // es. pippo.tif
STOP_FRAME = -3
};
enum FrameFormat {
@ -86,6 +87,7 @@ public:
bool isEmptyFrame() const { return m_frame == EMPTY_FRAME; }
bool isNoFrame() const { return m_frame == NO_FRAME; }
bool isStopFrame() const { return m_frame == STOP_FRAME; }
// operator string() const;
std::string expand(FrameFormat format = FOUR_ZEROS) const;
@ -280,6 +282,9 @@ type is a string that indicate the filename extension(ex:. bmp or .bmp)*/
TFilePath withNoFrame() const {
return withFrame(TFrameId(TFrameId::NO_FRAME));
} // pippo.tif
TFilePath withStopFrame() const {
return withFrame(TFrameId(TFrameId::STOP_FRAME));
}
TFilePath operator+(const TFilePath &fp) const;
TFilePath &operator+=(const TFilePath &fp) /*{*this=*this+fp;return *this;}*/;

View file

@ -304,6 +304,9 @@ public:
bool isAutoCreateEnabled() const { return getBoolValue(EnableAutocreation); }
int getNumberingSystem() const { return getIntValue(NumberingSystem); }
bool isAutoStretchEnabled() const { return getBoolValue(EnableAutoStretch); }
bool isImplicitHoldEnabled() const {
return getBoolValue(EnableImplicitHold);
}
bool isCreationInHoldCellsEnabled() const {
return getBoolValue(EnableCreationInHoldCells);
}

View file

@ -90,6 +90,7 @@ enum PreferencesItemId {
EnableAutocreation,
NumberingSystem,
EnableAutoStretch,
EnableImplicitHold,
EnableCreationInHoldCells,
EnableAutoRenumber,
vectorSnappingTarget,

View file

@ -141,7 +141,7 @@ Constructs a TXshColumn with default value.
virtual TXshZeraryFxColumn *getZeraryFxColumn() { return 0; }
virtual TXshMeshColumn *getMeshColumn() { return 0; }
virtual int getMaxFrame() const = 0;
virtual int getMaxFrame(bool ignoreLastStop = false) const = 0;
virtual TXshColumn *clone() const = 0;
@ -219,7 +219,7 @@ If r0=r1=row return false.
*/
virtual bool getLevelRange(int row, int &r0, int &r1) const = 0;
virtual int getRange(int &r0, int &r1) const {
virtual int getRange(int &r0, int &r1, bool ignoreLastStop = false) const {
r0 = 0;
r1 = -1;
return 0;
@ -330,7 +330,7 @@ Return not empty cell range. Set \b r0 and \b r1 to first
and last row with not empty cell.
\sa isEmpty() and getRowCount()
*/
int getRange(int &r0, int &r1) const override;
int getRange(int &r0, int &r1, bool ignoreLastStop = false) const override;
/*!
Return row count.
\sa isEmpty() and getRange()
@ -386,7 +386,7 @@ Clear \b rowCount cells from line \b row, without shift.
/*!
Return last row with not empty cell.
*/
int getMaxFrame() const override;
int getMaxFrame(bool ignoreLastStop = false) const override;
/*!
Return first not empty row.

View file

@ -196,6 +196,10 @@ public:
const TXshCell &getCell(const CellPosition &pos) const;
bool isImplicitCell(int row, int col) const;
bool isImplicitCell(const CellPosition &pos) const;
bool setCell(int row, int col, const TXshCell &cell);
/*! Set \b \e cells[] to \b \e rowCount cells of column identified by index \b
\e col starting from row identified by index \b \e row. If column is empty

View file

@ -129,11 +129,11 @@ public:
void saveData(TOStream &os) override;
/*! r0 : min row not empty, r1 : max row not empty. Return row count.*/
int getRange(int &r0, int &r1) const override;
int getRange(int &r0, int &r1, bool ignoreLastStop = false) const override;
/*! Last not empty row - first not empty row. */
int getRowCount() const override;
/*! Return max row not empty. */
int getMaxFrame() const override;
int getMaxFrame(bool ignoreLastStop = false) const override;
/*! Return min row not empty.*/
int getFirstRow() const override;

View file

@ -61,6 +61,17 @@ TPalette *getPalette(TXshColumn *column, int frame) {
if (!cellColumn) return 0;
TXshCell cell = cellColumn->getCell(frame);
// This is only relevant when Implicit Holds are enabled
if (cell.isEmpty()) {
int r0, r1;
cellColumn->getRange(r0, r1);
for (int r = std::min(r1, frame); r >= r0; r--) {
cell = cellColumn->getCell(r);
if (cell.isEmpty()) continue;
break;
}
}
if (cell.isEmpty()) return 0;
TXshPaletteLevel *pl = cell.m_level->getPaletteLevel();

View file

@ -353,6 +353,11 @@ TImage *TTool::touchImage() {
if (!xsh) return 0;
TXshCell cell = xsh->getCell(row, col);
bool isImplicitCell = xsh->isImplicitCell(row, col);
// Stop frames cannot be modified
if (cell.getFrameId().isStopFrame()) return 0;
TXshSimpleLevel *sl = cell.getSimpleLevel();
if (sl) {
@ -380,7 +385,9 @@ 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) r1++;
while (xsh->getCell(r1 + 1, col) == cell &&
!xsh->isImplicitCell(r1 + 1, col))
r1++;
// find the proper frameid (possibly addisng suffix, in order to avoid a
// fid already used)
// find the proper frameid
@ -418,7 +425,10 @@ TImage *TTool::touchImage() {
currentXsheet->notifyXsheetChanged();
currentScene->notifyCastChange();
currentLevel->notifyLevelChange();
m_cellsData.push_back({r0, r1, CellOps::ExistingToNew});
if (isImplicitCell)
m_cellsData.push_back({r0, r1, CellOps::BlankToNew});
else
m_cellsData.push_back({r0, r1, CellOps::ExistingToNew});
}
// if the level does not contain a frame in the current cell
// (i.e. drawing on the cell with red numbers)
@ -728,7 +738,8 @@ TFrameId TTool::getCurrentFid() const {
int col = m_application->getCurrentColumn()->getColumnIndex();
TXshCell cell =
m_application->getCurrentXsheet()->getXsheet()->getCell(row, col);
if (cell.isEmpty()) return TFrameId::NO_FRAME;
if (cell.isEmpty() || cell.getFrameId().isStopFrame())
return TFrameId::NO_FRAME;
return cell.getFrameId();
}
@ -1108,6 +1119,13 @@ QString TTool::updateEnabled(int rowIndex, int columnIndex) {
"frames of a Single Frame level."));
}
}
// Stop frames cannot be modified
if (xsh->getCell(rowIndex, columnIndex).getFrameId().isStopFrame()) {
return (
enable(false),
QObject::tr("The current tool cannot be used on a stop frame."));
}
}
}

View file

@ -149,12 +149,25 @@ AutoInputCellNumberUndo::AutoInputCellNumberUndo(int increment, int interval,
(m_r1 == -1) ? m_rowsCount - 1 : std::min(m_r1, m_r0 + m_rowsCount - 1);
m_beforeCells.reset(
new TXshCell[m_columnIndices.size() * (rowUpTo - m_r0 + 1)]);
int k = 0;
int k = 0;
TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
for (int c = 0; c < m_columnIndices.size(); ++c) {
for (int r = m_r0; r <= rowUpTo; ++r)
for (int r = m_r0; r <= rowUpTo; ++r) {
const TXshCell &cell = xsh->getCell(r, m_columnIndices.at(c));
m_beforeCells[k++] =
TApp::instance()->getCurrentXsheet()->getXsheet()->getCell(
r, m_columnIndices.at(c));
xsh->isImplicitCell(r, m_columnIndices.at(c)) ? TXshCell() : cell;
}
}
} else {
// Need to restore rows starting with implicit cells that were converted to
// actual cells by this process
m_beforeCells.reset(new TXshCell[m_columnIndices.size()]);
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;
}
}
}
@ -178,6 +191,15 @@ void AutoInputCellNumberUndo::undo() const {
} else { // on insert case, remove inserted cells
for (int c = 0; c < m_columnIndices.size(); ++c)
xsh->removeCells(m_r0, m_columnIndices.at(c), m_rowsCount);
int k = 0;
for (int c = 0; c < m_columnIndices.size(); ++c) {
if (m_beforeCells[k].isEmpty())
xsh->clearCells(m_r0, m_columnIndices.at(c));
else
xsh->setCell(m_r0, m_columnIndices.at(c), m_beforeCells[k]);
k++;
}
}
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
}

View file

@ -11,6 +11,7 @@
#include "toonz/tcolumnfx.h"
#include "toonz/fxdag.h"
#include "toonz/txshlevelcolumn.h"
#include "toonz/preferences.h"
//-----------------------------------------------------------------------------
@ -194,7 +195,12 @@ void TCellData::cloneZeraryFx(int index, std::vector<TXshCell> &cells) const {
newFxLevel->setColumn(newFxColumn);
// replace the zerary fx cells by the new fx
int r;
for (r = firstNotEmptyIndex; r < (index + 1) * m_rowCount; r++)
cells[r] = TXshCell(newFxLevel, m_cells[r].getFrameId());
for (r = firstNotEmptyIndex; r < (index + 1) * m_rowCount; r++) {
if (Preferences::instance()->isImplicitHoldEnabled() &&
m_cells[r].getFrameId().isEmptyFrame())
cells[r] = TXshCell(0, m_cells[r].getFrameId());
else
cells[r] = TXshCell(newFxLevel, m_cells[r].getFrameId());
}
}
}

View file

@ -53,6 +53,8 @@
#include "toonz/levelset.h"
#include "toonz/tstageobjecttree.h"
#include "toonz/stage.h"
#include "toonz/txshzeraryfxlevel.h"
#include "toonz/txshpalettelevel.h"
#include "vectorizerpopup.h"
#include "tools/rasterselection.h"
#include "tools/strokeselection.h"
@ -1264,6 +1266,47 @@ public:
//-----------------------------------------------------------------------------
class StopFrameHoldUndo final : public TUndo {
TXshLevel *m_level;
TXshCell m_oldCell;
int m_row;
int m_col;
public:
StopFrameHoldUndo(TXshLevel *level, int row, int col, TXshCell oldCell)
: m_level(level), m_row(row), m_col(col), m_oldCell(oldCell) {}
~StopFrameHoldUndo() {}
void undo() const override {
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
xsh->clearCells(m_row, m_col, 1);
xsh->setCell(m_row, m_col, m_oldCell);
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
}
void redo() const override {
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
xsh->setCell(m_row, m_col, TXshCell(m_level, TFrameId::STOP_FRAME));
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
}
int getSize() const override { return sizeof(*this); }
QString getHistoryString() override {
return QObject::tr("Set Stop Frame Hold");
}
int getHistoryType() override { return HistoryType::Xsheet; }
//-----------------------------------------------------------------------------
};
//-----------------------------------------------------------------------------
class DuplicateDrawingUndo final : public ToolUtils::TToolUndo {
TFrameId origFrameId;
TFrameId dupFrameId;
@ -1511,6 +1554,7 @@ void TCellSelection::enableCommands() {
&TCellSelection::createBlankDrawings);
enableCommand(this, MI_Duplicate, &TCellSelection::duplicateFrames);
enableCommand(this, MI_PasteDuplicate, &TCellSelection::pasteDuplicateCells);
enableCommand(this, MI_StopFrameHold, &TCellSelection::stopFrameHold);
}
//-----------------------------------------------------------------------------
// Used in RenameCellField::eventFilter()
@ -1555,7 +1599,8 @@ bool TCellSelection::isEnabledCommand(
MI_ConvertToToonzRaster,
MI_ConvertVectorToVector,
MI_CreateBlankDrawing,
MI_FillEmptyCell};
MI_FillEmptyCell,
MI_StopFrameHold};
return commands.contains(commandId);
}
@ -2714,8 +2759,9 @@ void TCellSelection::createBlankDrawing(int row, int col, bool multiple) {
TXshCell cell = xsh->getCell(row, col);
TXshSimpleLevel *sl = cell.getSimpleLevel();
bool isStopFrame = cell.getFrameId().isStopFrame();
if (!img || !sl) {
if ((!img || !sl) && !isStopFrame) {
//----- Restore previous states of autocreation
if (!isAutoCreateEnabled)
Preferences::instance()->setValue(EnableAutocreation, false, false);
@ -2738,8 +2784,12 @@ void TCellSelection::createBlankDrawing(int row, int col, bool multiple) {
false);
//------------------
if (!multiple)
DVGui::warning(QObject::tr(
"Unable to replace the current drawing with a blank drawing"));
if (isStopFrame)
DVGui::warning(QObject::tr(
"Unable to replace a Stop Frame Hold with a blank drawing"));
else
DVGui::warning(QObject::tr(
"Unable to replace the current drawing with a blank drawing"));
return;
}
@ -2787,6 +2837,98 @@ void TCellSelection::createBlankDrawings() {
//-----------------------------------------------------------------------------
void TCellSelection::stopFrameHold(int row, int col, bool multiple) {
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
if (col < 0) {
if (!multiple)
DVGui::warning(QObject::tr(
"Unable to create a stop frame hold on the camera column"));
return;
}
TXshColumn *column = xsh->getColumn(col);
if (column && column->isLocked()) {
if (!multiple) DVGui::warning(QObject::tr("The current column is locked"));
return;
}
TApp::instance()->getCurrentColumn()->setColumnIndex(col);
TApp::instance()->getCurrentFrame()->setCurrentFrame(row + 1);
TXshLevel *level = TApp::instance()->getCurrentLevel()->getLevel();
if (!level) {
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 == SND_XSHLEVEL || levelType == SND_TXT_XSHLEVEL) {
if (!multiple)
DVGui::warning(QObject::tr(
"Cannot create a stop frame hold on the current column"));
return;
}
} else {
if (!multiple)
DVGui::warning(QObject::tr(
"Cannot create a stop from hold on a column without a level"));
return;
}
TXshLevel *lvl = level->getSimpleLevel();
if (!lvl) lvl = level->getChildLevel();
if (!lvl) lvl = dynamic_cast<TXshLevel *>(level->getPaletteLevel());
if (!lvl) lvl = dynamic_cast<TXshLevel *>(level->getZeraryFxLevel());
if (!lvl) {
if (!multiple)
DVGui::warning(QObject::tr(
"Unable to create a stop frame hold on the current column"));
return;
}
TXshCell cell;
if (!xsh->isImplicitCell(row, col)) cell = xsh->getCell(row, col);
StopFrameHoldUndo *undo = new StopFrameHoldUndo(lvl, row, col, cell);
TUndoManager::manager()->add(undo);
undo->redo();
}
//-----------------------------------------------------------------------------
void TCellSelection::stopFrameHold() {
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++) {
stopFrameHold(r, c, multiple);
}
}
TUndoManager::manager()->endBlock();
TApp::instance()->getCurrentColumn()->setColumnIndex(col);
TApp::instance()->getCurrentFrame()->setCurrentFrame(row + 1);
}
//-----------------------------------------------------------------------------
void TCellSelection::duplicateFrame(int row, int col, bool multiple) {
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
@ -2811,7 +2953,7 @@ void TCellSelection::duplicateFrame(int row, int col, bool multiple) {
Preferences::instance()->isAnimationSheetEnabled()) {
int r0, r1;
xsh->getCellRange(col, r0, r1);
for (int r = std::min(r1, row); r > r0; r--) {
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();
@ -2838,7 +2980,6 @@ void TCellSelection::duplicateFrame(int row, int col, bool multiple) {
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) {
@ -2849,6 +2990,12 @@ void TCellSelection::duplicateFrame(int row, int col, bool multiple) {
row++;
}
if (prevCell.getFrameId().isStopFrame()) {
if (!xsh->isImplicitCell(row - 1, col) && !multiple)
DVGui::warning(QObject::tr("Cannot duplicate a Stop Frame Hold"));
return;
}
if (prevCell.isEmpty() || !(prevCell.m_level->getSimpleLevel())) return;
TXshSimpleLevel *sl = prevCell.getSimpleLevel();

View file

@ -125,6 +125,8 @@ public:
void createBlankDrawing(int row, int col, bool inRange);
void createBlankDrawings();
void stopFrameHold(int row, int col, bool inRange);
void stopFrameHold();
void fillEmptyCell();
};

View file

@ -209,7 +209,7 @@ void IncrementUndo::undo() const {
const TRect &r = m_undoCells[i].first;
int size = r.x1 - r.x0 + 1;
if (m_undoCells[i].second.isEmpty())
if (m_undoCells[i].second.getFrameId().isNoFrame())
xsh->removeCells(r.x0, r.y0, size);
else {
xsh->insertCells(r.x0, r.y0, size);
@ -387,11 +387,13 @@ StepUndo::StepUndo(int r0, int c0, int r1, int c1, int step)
assert(m_rowsCount > 0 && m_colsCount > 0 && step > 0);
assert(m_cells);
int k = 0;
TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
int k = 0;
for (int r = r0; r <= r1; ++r)
for (int c = c0; c <= c1; ++c)
m_cells[k++] =
TApp::instance()->getCurrentXsheet()->getXsheet()->getCell(r, c);
for (int c = c0; c <= c1; ++c) {
const TXshCell &cell = xsh->getCell(r, c);
m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell;
}
}
//-----------------------------------------------------------------------------
@ -489,11 +491,13 @@ EachUndo::EachUndo(int r0, int c0, int r1, int c1, int each)
assert(m_rowsCount > 0 && m_colsCount > 0 && each > 0);
assert(m_cells);
int k = 0;
int k = 0;
TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
for (int r = r0; r <= r1; ++r)
for (int c = c0; c <= c1; ++c)
m_cells[k++] =
TApp::instance()->getCurrentXsheet()->getXsheet()->getCell(r, c);
for (int c = c0; c <= c1; ++c) {
const TXshCell &cell = xsh->getCell(r, c);
m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell;
}
}
//-----------------------------------------------------------------------------
@ -598,13 +602,16 @@ ReframeUndo::ReframeUndo(int r0, int r1, std::vector<int> columnIndeces,
, m_withBlank(withBlank) {
m_nr = m_r1 - m_r0 + 1;
assert(m_nr > 0);
m_cells.reset(new TXshCell[m_nr * (int)m_columnIndeces.size()]);
m_cells.reset(new TXshCell[(m_nr + 1) * (int)m_columnIndeces.size()]);
assert(m_cells);
int k = 0;
for (int r = r0; r <= r1; r++)
for (int c = 0; c < (int)m_columnIndeces.size(); c++)
m_cells[k++] = TApp::instance()->getCurrentXsheet()->getXsheet()->getCell(
r, m_columnIndeces[c]);
int k = 0;
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;
}
m_newRows.clear();
}
@ -633,7 +640,7 @@ void ReframeUndo::undo() const {
if (m_cells) {
int k = 0;
for (int r = m_r0; r <= m_r1; r++)
for (int r = m_r0; r <= m_r1 + 1; r++)
for (int c = 0; c < m_columnIndeces.size(); c++) {
if (m_cells[k].isEmpty())
xsh->clearCells(r, m_columnIndeces[c]);
@ -834,10 +841,10 @@ ResetStepUndo::ResetStepUndo(int r0, int c0, int r1, int c1)
TXshCell prevCell;
m_insertedCells[c] = 0;
TXsheetP xsh = app->getCurrentXsheet()->getXsheet();
for (int r = r0; r <= r1; ++r) {
const TXshCell &cell =
app->getCurrentXsheet()->getXsheet()->getCell(r, c);
m_cells[k++] = cell;
const TXshCell &cell = xsh->getCell(r, c);
m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell;
if (prevCell != cell) {
prevCell = cell;
@ -934,10 +941,10 @@ IncreaseStepUndo::IncreaseStepUndo(int r0, int c0, int r1, int c1)
TXshCell prevCell;
m_insertedCells[c] = 0;
TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
for (int r = r0; r <= r1; ++r) {
const TXshCell &cell =
TApp::instance()->getCurrentXsheet()->getXsheet()->getCell(r, c);
m_cells[k++] = cell;
const TXshCell &cell = xsh->getCell(r, c);
m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell;
if (prevCell != cell) {
prevCell = cell;
@ -1045,19 +1052,18 @@ DecreaseStepUndo::DecreaseStepUndo(int r0, int c0, int r1, int c1)
, m_newR1(m_r1) {
assert(m_cells);
int k = 0;
int k = 0;
TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
for (int c = c0; c <= c1; ++c) {
TXshCell prevCell =
TApp::instance()->getCurrentXsheet()->getXsheet()->getCell(r0, c);
TXshCell prevCell = xsh->getCell(r0, c);
m_removedCells[c] = 0;
bool removed = false;
m_cells[k++] = prevCell;
m_cells[k++] = xsh->isImplicitCell(r0, c) ? TXshCell() : prevCell;
for (int r = r0 + 1; r <= r1; ++r) {
const TXshCell &cell =
TApp::instance()->getCurrentXsheet()->getXsheet()->getCell(r, c);
m_cells[k++] = cell;
const TXshCell &cell = xsh->getCell(r, c);
m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell;
if (prevCell == cell) {
if (!removed) {
@ -1120,7 +1126,8 @@ void TCellSelection::decreaseStepCells() {
for (int i = 1; sameCells; i++) {
nextCell = xsh->getCell(row + i, col);
if (nextCell.m_frameId == cell.m_frameId &&
nextCell.m_level == cell.m_level) {
nextCell.m_level == cell.m_level &&
!xsh->isImplicitCell(row + i, col)) {
r1 = row + i;
} else
sameCells = false;
@ -1595,20 +1602,35 @@ void CloneLevelUndo::insertCells() const {
m_insertedColumns.insert(colIndex);
}
bool useImplicitHold = Preferences::instance()->isImplicitHoldEnabled();
// 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) {
const TXshCell &srcCell = xsh->getCell(r, c);
TXshCell srcCell = xsh->getCell(r, c);
if (useImplicitHold) {
if (r > m_range.m_r0 &&
(prevCell == srcCell || xsh->isImplicitCell(r, c)))
srcCell = TXshCell();
prevCell = srcCell;
}
if (TXshSimpleLevel *srcSl = srcCell.getSimpleLevel()) {
std::map<TXshSimpleLevel *, TXshLevelP>::iterator lt =
m_insertedLevels.find(srcSl);
if (lt != m_insertedLevels.end()) {
lastLevel = lt->second;
TXshCell dstCell(lt->second, srcCell.getFrameId());
xsh->setCell(r, c + m_range.getColCount(), dstCell);
}
}
}
if (useImplicitHold &&
!xsh->getCell(m_range.m_r1, c + m_range.getColCount()).isEmpty())
xsh->setCell(m_range.m_r1 + 1, c + m_range.getColCount(),
TXshCell(lastLevel, TFrameId::STOP_FRAME));
}
}

View file

@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
version="1.1"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
id="svg20"
sodipodi:docname="implicit_hold.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata
id="metadata26"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs24" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1013"
id="namedview22"
showgrid="true"
inkscape:zoom="51.250051"
inkscape:cx="8.0000125"
inkscape:cy="7.999996"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="new_vector_level"
showguides="false"><inkscape:grid
type="xygrid"
id="grid833" /></sodipodi:namedview>
<g
transform="matrix(1,0,0,1,-170,-210)"
id="g18">
<g
id="new_vector_level"
transform="matrix(1,0,0,1,60,-20)">
<g
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
transform="matrix(-0.110345,0,0,0.121212,142.22074,211.09094)"
id="bg-1"><rect
id="rect2-3"
style="fill:#878787;fill-opacity:0"
height="132"
width="145"
y="156"
x="147" /></g><g
transform="translate(109.99996,229.99997)"
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
id="g4549"><path
inkscape:connector-curvature="0"
d="M 143.025,25 C 144.116,25 145,24.116 145,23.025 V 12.984 c 0,-0.527 -0.209,-1.031 -0.581,-1.403 C 144.047,11.209 143.543,11 143.016,11 c -2.663,0 -7.369,0 -10.032,0 -0.527,0 -1.031,0.209 -1.403,0.581 -0.372,0.372 -0.581,0.876 -0.581,1.403 v 10.032 c 0,0.527 0.209,1.031 0.581,1.403 0.372,0.372 0.876,0.581 1.403,0.581 2.666,0 7.378,0 10.041,0 z m 0.014,-1 C 143.57,24 144,23.57 144,23.039 V 13.017 c 0,-0.269 -0.107,-0.528 -0.298,-0.719 C 143.511,12.107 143.252,12 142.983,12 h -9.966 c -0.269,0 -0.528,0.107 -0.719,0.298 -0.191,0.191 -0.298,0.45 -0.298,0.719 v 9.966 c 0,0.269 0.107,0.528 0.298,0.719 0.191,0.191 0.45,0.298 0.719,0.298 z M 136,13.5 c 0,-0.133 -0.053,-0.26 -0.146,-0.354 C 135.76,13.053 135.633,13 135.5,13 c -0.555,0 -1.445,0 -2,0 -0.133,0 -0.26,0.053 -0.354,0.146 C 133.053,13.24 133,13.367 133,13.5 c 0,0.133 0.053,0.26 0.146,0.354 0.094,0.093 0.221,0.146 0.354,0.146 0.555,0 1.445,0 2,0 0.133,0 0.26,-0.053 0.354,-0.146 C 135.947,13.76 136,13.633 136,13.5 Z m 3,0 c 0,-0.133 -0.053,-0.26 -0.146,-0.354 C 138.76,13.053 138.633,13 138.5,13 c -0.305,0 -0.695,0 -1,0 -0.133,0 -0.26,0.053 -0.354,0.146 C 137.053,13.24 137,13.367 137,13.5 c 0,0.133 0.053,0.26 0.146,0.354 0.094,0.093 0.221,0.146 0.354,0.146 0.305,0 0.695,0 1,0 0.133,0 0.26,-0.053 0.354,-0.146 C 138.947,13.76 139,13.633 139,13.5 Z m 4,0 c 0,-0.133 -0.053,-0.26 -0.146,-0.354 C 142.76,13.053 142.633,13 142.5,13 c -0.555,0 -1.445,0 -2,0 -0.133,0 -0.26,0.053 -0.354,0.146 C 140.053,13.24 140,13.367 140,13.5 c 0,0.133 0.053,0.26 0.146,0.354 0.094,0.093 0.221,0.146 0.354,0.146 0.555,0 1.445,0 2,0 0.133,0 0.26,-0.053 0.354,-0.146 C 142.947,13.76 143,13.633 143,13.5 Z"
id="path5-1"
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
transform="translate(-129.99996,-9.999966)" /><g
transform="matrix(0.71689545,0,0,0.56820456,-90.925068,-1.2051139)"
id="g7-2-9"
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"><path
sodipodi:nodetypes="ssssssssssssssssssssssssccccccccccccccc"
inkscape:connector-curvature="0"
d="M 143.025,25 C 144.116,25 145,24.116 145,23.025 V 12.984 c 0,-0.527 -0.209,-1.031 -0.581,-1.403 C 144.047,11.209 143.543,11 143.016,11 h -10.032 c -0.527,0 -1.031,0.209 -1.403,0.581 -0.372,0.372 -0.581,0.876 -0.581,1.403 v 10.032 c 0,0.527 0.209,1.031 0.581,1.403 0.372,0.372 0.876,0.581 1.403,0.581 z m 0.014,-1 C 143.57,24 144,23.57 144,23.039 V 13.017 c 0,-0.269 -0.107,-0.528 -0.298,-0.719 C 143.511,12.107 143.252,12 142.983,12 h -9.966 c -0.269,0 -0.528,0.107 -0.719,0.298 -0.191,0.191 -0.298,0.45 -0.298,0.719 v 9.966 c 0,0.269 0.107,0.528 0.298,0.719 0.191,0.191 0.45,0.298 0.719,0.298 z m -6.83211,-11.319507 -3.41581,10e-7 v 1.75993 l 3.41965,-2e-6 z m 2.78822,0 h -2.01706 l -0.0135,1.759929 h 2.02473 z m 4.19839,10e-7 -3.4197,-10e-7 -0.006,1.759929 3.41008,2e-6 z"
id="path5-1-8" /></g></g></g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
version="1.1"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
id="svg20"
sodipodi:docname="implicit_hold_on.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata
id="metadata26"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs24"><pattern
y="0"
x="0"
height="6"
width="6"
patternUnits="userSpaceOnUse"
id="EMFhbasepattern" /></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1013"
id="namedview22"
showgrid="true"
inkscape:zoom="51.25"
inkscape:cx="8"
inkscape:cy="8"
inkscape:window-x="-9"
inkscape:window-y="-9"
inkscape:window-maximized="1"
inkscape:current-layer="svg20"><inkscape:grid
type="xygrid"
id="grid833" /></sodipodi:namedview>
<g
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
transform="matrix(-0.110345,0,0,0.121212,32.22074,-18.909056)"
id="bg-1"><rect
id="rect2-3"
style="fill:#878787;fill-opacity:0"
height="132"
width="145"
y="156"
x="147" /></g><g
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
id="g7-2"
transform="translate(-129.99996,-9.999966)" /><g
id="g4549"><path
inkscape:connector-curvature="0"
d="M 143.025,25 C 144.116,25 145,24.116 145,23.025 V 12.984 c 0,-0.527 -0.209,-1.031 -0.581,-1.403 C 144.047,11.209 143.543,11 143.016,11 c -2.663,0 -7.369,0 -10.032,0 -0.527,0 -1.031,0.209 -1.403,0.581 -0.372,0.372 -0.581,0.876 -0.581,1.403 v 10.032 c 0,0.527 0.209,1.031 0.581,1.403 0.372,0.372 0.876,0.581 1.403,0.581 2.666,0 7.378,0 10.041,0 z m 0.014,-1 C 143.57,24 144,23.57 144,23.039 V 13.017 c 0,-0.269 -0.107,-0.528 -0.298,-0.719 C 143.511,12.107 143.252,12 142.983,12 h -9.966 c -0.269,0 -0.528,0.107 -0.719,0.298 -0.191,0.191 -0.298,0.45 -0.298,0.719 v 9.966 c 0,0.269 0.107,0.528 0.298,0.719 0.191,0.191 0.45,0.298 0.719,0.298 z M 136,13.5 c 0,-0.133 -0.053,-0.26 -0.146,-0.354 C 135.76,13.053 135.633,13 135.5,13 c -0.555,0 -1.445,0 -2,0 -0.133,0 -0.26,0.053 -0.354,0.146 C 133.053,13.24 133,13.367 133,13.5 c 0,0.133 0.053,0.26 0.146,0.354 0.094,0.093 0.221,0.146 0.354,0.146 0.555,0 1.445,0 2,0 0.133,0 0.26,-0.053 0.354,-0.146 C 135.947,13.76 136,13.633 136,13.5 Z m 3,0 c 0,-0.133 -0.053,-0.26 -0.146,-0.354 C 138.76,13.053 138.633,13 138.5,13 c -0.305,0 -0.695,0 -1,0 -0.133,0 -0.26,0.053 -0.354,0.146 C 137.053,13.24 137,13.367 137,13.5 c 0,0.133 0.053,0.26 0.146,0.354 0.094,0.093 0.221,0.146 0.354,0.146 0.305,0 0.695,0 1,0 0.133,0 0.26,-0.053 0.354,-0.146 C 138.947,13.76 139,13.633 139,13.5 Z m 4,0 c 0,-0.133 -0.053,-0.26 -0.146,-0.354 C 142.76,13.053 142.633,13 142.5,13 c -0.555,0 -1.445,0 -2,0 -0.133,0 -0.26,0.053 -0.354,0.146 C 140.053,13.24 140,13.367 140,13.5 c 0,0.133 0.053,0.26 0.146,0.354 0.094,0.093 0.221,0.146 0.354,0.146 0.555,0 1.445,0 2,0 0.133,0 0.26,-0.053 0.354,-0.146 C 142.947,13.76 143,13.633 143,13.5 Z"
id="path5-1"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"
transform="translate(-129.99996,-9.999966)" /><g
transform="matrix(0.71689545,0,0,0.56820456,-90.925068,-1.2051139)"
id="g7-2-9"
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"><path
sodipodi:nodetypes="ssssssssssssssssssssssssccccccccccccccc"
inkscape:connector-curvature="0"
d="M 143.025,25 C 144.116,25 145,24.116 145,23.025 V 12.984 c 0,-0.527 -0.209,-1.031 -0.581,-1.403 C 144.047,11.209 143.543,11 143.016,11 h -10.032 c -0.527,0 -1.031,0.209 -1.403,0.581 -0.372,0.372 -0.581,0.876 -0.581,1.403 v 10.032 c 0,0.527 0.209,1.031 0.581,1.403 0.372,0.372 0.876,0.581 1.403,0.581 z m 0.014,-1 C 143.57,24 144,23.57 144,23.039 V 13.017 c 0,-0.269 -0.107,-0.528 -0.298,-0.719 C 143.511,12.107 143.252,12 142.983,12 h -9.966 c -0.269,0 -0.528,0.107 -0.719,0.298 -0.191,0.191 -0.298,0.45 -0.298,0.719 v 9.966 c 0,0.269 0.107,0.528 0.298,0.719 0.191,0.191 0.45,0.298 0.719,0.298 z m -6.83211,-11.319507 -3.41581,10e-7 v 1.75993 l 3.41965,-2e-6 z m 2.78822,0 h -2.01706 l -0.0135,1.759929 2.02473,0 z m 4.19839,10e-7 -3.4197,-10e-7 -0.006,1.759929 3.41008,2e-6 z"
id="path5-1-8" /></g></g></svg>

After

Width:  |  Height:  |  Size: 5 KiB

View file

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16px"
height="16px"
version="1.1"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
id="svg12"
sodipodi:docname="stop_frame_hold.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata
id="metadata18"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
id="defs16">
</defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1672"
inkscape:window-height="865"
id="namedview14"
showgrid="true"
inkscape:zoom="41.7193"
inkscape:cx="11.121506"
inkscape:cy="7.0977181"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="0"
inkscape:current-layer="svg12"
inkscape:snap-grids="true"><inkscape:grid
type="xygrid"
id="grid827" /></sodipodi:namedview>
<g
transform="matrix(-1,0,0,1,126,-10)"
id="add_cell">
<g
transform="matrix(0.110345,0,0,0.121212,93.7793,-8.90909)"
id="bg">
<rect
id="rect2"
style="fill:#878787;fill-opacity:0"
height="132"
width="145"
y="156"
x="147" />
</g>
<g
id="g7"
transform="matrix(-1,0,0,1,256,0)">
<path
inkscape:connector-curvature="0"
id="path5"
d="m 145,21 v -8.016 c 0,-0.527 -0.209,-1.031 -0.581,-1.403 C 144.047,11.209 143.543,11 143.016,11 h -10.032 c -0.527,0 -1.031,0.209 -1.403,0.581 -0.372,0.372 -0.581,0.876 -0.581,1.403 v 10.032 c 0,0.527 0.209,1.031 0.581,1.403 0.372,0.372 0.876,0.581 1.403,0.581 H 141 c 0.265,0 0.52,-0.105 0.707,-0.293 l 3,-3 C 144.895,21.52 145,21.265 145,21 Z m -1,-1 v -6.983 c 0,-0.27 -0.107,-0.528 -0.298,-0.719 C 143.511,12.107 143.252,12 142.983,12 h -9.966 c -0.269,0 -0.528,0.107 -0.719,0.298 -0.191,0.191 -0.298,0.45 -0.298,0.719 v 9.966 c 0,0.269 0.107,0.528 0.298,0.719 0.191,0.191 0.449,0.298 0.719,0.298 H 140 v -4 z m -3,1 v 3 l 3,-3 z m -5,-7.5 c 0,-0.133 -0.053,-0.26 -0.146,-0.354 C 135.76,13.053 135.633,13 135.5,13 h -2 c -0.133,0 -0.26,0.053 -0.354,0.146 C 133.053,13.24 133,13.367 133,13.5 c 0,0.133 0.053,0.26 0.146,0.354 0.094,0.093 0.221,0.146 0.354,0.146 h 2 c 0.133,0 0.26,-0.053 0.354,-0.146 C 135.947,13.76 136,13.633 136,13.5 Z m 3,0 c 0,-0.133 -0.053,-0.26 -0.146,-0.354 C 138.76,13.053 138.633,13 138.5,13 h -1 c -0.133,0 -0.26,0.053 -0.354,0.146 C 137.053,13.24 137,13.367 137,13.5 c 0,0.133 0.053,0.26 0.146,0.354 0.094,0.093 0.221,0.146 0.354,0.146 h 1 c 0.133,0 0.26,-0.053 0.354,-0.146 C 138.947,13.76 139,13.633 139,13.5 Z m 4,0 c 0,-0.133 -0.053,-0.26 -0.146,-0.354 C 142.76,13.053 142.633,13 142.5,13 h -2 c -0.133,0 -0.26,0.053 -0.354,0.146 C 140.053,13.24 140,13.367 140,13.5 c 0,0.133 0.053,0.26 0.146,0.354 0.094,0.093 0.221,0.146 0.354,0.146 h 2 c 0.133,0 0.26,-0.053 0.354,-0.146 C 142.947,13.76 143,13.633 143,13.5 Z"
sodipodi:nodetypes="sssssssssssccscssssssssscccccccscsscscsscsscsscscsscsscsscscsscs" />
</g>
</g>
<path
style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
d="m 4,6 6.256939,4.520606"
id="path4542"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" /><path
style="clip-rule:evenodd;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:2;stroke-opacity:1"
d="M 12,6 4,12"
id="path4542-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" /></svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

@ -322,7 +322,9 @@ 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(); i++) {
for (i = 0; i < rowCount && (xsh->getCell(row + i, col).isEmpty() ||
xsh->isImplicitCell(row + i, col));
i++) {
}
int type = (column && !column->isEmpty()) ? column->getColumnType()
: newLevelColumnType;
@ -508,8 +510,10 @@ public:
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
for (c = m_col0; c <= m_col1; c++)
for (r = m_row0; r <= m_row1; r++) {
TXshSimpleLevel *oldLevel = xsh->getCell(r, c).getSimpleLevel();
TFrameId fid = xsh->getCell(r, c).getFrameId();
TXshCell cell;
if (!xsh->isImplicitCell(r, c)) cell = xsh->getCell(r, c);
TXshSimpleLevel *oldLevel = cell.getSimpleLevel();
TFrameId fid = cell.getFrameId();
QPair<int, int> cellId(r, c);
m_oldLevels[cellId] = QPair<TXshSimpleLevelP, TFrameId>(oldLevel, fid);
}

View file

@ -2061,6 +2061,8 @@ void MainWindow::defineActions() {
createMenuCellsAction(MI_CreateBlankDrawing,
QT_TR_NOOP("&Create Blank Drawing"), "Alt+D",
"add_cell");
createMenuCellsAction(MI_StopFrameHold, QT_TR_NOOP("&Stop Frame Hold"), "",
"stop_frame_hold");
createMenuCellsAction(MI_Duplicate, QT_TR_NOOP("&Duplicate Drawing "), "D",
"duplicate_drawing");
createMenuCellsAction(MI_Autorenumber, QT_TR_NOOP("&Autorenumber"), "",
@ -2501,6 +2503,10 @@ void MainWindow::defineActions() {
createToggle(MI_ViewerIndicator, QT_TR_NOOP("Toggle Viewer Indicators"), "",
Preferences::instance()->isViewerIndicatorEnabled(),
RightClickMenuCommandType);
createToggle(MI_ToggleImplicitHold, QT_TR_NOOP("Toggle Implicit Hold"), "",
Preferences::instance()->isImplicitHoldEnabled(),
MiscCommandType, "implicit_hold",
tr("Toggles the implicit hold of a frame to the next frame"));
// Tools

View file

@ -537,6 +537,7 @@ void TopBar::loadMenubar() {
addMenuItem(cellsMenu, MI_Autorenumber);
addMenuItem(cellsMenu, MI_CreateBlankDrawing);
addMenuItem(cellsMenu, MI_Duplicate);
addMenuItem(cellsMenu, MI_StopFrameHold);
addMenuItem(cellsMenu, MI_MergeFrames);
addMenuItem(cellsMenu, MI_CloneLevel);
cellsMenu->addSeparator();

View file

@ -153,6 +153,7 @@
#define MI_Autorenumber "MI_Autorenumber"
#define MI_CreateBlankDrawing "MI_CreateBlankDrawing"
#define MI_FillEmptyCell "MI_FillEmptyCell"
#define MI_StopFrameHold "MI_StopFrameHold"
#define MI_MergeFrames "MI_MergeFrames"
#define MI_Reverse "MI_Reverse"
@ -478,4 +479,6 @@
#define MI_ToggleCreationInHoldCells "MI_ToggleCreationInHoldCells"
#define MI_ToggleAutoStretch "MI_ToggleAutoStretch"
#define MI_ToggleImplicitHold "MI_ToggleImplicitHold"
#endif

View file

@ -1062,6 +1062,7 @@ QString PreferencesPopup::getUIString(PreferencesItemId id) {
{EnableAutoStretch, tr("Enable Auto-stretch Frame")},
{EnableCreationInHoldCells, tr("Enable Creation in Hold Cells")},
{EnableAutoRenumber, tr("Enable Autorenumber")},
{EnableImplicitHold, tr("Enable Implicit Hold")},
{vectorSnappingTarget, tr("Vector Snapping:")},
{saveUnpaintedInCleanup,
tr("Keep Original Cleaned Up Drawings As Backup")},
@ -1679,6 +1680,7 @@ QWidget* PreferencesPopup::createDrawingPage() {
{
insertUI(NumberingSystem, creationLay, getComboItemList(NumberingSystem));
insertUI(EnableAutoStretch, creationLay);
insertUI(EnableImplicitHold, creationLay);
insertUI(EnableAutoRenumber, creationLay);
}
QGridLayout* autoCreationLay = insertGroupBoxUI(EnableAutocreation, lay);

View file

@ -64,11 +64,13 @@ public:
assert(nr > 0 && nc > 0);
m_cells.reset(new TXshCell[nr * nc]);
assert(m_cells);
int k = 0;
int k = 0;
TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
for (int c = c0; c <= c1; c++)
for (int r = r0; r <= r1; r++)
m_cells[k++] =
TApp::instance()->getCurrentXsheet()->getXsheet()->getCell(r, c);
for (int r = r0; r <= r1; r++) {
const TXshCell &cell = xsh->getCell(r, c);
m_cells[k++] = xsh->isImplicitCell(r, c) ? TXshCell() : cell;
}
}
~TimeStretchUndo() {}
@ -102,7 +104,7 @@ public:
for (i = 0; i < nr; i++)
xsh->setCell(i + m_r0, c, m_cells[i + nr * (c - m_c0)]);
int dn = oldNr - nr;
xsh->removeCells(m_r1, c, dn);
xsh->removeCells(m_r1 + 1, c, dn);
}
}

View file

@ -329,8 +329,10 @@
<file>icons/dark/actions/16/auto_stretch_on.svg</file>
<file>icons/dark/actions/16/create_in_hold.svg</file>
<file>icons/dark/actions/16/create_in_hold_on.svg</file>
<file>icons/dark/actions/16/implicit_hold.svg</file>
<file>icons/dark/actions/16/implicit_hold_on.svg</file>
<file>icons/dark/actions/16/on_1s.svg</file>
<file>icons/dark/actions/16/on_1s.svg</file>
<file>icons/dark/actions/16/on_2s.svg</file>
<file>icons/dark/actions/16/on_3s.svg</file>
<file>icons/dark/actions/16/on_4s.svg</file>
@ -361,6 +363,7 @@
<file>icons/dark/actions/16/remove_cells.svg</file>
<file>icons/dark/actions/16/duplicate_drawing.svg</file>
<file>icons/dark/actions/16/tracking_options.svg</file>
<file>icons/dark/actions/16/stop_frame_hold.svg</file>
<file>icons/dark/actions/16/camera_settings.svg</file>
<file>icons/dark/actions/16/autoexpose.svg</file>

View file

@ -201,7 +201,9 @@ 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()) return false;
if (!xsh->getCell(r + j, c + i).isEmpty() &&
!xsh->isImplicitCell(r + j, c + i))
return false;
count++;
}
}

View file

@ -1880,6 +1880,25 @@ void CellArea::drawFrameMarker(QPainter &p, const QPoint &xy, QColor color,
//-----------------------------------------------------------------------------
void CellArea::drawEndOfLevelMarker(QPainter &p, QRect rect, bool isStopFrame) {
const Orientation *o = m_viewer->orientation();
QColor levelEndColor = m_viewer->getTextColor();
QPoint topLeft = rect.topLeft();
QPoint topRight = rect.topRight();
if (!o->isVerticalTimeline() && isStopFrame) {
QRect dragRect = o->rect(PredefinedRect::DRAG_AREA);
topLeft.setY(topLeft.y() + dragRect.height());
topRight.setY(topRight.y() + dragRect.height());
}
levelEndColor.setAlphaF(0.3);
p.setPen(levelEndColor);
p.drawLine(topLeft, rect.bottomRight());
p.drawLine(topRight, rect.bottomLeft());
}
//-----------------------------------------------------------------------------
void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
bool showLevelName) {
const Orientation *o = m_viewer->orientation();
@ -1907,8 +1926,14 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
columnSelection->isColumnSelected(col);
bool isSimpleView = m_viewer->getFrameZoomFactor() <=
o->dimension(PredefinedDimension::SCALE_THRESHOLD);
bool isImplicitCell = xsh->isImplicitCell(row, col);
bool isStopFrame = isImplicitCell ? false : cell.getFrameId().isStopFrame();
if (row > 0) prevCell = xsh->getCell(row - 1, col); // cell in previous frame
bool prevIsImplicit = false;
if (row > 0) {
prevCell = xsh->getCell(row - 1, col); // cell in previous frame
prevIsImplicit = xsh->isImplicitCell(row - 1, col);
}
bool sameLevel = prevCell.m_level.getPointer() == cell.m_level.getPointer();
@ -1931,7 +1956,12 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
.translated(QPoint(x, y));
cellRect.adjust(0, 0, -frameAdj.x(), -frameAdj.y());
QRect rect = cellRect.adjusted(
1, 1, (!o->isVerticalTimeline() && !nextCell.isEmpty() ? 2 : 0), 0);
1, 1, (!o->isVerticalTimeline() && !nextCell.isEmpty() &&
!xsh->isImplicitCell(row + 1, col) &&
!nextCell.getFrameId().isStopFrame()
? 2
: 0),
0);
QRect markRect =
o->rect(PredefinedRect::CELL_MARK_AREA)
@ -1988,7 +2018,8 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
}
bool heldFrame = (!o->isVerticalTimeline() && sameLevel &&
prevCell.m_frameId == cell.m_frameId);
prevCell.m_frameId == cell.m_frameId) &&
!isImplicitCell;
drawFrameSeparator(p, row, col, false, heldFrame);
if (cell.isEmpty()) { // it means previous is not empty
@ -2001,11 +2032,9 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
p.drawEllipse(markRect);
}
QColor levelEndColor = m_viewer->getTextColor();
levelEndColor.setAlphaF(0.3);
p.setPen(levelEndColor);
p.drawLine(rect.topLeft(), rect.bottomRight());
p.drawLine(rect.topRight(), rect.bottomLeft());
// Implicit holds use Stop Frame Hold to denote end of level
if (!Preferences::instance()->isImplicitHoldEnabled())
drawEndOfLevelMarker(p, rect);
if (TApp::instance()->getCurrentFrame()->isEditingScene() &&
!m_viewer->orientation()->isVerticalTimeline() &&
@ -2024,6 +2053,8 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
int levelType;
m_viewer->getCellTypeAndColors(levelType, cellColor, sideColor, cell,
isSelected);
if (isImplicitCell) cellColor.setAlpha(m_viewer->getImplicitCellAlpha());
if (isStopFrame) cellColor.setAlpha(0);
}
// check if the level is scanned but not cleanupped
@ -2044,17 +2075,8 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
else
p.fillRect(rect, QBrush(cellColor));
if (yetToCleanupCell) // ORIENTATION: what's this?
{
if (o->isVerticalTimeline())
p.fillRect(rect.adjusted(rect.width() / 2, 0, 0, 0),
(isSelected) ? m_viewer->getSelectedFullcolorColumnColor()
: m_viewer->getFullcolorColumnColor());
else
p.fillRect(rect.adjusted(0, rect.height() / 2, 0, 0),
(isSelected) ? m_viewer->getSelectedFullcolorColumnColor()
: m_viewer->getFullcolorColumnColor());
}
// Implicit holds use Stop Frame Hold to denote end of level
if (isStopFrame) drawEndOfLevelMarker(p, rect, true);
if (TApp::instance()->getCurrentFrame()->isEditingScene() &&
!m_viewer->orientation()->isVerticalTimeline() &&
@ -2062,13 +2084,27 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
Preferences::instance()->isCurrentTimelineIndicatorEnabled())
drawCurrentTimeIndicator(p, xy);
drawDragHandle(p, xy, sideColor);
if (!isImplicitCell) {
if (yetToCleanupCell) // ORIENTATION: what's this?
{
if (o->isVerticalTimeline())
p.fillRect(rect.adjusted(rect.width() / 2, 0, 0, 0),
(isSelected) ? m_viewer->getSelectedFullcolorColumnColor()
: m_viewer->getFullcolorColumnColor());
else
p.fillRect(rect.adjusted(0, rect.height() / 2, 0, 0),
(isSelected) ? m_viewer->getSelectedFullcolorColumnColor()
: m_viewer->getFullcolorColumnColor());
}
bool isLastRow = nextCell.isEmpty() ||
cell.m_level.getPointer() != nextCell.m_level.getPointer();
drawEndOfDragHandle(p, isLastRow, xy, cellColor);
drawDragHandle(p, xy, sideColor);
drawLockedDottedLine(p, xsh->getColumn(col)->isLocked(), xy, cellColor);
bool isLastRow = nextCell.isEmpty() ||
cell.m_level.getPointer() != nextCell.m_level.getPointer();
drawEndOfDragHandle(p, isLastRow, xy, cellColor);
drawLockedDottedLine(p, xsh->getColumn(col)->isLocked(), xy, cellColor);
}
int distance, offset;
TApp::instance()->getCurrentScene()->getScene()->getProperties()->getMarkers(
@ -2096,11 +2132,13 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
nameRect.adjust(0, 0, -frameAdj.x(), -frameAdj.y());
// draw text in red if the file does not exist
bool isRed = false;
TXshSimpleLevel *sl = cell.getSimpleLevel();
if (sl && !sl->isFid(cell.m_frameId)) isRed = true;
TXshChildLevel *cl = cell.getChildLevel();
if (cl && cell.getFrameId().getNumber() - 1 >= cl->getFrameCount())
bool isRed = false;
TXshSimpleLevel *sl = cell.getSimpleLevel();
if (sl && !cell.getFrameId().isStopFrame() && !sl->isFid(cell.m_frameId))
isRed = true;
TXshChildLevel *cl = cell.getChildLevel();
if (cl && !cell.getFrameId().isStopFrame() &&
cell.getFrameId().getNumber() - 1 >= cl->getFrameCount())
isRed = true;
QColor penColor =
isRed ? QColor(m_viewer->getErrorTextColor()) : m_viewer->getTextColor();
@ -2124,7 +2162,8 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
// if the same level & same fId with the previous cell,
// draw continue line
QString fnum;
if (sameLevel && prevCell.m_frameId == cell.m_frameId) {
if ((sameLevel && prevCell.m_frameId == cell.m_frameId && !prevIsImplicit) ||
isImplicitCell) {
if (o->isVerticalTimeline()) {
// not on line marker
PredefinedLine which =
@ -2161,7 +2200,8 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
if (pegbar->isKeyframe(row)) return;
}
drawFrameMarker(p, QPoint(x, y), (isRed ? Qt::red : Qt::black));
if (!isStopFrame)
drawFrameMarker(p, QPoint(x, y), (isRed ? Qt::red : Qt::black));
return;
}
@ -2169,7 +2209,9 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
// convert the last one digit of the frame number to alphabet
// Ex. 12 -> 1B 21 -> 2A 30 -> 3
if (Preferences::instance()->isShowFrameNumberWithLettersEnabled())
if (fid.isStopFrame())
fnum = "";
else if (Preferences::instance()->isShowFrameNumberWithLettersEnabled())
fnum = m_viewer->getFrameNumberWithLetters(fid.getNumber());
else {
QString frameNumber("");
@ -2180,8 +2222,9 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
fnum = frameNumber;
}
int alignFlag =
((showLevelName) ? Qt::AlignRight | Qt::AlignBottom : Qt::AlignCenter);
int alignFlag = ((showLevelName && !fid.isStopFrame())
? Qt::AlignRight | Qt::AlignBottom
: Qt::AlignCenter);
p.drawText(nameRect, alignFlag, fnum);
}
@ -2193,9 +2236,11 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference,
p.setPen(penColor);
}
if (isImplicitCell || isStopFrame) return;
// draw level name
if (showLevelName &&
(!sameLevel ||
(!sameLevel || (row > 0 && xsh->isImplicitCell(row - 1, col)) ||
(isAfterMarkers && !isSimpleView &&
Preferences::instance()->isLevelNameOnEachMarkerEnabled()))) {
std::wstring levelName = cell.m_level->getName();
@ -2285,11 +2330,7 @@ void CellArea::drawSoundTextCell(QPainter &p, int row, int col) {
drawFrameSeparator(p, row, col, false, heldFrame);
if (cell.isEmpty()) { // diagonal cross meaning end of level
QColor levelEndColor = m_viewer->getTextColor();
levelEndColor.setAlphaF(0.3);
p.setPen(levelEndColor);
p.drawLine(rect.topLeft(), rect.bottomRight());
p.drawLine(rect.topRight(), rect.bottomLeft());
drawEndOfLevelMarker(p, rect);
// only draw mark
if (markId >= 0) {
@ -2512,13 +2553,7 @@ void CellArea::drawSoundTextColumn(QPainter &p, int r0, int r1, int col) {
// draw X shape after the occupied cell
TXshCell prevCell;
if (row > 0) prevCell = xsh->getCell(row - 1, col);
if (!prevCell.isEmpty()) {
QColor levelEndColor = m_viewer->getTextColor();
levelEndColor.setAlphaF(0.3);
p.setPen(levelEndColor);
p.drawLine(info.rect.topLeft(), info.rect.bottomRight());
p.drawLine(info.rect.topRight(), info.rect.bottomLeft());
}
if (!prevCell.isEmpty()) drawEndOfLevelMarker(p, info.rect);
if (TApp::instance()->getCurrentFrame()->isEditingScene() &&
!m_viewer->orientation()->isVerticalTimeline() &&
row == m_viewer->getCurrentRow() &&
@ -2687,6 +2722,8 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col,
TCellSelection *cellSelection = m_viewer->getCellSelection();
bool isSelected = cellSelection->isCellSelected(row, col);
bool isImplicitCell = xsh->isImplicitCell(row, col);
bool isStopFrame = isImplicitCell ? false : cell.getFrameId().isStopFrame();
if (row > 0) prevCell = xsh->getCell(row - 1, col);
TXshCell nextCell = xsh->getCell(row + 1, col);
@ -2722,7 +2759,9 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col,
cellRect.adjust(0, 0, -frameAdj.x(), -frameAdj.y());
QRect rect = cellRect.adjusted(
1, 1,
(!m_viewer->orientation()->isVerticalTimeline() && !nextCell.isEmpty()
(!m_viewer->orientation()->isVerticalTimeline() && !nextCell.isEmpty() &&
!xsh->isImplicitCell(row + 1, col) &&
!nextCell.getFrameId().isStopFrame()
? 2
: 0),
0);
@ -2758,15 +2797,14 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col,
}
bool heldFrame = (!o->isVerticalTimeline() && !isAfterMarkers && sameLevel &&
prevCell.m_frameId == cell.m_frameId);
prevCell.m_frameId == cell.m_frameId) &&
!isImplicitCell;
drawFrameSeparator(p, row, col, false, heldFrame);
if (cell.isEmpty()) { // this means the former is not empty
QColor levelEndColor = m_viewer->getTextColor();
levelEndColor.setAlphaF(0.3);
p.setPen(levelEndColor);
p.drawLine(rect.topLeft(), rect.bottomRight());
p.drawLine(rect.topRight(), rect.bottomLeft());
// Implicit holds use Stop Frame Hold to denote end of level
if (!Preferences::instance()->isImplicitHoldEnabled())
drawEndOfLevelMarker(p, rect);
// only draw mark
if (markId >= 0) {
@ -2780,12 +2818,6 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col,
Preferences::instance()->isCurrentTimelineIndicatorEnabled())
drawCurrentTimeIndicator(p, xy);
// only draw mark
if (markId >= 0) {
p.setBrush(markColor);
p.setPen(Qt::NoPen);
p.drawEllipse(markRect);
}
return;
}
@ -2798,6 +2830,8 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col,
cellColor = (isSelected) ? m_viewer->getSelectedPaletteColumnColor()
: m_viewer->getPaletteColumnColor();
sideColor = m_viewer->getPaletteColumnBorderColor();
if (isImplicitCell) cellColor.setAlpha(m_viewer->getImplicitCellAlpha());
if (isStopFrame) cellColor.setAlpha(0);
}
// paint cell
@ -2809,26 +2843,31 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col,
else
p.fillRect(rect, QBrush(cellColor));
// Implicit holds use Stop Frame Hold to denote end of level
if (isStopFrame) drawEndOfLevelMarker(p, rect, true);
if (TApp::instance()->getCurrentFrame()->isEditingScene() &&
!m_viewer->orientation()->isVerticalTimeline() &&
row == m_viewer->getCurrentRow() &&
Preferences::instance()->isCurrentTimelineIndicatorEnabled())
drawCurrentTimeIndicator(p, xy);
drawDragHandle(p, xy, sideColor);
bool isLastRow = nextCell.isEmpty() ||
cell.m_level.getPointer() != nextCell.m_level.getPointer();
drawEndOfDragHandle(p, isLastRow, xy, cellColor);
drawLockedDottedLine(p, xsh->getColumn(col)->isLocked(), xy, cellColor);
if (!isImplicitCell) {
drawDragHandle(p, xy, sideColor);
bool isLastRow = nextCell.isEmpty() ||
cell.m_level.getPointer() != nextCell.m_level.getPointer();
drawEndOfDragHandle(p, isLastRow, xy, cellColor);
drawLockedDottedLine(p, xsh->getColumn(col)->isLocked(), xy, cellColor);
}
if (o->isVerticalTimeline() && isAfterMarkers) {
p.setPen(m_viewer->getMarkerLineColor());
p.drawLine(o->line(PredefinedLine::SEE_MARKER_THROUGH).translated(xy));
}
if (sameLevel && prevCell.m_frameId == cell.m_frameId &&
!isAfterMarkers) { // cell equal to previous one (not on marker line):
// do not write anything and draw a vertical line
if ((sameLevel && prevCell.m_frameId == cell.m_frameId && !isAfterMarkers) ||
isImplicitCell) { // cell equal to previous one (not on marker line):
// do not write anything and draw a vertical line
if (o->isVerticalTimeline()) {
QPen oldPen = p.pen();
p.setPen(QPen(m_viewer->getTextColor(), 1));
@ -2852,7 +2891,8 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col,
TStageObject *pegbar = xsh->getStageObject(m_viewer->getObjectId(col));
if (pegbar->isKeyframe(row)) return;
}
drawFrameMarker(p, QPoint(x, y), (isRed ? Qt::red : Qt::black));
if (!isStopFrame)
drawFrameMarker(p, QPoint(x, y), (isRed ? Qt::red : Qt::black));
return;
}
@ -2905,10 +2945,15 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col,
} else {
QString frameNumber("");
// set number
if (fid.getNumber() > 0) frameNumber = QString::number(fid.getNumber());
if (fid.isStopFrame())
frameNumber = "";
else if (fid.getNumber() > 0)
frameNumber = QString::number(fid.getNumber());
// add letter
if (!fid.getLetter().isEmpty()) frameNumber += fid.getLetter();
p.drawText(nameRect, Qt::AlignRight | Qt::AlignBottom, frameNumber);
int alignFlag = (!fid.isStopFrame() ? Qt::AlignRight | Qt::AlignBottom
: Qt::AlignCenter);
p.drawText(nameRect, alignFlag, frameNumber);
}
}
@ -2970,9 +3015,9 @@ void CellArea::drawKeyframe(QPainter &p, const QRect toBeUpdated) {
row0 = std::max(row0, r0);
row1 = std::min(row1, r1);
QRect tmpKeyRect = (col >= 0) ? keyRect
: o->rect(PredefinedRect::CAMERA_KEY_ICON)
.translated(-frameAdj / 2);
QRect tmpKeyRect =
(col >= 0) ? keyRect : o->rect(PredefinedRect::CAMERA_KEY_ICON)
.translated(-frameAdj / 2);
/*- first, draw key segments -*/
p.setPen(m_viewer->getTextColor());
@ -3443,7 +3488,8 @@ void CellArea::mousePressEvent(QMouseEvent *event) {
m_viewer->getKeyframeSelection()->selectNone();
setDragTool(
XsheetGUI::DragTool::makeLevelExtenderTool(m_viewer, false, true));
} else if ((!xsh->getCell(row, col).isEmpty()) &&
} else if ((!xsh->getCell(row, col).isEmpty() &&
!xsh->isImplicitCell(row, col)) &&
o->rect(PredefinedRect::DRAG_AREA)
.adjusted(0, 0, -frameAdj.x(), -frameAdj.y())
.contains(mouseInCell)) {
@ -3714,7 +3760,7 @@ void CellArea::contextMenuEvent(QContextMenuEvent *event) {
int row = cellPosition.frame();
int col = cellPosition.layer();
TXshCell cell = m_viewer->getXsheet()->getCell(row, col);
bool isImplicitCell = m_viewer->getXsheet()->isImplicitCell(row, col);
QMenu menu(this);
// Verifico se ho cliccato su una nota
@ -3783,13 +3829,13 @@ void CellArea::contextMenuEvent(QContextMenuEvent *event) {
}
if (areCellsEmpty) break;
}
createCellMenu(menu, areCellsEmpty, cell, row, col);
createCellMenu(menu, areCellsEmpty, cell, row, col, isImplicitCell);
} else {
m_viewer->getCellSelection()->makeCurrent();
m_viewer->getCellSelection()->selectCell(row, col);
m_viewer->setCurrentColumn(col);
createCellMenu(menu, !cell.isEmpty(), cell, row, col);
createCellMenu(menu, !cell.isEmpty(), cell, row, col, isImplicitCell);
}
if (!menu.isEmpty()) menu.exec(event->globalPos());
@ -3879,7 +3925,7 @@ const bool CellArea::isControlPressed() { return isCtrlPressed; }
//-----------------------------------------------------------------------------
void CellArea::createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell,
int row, int col) {
int row, int col, bool isImplicitCell) {
CommandManager *cmdManager = CommandManager::instance();
bool soundCellsSelected = m_viewer->areSoundCellsSelected();
@ -3952,11 +3998,13 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell,
}
menu.addMenu(editCellNumbersMenu);
}
menu.addAction(cmdManager->getAction(MI_FillEmptyCell));
menu.addAction(cmdManager->getAction(MI_StopFrameHold));
menu.addSeparator();
if (!soundTextCellsSelected)
if (!soundTextCellsSelected && !isImplicitCell)
menu.addAction(cmdManager->getAction(MI_Autorenumber));
}
@ -3997,17 +4045,19 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell,
replaceMenu->addAction(tmpAction);
}
}
if (!soundCellsSelected && !soundTextCellsSelected) {
if (selectionContainTlvImage(m_viewer->getCellSelection(),
m_viewer->getXsheet()))
replaceLevelMenu->addAction(
cmdManager->getAction(MI_RevertToCleanedUp));
if (selectionContainLevelImage(m_viewer->getCellSelection(),
m_viewer->getXsheet()))
replaceLevelMenu->addAction(
cmdManager->getAction(MI_RevertToLastSaved));
}
}
if (!soundCellsSelected && !soundTextCellsSelected) {
if (selectionContainTlvImage(m_viewer->getCellSelection(),
m_viewer->getXsheet()))
replaceLevelMenu->addAction(
cmdManager->getAction(MI_RevertToCleanedUp));
if (selectionContainLevelImage(m_viewer->getCellSelection(),
m_viewer->getXsheet()))
replaceLevelMenu->addAction(
cmdManager->getAction(MI_RevertToLastSaved));
menu.addAction(cmdManager->getAction(MI_SetKeyframes));
menu.addAction(cmdManager->getAction(MI_ShiftKeyframesDown));
menu.addAction(cmdManager->getAction(MI_ShiftKeyframesUp));
@ -4015,8 +4065,10 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell,
menu.addSeparator();
}
menu.addAction(cmdManager->getAction(MI_Cut));
menu.addAction(cmdManager->getAction(MI_Copy));
if (!isImplicitCell) {
menu.addAction(cmdManager->getAction(MI_Cut));
menu.addAction(cmdManager->getAction(MI_Copy));
}
menu.addAction(cmdManager->getAction(MI_Paste));
QMenu *pasteSpecialMenu = new QMenu(tr("Paste Special"), this);
@ -4029,7 +4081,7 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell,
}
menu.addMenu(pasteSpecialMenu);
menu.addAction(cmdManager->getAction(MI_Clear));
if (!isImplicitCell) menu.addAction(cmdManager->getAction(MI_Clear));
menu.addAction(cmdManager->getAction(MI_Insert));
if (!soundTextCellsSelected) {
menu.addAction(cmdManager->getAction(MI_CreateBlankDrawing));
@ -4086,6 +4138,7 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell,
menu.addAction(cmdManager->getAction(MI_CreateBlankDrawing));
menu.addSeparator();
menu.addAction(cmdManager->getAction(MI_FillEmptyCell));
menu.addAction(cmdManager->getAction(MI_StopFrameHold));
if (cameraCellsSelected) {
menu.addSeparator();
menu.addAction(cmdManager->getAction(MI_SetKeyframes));
@ -4131,6 +4184,7 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell,
menu.addAction(cmdManager->getAction(MI_ToggleAutoCreate));
menu.addAction(cmdManager->getAction(MI_ToggleCreationInHoldCells));
menu.addAction(cmdManager->getAction(MI_ToggleAutoStretch));
menu.addAction(cmdManager->getAction(MI_ToggleImplicitHold));
}
//-----------------------------------------------------------------------------
@ -4160,7 +4214,7 @@ void CellArea::onReplaceByCastedLevel(QAction *action) {
if (!cell.m_level.getPointer() || cell.m_level.getPointer() == level)
continue;
TXshCell oldCell = cell;
TXshCell oldCell = xsh->isImplicitCell(r, c) ? TXshCell() : cell;
cell.m_level = TXshLevelP(level);
xsh->setCell(r, c, cell);

View file

@ -131,6 +131,7 @@ class CellArea final : public QWidget {
void drawFrameMarker(QPainter &p, const QPoint &xy, QColor color,
bool isKeyFrame = false, bool isCamera = false);
void drawEndOfLevelMarker(QPainter &p, QRect rect, bool isStopFrame = false);
// Restistusce true
bool getEaseHandles(int r0, int r1, double e0, double e1, int &rh0, int &rh1);
@ -183,7 +184,7 @@ protected:
cella,
distinguendo i due casi: cella piena, cella vuota.*/
void createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell, int row,
int col);
int col, bool isImplicitCell);
//! Crea il menu' del tasto destro che si visualizza si clicca su un key
//! frame.
void createKeyMenu(QMenu &menu);

View file

@ -102,7 +102,7 @@ bool containsRasterLevel(TColumnSelection *selection) {
if (!cellCol) continue;
int i;
for (i = 0; i < cellCol->getMaxFrame() + 1; i++) {
for (i = 0; i < cellCol->getMaxFrame(true) + 1; i++) {
TXshCell cell = cellCol->getCell(i);
if (cell.isEmpty()) continue;
TXshSimpleLevel *level = cell.getSimpleLevel();

View file

@ -169,7 +169,10 @@ void InsertSceneFrameUndo::doInsertSceneFrame(int frame) {
objectId = TStageObjectId::ColumnId(c);
xsh->insertCells(frame, c);
xsh->setCell(frame, c, xsh->getCell(frame + 1, c));
TXshCell cell;
if (!Preferences::instance()->isImplicitHoldEnabled() && frame > 0)
cell = xsh->getCell(frame - 1, c);
xsh->setCell(frame, c, cell);
}
if (!xsh->getColumn(c) || xsh->getColumn(c)->isLocked()) continue;
@ -288,6 +291,24 @@ public:
}
} ToggleAutoStretchCommand;
//=============================================================================
class ToggleImplicitHoldCommand final : public MenuItemHandler {
public:
ToggleImplicitHoldCommand() : MenuItemHandler(MI_ToggleImplicitHold) {}
void execute() override {
bool currentImplicitHoldEnabled =
Preferences::instance()->isImplicitHoldEnabled();
if (CommandManager::instance()
->getAction(MI_ToggleImplicitHold)
->isChecked() == currentImplicitHoldEnabled)
return;
Preferences::instance()->setValue(EnableImplicitHold,
!currentImplicitHoldEnabled);
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
}
} ToggleImplicitHoldCommand;
//*****************************************************************************
// RemoveSceneFrame command
//*****************************************************************************
@ -314,7 +335,8 @@ public:
for (int c = 0; c != colsCount; ++c) {
// Store cell
m_cells[c] = xsh->getCell(m_frame, c);
const TXshCell &cell = xsh->getCell(m_frame, c);
m_cells[c] = xsh->isImplicitCell(m_frame, c) ? TXshCell() : cell;
// Store stage object keyframes
TStageObject *obj = xsh->getStageObject(TStageObjectId::ColumnId(c));
@ -638,9 +660,10 @@ public:
int r = m_range.m_r0;
while (c <= m_range.m_c1) {
tempCol = c;
while (r <= m_range.m_r1) {
while (r <= m_range.m_r1 + 1) {
tempRow = r;
if (xsh->getCell(tempRow, tempCol).isEmpty()) {
if (xsh->getCell(tempRow, tempCol).isEmpty() ||
xsh->isImplicitCell(tempRow, tempCol)) {
emptyCells.push_back(std::make_pair(tempRow, tempCol));
}
r++;
@ -664,7 +687,7 @@ public:
int r = m_range.m_r0;
while (c <= m_range.m_c1) {
col = c;
while (r <= m_range.m_r1) {
while (r <= m_range.m_r1 + 1) {
row = r;
bool found = false;
for (int i = 0; i < emptyCells.size(); i++) {
@ -677,7 +700,7 @@ public:
r++;
continue;
}
changeDrawing(-m_direction, row, col);
if (r <= m_range.m_r1) changeDrawing(-m_direction, row, col);
r++;
}
r = m_range.m_r0;
@ -698,11 +721,18 @@ public:
int col, row;
int c = m_range.m_c0;
int r = m_range.m_r0;
TXsheetP xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
while (c <= m_range.m_c1) {
col = c;
// Convert implicit cell at end of selected range into a populated cell
if (xsh->isImplicitCell((m_range.m_r1 + 1), col)) {
TXshCell origCell = xsh->getCell((m_range.m_r1 + 1), col);
xsh->setCell((m_range.m_r1 + 1), col, origCell);
}
while (r <= m_range.m_r1) {
row = r;
changeDrawing(m_direction, row, col);
if (row == m_range.m_r0 || !xsh->isImplicitCell(row, col))
changeDrawing(m_direction, row, col);
r++;
}
r = m_range.m_r0;
@ -766,13 +796,16 @@ public:
// Find the 1st populated cell in the column
if (baseCell.isEmpty()) continue;
if (xsh->isImplicitCell(r, c))
emptyCells.push_back(std::make_pair(r, c));
FramesMap::key_type frameBaseKey(r, c);
int frameCount = 1;
TXshCell nextCell = xsh->getCell((r + frameCount), c);
while (nextCell == baseCell ||
(nextCell.isEmpty() && (r + frameCount) <= m_range.m_r1)) {
if (nextCell.isEmpty())
if ((r + frameCount) >= xsh->getFrameCount()) break;
if (nextCell.isEmpty() || xsh->isImplicitCell((r + frameCount), c))
emptyCells.push_back(std::make_pair((r + frameCount), c));
frameCount++;
@ -820,7 +853,10 @@ public:
while (n < ct->second) {
int row = ct->first.first + n;
int col = ct->first.second;
DrawingSubtitutionUndo::changeDrawing(m_direction, row, col);
if (n == 0 ||
!TApp::instance()->getCurrentXsheet()->getXsheet()->isImplicitCell(
row, col))
DrawingSubtitutionUndo::changeDrawing(m_direction, row, col);
n++;
}
}
@ -853,10 +889,12 @@ bool DrawingSubtitutionUndo::changeDrawing(int delta, int row, int col) {
return false;
cell = prevCell;
usePrevCell = true;
} else if (!cell.m_level || !(cell.m_level->getSimpleLevel() ||
cell.m_level->getChildLevel() ||
cell.m_level->getSoundTextLevel()))
} else if (cell.getFrameId().isStopFrame() || !cell.m_level ||
!(cell.m_level->getSimpleLevel() ||
cell.m_level->getChildLevel() ||
cell.m_level->getSoundTextLevel()))
return false;
TXshLevel *level = cell.m_level->getSimpleLevel();
if (!level) level = cell.m_level->getChildLevel();
if (!level) level = cell.m_level->getSoundTextLevel();
@ -2316,11 +2354,10 @@ public:
while (!exit) {
TXshCell cell = TApp::instance()->getCurrentXsheetViewer()->getXsheet()->getCell(currentPos, column);
if (cell.isEmpty()) {
if (cell.isEmpty() || cell.getFrameId().isStopFrame()) {
(direction == up) ? currentPos++ : currentPos--;
exit = true;
}
else
} else
(direction == up) ? currentPos-- : currentPos++;
}
@ -2328,15 +2365,19 @@ public:
}
void execute() override {
int col = TApp::instance()->getCurrentColumn()->getColumnIndex();
int row = TApp::instance()->getCurrentFrame()->getFrame();
TXshCell cell =
TApp::instance()->getCurrentXsheetViewer()->getXsheet()->getCell(row, col);
if (cell.isEmpty()) return;
int col = TApp::instance()->getCurrentColumn()->getColumnIndex();
int row = TApp::instance()->getCurrentFrame()->getFrame();
TXsheet *xsh = TApp::instance()->getCurrentXsheetViewer()->getXsheet();
TXshCell cell = xsh->getCell(row, col);
if (cell.isEmpty() || cell.getFrameId().isStopFrame()) return;
int step, r0, r1;
xsh->getCellRange(col, r0, r1);
int top = getNonEmptyCell(row, col, Direction::up);
int bottom = getNonEmptyCell(row, col, Direction::down);
int bottom = (xsh->isImplicitCell(row, col) && row > r1)
? row
: getNonEmptyCell(row, col, Direction::down);
XsheetGUI::getPlayRange(r0, r1, step);
XsheetGUI::setPlayRange(top, bottom, step);

View file

@ -2063,7 +2063,8 @@ 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()) return false;
if (!xsh->getCell(r, c).isEmpty() && !xsh->isImplicitCell(r, c))
return false;
}
return true;
}

View file

@ -349,6 +349,11 @@ class XsheetViewer final : public QFrame, public SaveLoadQSettings {
Q_PROPERTY(QColor SelectedMeshColumnColor READ getSelectedMeshColumnColor
WRITE setSelectedMeshColumnColor)
// Implicit Cell alpha
int m_implicitCellAlpha;
Q_PROPERTY(int ImplicitCellAlpha READ getImplicitCellAlpha WRITE
setImplicitCellAlpha);
// Table color
QColor m_tableColor;
Q_PROPERTY(QColor TableColor READ getTableColor WRITE setTableColor)
@ -949,6 +954,10 @@ public:
return m_selectedMeshColumnColor;
}
// Implicit Cell Alpha
void setImplicitCellAlpha(const int &alpha) { m_implicitCellAlpha = alpha; }
int getImplicitCellAlpha() const { return m_implicitCellAlpha; }
// Table node
void setTableColor(const QColor &color) { m_tableColor = color; }
QColor getTableColor() const { return m_tableColor; }

View file

@ -1272,7 +1272,7 @@ void RowArea::contextMenuEvent(QContextMenuEvent *event) {
bool RowArea::canSetAutoMarkers() {
TXshCell cell =
m_viewer->getXsheet()->getCell(m_row, m_viewer->getCurrentColumn());
return cell.isEmpty() ? false : true;
return cell.isEmpty() || cell.getFrameId().isStopFrame() ? false : true;
}
//-----------------------------------------------------------------------------

View file

@ -16,6 +16,7 @@
#include "toonz/tfxhandle.h"
#include "toonz/tcolumnhandle.h"
#include "toonz/tscenehandle.h"
#include "toonz/preferences.h"
#include "historytypes.h"
// TnzBase includes
@ -309,7 +310,9 @@ TXshZeraryFxColumn *FxCommandUndo::createZeraryFxColumn(TXsheet *xsh, TFx *zfx,
int frameCount = xsh->getScene()->getFrameCount() - row;
TXshZeraryFxColumn *column =
new TXshZeraryFxColumn(frameCount > 0 ? frameCount : 100);
new TXshZeraryFxColumn(Preferences::instance()->isImplicitHoldEnabled()
? 1
: (frameCount > 0 ? frameCount : 100));
column->getZeraryColumnFx()->setZeraryFx(zfx);
column->insertEmptyCells(0, row);
@ -2541,7 +2544,9 @@ void UndoPasteFxs::initialize(const std::map<TFx *, int> &zeraryFxColumnSize,
// column with
// the specified column size
std::map<TFx *, int>::const_iterator it = zeraryFxColumnSize.find(fx);
int rows = (it == zeraryFxColumnSize.end()) ? 100 : it->second;
int rows = Preferences::instance()->isImplicitHoldEnabled()
? 1
: ((it == zeraryFxColumnSize.end()) ? 100 : it->second);
TXshZeraryFxColumn *column = new TXshZeraryFxColumn(rows);
TZeraryColumnFx *zcfx = column->getZeraryColumnFx();

View file

@ -512,7 +512,8 @@ void Preferences::definePreferenceItems() {
define(EnableAutocreation, "EnableAutocreation", QMetaType::Bool, true);
define(NumberingSystem, "NumberingSystem", QMetaType::Int, 0); // Incremental
define(EnableAutoStretch, "EnableAutoStretch", QMetaType::Bool, true);
define(EnableAutoStretch, "EnableAutoStretch", QMetaType::Bool, false);
define(EnableImplicitHold, "EnableImplicitHold", QMetaType::Bool, true);
define(EnableCreationInHoldCells, "EnableCreationInHoldCells",
QMetaType::Bool, true);
define(EnableAutoRenumber, "EnableAutoRenumber", QMetaType::Bool, true);

View file

@ -111,6 +111,15 @@ 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;
}
@ -801,6 +810,15 @@ 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に繋がっておらず、空セルの場合は 中身無しを返す --*/
@ -940,7 +958,17 @@ PlacedFx FxBuilder::makePF(TPaletteColumnFx *pcfx) {
if (!pcfx->getColumn()->isPreviewVisible()) return PlacedFx();
TXshCell cell = pcfx->getColumn()->getCell(tfloor(m_frame));
if (cell.isEmpty()) return PlacedFx();
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();
PlacedFx pf;
pf.m_columnIndex = pcfx->getColumn()->getIndex();
@ -968,6 +996,15 @@ 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;
@ -978,7 +1015,7 @@ PlacedFx FxBuilder::makePF(TZeraryColumnFx *zcfx) {
return PlacedFx();
// if the cell is empty, only inherits its placement
if (cell.isEmpty()) return pf;
if (cell.isEmpty() || cell.getFrameId().isStopFrame()) return pf;
// set m_fx only when the current cell is not empty
pf.m_fx =

View file

@ -364,22 +364,23 @@ void StageBuilder::addCell(PlayerSet &players, ToonzScene *scene, TXsheet *xsh,
double columnZ = pegbar->getZ(row);
double columnNoScaleZ = pegbar->getGlobalNoScaleZ();
TXshCell cell = xsh->getCell(row, col);
TXshLevel *xl = cell.m_level.getPointer();
TXshCell cell = xsh->getCell(row, col);
TXshLevel *xl = cell.m_level.getPointer();
TXshSimpleLevel *sl = xl ? xl->getSimpleLevel() : 0;
// check the previous row for a stop motion layer
if (!xl) {
// Get the last populated cell
cell = xsh->getCell(row - 1, col);
xl = cell.m_level.getPointer();
if (!xl) {
if (!xl) return;
sl = xl->getSimpleLevel();
if (sl && m_liveViewImage && sl == m_liveViewPlayer.m_sl)
row -= 1;
else
return;
} else {
xl = cell.m_level.getPointer();
TXshSimpleLevel *sl = xl->getSimpleLevel();
if (sl && m_liveViewImage && sl == m_liveViewPlayer.m_sl) {
row -= 1;
} else
return;
}
}
ZPlacement cameraPlacement;
@ -394,8 +395,6 @@ void StageBuilder::addCell(PlayerSet &players, ToonzScene *scene, TXsheet *xsh,
if (!columnBehindCamera) return;
TXshSimpleLevel *sl = xl->getSimpleLevel();
bool storePlayer =
sl || (xl->getChildLevel() &&
locals::applyPlasticDeform(column.getPointer(), m_vs) &&

View file

@ -819,7 +819,17 @@ bool TLevelColumnFx::canHandle(const TRenderSettings &info, double frame) {
if (!m_levelColumn) return true;
TXshCell cell = m_levelColumn->getCell(m_levelColumn->getFirstRow());
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();
@ -835,7 +845,17 @@ TAffine TLevelColumnFx::handledAffine(const TRenderSettings &info,
double frame) {
if (!m_levelColumn) return TAffine();
TXshCell cell = m_levelColumn->getCell(m_levelColumn->getFirstRow());
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();
@ -873,6 +893,16 @@ 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();
@ -894,6 +924,15 @@ 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();
@ -921,6 +960,15 @@ 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();
@ -971,7 +1019,15 @@ 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();
@ -1388,8 +1444,17 @@ bool TLevelColumnFx::doGetBBox(double frame, TRectD &bBox,
// Usual preliminaries (make sure a level/cell exists, etc...)
if (!m_levelColumn) return false;
int row = (int)frame;
const TXshCell &cell = m_levelColumn->getCell(row);
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;
@ -1418,7 +1483,17 @@ bool TLevelColumnFx::doGetBBox(double frame, TRectD &bBox,
dpi = imageInfo.m_dpix / Stage::inch;
} else {
TImageP img = m_levelColumn->getCell(row).getImage(false);
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();
}
@ -1484,10 +1559,19 @@ std::wstring TLevelColumnFx::getColumnName() const {
std::string TLevelColumnFx::getAlias(double frame,
const TRenderSettings &info) const {
if (!m_levelColumn || m_levelColumn->getCell((int)frame).isEmpty())
return std::string();
if (!m_levelColumn) return std::string();
const TXshCell &cell = m_levelColumn->getCell((int)frame);
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;
TXshSimpleLevel *sl = cell.getSimpleLevel();
@ -1548,6 +1632,15 @@ 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

@ -36,7 +36,7 @@ TXshCellColumn::~TXshCellColumn() { m_cells.clear(); }
//-----------------------------------------------------------------------------
int TXshCellColumn::getRange(int &r0, int &r1) const {
int TXshCellColumn::getRange(int &r0, int &r1, bool ignoreLastStop) const {
int cellCount = m_cells.size();
r0 = m_first;
r1 = r0 + cellCount - 1;
@ -51,8 +51,10 @@ int TXshCellColumn::getRange(int &r0, int &r1) const {
r0 = m_first + i;
for (i = cellCount - 1; i >= 0 && m_cells[i].isEmpty(); i--) {
}
r1 = m_first + i;
if (r1 < m_cells.size() && r1 > r0 && ignoreLastStop &&
m_cells[r1].getFrameId().isStopFrame())
r1--;
return r1 - r0 + 1;
}
@ -70,9 +72,9 @@ int TXshCellColumn::getRowCount() const {
//-----------------------------------------------------------------------------
int TXshCellColumn::getMaxFrame() const {
int TXshCellColumn::getMaxFrame(bool ignoreLastStop) const {
int r0, r1;
getRange(r0, r1);
getRange(r0, r1, ignoreLastStop);
return r1;
}

View file

@ -241,7 +241,49 @@ const TXshCell &TXsheet::getCell(const CellPosition &pos) const {
if (!column) return emptyCell;
TXshCellColumn *xshColumn = column->getCellColumn();
if (!xshColumn) return emptyCell;
return xshColumn->getCell(pos.frame());
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);
}
//-----------------------------------------------------------------------------
bool TXsheet::isImplicitCell(int row, int col) const {
return isImplicitCell(CellPosition(row, col));
}
bool TXsheet::isImplicitCell(const CellPosition &pos) const {
if (!Preferences::instance()->isImplicitHoldEnabled()) return false;
TXshColumnP column = m_imp->m_columnSet.getColumn(pos.layer());
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.isEmpty()) return true;
if (tempCell.getFrameId().isStopFrame()) return false;
}
return false;
}
//-----------------------------------------------------------------------------
@ -251,8 +293,7 @@ bool TXsheet::setCell(int row, int col, const TXshCell &cell) {
bool wasColumnEmpty = isColumnEmpty(col);
TXshCellColumn *cellColumn;
if (!cell.isEmpty()) {
if (!cell.isEmpty() && !isImplicitCell(row, col)) {
TXshLevel *level = cell.m_level.getPointer();
assert(level);
@ -297,7 +338,7 @@ bool TXsheet::setCell(int row, int col, const TXshCell &cell) {
if (cell.isEmpty())
updateFrameCount();
else if (row >= m_imp->m_frameCount)
m_imp->m_frameCount = row + 1;
m_imp->m_frameCount = row + (cell.getFrameId().isStopFrame() ? 0 : 1);
TNotifier::instance()->notify(TXsheetChange());
@ -360,7 +401,7 @@ bool TXsheet::setCells(int row, int col, int rowCount, const TXshCell cells[]) {
TXshCellColumn *column = touchColumn(col, type)->getCellColumn();
if (!column) return false;
int oldColRowCount = column->getMaxFrame() + 1;
int oldColRowCount = column->getMaxFrame(true) + 1;
bool ret = column->setCells(row, rowCount, cells);
if (!ret || column->isLocked()) {
if (wasColumnEmpty) {
@ -369,7 +410,7 @@ bool TXsheet::setCells(int row, int col, int rowCount, const TXshCell cells[]) {
}
return false;
}
int newColRowCount = column->getMaxFrame() + 1;
int newColRowCount = column->getMaxFrame(true) + 1;
TFx *fx = column->getFx();
if (wasColumnEmpty && fx && fx->getOutputConnectionCount() == 0)
@ -396,7 +437,7 @@ void TXsheet::insertCells(int row, int col, int rowCount) {
if (!xshColumn) return;
xshColumn->insertEmptyCells(row, rowCount);
// aggiorno il frame count
int fc = xshColumn->getMaxFrame() + 1;
int fc = xshColumn->getMaxFrame(true) + 1;
if (fc > m_imp->m_frameCount) m_imp->m_frameCount = fc;
}
@ -409,7 +450,7 @@ void TXsheet::removeCells(int row, int col, int rowCount) {
TXshCellColumn *xshCellColumn = column->getCellColumn();
if (!xshCellColumn) return;
int oldColRowCount = xshCellColumn->getMaxFrame() + 1;
int oldColRowCount = xshCellColumn->getMaxFrame(true) + 1;
xshCellColumn->removeCells(row, rowCount);
// aggiornamento framecount
@ -427,7 +468,7 @@ void TXsheet::clearCells(int row, int col, int rowCount) {
TXshCellColumn *xshCellColumn = column->getCellColumn();
if (!xshCellColumn) return;
int oldColRowCount = xshCellColumn->getMaxFrame() + 1;
int oldColRowCount = xshCellColumn->getMaxFrame(true) + 1;
xshCellColumn->clearCells(row, rowCount);
// aggiornamento framecount
@ -636,8 +677,12 @@ 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 = getCell(CellPosition(i1, j));
TXshCell app2 = getCell(CellPosition(i2, j));
TXshCell app1;
if (!isImplicitCell(CellPosition(i1, j)))
app1 = getCell(CellPosition(i1, j));
TXshCell app2;
if (!isImplicitCell(CellPosition(i2, j)))
app2 = getCell(CellPosition(i2, j));
setCell(i1, j, app2);
setCell(i2, j, app1);
}
@ -654,7 +699,9 @@ 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 = getCell(CellPosition(i2, j));
TXshCell cell;
if (!isImplicitCell(CellPosition(i2, j)))
cell = getCell(CellPosition(i2, j));
setCell(i1, j, cell);
}
}
@ -684,14 +731,17 @@ bool TXsheet::incrementCells(int r0, int c0, int r1, int c1,
if (getCell(CellPosition(i + 1, j)).isEmpty()) continue;
int frame1 = getCell(CellPosition(i, j)).getFrameId().getNumber();
if (frame1 == -1) break;
if (frame1 == TFrameId::EMPTY_FRAME || frame1 == TFrameId::STOP_FRAME)
break;
while (!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())
i++, count++;
int frame2 = getCell(CellPosition(i + 1, j)).getFrameId().getNumber();
if (frame2 == -1) break;
if (frame2 == TFrameId::EMPTY_FRAME || frame2 == TFrameId::STOP_FRAME)
break;
if (frame1 + count == frame2)
continue;
@ -699,19 +749,26 @@ bool TXsheet::incrementCells(int r0, int c0, int r1, int c1,
{
int numCells = frame2 - frame1 - count;
insertCells(i + 1, j, numCells);
TXshCell cell(0, TFrameId::NO_FRAME);
forUndo.push_back(std::pair<TRect, TXshCell>(
TRect(i + 1, j, i + 1 + numCells - 1, j), TXshCell()));
for (int k = 1; k <= numCells; k++)
setCell(i + k, j, getCell(CellPosition(i, j)));
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));
setCell(i + k, j, cell);
}
i += numCells;
r1 += numCells;
} else // remove
{
int numCells = count - frame2 + frame1;
i = i - numCells;
forUndo.push_back(
std::pair<TRect, TXshCell>(TRect(i + 1, j, i + 1 + numCells - 1, j),
getCell(CellPosition(i + 1, j))));
TXshCell cell;
if (!isImplicitCell(CellPosition(i + 1, j)))
cell = getCell(CellPosition(i + 1, j));
forUndo.push_back(std::pair<TRect, TXshCell>(
TRect(i + 1, j, i + 1 + numCells - 1, j), cell));
removeCells(i + 1, j, numCells);
r1 -= numCells;
}
@ -728,8 +785,13 @@ void TXsheet::duplicateCells(int r0, int c0, int r1, int c1, int upTo) {
for (int j = c0; j <= c1; j++) {
insertCells(r1 + 1, j, upTo - (r1 + 1) + 1);
for (int i = r1 + 1; i <= upTo; i++)
setCell(i, j, getCell(CellPosition(r0 + ((i - (r1 + 1)) % chunk), j)));
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));
setCell(i, j, cell);
}
}
}
@ -746,18 +808,20 @@ 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++) {
cells[k++] = getCell(CellPosition(r, c));
const TXshCell &cell = getCell(CellPosition(r, c));
cells[k++] = isImplicitCell(CellPosition(r, c)) ? TXshCell() : cell;
}
int nrows = nr * (type - 1);
for (int c = c0; c <= c1; ++c) insertCells(r1 + 1, c, nrows);
bool useImplicitHold = Preferences::instance()->isImplicitHoldEnabled();
for (int j = c0; j <= c1; j++) {
int i, k;
for (i = r0, k = j - c0; k < size; k += nc) {
for (int i1 = 0; i1 < type; i1++) {
if (cells[k].isEmpty())
if (cells[k].isEmpty() || (useImplicitHold && i1 > 0))
clearCells(i + i1, j);
else
setCell(i + i1, j, cells[k]);
@ -772,13 +836,18 @@ void TXsheet::stepCells(int r0, int c0, int r1, int c1, int type) {
void TXsheet::increaseStepCells(int r0, int c0, int &r1, int c1) {
int c, size = r1 - r0 + 1;
QList<int> ends;
bool useImplicit = Preferences::instance()->isImplicitHoldEnabled();
for (c = c0; c <= c1; c++) {
int r = r0, i = 0, rEnd = r1;
while (r <= rEnd) {
TXshCell cell = getCell(CellPosition(r, c));
if (!cell.isEmpty()) {
insertCells(r, c);
setCell(r, c, cell);
if (useImplicit)
insertCells(r + 1, c);
else {
insertCells(r, c);
setCell(r, c, cell);
}
rEnd++;
r++;
while (cell == getCell(CellPosition(r, c)) && r <= rEnd) r++;
@ -848,7 +917,10 @@ void TXsheet::eachCells(int r0, int c0, int r1, int c1, int type) {
for (j = r0, i = 0; i < size;
j += type) // in cells copio il contenuto delle celle che mi interessano
{
for (k = c0; k <= c1; k++, i++) cells[i] = getCell(CellPosition(j, k));
for (k = c0; k <= c1; k++, i++) {
const TXshCell &cell = getCell(CellPosition(j, k));
cells[i] = isImplicitCell(j, k) ? TXshCell() : cell;
}
}
int c;
@ -880,19 +952,29 @@ int TXsheet::reframeCells(int r0, int r1, int col, int type, int withBlank) {
cells.clear();
for (int r = r0; r <= r1; r++) {
if (cells.size() == 0 || cells.last() != getCell(CellPosition(r, col)))
cells.push_back(getCell(CellPosition(r, col)));
const TXshCell &cell = getCell(CellPosition(r, col));
if (cells.size() == 0 || cells.last() != cell) {
if (cell.isEmpty() && cells.last().getFrameId() == TFrameId::STOP_FRAME)
continue;
cells.push_back(cell);
}
}
// if withBlank is greater than -1, remove empty cells from cell order
if (withBlank >= 0) {
auto itr = cells.begin();
while (itr != cells.end()) {
if ((*itr).isEmpty())
if ((*itr).isEmpty() || (*itr).getFrameId().isStopFrame())
itr = cells.erase(itr);
else
itr++;
}
// Convert implicit cell at end of selected range into a populated cell
if (withBlank > 0 && isImplicitCell((r1 + 1), col)) {
const TXshCell &origCell = getCell((r1 + 1), col);
setCell((r1 + 1), col, origCell);
}
}
if (cells.empty()) return 0;
@ -913,9 +995,13 @@ int TXsheet::reframeCells(int r0, int r1, int col, int type, int withBlank) {
removeCells(r0 + nrows, col, nr - nrows);
}
bool useImplicitHold = Preferences::instance()->isImplicitHoldEnabled();
for (int i = r0, k = 0; i < r0 + nrows; k++) {
TXshLevelP level = cells[k].m_level;
if (useImplicitHold && !level) level = getCell(i, col).m_level;
for (int i1 = 0; i1 < type; i1++) {
if (cells[k].isEmpty())
// Cell is empty, find last level
if (cells[k].isEmpty() || (useImplicitHold && i1 > 0))
clearCells(i + i1, col);
else
setCell(i + i1, col, cells[k]);
@ -924,7 +1010,10 @@ int TXsheet::reframeCells(int r0, int r1, int col, int type, int withBlank) {
if (withBlank > 0) {
for (int i1 = 0; i1 < withBlank * type; i1++) {
clearCells(i + i1, col);
if (useImplicitHold && i1 == 0)
setCell(i + i1, col, TXshCell(level, TFrameId::STOP_FRAME));
else
clearCells(i + i1, col);
}
i += withBlank * type;
}
@ -1008,6 +1097,7 @@ void TXsheet::rolldownCells(int r0, int c0, int r1, int c1) {
If nr>r1-r0+1 add cells, otherwise remove cells. */
void TXsheet::timeStretch(int r0, int c0, int r1, int c1, int nr) {
int oldNr = r1 - r0 + 1;
bool useImplicitHold = Preferences::instance()->isImplicitHoldEnabled();
if (nr > oldNr) /* ingrandisce */
{
int c;
@ -1019,9 +1109,14 @@ void TXsheet::timeStretch(int r0, int c0, int r1, int c1, int nr) {
getCells(r0, c, oldNr, cells.get());
insertCells(r0 + 1, c, dn);
int i;
for (i = nr - 1; i >= 0; i--) {
for (i = 0; i < nr; i++) {
int j = i * double(oldNr) / double(nr);
if (j < i) setCell(i + r0, c, cells[j]);
if (j < i) {
int prevj = (i - 1) * double(oldNr) / double(nr);
TXshCell cell =
(useImplicitHold && j == prevj) ? TXshCell() : cells[j];
setCell(i + r0, c, cell);
}
}
}
} else /* rimpicciolisce */
@ -1035,7 +1130,12 @@ void TXsheet::timeStretch(int r0, int c0, int r1, int c1, int nr) {
int i;
for (i = 0; i < nr; i++) {
int j = i * double(oldNr) / double(nr);
if (j > i) setCell(i + r0, c, cells[j]);
if (j > i) {
int prevj = (i - 1) * double(oldNr) / double(nr);
TXshCell cell =
(useImplicitHold && j == prevj) ? TXshCell() : cells[j];
setCell(i + r0, c, cell);
}
}
removeCells(r1 - dn + 1, c, dn);
}
@ -1170,9 +1270,12 @@ void TXsheet::updateFrameCount() {
m_imp->m_frameCount = 0;
for (int i = 0; i < m_imp->m_columnSet.getColumnCount(); ++i) {
TXshColumnP cc = m_imp->m_columnSet.getColumn(i);
if (cc && !cc->isEmpty())
m_imp->m_frameCount =
std::max(m_imp->m_frameCount, cc->getMaxFrame() + 1);
if (cc && !cc->isEmpty()) {
int maxFrame = cc->getMaxFrame();
TXshCell cell = getCell(maxFrame, i);
if (cell.getFrameId().isStopFrame()) maxFrame--;
m_imp->m_frameCount = std::max(m_imp->m_frameCount, maxFrame + 1);
}
}
}
@ -1744,13 +1847,22 @@ void TXsheet::autoInputCellNumbers(int increment, int interval, int step,
int rowUpTo = (r1 == -1) ? rowsCount - 1
: ((isOverwrite) ? std::min(r1, r0 + rowsCount - 1)
: r0 + rowsCount - 1);
bool useImplicitHold = Preferences::instance()->isImplicitHoldEnabled();
// for each column
for (int c = 0; c < columnIndices.size(); c++) {
int columnIndex = columnIndices.at(c);
TXshLevelP level = levels.at(c);
// on insertion, insert empty cells first
if (!isOverwrite) insertCells(r0, columnIndex, rowsCount);
if (!isOverwrite) {
// If implicit cell, convert to real cell
if (isImplicitCell(r0, columnIndex)) {
TXshCell cell = getCell(r0, columnIndex);
setCell(r0, columnIndex, cell);
}
insertCells(r0, columnIndex, rowsCount);
}
// obtain fids to be input
std::vector<TFrameId> fids;
@ -1794,11 +1906,19 @@ void TXsheet::autoInputCellNumbers(int increment, int interval, int step,
int step_interv_itr = 0;
while (row <= rowUpTo) {
// input cell
if (step_interv_itr < step)
setCell(row, columnIndex, TXshCell(level, fids.at(fid_itr)));
if (step_interv_itr < step) {
TXshCell cell;
if (useImplicitHold && step_interv_itr == 0)
cell = TXshCell(level, fids.at(fid_itr));
setCell(row, columnIndex, cell);
}
// .. or set empty cell as interval
else
setCell(row, columnIndex, TXshCell());
else {
TXshCell emptyCell;
if (useImplicitHold && step_interv_itr == step)
emptyCell = TXshCell(level, TFrameId::STOP_FRAME);
setCell(row, columnIndex, emptyCell);
}
// increment
step_interv_itr++;

View file

@ -17,6 +17,8 @@ TFrameId qstringToFrameId(QString str) {
return TFrameId::EMPTY_FRAME;
else if (str == "-" || str == "-2")
return TFrameId::NO_FRAME;
else if (str == "x" || str == "-3")
return TFrameId::STOP_FRAME;
QString regExpStr = QString("^%1$").arg(TFilePath::fidRegExpStr());
QRegExp rx(regExpStr);

View file

@ -287,7 +287,7 @@ void TXshSoundColumn::saveData(TOStream &os) {
//-----------------------------------------------------------------------------
int TXshSoundColumn::getRange(int &r0, int &r1) const {
int TXshSoundColumn::getRange(int &r0, int &r1, bool ignoreLastStop) const {
r0 = getFirstRow();
r1 = getMaxFrame();
return r1 - r0 + 1;
@ -301,7 +301,7 @@ int TXshSoundColumn::getRowCount() const {
//-----------------------------------------------------------------------------
int TXshSoundColumn::getMaxFrame() const {
int TXshSoundColumn::getMaxFrame(bool ignoreLastStop) const {
int levelsCount = m_levels.size();
if (levelsCount == 0) return -1;
return m_levels.at(levelsCount - 1)->getVisibleEndFrame();

View file

@ -7,6 +7,7 @@
#include "toonz/txsheet.h"
#include "toonz/fxdag.h"
#include "toonz/txshzeraryfxlevel.h"
#include "toonz/preferences.h"
#include "tstream.h"
@ -21,6 +22,7 @@ TXshZeraryFxColumn::TXshZeraryFxColumn(int frameCount)
m_zeraryColumnFx->setColumn(this);
m_zeraryFxLevel->addRef();
m_zeraryFxLevel->setColumn(this);
if (frameCount <= 0) return;
for (int i = 0; i < frameCount; i++)
setCell(i, TXshCell(m_zeraryFxLevel, TFrameId(1)));
}
@ -37,8 +39,13 @@ TXshZeraryFxColumn::TXshZeraryFxColumn(const TXshZeraryFxColumn &src)
m_zeraryFxLevel->setColumn(this);
m_first = src.m_first;
int i;
for (i = 0; i < (int)src.m_cells.size(); i++)
m_cells.push_back(TXshCell(m_zeraryFxLevel, src.m_cells[i].getFrameId()));
for (i = 0; i < (int)src.m_cells.size(); i++) {
if (Preferences::instance()->isImplicitHoldEnabled() &&
src.m_cells[i].getFrameId().isEmptyFrame())
m_cells.push_back(TXshCell(0, src.m_cells[i].getFrameId()));
else
m_cells.push_back(TXshCell(m_zeraryFxLevel, src.m_cells[i].getFrameId()));
}
assert((int)src.m_cells.size() == (int)m_cells.size());
TFx *fx = src.getZeraryColumnFx()->getZeraryFx();
if (fx) {
@ -104,9 +111,13 @@ bool TXshZeraryFxColumn::setCells(int row, int rowCount,
bool isEmptyColumn = isEmpty() && getZeraryColumnFx()->getZeraryFx() == 0;
int i;
for (i = 0; i < rowCount; i++) {
if (isEmptyColumn)
newCells.push_back(TXshCell(m_zeraryFxLevel, cells[i].getFrameId()));
else
if (isEmptyColumn) {
if (Preferences::instance()->isImplicitHoldEnabled() &&
cells[i].getFrameId().isEmptyFrame())
newCells.push_back(TXshCell(0, cells[i].getFrameId()));
else
newCells.push_back(TXshCell(m_zeraryFxLevel, cells[i].getFrameId()));
} else
newCells.push_back(cells[i]);
}
// Sto settando delle celle in una colonna nuova, devo settare anche
@ -141,7 +152,7 @@ void TXshZeraryFxColumn::loadData(TIStream &is) {
int r0, r1;
bool touched = false;
const TXshCell cell(m_zeraryFxLevel, TFrameId(1));
TXshCell cell(m_zeraryFxLevel, TFrameId(1));
std::string tagName;
while (is.matchTag(tagName)) {
if (tagName == "status") {
@ -157,6 +168,10 @@ void TXshZeraryFxColumn::loadData(TIStream &is) {
}
int r, n;
is >> r >> n;
if (is.getTagAttribute("stopframe") == "yes")
cell.m_frameId = TFrameId::STOP_FRAME;
else
cell.m_frameId = 1;
for (int i = 0; i < n; i++) setCell(r++, cell);
} else
throw TException("expected <cell>");
@ -181,9 +196,35 @@ void TXshZeraryFxColumn::saveData(TOStream &os) {
for (int r = r0; r <= r1; r++) {
TXshCell cell = getCell(r);
if (cell.isEmpty()) continue;
int n = 1;
while (r + n <= r1 && !getCell(r + n).isEmpty()) n++;
os.child("cell") << r << n;
int fnum = cell.m_frameId.getNumber();
if (fnum > 1) fnum = 1; // Should always be 1 unless it's stopframe
int n = 1;
if (r < r1) {
TXshCell cell2 = getCell(r + 1);
if (!cell2.isEmpty()) {
int fnum2 = cell2.m_frameId.getNumber();
if (fnum2 > 1) fnum2 = 1; // Should always be 1 unless it's stopframe
if (fnum == fnum2) {
n++;
for (;;) {
if (r + n > r1) break;
cell2 = getCell(r + n);
if (cell2.isEmpty()) break;
fnum2 = cell2.m_frameId.getNumber();
if (fnum2 > 1)
fnum2 = 1; // Should always be 1 unless it's stopframe
if (fnum != fnum2) break;
n++;
}
}
}
}
std::map<std::string, std::string> attr;
if (cell.m_frameId.isStopFrame()) attr["stopframe"] = "yes";
os.openChild("cell", attr);
os << r << n;
os.closeChild();
r += n - 1;
}
os.closeChild();