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 @@ - - - - - - - - - + +image/svg+xml \ No newline at end of file