Auto Input Cell Number command (#1479)

* auto input cell number

* from frame - to frame
This commit is contained in:
shun-iwasawa 2017-09-22 08:53:49 +09:00 committed by masafumi-inoue
parent 20c9615add
commit 947ad3809f
14 changed files with 765 additions and 9 deletions

Binary file not shown.

View file

@ -169,6 +169,7 @@
<command>MI_Rollup</command>
<command>MI_Rolldown</command>
<command>MI_TimeStretch</command>
<command>MI_AutoInputCellNumber</command>
<separator/>
<command>MI_DrawingSubForward</command>
<command>MI_DrawingSubBackward</command>

View file

@ -159,6 +159,7 @@
<command>MI_Rollup</command>
<command>MI_Rolldown</command>
<command>MI_TimeStretch</command>
<command>MI_AutoInputCellNumber</command>
<separator/>
<command>MI_Autorenumber</command>
<command>MI_Duplicate</command>

View file

@ -61,6 +61,7 @@
<command>MI_Swing</command>
<command>MI_Random</command>
<command>MI_TimeStretch</command>
<command>MI_AutoInputCellNumber</command>
<separator/>
<menu title="Reframe">
<command>MI_Reframe1</command>

View file

@ -12,6 +12,7 @@
// TnzLib includes
#include "toonz/txshcolumn.h"
#include "toonz/txshlevel.h"
#include "cellposition.h"
@ -549,6 +550,11 @@ in TXsheetImp.
//! Returns the xsheet content's \a camstand bbox at the specified row.
TRectD getBBox(int row) const;
void autoInputCellNumbers(int increment, int interval, int step, int repeat,
int from, int to, int r0, int r1, bool isOverwrite,
std::vector<int> columnIndices,
std::vector<TXshLevelP> levels, int rowsCount);
protected:
bool checkCircularReferences(TXsheet *childCandidate);

View file

@ -151,6 +151,7 @@ set(MOC_HEADERS
locatorpopup.h
styleshortcutswitchablepanel.h
cameracapturelevelcontrol.h
autoinputcellnumberpopup.h
# Tracker file
dummyprocessor.h
metnum.h
@ -317,6 +318,7 @@ set(SOURCES
locatorpopup.cpp
styleshortcutswitchablepanel.cpp
cameracapturelevelcontrol.cpp
autoinputcellnumberpopup.cpp
# Tracker file
dummyprocessor.cpp
metnum.cpp

View file

@ -0,0 +1,480 @@
#include "autoinputcellnumberpopup.h"
// Tnz includes
#include "tapp.h"
#include "menubarcommandids.h"
#include "cellselection.h"
#include "columnselection.h"
#include "penciltestpopup.h" // for FrameNumberLineEdit
// TnzQt includes
#include "toonzqt/intfield.h"
#include "toonzqt/tselectionhandle.h"
#include "toonzqt/selection.h"
#include "toonzqt/dvdialog.h"
// TnzLib includes
#include "toonz/txsheethandle.h"
#include "toonz/txshcell.h"
#include "toonz/txshsimplelevel.h"
#include "toonz/txshchildlevel.h"
#include "toonz/preferences.h"
#include "tundo.h"
#include "historytypes.h"
#include <QMainWindow>
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <iostream>
namespace {
class AutoInputCellNumberUndo final : public TUndo {
int m_increment, m_interval, m_step, m_repeat;
int m_from, m_to;
int m_r0, m_r1;
bool m_isOverwrite;
std::vector<int> m_columnIndices;
std::vector<TXshLevelP> m_levels;
int m_rowsCount;
std::unique_ptr<TXshCell[]> m_beforeCells;
public:
AutoInputCellNumberUndo(int increment, int interval, int step, int repeat,
int from, int to, int r0, int r1, bool isOverwrite,
std::vector<int> columnIndices,
std::vector<TXshLevelP> levels);
~AutoInputCellNumberUndo() {}
void undo() const override;
void redo() const override;
int getSize() const override { return sizeof(*this); }
QString getHistoryString() override {
return QObject::tr("Auto Input Cell Numbers : %1")
.arg((m_isOverwrite) ? QObject::tr("Overwrite")
: QObject::tr("Insert"));
}
int getHistoryType() override { return HistoryType::Xsheet; }
int rowsCount() { return m_rowsCount; }
};
};
//-----------------------------------------------------------------------------
// executing this on column selection, set r1 = -1.
// Here are the expected behaviors
// 1. Cell Selection + Overwrite
// Cells will be input from the top of the selected range.
// New arrangement CANNOT run over the selected range.
// If the new arrangement is shorter than the selected range,
// excess cells will not be cleared but keep their contents.
// (It is the same behavior as Celsys' QuickChecker)
// 2. Cell Selection + Insert
// New arrangement will be inserted before the selected range.
// If the selected range has multiple columns, then the inserted
// cells will be expanded to the longest arrangement with empty cells.
// 3. Column Selection + Overwrite
// Cells will be input from the top of the columns.
// New arrangement CAN run over the existing column range.
// If the new arrangement is shorter than the selected range,
// excess cells will not be cleared but keep their contents.
// 4. Column Selection + Insert
// New arrangement will be inserted at the top of the columns.
// If multiple columns are selected, then the inserted cells
// will be expanded to the longest arrangement with empty cells.
//
AutoInputCellNumberUndo::AutoInputCellNumberUndo(int increment, int interval,
int step, int repeat, int from,
int to, int r0, int r1,
bool isOverwrite,
std::vector<int> columnIndices,
std::vector<TXshLevelP> levels)
: m_increment(increment)
, m_interval(interval)
, m_step(step)
, m_repeat(repeat)
, m_from(from)
, m_to(to)
, m_r0(r0)
, m_r1(r1)
, m_isOverwrite(isOverwrite)
, m_columnIndices(columnIndices)
, m_levels(levels) {
if (Preferences::instance()->isShowFrameNumberWithLettersEnabled())
m_increment *= 10;
int maxInputFrameAmount = 0;
int frameRangeMin = std::min(m_from, m_to);
int frameRangeMax = std::max(m_from, m_to);
if (m_increment == 0) {
// obtain the maximum frame amount to be input
for (int lv = 0; lv < m_levels.size(); lv++) {
TXshLevelP level = m_levels.at(lv);
std::vector<TFrameId> fids;
level->getFids(fids);
int fCount = 0;
for (auto itr = fids.begin(); itr != fids.end(); ++itr) {
if ((*itr).getNumber() >= frameRangeMin &&
(*itr).getNumber() <= frameRangeMax) {
fCount++;
} else if ((*itr).getNumber() > frameRangeMax)
break;
}
if (maxInputFrameAmount < fCount) maxInputFrameAmount = fCount;
}
} else
maxInputFrameAmount = (int)std::ceil(
(float)(frameRangeMax - frameRangeMin + 1) / (float)m_increment);
maxInputFrameAmount *= m_repeat;
// compute maximum row amount to be arranged
if (maxInputFrameAmount == 0) {
m_rowsCount = 0;
return;
} else
m_rowsCount =
maxInputFrameAmount * m_step + (maxInputFrameAmount - 1) * m_interval;
// on overwrite case, keep existing cells for undo
if (m_isOverwrite) {
int rowUpTo =
(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;
for (int c = 0; c < m_columnIndices.size(); ++c) {
for (int r = m_r0; r <= rowUpTo; ++r)
m_beforeCells[k++] =
TApp::instance()->getCurrentXsheet()->getXsheet()->getCell(
r, m_columnIndices.at(c));
}
}
}
void AutoInputCellNumberUndo::undo() const {
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
// on overwrite case, retrieve cells
if (m_isOverwrite) {
int rowUpTo =
(m_r1 == -1) ? m_rowsCount - 1 : std::min(m_r1, m_r0 + m_rowsCount - 1);
int k = 0;
for (int c = 0; c < m_columnIndices.size(); ++c) {
for (int r = m_r0; r <= rowUpTo; ++r) {
if (m_beforeCells[k].isEmpty())
xsh->clearCells(r, m_columnIndices.at(c));
else
xsh->setCell(r, m_columnIndices.at(c), m_beforeCells[k]);
k++;
}
}
} 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);
}
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
}
void AutoInputCellNumberUndo::redo() const {
TApp::instance()->getCurrentXsheet()->getXsheet()->autoInputCellNumbers(
m_increment, m_interval, m_step, m_repeat, m_from, m_to, m_r0, m_r1,
m_isOverwrite, m_columnIndices, m_levels, m_rowsCount);
TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
}
//=============================================================================
AutoInputCellNumberPopup::AutoInputCellNumberPopup()
: Dialog(TApp::instance()->getMainWindow(), false, true,
"AutoInputCellNumberPopup") {
setWindowTitle(tr("Auto Input Cell Number"));
m_from = new FrameNumberLineEdit(this);
m_increment = new DVGui::IntLineEdit(this, 0, 0);
m_to = new FrameNumberLineEdit(this);
m_interval = new DVGui::IntLineEdit(this, 0, 0);
m_step = new DVGui::IntLineEdit(this, 1, 1);
m_repeat = new DVGui::IntLineEdit(this, 1, 1);
m_overwriteBtn = new QPushButton(tr("Overwrite"), this);
m_insertBtn = new QPushButton(tr("Insert"), this);
QPushButton *cancelBtn = new QPushButton(tr("Cancel"), this);
m_increment->setToolTip(
tr("Setting this value 0 will automatically \npick up all frames in the "
"selected level."));
// layout
QGridLayout *mainLay = new QGridLayout();
mainLay->setHorizontalSpacing(5);
mainLay->setVerticalSpacing(10);
{
mainLay->addWidget(new QLabel(tr("From frame"), this), 0, 0,
Qt::AlignRight | Qt::AlignVCenter);
mainLay->addWidget(m_from, 0, 1);
mainLay->addWidget(new QLabel(tr(" ", "from frame"), this), 0, 2, 1, 2);
mainLay->addWidget(new QLabel(tr("with"), this), 1, 0, 1, 2,
Qt::AlignRight | Qt::AlignVCenter);
mainLay->addWidget(m_increment, 1, 2);
mainLay->addWidget(new QLabel(tr("frames increment"), this), 1, 3);
mainLay->addWidget(new QLabel(tr("To frame"), this), 2, 0,
Qt::AlignRight | Qt::AlignVCenter);
mainLay->addWidget(m_to, 2, 1);
mainLay->addWidget(new QLabel(tr(" ", "to frame"), this), 2, 2, 1, 2);
mainLay->addWidget(new QLabel(tr("inserting"), this), 3, 0, 1, 2,
Qt::AlignRight | Qt::AlignVCenter);
mainLay->addWidget(m_interval, 3, 2);
mainLay->addWidget(new QLabel(tr("empty cell intervals"), this), 3, 3);
mainLay->addWidget(new QLabel(tr("with"), this), 4, 0,
Qt::AlignRight | Qt::AlignVCenter);
mainLay->addWidget(m_step, 4, 1);
mainLay->addWidget(new QLabel(tr("cell steps"), this), 4, 2, 1, 2);
mainLay->addWidget(new QLabel(tr("Repeat"), this), 5, 0,
Qt::AlignRight | Qt::AlignVCenter);
mainLay->addWidget(m_repeat, 5, 1);
mainLay->addWidget(new QLabel(tr("times"), this), 5, 2, 1, 2);
}
m_topLayout->addLayout(mainLay);
m_buttonFrame = new QFrame(this);
m_buttonFrame->setObjectName("dialogButtonFrame");
m_buttonFrame->setFrameStyle(QFrame::StyledPanel);
m_buttonFrame->setFixedHeight(45);
m_buttonLayout = new QHBoxLayout;
m_buttonLayout->setMargin(0);
m_buttonLayout->setSpacing(20);
m_buttonLayout->setAlignment(Qt::AlignHCenter);
{
m_buttonLayout->addSpacing(20);
m_buttonLayout->addWidget(m_overwriteBtn, 0);
m_buttonLayout->addWidget(m_insertBtn, 0);
m_buttonLayout->addWidget(cancelBtn, 0);
m_buttonLayout->addSpacing(20);
}
m_buttonFrame->setLayout(m_buttonLayout);
layout()->addWidget(m_buttonFrame);
// signal-slot connections
bool ret = true;
ret = ret && connect(m_overwriteBtn, SIGNAL(clicked()), this,
SLOT(onOverwritePressed()));
ret = ret &&
connect(m_insertBtn, SIGNAL(clicked()), this, SLOT(onInsertPressed()));
ret = ret && connect(cancelBtn, SIGNAL(clicked()), this, SLOT(close()));
assert(ret);
}
//-----------------------------------------------------------------------------
void AutoInputCellNumberPopup::onOverwritePressed() { doExecute(true); }
//-----------------------------------------------------------------------------
void AutoInputCellNumberPopup::onInsertPressed() { doExecute(false); }
//-----------------------------------------------------------------------------
void AutoInputCellNumberPopup::doExecute(bool overwrite) {
std::vector<int> columnIndices;
std::vector<TXshLevelP> levels;
int r0, r1;
bool found = getTarget(columnIndices, levels, r0, r1);
// just in case the execution is done to empty column
if (!found) {
DVGui::MsgBox(DVGui::WARNING,
tr("No available cells or columns are selected."));
return;
}
AutoInputCellNumberUndo *undo = new AutoInputCellNumberUndo(
m_increment->getValue(), m_interval->getValue(), m_step->getValue(),
m_repeat->getValue(), m_from->getValue(), m_to->getValue(), r0, r1,
overwrite, columnIndices, levels);
// if no cells will be arranged, then return
if (undo->rowsCount() == 0) {
DVGui::MsgBox(DVGui::WARNING,
tr("Selected level has no frames between From and To."));
delete undo;
return;
}
undo->redo();
TUndoManager::manager()->add(undo);
// on cell selection & insert case, select the inserted cell range
if (!overwrite && r1 != -1) {
TSelection *selection =
TApp::instance()->getCurrentSelection()->getSelection();
if (!selection) return;
TCellSelection *cellSelection = dynamic_cast<TCellSelection *>(selection);
if (!cellSelection) return;
int c0, c1;
cellSelection->getSelectedCells(r0, c0, r1, c1);
cellSelection->selectCells(r0, c0, r0 + undo->rowsCount() - 1, c1);
TApp::instance()->getCurrentSelection()->notifySelectionChanged();
}
// If exection is properly completed, then close this popup
close();
}
//-----------------------------------------------------------------------------
void AutoInputCellNumberPopup::onSelectionChanged() {
// enable buttons only if they will work
m_overwriteBtn->setEnabled(false);
m_insertBtn->setEnabled(false);
std::vector<int> columnIndices;
std::vector<TXshLevelP> levels;
int r0, r1;
bool found = getTarget(columnIndices, levels, r0, r1, true);
// if no reference level is found, return
if (!found) return;
int from, to;
std::vector<TFrameId> fids;
levels.front()->getFids(fids);
from = fids.front().getNumber();
to = fids.back().getNumber();
m_from->setValue(from);
m_to->setValue(to);
// enable buttons
m_overwriteBtn->setEnabled(true);
m_insertBtn->setEnabled(true);
}
//-----------------------------------------------------------------------------
void AutoInputCellNumberPopup::showEvent(QShowEvent *) {
bool ret = connect(TApp::instance()->getCurrentSelection(),
SIGNAL(selectionChanged(TSelection *)), this,
SLOT(onSelectionChanged()));
assert(ret);
onSelectionChanged();
}
//-----------------------------------------------------------------------------
void AutoInputCellNumberPopup::hideEvent(QHideEvent *) {
bool ret = disconnect(TApp::instance()->getCurrentSelection(),
SIGNAL(selectionChanged(TSelection *)), this,
SLOT(onSelectionChanged()));
assert(ret);
}
//-----------------------------------------------------------------------------
bool AutoInputCellNumberPopup::getTarget(std::vector<int> &columnIndices,
std::vector<TXshLevelP> &levels,
int &r0, int &r1, bool forCheck) {
TSelection *selection =
TApp::instance()->getCurrentSelection()->getSelection();
if (!selection) return false;
// something must be selected
if (selection->isEmpty()) return false;
// selection must be cells or collumns
TCellSelection *cellSelection = dynamic_cast<TCellSelection *>(selection);
TColumnSelection *columnSelection =
dynamic_cast<TColumnSelection *>(selection);
if (!cellSelection && !columnSelection) return false;
TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet();
// TXshLevelP refLevel;
if (cellSelection) {
// if cells are selected, selected range must contain at least one available
// level
int c0, c1;
cellSelection->getSelectedCells(r0, c0, r1, c1);
for (int col = c0; col <= c1; col++) {
// column should not be empty or locked
if (xsh->isColumnEmpty(col)) continue;
TXshColumn *column = xsh->getColumn(col);
if (column->isLocked()) continue;
// column type should be "level"
if (column->getColumnType() != TXshColumn::eLevelType) continue;
// try to find the topmost available level in the column
for (int row = r0; row <= r1; row++) {
TXshCell cell = xsh->getCell(row, col);
if (cell.isEmpty()) continue;
TXshSimpleLevel *simpleLevel = cell.getSimpleLevel();
TXshChildLevel *childLevel = cell.getChildLevel();
if (!simpleLevel && !childLevel) continue;
if (simpleLevel) {
TFrameId fid = simpleLevel->getFirstFid();
// the level should not be single-framed
if (fid.getNumber() == TFrameId::EMPTY_FRAME ||
fid.getNumber() == TFrameId::NO_FRAME)
continue;
}
levels.push_back(cell.m_level);
columnIndices.push_back(col);
break;
}
// if some level found, break the loop for check
if (forCheck && !levels.empty()) break;
}
}
else { // columnSelection case
r0 = 0;
r1 = -1;
std::set<int> indices = columnSelection->getIndices();
// try to find the leftmost available column
for (auto id = indices.begin(); id != indices.end(); ++id) {
TXshColumn *column = xsh->getColumn(*id);
if (!column) continue;
if (column->isEmpty() || column->isLocked()) continue;
// column type should be "level"
if (column->getColumnType() != TXshColumn::eLevelType) continue;
// try to find the topmost available level in the column
TXshCellColumn *xshColumn = column->getCellColumn();
if (!xshColumn) continue;
int tmpR0, tmpR1;
column->getRange(tmpR0, tmpR1);
for (int row = tmpR0; row <= tmpR1; row++) {
TXshCell cell = xshColumn->getCell(row);
if (cell.isEmpty()) continue;
TXshSimpleLevel *simpleLevel = cell.getSimpleLevel();
TXshChildLevel *childLevel = cell.getChildLevel();
if (!simpleLevel && !childLevel) continue;
if (simpleLevel) {
TFrameId fid = simpleLevel->getFirstFid();
// the level should not be single-framed
if (fid.getNumber() == TFrameId::EMPTY_FRAME ||
fid.getNumber() == TFrameId::NO_FRAME)
continue;
}
levels.push_back(cell.m_level);
columnIndices.push_back(*id);
break;
}
// if some level found, break the loop for check
if (forCheck && !levels.empty()) break;
}
}
return !levels.empty();
}
//-----------------------------------------------------------------------------
OpenPopupCommandHandler<AutoInputCellNumberPopup> openAutoInputCellNumberPopup(
MI_AutoInputCellNumber);

View file

@ -0,0 +1,44 @@
#pragma once
#ifndef AUTOINPUTCELLNUMBERPOPUP_H
#define AUTOINPUTCELLNUMBERPOPUP_H
#include "toonzqt/dvdialog.h"
#include "toonz/txshlevel.h"
class TSelection;
class QPushButton;
class FrameNumberLineEdit;
namespace DVGui {
class IntLineEdit;
}
//=============================================================================
// AutoInputCellNumberPopup
//-----------------------------------------------------------------------------
class AutoInputCellNumberPopup final : public DVGui::Dialog {
Q_OBJECT
DVGui::IntLineEdit *m_increment, *m_interval, *m_step, *m_repeat;
FrameNumberLineEdit *m_from, *m_to;
QPushButton *m_overwriteBtn, *m_insertBtn;
bool getTarget(std::vector<int> &columnIndices,
std::vector<TXshLevelP> &levels, int &r0, int &r1,
bool forCheck = false);
void doExecute(bool overwrite);
public:
AutoInputCellNumberPopup();
public slots:
void onOverwritePressed();
void onInsertPressed();
void onSelectionChanged();
protected:
void showEvent(QShowEvent *) override;
void hideEvent(QHideEvent *) override;
};
#endif // AUTOINPUTCELLNUMBERPOPUP_H

View file

@ -1855,6 +1855,9 @@ void MainWindow::defineActions() {
createMenuCellsAction(MI_Reframe4, tr("4's"), "");
createMenuCellsAction(MI_AutoInputCellNumber, tr("Auto Input Cell Number..."),
"");
createRightClickMenuAction(MI_SetKeyframes, tr("&Set Key"), "Z");
createToggle(MI_ViewCamera, tr("&Camera Box"), "",
@ -2344,9 +2347,9 @@ RecentFiles::~RecentFiles() {}
void RecentFiles::addFilePath(QString path, FileType fileType) {
QList<QString> files =
(fileType == Scene) ? m_recentScenes : (fileType == Level)
? m_recentLevels
: m_recentFlipbookImages;
(fileType == Scene)
? m_recentScenes
: (fileType == Level) ? m_recentLevels : m_recentFlipbookImages;
int i;
for (i = 0; i < files.size(); i++)
if (files.at(i) == path) files.removeAt(i);
@ -2471,9 +2474,9 @@ void RecentFiles::saveRecentFiles() {
QList<QString> RecentFiles::getFilesNameList(FileType fileType) {
QList<QString> files =
(fileType == Scene) ? m_recentScenes : (fileType == Level)
? m_recentLevels
: m_recentFlipbookImages;
(fileType == Scene)
? m_recentScenes
: (fileType == Level) ? m_recentLevels : m_recentFlipbookImages;
QList<QString> names;
int i;
for (i = 0; i < files.size(); i++) {
@ -2500,9 +2503,9 @@ void RecentFiles::refreshRecentFilesMenu(FileType fileType) {
menu->setEnabled(false);
else {
CommandId clearActionId =
(fileType == Scene) ? MI_ClearRecentScene : (fileType == Level)
? MI_ClearRecentLevel
: MI_ClearRecentImage;
(fileType == Scene)
? MI_ClearRecentScene
: (fileType == Level) ? MI_ClearRecentLevel : MI_ClearRecentImage;
menu->setActions(names);
menu->addSeparator();
QAction *clearAction = CommandManager::instance()->getAction(clearActionId);

View file

@ -319,4 +319,5 @@
#define MI_StartupPopup "MI_StartupPopup"
#define MI_PencilTest "MI_PencilTest"
#define MI_AudioRecording "MI_AudioRecording"
#define MI_AutoInputCellNumber "MI_AutoInputCellNumber"
#endif

View file

@ -2615,6 +2615,7 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected) {
menu.addAction(cmdManager->getAction(MI_Rollup));
menu.addAction(cmdManager->getAction(MI_Rolldown));
menu.addAction(cmdManager->getAction(MI_TimeStretch));
menu.addAction(cmdManager->getAction(MI_AutoInputCellNumber));
menu.addSeparator();
menu.addAction(cmdManager->getAction(MI_Autorenumber));
}

View file

@ -2053,6 +2053,7 @@ void ColumnArea::contextMenuEvent(QContextMenuEvent *event) {
reframeSubMenu->addAction(cmdManager->getAction(MI_Reframe4));
}
menu.addMenu(reframeSubMenu);
menu.addAction(cmdManager->getAction(MI_AutoInputCellNumber));
}
if (containsRasterLevel(m_viewer->getColumnSelection())) {

View file

@ -1611,3 +1611,111 @@ bool TXsheet::isRectEmpty(const CellPosition &pos0,
if (!getCell(CellPosition(frame, layer)).isEmpty()) return false;
return true;
}
//-----------------------------------------------------------------------
// Function triggered by AutoInputCellNumberPopup.
// executing this on column selection, set r1 = -1.
// Here are the expected behaviors
// 1. Cell Selection + Overwrite
// Cells will be input from the top of the selected range.
// New arrangement CANNOT run over the selected range.
// If the new arrangement is shorter than the selected range,
// excess cells will not be cleared but keep their contents.
// (It is the same behavior as Celsys' QuickChecker)
// 2. Cell Selection + Insert
// New arrangement will be inserted before the selected range.
// If the selected range has multiple columns, then the inserted
// cells will be expanded to the longest arrangement with empty cells.
// 3. Column Selection + Overwrite
// Cells will be input from the top of the columns.
// New arrangement CAN run over the existing column range.
// If the new arrangement is shorter than the selected range,
// excess cells will not be cleared but keep their contents.
// 4. Column Selection + Insert
// New arrangement will be inserted at the top of the columns.
// If multiple columns are selected, then the inserted cells
// will be expanded to the longest arrangement with empty cells.
//
void TXsheet::autoInputCellNumbers(int increment, int interval, int step,
int repeat, int from, int to, int r0, int r1,
bool isOverwrite,
std::vector<int> columnIndices,
std::vector<TXshLevelP> levels,
int rowsCount) {
int rowUpTo = (r1 == -1) ? rowsCount - 1
: ((isOverwrite) ? std::min(r1, r0 + rowsCount - 1)
: r0 + rowsCount - 1);
// 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);
// obtain fids to be input
std::vector<TFrameId> fids;
if (increment == 0) {
std::vector<TFrameId> wholeFids;
level->getFids(wholeFids);
if (from <= to) {
for (auto itr = wholeFids.begin(); itr != wholeFids.end(); ++itr) {
if ((*itr).getNumber() >= from && (*itr).getNumber() <= to)
fids.push_back(*itr);
else if ((*itr).getNumber() > to)
break;
}
} else { // from > to
for (auto itr = wholeFids.rbegin(); itr != wholeFids.rend(); ++itr) {
if ((*itr).getNumber() <= from && (*itr).getNumber() >= to)
fids.push_back(*itr);
else if ((*itr).getNumber() < to)
break;
}
}
} else { // increment != 0
int f = from;
if (from <= to) {
while (f <= to) {
fids.push_back(TFrameId(f));
f += increment;
}
} else { // from > to
while (f >= to) {
fids.push_back(TFrameId(f));
f -= increment;
}
}
}
// input cells
int row = r0;
int repeat_itr = 0;
int fid_itr = 0;
int step_interv_itr = 0;
while (row <= rowUpTo) {
// input cell
if (step_interv_itr < step)
setCell(row, columnIndex, TXshCell(level, fids.at(fid_itr)));
// .. or set empty cell as interval
else
setCell(row, columnIndex, TXshCell());
// increment
step_interv_itr++;
// next frame
if (step_interv_itr == step + interval) {
fid_itr++;
step_interv_itr = 0;
}
// next repeat cycle
if (fid_itr == fids.size()) {
repeat_itr++;
fid_itr = 0;
}
if (repeat_itr == repeat) break;
row++;
}
}
}

View file

@ -142,6 +142,85 @@ Please select a different device or check the microphone.</source>
</translation>
</message>
</context>
<context>
<name>AutoInputCellNumberPopup</name>
<message>
<source>Auto Input Cell Number</source>
<translation></translation>
</message>
<message>
<source>Overwrite</source>
<translation></translation>
</message>
<message>
<source>Insert</source>
<translation></translation>
</message>
<message>
<source>Cancel</source>
<translation></translation>
</message>
<message>
<source>with</source>
<translation> </translation>
</message>
<message>
<source>frames increment</source>
<translation></translation>
</message>
<message>
<source>inserting</source>
<translation> </translation>
</message>
<message>
<source>empty cell intervals</source>
<translation></translation>
</message>
<message>
<source>cell steps</source>
<translation></translation>
</message>
<message>
<source>Repeat</source>
<translation></translation>
</message>
<message>
<source>times</source>
<translation></translation>
</message>
<message>
<source>No available cells or columns are selected.</source>
<translation></translation>
</message>
<message>
<source>Selected level has no frames between From and To.</source>
<translation></translation>
</message>
<message>
<source>Setting this value 0 will automatically
pick up all frames in the selected level.</source>
<translation>
</translation>
</message>
<message>
<source>From frame</source>
<translation></translation>
</message>
<message>
<source> </source>
<comment>from frame</comment>
<translation></translation>
</message>
<message>
<source>To frame</source>
<translation> </translation>
</message>
<message>
<source> </source>
<comment>to frame</comment>
<translation></translation>
</message>
</context>
<context>
<name>AutocenterPopup</name>
<message>
@ -4631,6 +4710,10 @@ Do you want to create it?</source>
<source>New Raster Level</source>
<translation></translation>
</message>
<message>
<source>Auto Input Cell Number...</source>
<translation>...</translation>
</message>
<message>
<source>Alpha Channel</source>
<translation></translation>
@ -6518,6 +6601,22 @@ Is it OK to release these shortcuts?</source>
<source>Enable OpenToonz Commands&apos; Shortcut Keys While Renaming Cell</source>
<translation>OpenToonzコマンドのショートカットキーを有効にする</translation>
</message>
<message>
<source>Life is too short for Comic Sans</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Good luck. You&apos;re on your own from here.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Font *:</source>
<translation> *</translation>
</message>
<message>
<source>Font Weight *:</source>
<translation> *</translation>
</message>
</context>
<context>
<name>PreferencesPopup::FormatProperties</name>
@ -8231,6 +8330,14 @@ Are you sure?</source>
<source>Layer name</source>
<translation></translation>
</message>
<message>
<source>Auto Input Cell Numbers : %1</source>
<translation></translation>
</message>
<message>
<source>Insert</source>
<translation></translation>
</message>
<message>
<source>Command Bar</source>
<translation></translation>