diff --git a/stuff/profiles/layouts/rooms/Default/menubar_template.xml b/stuff/profiles/layouts/rooms/Default/menubar_template.xml
index 637ef44..6d797d7 100644
--- a/stuff/profiles/layouts/rooms/Default/menubar_template.xml
+++ b/stuff/profiles/layouts/rooms/Default/menubar_template.xml
@@ -138,6 +138,7 @@
MI_InsertFx
MI_NewOutputFx
+ MI_NewNoteLevel
MI_InsertSceneFrame
MI_RemoveSceneFrame
diff --git a/toonz/sources/toonz/levelcreatepopup.cpp b/toonz/sources/toonz/levelcreatepopup.cpp
index 7391097..3cc83d5 100644
--- a/toonz/sources/toonz/levelcreatepopup.cpp
+++ b/toonz/sources/toonz/levelcreatepopup.cpp
@@ -434,6 +434,10 @@ bool LevelCreatePopup::apply() {
ToonzScene *scene = app->getCurrentScene()->getScene();
TXsheet *xsh = scene->getXsheet();
+ bool validColumn = true;
+ if (xsh->getColumn(col))
+ validColumn = xsh->getColumn(col)->getColumnType() == 0;
+
int from = (int)m_fromFld->getValue();
int to = (int)m_toFld->getValue();
int inc = (int)m_incFld->getValue();
@@ -539,6 +543,10 @@ bool LevelCreatePopup::apply() {
}
cell = xsh->getCell(i, col);
}
+ if (!validColumn) {
+ isInRange = false;
+ }
+
/*-- 別のLevelに占有されていた場合、Columnを1つ右に移動 --*/
if (!isInRange) {
col += 1;
@@ -628,7 +636,7 @@ void LevelCreatePopup::update() {
break;
}
if (index >= 0) m_levelTypeOm->setCurrentIndex(index);
-
+
/*
(old behaviour)
TCamera* camera = scene->getCurrentCamera();
diff --git a/toonz/sources/toonz/mainwindow.cpp b/toonz/sources/toonz/mainwindow.cpp
index 9dcc908..af63972 100644
--- a/toonz/sources/toonz/mainwindow.cpp
+++ b/toonz/sources/toonz/mainwindow.cpp
@@ -1811,6 +1811,7 @@ void MainWindow::defineActions() {
"");
createMenuXsheetAction(MI_RemoveGlobalKeyframe, tr("Remove Multiple Keys"),
"");
+ createMenuXsheetAction(MI_NewNoteLevel, tr("New Note Level"), "");
createMenuXsheetAction(MI_LipSyncPopup, tr("&Apply Lip Sync Data to Column"),
"Alt+L");
createRightClickMenuAction(MI_ToggleXSheetToolbar,
diff --git a/toonz/sources/toonz/menubar.cpp b/toonz/sources/toonz/menubar.cpp
index 9045058..6212f2a 100644
--- a/toonz/sources/toonz/menubar.cpp
+++ b/toonz/sources/toonz/menubar.cpp
@@ -1232,6 +1232,7 @@ QMenuBar *StackedMenuBar::createFullMenuBar() {
xsheetMenu->addSeparator();
addMenuItem(xsheetMenu, MI_InsertFx);
addMenuItem(xsheetMenu, MI_NewOutputFx);
+ addMenuItem(xsheetMenu, MI_NewNoteLevel);
xsheetMenu->addSeparator();
addMenuItem(xsheetMenu, MI_InsertSceneFrame);
addMenuItem(xsheetMenu, MI_RemoveSceneFrame);
diff --git a/toonz/sources/toonz/menubarcommandids.h b/toonz/sources/toonz/menubarcommandids.h
index 89b7e2b..0543d9f 100644
--- a/toonz/sources/toonz/menubarcommandids.h
+++ b/toonz/sources/toonz/menubarcommandids.h
@@ -38,6 +38,7 @@
#define MI_OverwritePalette "MI_OverwritePalette"
#define MI_LoadColorModel "MI_LoadColorModel"
#define MI_ImportMagpieFile "MI_ImportMagpieFile"
+#define MI_NewNoteLevel "MI_NewNoteLevel"
#define MI_NewProject "MI_NewProject"
#define MI_ProjectSettings "MI_ProjectSettings"
#define MI_SaveDefaultSettings "MI_SaveDefaultSettings"
diff --git a/toonz/sources/toonz/xshcellmover.cpp b/toonz/sources/toonz/xshcellmover.cpp
index 60359e7..da4797b 100644
--- a/toonz/sources/toonz/xshcellmover.cpp
+++ b/toonz/sources/toonz/xshcellmover.cpp
@@ -157,7 +157,9 @@ bool CellsMover::canMoveCells(const TPoint &pos) {
TXshColumn::ColumnType srcType = getColumnTypeFromCell(i);
int dstIndex = pos.x + i;
TXshColumn *dstColumn = xsh->getColumn(dstIndex);
- if (srcType == TXshColumn::eZeraryFxType) return false;
+ if (srcType == TXshColumn::eZeraryFxType ||
+ srcType == TXshColumn::eSoundTextType)
+ return false;
if (dstColumn && !dstColumn->isEmpty() &&
dstColumn->getColumnType() != srcType)
return false;
diff --git a/toonz/sources/toonz/xshcellviewer.cpp b/toonz/sources/toonz/xshcellviewer.cpp
index 0f30930..c4c7274 100644
--- a/toonz/sources/toonz/xshcellviewer.cpp
+++ b/toonz/sources/toonz/xshcellviewer.cpp
@@ -52,6 +52,7 @@
#include "toonz/tcolumnfx.h"
#include "toonz/txshchildlevel.h"
#include "toonz/txshzeraryfxcolumn.h"
+#include "toonz/txshsoundtextcolumn.h"
#include "toonz/txshsoundtextlevel.h"
#include "toonz/txshpalettelevel.h"
#include "toonz/doubleparamcmd.h"
@@ -482,6 +483,55 @@ public:
int getHistoryType() override { return HistoryType::Xsheet; }
};
+//-----------------------------------------------------------------------------
+
+class RenameTextCellUndo final : public TUndo {
+ int m_row;
+ int m_col;
+ const TXshCell m_oldCell;
+ const TXshCell m_newCell;
+ QString m_oldText, m_newText;
+ TXshSoundTextLevel *m_level;
+
+public:
+ RenameTextCellUndo(int row, int col, TXshCell oldCell, TXshCell newCell,
+ QString oldText, QString newText,
+ TXshSoundTextLevel *level)
+ : m_row(row)
+ , m_col(col)
+ , m_oldCell(oldCell)
+ , m_newCell(newCell)
+ , m_oldText(oldText)
+ , m_newText(newText)
+ , m_level(level) {}
+
+ void setcell(const TXshCell cell, QString text = "") const {
+ TApp *app = TApp::instance();
+ TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
+ assert(xsh);
+ if (cell.isEmpty())
+ xsh->clearCells(m_row, m_col);
+ else {
+ xsh->setCell(m_row, m_col, cell);
+ m_level->setFrameText(cell.getFrameId().getNumber() - 1, text);
+ }
+ app->getCurrentXsheet()->notifyXsheetChanged();
+ }
+
+ void undo() const override { setcell(m_oldCell, m_oldText); }
+
+ void redo() const override { setcell(m_newCell, m_newText); }
+
+ int getSize() const override { return sizeof *this; }
+
+ QString getHistoryString() override {
+ return QObject::tr("Change Text at Column %1 Frame %2")
+ .arg(QString::number(m_col + 1))
+ .arg(QString::number(m_row + 1));
+ }
+ int getHistoryType() override { return HistoryType::Xsheet; }
+};
+
// display upper-directional smart tab only when pressing ctrl key
bool isCtrlPressed = false;
@@ -569,7 +619,8 @@ void RenameCellField::showInRowCol(int row, int col, bool multiColumnSelected) {
// convert the last one digit of the frame number to alphabet
// Ex. 12 -> 1B 21 -> 2A 30 -> 3
- if (Preferences::instance()->isShowFrameNumberWithLettersEnabled())
+ if (Preferences::instance()->isShowFrameNumberWithLettersEnabled() &&
+ cell.m_level->getType() != TXshLevelType::SND_TXT_XSHLEVEL)
setText(
(fid.isEmptyFrame() || fid.isNoFrame())
? QString::fromStdWString(levelName)
@@ -581,12 +632,25 @@ void RenameCellField::showInRowCol(int row, int col, bool multiColumnSelected) {
std::string frameNumber("");
if (fid.getNumber() > 0) frameNumber = std::to_string(fid.getNumber());
if (fid.getLetter() != 0) frameNumber.append(1, fid.getLetter());
- setText((frameNumber.empty())
- ? QString::fromStdWString(levelName)
- : (multiColumnSelected)
- ? QString::fromStdString(frameNumber)
- : QString::fromStdWString(levelName) + QString(" ") +
- QString::fromStdString(frameNumber));
+
+ // get text from sound text level
+ if (cell.m_level->getType() == TXshLevelType::SND_TXT_XSHLEVEL) {
+ TXshSoundTextLevelP textLevel = cell.m_level->getSoundTextLevel();
+ if (textLevel) {
+ std::string frameText =
+ textLevel->getFrameText(fid.getNumber() - 1).toStdString();
+ setText(textLevel->getFrameText(fid.getNumber() - 1));
+ }
+ }
+ // other level types
+ else {
+ setText((frameNumber.empty())
+ ? QString::fromStdWString(levelName)
+ : (multiColumnSelected)
+ ? QString::fromStdString(frameNumber)
+ : QString::fromStdWString(levelName) + QString(" ") +
+ QString::fromStdString(frameNumber));
+ }
}
selectAll();
}
@@ -613,13 +677,80 @@ void RenameCellField::renameCell() {
std::wstring levelName;
TFrameId fid;
+ TXsheet *xsheet = m_viewer->getXsheet();
+ TXshSoundTextColumn *sndTextCol =
+ xsheet->getColumn(m_col)->getSoundTextColumn();
+ if (sndTextCol) {
+ QString oldText = "changeMe"; // text for undo - changed later
+ TXshCell cell = xsheet->getCell(m_row, m_col);
+ TXshCell oldCell = cell;
+ // the text index is always one less than the frame number
+ int textIndex = cell.getFrameId().getNumber() - 1;
+ if (!cell.m_level) { // cell not part of a level
+ oldText = "";
+ int lastFrame = sndTextCol->getMaxFrame();
+ TXshSoundTextLevel *sndTextLevel;
+ TXshCell lastCell;
+ TFrameId newId;
+ if (lastFrame < 0) { // no level on column
+ sndTextLevel = new TXshSoundTextLevel();
+ sndTextLevel->setType(SND_TXT_XSHLEVEL);
+ newId = TFrameId(1);
+ cell = TXshCell(sndTextLevel, newId);
+ sndTextCol->setCell(m_row, cell);
+ textIndex = 0;
+ } else {
+ TXshCell lastCell = xsheet->getCell(lastFrame, m_col);
+ TXshSoundTextLevel *sndTextLevel =
+ lastCell.m_level->getSoundTextLevel();
+ int textSize = sndTextLevel->m_framesText.size();
+ textIndex = textSize;
+ newId = TFrameId(textSize + 1);
+ cell = TXshCell(sndTextLevel, newId);
+ sndTextCol->setCell(m_row, cell);
+ }
+ }
+
+ TXshCell prevCell = xsheet->getCell(m_row - 1, m_col);
+ TXshSoundTextLevel *textLevel = cell.m_level->getSoundTextLevel();
+ if (oldText == "changeMe")
+ oldText = textLevel->getFrameText(cell.getFrameId().getNumber() - 1);
+ if (!prevCell.isEmpty()) {
+ // check if the previous cell had the same content as the entered text
+ // just extend the frame if so
+ if (textLevel->getFrameText(prevCell.getFrameId().getNumber() - 1) == s) {
+ sndTextCol->setCell(m_row, prevCell);
+ RenameTextCellUndo *undo = new RenameTextCellUndo(
+ m_row, m_col, oldCell, prevCell, oldText, s, textLevel);
+ TUndoManager::manager()->add(undo);
+ return;
+ }
+ // check if the cell was part of an extended frame, but now has different
+ // text
+ else if (textLevel->getFrameText(textIndex) ==
+ textLevel->getFrameText(prevCell.getFrameId().getNumber() -
+ 1) &&
+ textLevel->getFrameText(textIndex) != s) {
+ int textSize = textLevel->m_framesText.size();
+ textIndex = textSize;
+ TFrameId newId = TFrameId(textSize + 1);
+ cell = TXshCell(textLevel, newId);
+ sndTextCol->setCell(m_row, cell);
+ }
+ }
+ RenameTextCellUndo *undo = new RenameTextCellUndo(
+ m_row, m_col, oldCell, cell, oldText, s, textLevel);
+ TUndoManager::manager()->add(undo);
+ textLevel->setFrameText(textIndex, s);
+ TApp::instance()->getCurrentXsheet()->notifyXsheetChanged();
+ return;
+ }
// convert the last one digit of the frame number to alphabet
// Ex. 12 -> 1B 21 -> 2A 30 -> 3
if (Preferences::instance()->isShowFrameNumberWithLettersEnabled())
parse_with_letter(QString::fromStdWString(newName), levelName, fid);
else
parse(QString::fromStdWString(newName), levelName, fid);
- TXsheet *xsheet = m_viewer->getXsheet();
bool animationSheetEnabled =
Preferences::instance()->isAnimationSheetEnabled();
@@ -1648,6 +1779,8 @@ void CellArea::drawSoundTextCell(QPainter &p, int row, int col) {
drawLockedDottedLine(p, xsh->getColumn(col)->isLocked(), xy, cellColor);
bool sameLevel = prevCell.m_level.getPointer() == cell.m_level.getPointer();
+ TFrameId fid = cell.m_frameId;
+ if (fid.getNumber() - 1 < 0) return;
int distance, offset;
TApp::instance()->getCurrentScene()->getScene()->getProperties()->getMarkers(
distance, offset);
@@ -2464,8 +2597,7 @@ void CellArea::mouseDoubleClickEvent(QMouseEvent *event) {
int col = cellPosition.layer();
// Se la colonna e' sound non devo fare nulla
TXshColumn *column = m_viewer->getXsheet()->getColumn(col);
- if (column && (column->getSoundColumn() || column->getSoundTextColumn()))
- return;
+ if (column && column->getSoundColumn()) return;
// Se ho cliccato su una nota devo aprire il popup
TXshNoteSet *notes = m_viewer->getXsheet()->getNotes();
diff --git a/toonz/sources/toonz/xshcolumnviewer.cpp b/toonz/sources/toonz/xshcolumnviewer.cpp
index 0fe6183..b8509fb 100644
--- a/toonz/sources/toonz/xshcolumnviewer.cpp
+++ b/toonz/sources/toonz/xshcolumnviewer.cpp
@@ -2198,6 +2198,7 @@ void ColumnArea::contextMenuEvent(QContextMenuEvent *event) {
menu.addAction(cmdManager->getAction(MI_Insert));
menu.addSeparator();
menu.addAction(cmdManager->getAction(MI_InsertFx));
+ menu.addAction(cmdManager->getAction(MI_NewNoteLevel));
menu.addSeparator();
if (m_viewer->getXsheet()->isColumnEmpty(col) ||
(cell.m_level && cell.m_level->getChildLevel()))
diff --git a/toonz/sources/toonz/xsheetcmd.cpp b/toonz/sources/toonz/xsheetcmd.cpp
index 3f912ef..9fa7306 100644
--- a/toonz/sources/toonz/xsheetcmd.cpp
+++ b/toonz/sources/toonz/xsheetcmd.cpp
@@ -24,10 +24,12 @@
#include "toonz/txshlevelhandle.h"
#include "toonz/txsheet.h"
#include "toonz/txshcell.h"
+#include "toonz/txshcolumn.h"
#include "toonz/toonzscene.h"
#include "toonz/levelset.h"
#include "toonz/txshsimplelevel.h"
#include "toonz/txshleveltypes.h"
+#include "toonz/txshsoundtextcolumn.h"
#include "toonz/txshsoundtextlevel.h"
#include "toonz/tstageobjecttree.h"
#include "toonz/tstageobjectkeyframe.h"
@@ -926,6 +928,92 @@ public:
//============================================================
+class NewNoteLevelUndo final : public TUndo {
+ TXshSoundTextColumnP m_soundtextColumn;
+ int m_col;
+ QString m_columnName;
+
+public:
+ NewNoteLevelUndo(TXshSoundTextColumn *soundtextColumn, int col,
+ QString columnName)
+ : m_soundtextColumn(soundtextColumn)
+ , m_col(col)
+ , m_columnName(columnName) {}
+
+ void undo() const override {
+ TApp *app = TApp::instance();
+ TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
+ xsh->removeColumn(m_col);
+ app->getCurrentXsheet()->notifyXsheetChanged();
+ }
+
+ void redo() const override {
+ TApp *app = TApp::instance();
+ TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
+ xsh->insertColumn(m_col, m_soundtextColumn.getPointer());
+
+ TStageObject *obj = xsh->getStageObject(TStageObjectId::ColumnId(m_col));
+ std::string str = m_columnName.toStdString();
+ obj->setName(str);
+
+ app->getCurrentXsheet()->notifyXsheetChanged();
+ }
+
+ int getSize() const override { return sizeof(*this); }
+
+ QString getHistoryString() override { return QObject::tr("New Note Level"); }
+
+ int getHistoryType() override { return HistoryType::Xsheet; }
+};
+
+//============================================================
+
+static void newNoteLevel() {
+ TTool::Application *app = TTool::getApplication();
+ TXsheet *xsh = app->getCurrentScene()->getScene()->getXsheet();
+ int col = TTool::getApplication()->getCurrentColumn()->getColumnIndex();
+ TXshSoundTextColumn *textSoundCol = new TXshSoundTextColumn();
+
+ textSoundCol->setXsheet(xsh);
+ QList textList;
+ textList << " ";
+ textSoundCol->createSoundTextLevel(0, textList);
+ xsh->insertColumn(col, textSoundCol);
+
+ // name the level a unique NoteLevel number
+ TStageObjectTree *objects = xsh->getStageObjectTree();
+ int objectCount = objects->getStageObjectCount();
+ int maxTextColumns = 1;
+ for (int i = 0; i < objectCount; i++) {
+ TStageObject *object = objects->getStageObject(i);
+ std::string objName = object->getName();
+ int pos = objName.find("NoteLevel");
+ if (pos != std::string::npos && pos == 0) {
+ std::string currStrCount = objName.substr(9);
+ bool ok;
+ int currCount = QString::fromStdString(currStrCount).toInt(&ok);
+ if (ok && currCount >= maxTextColumns) {
+ maxTextColumns = currCount + 1;
+ }
+ }
+ }
+ TStageObject *obj = xsh->getStageObject(TStageObjectId::ColumnId(col));
+ QString str = "NoteLevel" + QString::number(maxTextColumns);
+ obj->setName(str.toStdString());
+
+ TUndoManager::manager()->add(new NewNoteLevelUndo(textSoundCol, col, str));
+}
+
+//============================================================
+
+class NewNoteLevelCommand final : public MenuItemHandler {
+public:
+ NewNoteLevelCommand() : MenuItemHandler(MI_NewNoteLevel) {}
+ void execute() override { XshCmd::newNoteLevel(); }
+} NewNoteLevelCommand;
+
+//============================================================
+
} // namespace XshCmd
//*****************************************************************************
diff --git a/toonz/sources/toonzlib/txshsoundtextlevel.cpp b/toonz/sources/toonzlib/txshsoundtextlevel.cpp
index 860eaef..8f213f5 100644
--- a/toonz/sources/toonzlib/txshsoundtextlevel.cpp
+++ b/toonz/sources/toonzlib/txshsoundtextlevel.cpp
@@ -29,7 +29,9 @@ TXshSoundTextLevel *TXshSoundTextLevel::clone() const {
//-----------------------------------------------------------------------------
void TXshSoundTextLevel::setFrameText(int frameIndex, QString text) {
- while (frameIndex >= m_framesText.size()) m_framesText.append(QString());
+ while (frameIndex >= m_framesText.size()) {
+ m_framesText.append(QString(" "));
+ }
m_framesText.replace(frameIndex, text);
}
diff --git a/toonz/sources/toonzqt/Resources/magpie.svg b/toonz/sources/toonzqt/Resources/magpie.svg
index 9e768d0..8bdab15 100644
--- a/toonz/sources/toonzqt/Resources/magpie.svg
+++ b/toonz/sources/toonzqt/Resources/magpie.svg
@@ -1,19 +1,42 @@
-
-
-
+
+
\ No newline at end of file