diff --git a/toonz/sources/include/cellposition.h b/toonz/sources/include/cellposition.h index e510d10..3a39eae 100644 --- a/toonz/sources/include/cellposition.h +++ b/toonz/sources/include/cellposition.h @@ -34,8 +34,8 @@ public: return CellPosition(_frame * mult._frame, _layer * mult._layer); } void ensureValid() { - if (_frame < 0) _frame = 0; - if (_layer < 0) _layer = 0; + if (_frame < 0) _frame = 0; + if (_layer < -1) _layer = -1; } }; diff --git a/toonz/sources/include/toonz/columnfan.h b/toonz/sources/include/toonz/columnfan.h index 062510e..a892725 100644 --- a/toonz/sources/include/toonz/columnfan.h +++ b/toonz/sources/include/toonz/columnfan.h @@ -42,10 +42,10 @@ class DVAPI ColumnFan { std::map m_table; int m_firstFreePos; int m_unfolded, m_folded; - + bool m_cameraActive; /*! -Called by activate() and deactivate() to update columns coordinates. -*/ + Called by activate() and deactivate() to update columns coordinates. + */ void update(); public: diff --git a/toonz/sources/include/toonz/preferences.h b/toonz/sources/include/toonz/preferences.h index 2dc09f0..9001bf9 100644 --- a/toonz/sources/include/toonz/preferences.h +++ b/toonz/sources/include/toonz/preferences.h @@ -468,6 +468,9 @@ public: currentColumnColor = m_currentColumnColor; } + void enableXsheetCameraColumn(bool on); + bool isXsheetCameraColumnEnabled() const { return m_showXsheetCameraColumn; } + // Animation tab void setKeyframeType(int s); @@ -724,6 +727,8 @@ private: bool m_enableWinInk = false; bool m_useOnionColorsForShiftAndTraceGhosts = false; + bool m_showXsheetCameraColumn = true; + private: Preferences(); ~Preferences(); diff --git a/toonz/sources/tnztools/tool.cpp b/toonz/sources/tnztools/tool.cpp index 8f8e641..ac7e529 100644 --- a/toonz/sources/tnztools/tool.cpp +++ b/toonz/sources/tnztools/tool.cpp @@ -842,6 +842,11 @@ QString TTool::updateEnabled() { Preferences::instance()->isMultiLayerStylePickerEnabled()) return (enable(true), QString()); + // Check against camera column + if (columnIndex < 0 && (targetType & TTool::EmptyTarget) && + (m_name == T_Type || m_name == T_Geometric || m_name == T_Brush)) + return (enable(false), QString()); + // Check against unplaced columns (not in filmstrip mode) if (column && !filmstrip) { if (column->isLocked()) diff --git a/toonz/sources/toonz/cellselection.cpp b/toonz/sources/toonz/cellselection.cpp index f4179a9..fd041a9 100644 --- a/toonz/sources/toonz/cellselection.cpp +++ b/toonz/sources/toonz/cellselection.cpp @@ -244,7 +244,8 @@ public: DeleteCellsUndo(TCellSelection *selection, QMimeData *data) : m_data(data) { int r0, c0, r1, c1; selection->getSelectedCells(r0, c0, r1, c1); - m_selection = new TCellSelection(); + if (c0 < 0) c0 = 0; // Ignore camera column + m_selection = new TCellSelection(); m_selection->selectCells(r0, c0, r1, c1); TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); @@ -331,7 +332,8 @@ public: CutCellsUndo(TCellSelection *selection) : m_data() { int r0, c0, r1, c1; selection->getSelectedCells(r0, c0, r1, c1); - m_selection = new TCellSelection(); + if (c0 < 0) c0 = 0; // Ignore camera column + m_selection = new TCellSelection(); m_selection->selectCells(r0, c0, r1, c1); TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); @@ -1814,7 +1816,8 @@ void TCellSelection::deleteCells() { if (isEmpty()) return; int r0, c0, r1, c1; getSelectedCells(r0, c0, r1, c1); - TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + if (c0 < 0) c0 = 0; // Ignore camera column + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); // if all the selected cells are already empty, then do nothing if (xsh->isRectEmpty(CellPosition(r0, c0), CellPosition(r1, c1))) return; TCellData *data = new TCellData(); @@ -1847,6 +1850,7 @@ void TCellSelection::cutCells(bool withoutCopy) { int r0, c0, r1, c1; getSelectedCells(r0, c0, r1, c1); + if (c0 < 0) c0 = 0; // Ignore camera column undo->setCurrentData(r0, c0, r1, c1); if (!withoutCopy) copyCellsWithoutUndo(r0, c0, r1, c1); @@ -2408,6 +2412,7 @@ void TCellSelection::overWritePasteCells() { void TCellSelection::overwritePasteNumbers() { int r0, c0, r1, c1; getSelectedCells(r0, c0, r1, c1); + if (c0 < 0) c0 = 0; // Ignore camera column QClipboard *clipboard = QApplication::clipboard(); const QMimeData *mimeData = clipboard->mimeData(); diff --git a/toonz/sources/toonz/cellselectioncommand.cpp b/toonz/sources/toonz/cellselectioncommand.cpp index cc78814..99c8fca 100644 --- a/toonz/sources/toonz/cellselectioncommand.cpp +++ b/toonz/sources/toonz/cellselectioncommand.cpp @@ -1237,7 +1237,8 @@ void TCellSelection::setKeyframes() { const TXshCell &cell = xsh->getCell(row, col); if (cell.getSoundLevel() || cell.getSoundTextLevel()) return; - const TStageObjectId &id = TStageObjectId::ColumnId(col); + const TStageObjectId &id = + col >= 0 ? TStageObjectId::ColumnId(col) : TStageObjectId::CameraId(0); TStageObject *obj = xsh->getStageObject(id); if (!obj) return; diff --git a/toonz/sources/toonz/columncommand.cpp b/toonz/sources/toonz/columncommand.cpp index ad92e0c..2b8002b 100644 --- a/toonz/sources/toonz/columncommand.cpp +++ b/toonz/sources/toonz/columncommand.cpp @@ -743,7 +743,14 @@ void ColumnCmd::insertEmptyColumns(const std::set &indices, bool insertAfter) { // Filter out all less than 0 indices (in particular, the 'camera' column // in the Toonz derivative product "Tab") - std::vector positiveIndices(indices.lower_bound(0), indices.end()); + std::vector positiveIndices(indices.begin(), indices.end()); + if (positiveIndices[0] < 0) { + if (!insertAfter) return; + // If inserting after on camera column, change it to insert before on column + // 1 + positiveIndices[0] = 0; + insertAfter = false; + } if (positiveIndices.empty()) return; std::unique_ptr undo( @@ -809,6 +816,7 @@ void ColumnCmd::pasteColumns(std::set &indices, void ColumnCmd::deleteColumns(std::set &indices, bool onlyColumns, bool withoutUndo) { + indices.erase(-1); // Ignore camera column if (indices.empty()) return; if (!withoutUndo && !onlyColumns) diff --git a/toonz/sources/toonz/columnselection.cpp b/toonz/sources/toonz/columnselection.cpp index 4bd705e..c0fb2eb 100644 --- a/toonz/sources/toonz/columnselection.cpp +++ b/toonz/sources/toonz/columnselection.cpp @@ -18,6 +18,7 @@ #include "toonz/txshcell.h" #include "toonz/levelproperties.h" #include "orientation.h" +#include "toonz/preferences.h" // TnzCore includes #include "tvectorimage.h" @@ -48,6 +49,8 @@ void TColumnSelection::enableCommands() { enableCommand(this, MI_Resequence, &TColumnSelection::resequence); enableCommand(this, MI_CloneChild, &TColumnSelection::cloneChild); enableCommand(this, MI_FoldColumns, &TColumnSelection::hideColumns); + enableCommand(this, MI_ToggleXsheetCameraColumn, + &TColumnSelection::toggleCameraColumn); enableCommand(this, MI_Reframe1, &TColumnSelection::reframe1Cells); enableCommand(this, MI_Reframe2, &TColumnSelection::reframe2Cells); @@ -63,7 +66,10 @@ bool TColumnSelection::isEmpty() const { return m_indices.empty(); } //----------------------------------------------------------------------------- -void TColumnSelection::copyColumns() { ColumnCmd::copyColumns(m_indices); } +void TColumnSelection::copyColumns() { + m_indices.erase(-1); // Ignore camera column + ColumnCmd::copyColumns(m_indices); +} //----------------------------------------------------------------------------- // pasteColumns will insert columns before the first column in the selection @@ -71,6 +77,8 @@ void TColumnSelection::pasteColumns() { std::set indices; if (isEmpty()) // in case that no columns are selected indices.insert(0); + else if (*m_indices.begin() < 0) // Do nothing + return; else indices.insert(*m_indices.begin()); ColumnCmd::pasteColumns(indices); @@ -114,6 +122,7 @@ void TColumnSelection::insertColumnsAbove() { //----------------------------------------------------------------------------- void TColumnSelection::collapse() { + m_indices.erase(-1); // Ignore camera column if (m_indices.empty()) return; SubsceneCmd::collapse(m_indices); } @@ -130,6 +139,8 @@ void TColumnSelection::explodeChild() { static bool canMergeColumns(int column, int mColumn, bool forMatchlines) { TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + if (column < 0 || mColumn < 0) return false; + if (xsh->getColumn(column)->isLocked()) return false; int start, end; @@ -197,6 +208,8 @@ void TColumnSelection::selectColumn(int col, bool on) { std::set::iterator it = m_indices.begin(); int firstCol = *it; + if (firstCol < 0) return; + for (++it; it != m_indices.end(); ++it) if (!canMergeColumns(firstCol, *it, false)) break; @@ -254,3 +267,11 @@ void TColumnSelection::hideColumns() { // TApp::instance()->->notify(TColumnHeadChange()); app->getCurrentScene()->setDirtyFlag(true); } + +//----------------------------------------------------------------------------- + +void TColumnSelection::toggleCameraColumn() { + Preferences *pref = Preferences::instance(); + pref->enableXsheetCameraColumn(!pref->isXsheetCameraColumnEnabled()); + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); +} diff --git a/toonz/sources/toonz/columnselection.h b/toonz/sources/toonz/columnselection.h index fad2253..3d7a955 100644 --- a/toonz/sources/toonz/columnselection.h +++ b/toonz/sources/toonz/columnselection.h @@ -45,6 +45,7 @@ public: void cloneChild(); void hideColumns(); + void toggleCameraColumn(); void reframeCells(int count); void reframe1Cells() { reframeCells(1); } diff --git a/toonz/sources/toonz/iocommand.cpp b/toonz/sources/toonz/iocommand.cpp index 98cd2be..c88ac14 100644 --- a/toonz/sources/toonz/iocommand.cpp +++ b/toonz/sources/toonz/iocommand.cpp @@ -324,7 +324,7 @@ bool beforeCellsInsert(TXsheet *xsh, int row, int &col, int rowCount, } int type = column ? column->getColumnType() : newLevelColumnType; // If some used cells in range or column type mismatch must insert a column. - if (i < rowCount || newLevelColumnType != type) { + if (col < 0 || i < rowCount || newLevelColumnType != type) { col += 1; TApp::instance()->getCurrentColumn()->setColumnIndex(col); shiftColumn = true; diff --git a/toonz/sources/toonz/levelcreatepopup.cpp b/toonz/sources/toonz/levelcreatepopup.cpp index 9f54ef0..901e0ae 100644 --- a/toonz/sources/toonz/levelcreatepopup.cpp +++ b/toonz/sources/toonz/levelcreatepopup.cpp @@ -523,12 +523,16 @@ bool LevelCreatePopup::apply() { bool areColumnsShifted = false; TXshCell cell = xsh->getCell(row, col); bool isInRange = true; - for (i = row; i < row + numFrames; i++) { - if (!cell.isEmpty()) { - isInRange = false; - break; + if (col < 0) + isInRange = false; + else { + for (i = row; i < row + numFrames; i++) { + if (!cell.isEmpty()) { + isInRange = false; + break; + } + cell = xsh->getCell(i, col); } - cell = xsh->getCell(i, col); } if (!validColumn) { isInRange = false; diff --git a/toonz/sources/toonz/mainwindow.cpp b/toonz/sources/toonz/mainwindow.cpp index 289f81a..ce1a254 100644 --- a/toonz/sources/toonz/mainwindow.cpp +++ b/toonz/sources/toonz/mainwindow.cpp @@ -1739,6 +1739,8 @@ void MainWindow::defineActions() { "Alt+L"); createRightClickMenuAction(MI_ToggleXSheetToolbar, tr("Toggle XSheet Toolbar"), ""); + createRightClickMenuAction(MI_ToggleXsheetCameraColumn, + tr("Show/Hide Xsheet Camera Column"), ""); createMenuCellsAction(MI_Reverse, tr("&Reverse"), ""); createMenuCellsAction(MI_Swing, tr("&Swing"), ""); createMenuCellsAction(MI_Random, tr("&Random"), ""); diff --git a/toonz/sources/toonz/menubarcommandids.h b/toonz/sources/toonz/menubarcommandids.h index 996825b..a28d708 100644 --- a/toonz/sources/toonz/menubarcommandids.h +++ b/toonz/sources/toonz/menubarcommandids.h @@ -306,6 +306,7 @@ #define MI_ToggleColumnLocks "MI_ToggleColumnLocks" #define MI_ToggleXSheetToolbar "MI_ToggleXSheetToolbar" #define MI_FoldColumns "MI_FoldColumns" +#define MI_ToggleXsheetCameraColumn "MI_ToggleXsheetCameraColumn" #define MI_ToggleCurrentTimeIndicator "MI_ToggleCurrentTimeIndicator" #define MI_LoadIntoCurrentPalette "MI_LoadIntoCurrentPalette" diff --git a/toonz/sources/toonz/penciltestpopup.cpp b/toonz/sources/toonz/penciltestpopup.cpp index a24894e..7e420de 100644 --- a/toonz/sources/toonz/penciltestpopup.cpp +++ b/toonz/sources/toonz/penciltestpopup.cpp @@ -2213,7 +2213,7 @@ bool PencilTestPopup::importImage(QImage& image) { // if the level is newly created or imported, then insert a new column if (state == NEWLEVEL) { - if (!xsh->isColumnEmpty(col)) { + if (col < 0 || !xsh->isColumnEmpty(col)) { col += 1; xsh->insertColumn(col); } diff --git a/toonz/sources/toonz/preferencespopup.cpp b/toonz/sources/toonz/preferencespopup.cpp index 73c23e4..7f6a45e 100644 --- a/toonz/sources/toonz/preferencespopup.cpp +++ b/toonz/sources/toonz/preferencespopup.cpp @@ -1252,6 +1252,13 @@ void PreferencesPopup::onRasterBackgroundColorChanged(const TPixel32 &color, m_pref->setRasterBackgroundColor(color); } +//--------------------------------------------------------------------------------------- + +void PreferencesPopup::onShowXsheetCameraColumnChanged(int index) { + m_pref->enableXsheetCameraColumn(index == Qt::Checked); + TApp::instance()->getCurrentScene()->notifyPreferenceChanged("XsheetCamera"); +} + //********************************************************************************** // PrefencesPopup's constructor //********************************************************************************** @@ -1531,6 +1538,8 @@ PreferencesPopup::PreferencesPopup() m_pref->getCurrentColumnData(currectColumnColor); m_currentColumnColor = new ColorField(this, false, currectColumnColor); + CheckBox *showXsheetCameraCB = new CheckBox(tr("Show Camera Column"), this); + //--- Animation ------------------------------ categoryList->addItem(tr("Animation")); @@ -1899,6 +1908,7 @@ PreferencesPopup::PreferencesPopup() m_pref->isSyncLevelRenumberWithXsheetEnabled()); showCurrentTimelineCB->setChecked( m_pref->isCurrentTimelineIndicatorEnabled()); + showXsheetCameraCB->setChecked(m_pref->isXsheetCameraColumnEnabled()); //--- Animation ------------------------------ QStringList list; @@ -2521,6 +2531,7 @@ PreferencesPopup::PreferencesPopup() xsheetFrameLay->addWidget(new QLabel(tr("Current Column Color:")), 15, 0, Qt::AlignRight | Qt::AlignVCenter); xsheetFrameLay->addWidget(m_currentColumnColor, 15, 1); + xsheetFrameLay->addWidget(showXsheetCameraCB, 16, 0, 1, 2); } xsheetFrameLay->setColumnStretch(0, 0); xsheetFrameLay->setColumnStretch(1, 0); @@ -2989,6 +3000,9 @@ PreferencesPopup::PreferencesPopup() SIGNAL(colorChanged(const TPixel32 &, bool)), SLOT(onCurrentColumnDataChanged(const TPixel32 &, bool))); + ret = ret && connect(showXsheetCameraCB, SIGNAL(stateChanged(int)), this, + SLOT(onShowXsheetCameraColumnChanged(int))); + //--- Animation ---------------------- ret = ret && connect(m_keyframeType, SIGNAL(currentIndexChanged(int)), SLOT(onKeyframeTypeChanged(int))); diff --git a/toonz/sources/toonz/preferencespopup.h b/toonz/sources/toonz/preferencespopup.h index 02e1d61..a80c1c0 100644 --- a/toonz/sources/toonz/preferencespopup.h +++ b/toonz/sources/toonz/preferencespopup.h @@ -83,7 +83,7 @@ private: *m_newLevelToCameraSizeCB, *m_ignoreImageDpiCB, *m_syncLevelRenumberWithXsheet, *m_downArrowInLevelStripCreatesNewFrame, *m_enableAutoStretch, *m_enableWinInk, - *m_useOnionColorsForShiftAndTraceCB; + *m_useOnionColorsForShiftAndTraceCB, *m_showXsheetCameraColCB; DVGui::FileField *m_customProjectRootFileField; @@ -221,6 +221,7 @@ private slots: void onCurrentColumnDataChanged(const TPixel32 &, bool isDragging); void onEnableWinInkChanged(int index); void onRasterBackgroundColorChanged(const TPixel32 &, bool isDragging); + void onShowXsheetCameraColumnChanged(int index); }; //********************************************************************************** diff --git a/toonz/sources/toonz/tapp.cpp b/toonz/sources/toonz/tapp.cpp index 8318336..4472023 100644 --- a/toonz/sources/toonz/tapp.cpp +++ b/toonz/sources/toonz/tapp.cpp @@ -508,6 +508,8 @@ void TApp::onColumnIndexSwitched() { int columnIndex = m_currentColumn->getColumnIndex(); if (columnIndex >= 0) m_currentObject->setObjectId(TStageObjectId::ColumnId(columnIndex)); + else + m_currentObject->setObjectId(TStageObjectId::CameraId(0)); } //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonz/vectorizerpopup.cpp b/toonz/sources/toonz/vectorizerpopup.cpp index 0b1335f..523ebc7 100644 --- a/toonz/sources/toonz/vectorizerpopup.cpp +++ b/toonz/sources/toonz/vectorizerpopup.cpp @@ -890,6 +890,7 @@ bool VectorizerPopup::apply() { int r1 = 0; int c1 = 0; bool isCellSelection = getSelectedLevels(levels, r0, c0, r1, c1); + if (c0 < 0) c0 = 0; if (levels.empty()) { error(tr("The current selection is invalid.")); return false; diff --git a/toonz/sources/toonz/xshcellviewer.cpp b/toonz/sources/toonz/xshcellviewer.cpp index 745e96f..28a6b60 100644 --- a/toonz/sources/toonz/xshcellviewer.cpp +++ b/toonz/sources/toonz/xshcellviewer.cpp @@ -982,8 +982,10 @@ void RenameCellField::keyPressEvent(QKeyEvent *event) { c1 + offset.layer()); } else { CellPosition offset(offset * stride); - int movedR0 = std::max(0, r0 + offset.frame()); - int movedC0 = std::max(0, c0 + offset.layer()); + int movedR0 = std::max(0, r0 + offset.frame()); + int firstCol = + Preferences::instance()->isXsheetCameraColumnEnabled() ? -1 : 0; + int movedC0 = std::max(firstCol, c0 + offset.layer()); int diffFrame = movedR0 - r0; int diffLayer = movedC0 - c0; // It needs to be discussed - I made not to rename cell with arrow key. @@ -991,7 +993,9 @@ void RenameCellField::keyPressEvent(QKeyEvent *event) { // renameCell(); cellSelection->selectCells(r0 + diffFrame, c0 + diffLayer, r1 + diffFrame, c1 + diffLayer); - showInRowCol(m_row + offset.frame(), m_col + offset.layer(), c1 - c0 > 0); + int newRow = std::max(0, m_row + offset.frame()); + int newCol = std::max(firstCol, m_col + offset.layer()); + showInRowCol(newRow, newCol, c1 - c0 > 0); } m_viewer->updateCells(); TApp::instance()->getCurrentSelection()->notifySelectionChanged(); @@ -1250,7 +1254,7 @@ void CellArea::drawNonEmptyBackground(QPainter &p) const { m_viewer->positionToXY(CellPosition(totalFrames, lastNonEmptyCol + 1)); } else { xyTop = m_viewer->positionToXY(CellPosition(0, lastNonEmptyCol)); - xyBottom = m_viewer->positionToXY(CellPosition(totalFrames, 0)); + xyBottom = m_viewer->positionToXY(CellPosition(totalFrames, -1)); ColumnFan *fan = xsh->getColumnFan(o); xyBottom.setY(xyBottom.y() + ((fan ? fan->isActive(0) : true) ? o->cellHeight() : 9)); @@ -3002,7 +3006,7 @@ void CellArea::contextMenuEvent(QContextMenuEvent *event) { TStageObject *pegbar = xsh->getStageObject(m_viewer->getObjectId(col)); int k0, k1; int r0, r1, c0, c1; - if (col >= 0) m_viewer->getCellSelection()->getSelectedCells(r0, c0, r1, c1); + m_viewer->getCellSelection()->getSelectedCells(r0, c0, r1, c1); QPoint cellTopLeft = m_viewer->positionToXY(CellPosition(row, col)); QPoint mouseInCell = event->pos() - cellTopLeft; @@ -3029,8 +3033,7 @@ void CellArea::contextMenuEvent(QContextMenuEvent *event) { !xsh->getColumn(col) ->isLocked()) // on the line between two keyframes createKeyLineMenu(menu, row, col); - } else if (col >= 0 && // Non e' la colonna di camera - m_viewer->getCellSelection()->isCellSelected( + } else if (m_viewer->getCellSelection()->isCellSelected( row, col) && // La cella e' selezionata (abs(r1 - r0) > 0 || abs(c1 - c0) > @@ -3049,11 +3052,9 @@ void CellArea::contextMenuEvent(QContextMenuEvent *event) { } createCellMenu(menu, areCellsEmpty, cell); } else { - if (col >= 0) { - m_viewer->getCellSelection()->makeCurrent(); - m_viewer->getCellSelection()->selectCell(row, col); - m_viewer->setCurrentColumn(col); - } + m_viewer->getCellSelection()->makeCurrent(); + m_viewer->getCellSelection()->selectCell(row, col); + m_viewer->setCurrentColumn(col); createCellMenu(menu, !cell.isEmpty(), cell); } @@ -3132,7 +3133,8 @@ const bool CellArea::isControlPressed() { return isCtrlPressed; } void CellArea::createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell) { CommandManager *cmdManager = CommandManager::instance(); - bool soundCellsSelected = m_viewer->areSoundCellsSelected(); + bool soundCellsSelected = m_viewer->areSoundCellsSelected(); + bool cameraCellsSelected = m_viewer->areCameraCellsSelected(); if (m_viewer->areSoundTextCellsSelected()) return; // Magpies stop here @@ -3304,6 +3306,10 @@ void CellArea::createCellMenu(QMenu &menu, bool isCellSelected, TXshCell cell) { menu.addAction(cmdManager->getAction(MI_LipSyncPopup)); } else { menu.addAction(cmdManager->getAction(MI_FillEmptyCell)); + if (cameraCellsSelected) { + menu.addSeparator(); + menu.addAction(cmdManager->getAction(MI_SetKeyframes)); + } } menu.addSeparator(); if (!soundCellsSelected) diff --git a/toonz/sources/toonz/xshcolumnviewer.cpp b/toonz/sources/toonz/xshcolumnviewer.cpp index b974f4b..d688516 100644 --- a/toonz/sources/toonz/xshcolumnviewer.cpp +++ b/toonz/sources/toonz/xshcolumnviewer.cpp @@ -19,6 +19,7 @@ #include "toonzqt/intfield.h" // TnzLib includes +#include "toonz/txshcolumn.h" #include "toonz/tscenehandle.h" #include "toonz/txsheethandle.h" #include "toonz/txshlevelhandle.h" @@ -481,7 +482,8 @@ void RenameColumnField::show(const QRect &rect, int col) { TXsheet *xsh = m_xsheetHandle->getXsheet(); std::string name = - xsh->getStageObject(TStageObjectId::ColumnId(col))->getName(); + col >= 0 ? xsh->getStageObject(TStageObjectId::ColumnId(col))->getName() + : xsh->getStageObject(TStageObjectId::CameraId(0))->getName(); TXshColumn *column = xsh->getColumn(col); TXshZeraryFxColumn *zColumn = dynamic_cast(column); if (zColumn) @@ -498,7 +500,8 @@ void RenameColumnField::show(const QRect &rect, int col) { void RenameColumnField::renameColumn() { std::string newName = text().toStdString(); - TStageObjectId columnId = TStageObjectId::ColumnId(m_col); + TStageObjectId columnId = m_col >= 0 ? TStageObjectId::ColumnId(m_col) + : TStageObjectId::CameraId(0); TXshColumn *column = m_xsheetHandle->getXsheet()->getColumn(columnId.getIndex()); TXshZeraryFxColumn *zColumn = dynamic_cast(column); @@ -547,6 +550,10 @@ ColumnArea::DrawHeader::DrawHeader(ColumnArea *nArea, QPainter &nP, int nCol) column = col >= 0 ? xsh->getColumn(col) : 0; isEmpty = col >= 0 && xsh->isColumnEmpty(col); + if (col < 0) { + column = TXshColumn::createEmpty(0); + isEmpty = false; + } TStageObjectId currentColumnId = app->getCurrentObject()->getObjectId(); // check if the column is current @@ -556,7 +563,7 @@ ColumnArea::DrawHeader::DrawHeader(ColumnArea *nArea, QPainter &nP, int nCol) else isCurrent = m_viewer->getCurrentColumn() == col; - orig = m_viewer->positionToXY(CellPosition(0, max(col, 0))); + orig = m_viewer->positionToXY(CellPosition(0, max(col, -1))); } void ColumnArea::DrawHeader::prepare() const { @@ -636,8 +643,10 @@ void ColumnArea::DrawHeader::drawBaseFill(const QColor &columnColor, int y1 = rect.bottom(); // fill base color - if (isEmpty || col < 0) + if (isEmpty) p.fillRect(rect, m_viewer->getEmptyColumnHeadColor()); + else if (col < 0) + p.fillRect(rect, columnColor); else { p.fillRect(rect, columnColor); @@ -659,7 +668,7 @@ void ColumnArea::DrawHeader::drawBaseFill(const QColor &columnColor, p.setPen(m_viewer->getVerticalLineColor()); QLine vertical = o->verticalLine(m_viewer->columnToLayerAxis(col), o->frameSide(rect)); - if (isEmpty || col < 0 || o->isVerticalTimeline()) p.drawLine(vertical); + if (isEmpty || o->isVerticalTimeline()) p.drawLine(vertical); // highlight selection bool isSelected = @@ -676,7 +685,7 @@ void ColumnArea::DrawHeader::drawBaseFill(const QColor &columnColor, } void ColumnArea::DrawHeader::drawEye() const { - if (col < 0 || isEmpty || !o->flag(PredefinedFlag::EYE_AREA_VISIBLE)) return; + if (isEmpty || !o->flag(PredefinedFlag::EYE_AREA_VISIBLE)) return; QColor bgColor; QImage icon; int buttonType = !column->isPreviewVisible() ? PREVIEW_OFF_XSHBUTTON @@ -688,7 +697,7 @@ void ColumnArea::DrawHeader::drawEye() const { // preview visible toggle p.setPen(m_viewer->getVerticalLineColor()); - if (column->getSoundTextColumn()) { + if (col < 0 || column->getSoundTextColumn()) { if (o->flag(PredefinedFlag::EYE_AREA_BORDER)) p.drawRect(prevViewRect); return; } @@ -706,9 +715,7 @@ void ColumnArea::DrawHeader::drawEye() const { } void ColumnArea::DrawHeader::drawPreviewToggle(int opacity) const { - if (col < 0 || isEmpty || - !o->flag(PredefinedFlag::PREVIEW_LAYER_AREA_VISIBLE)) - return; + if (isEmpty || !o->flag(PredefinedFlag::PREVIEW_LAYER_AREA_VISIBLE)) return; // camstand visible toggle QColor bgColor; QImage icon; @@ -725,7 +732,7 @@ void ColumnArea::DrawHeader::drawPreviewToggle(int opacity) const { p.setPen(m_viewer->getVerticalLineColor()); - if (column->getPaletteColumn() || column->getSoundTextColumn()) { + if (col < 0 || column->getPaletteColumn() || column->getSoundTextColumn()) { if (o->flag(PredefinedFlag::PREVIEW_LAYER_AREA_BORDER)) p.drawRect(tableViewRect); return; @@ -744,7 +751,7 @@ void ColumnArea::DrawHeader::drawPreviewToggle(int opacity) const { } void ColumnArea::DrawHeader::drawLock() const { - if (col < 0 || isEmpty || !o->flag(PredefinedFlag::LOCK_AREA_VISIBLE)) return; + if (isEmpty || !o->flag(PredefinedFlag::LOCK_AREA_VISIBLE)) return; QColor bgColor; QImage icon; int buttonType = !column->isLocked() ? LOCK_OFF_XSHBUTTON : LOCK_ON_XSHBUTTON; @@ -760,6 +767,12 @@ void ColumnArea::DrawHeader::drawLock() const { // lock button p.setPen(m_viewer->getVerticalLineColor()); + + if (col < 0) { + if (o->flag(PredefinedFlag::LOCK_AREA_BORDER)) p.drawRect(lockModeRect); + return; + } + p.fillRect(lockModeRect, bgColor); if (o->flag(PredefinedFlag::LOCK_AREA_BORDER)) p.drawRect(lockModeRect); @@ -772,8 +785,7 @@ void ColumnArea::DrawHeader::drawLock() const { } void ColumnArea::DrawHeader::drawConfig() const { - if (col < 0 || isEmpty || !o->flag(PredefinedFlag::CONFIG_AREA_VISIBLE)) - return; + if (isEmpty || !o->flag(PredefinedFlag::CONFIG_AREA_VISIBLE)) return; QColor bgColor; QImage icon; int buttonType = CONFIG_XSHBUTTON; @@ -789,7 +801,8 @@ void ColumnArea::DrawHeader::drawConfig() const { TXshZeraryFxColumn *zColumn = dynamic_cast(column); - if (zColumn || column->getPaletteColumn() || column->getSoundTextColumn()) + if (col < 0 || zColumn || column->getPaletteColumn() || + column->getSoundTextColumn()) return; p.drawImage(configImgRect, icon); @@ -822,7 +835,7 @@ void ColumnArea::DrawHeader::drawColumnName() const { // Build column name std::string name(columnObject->getName()); - if (col < 0) name = std::string("Camera"); + // if (col < 0) name = std::string("Camera"); // ZeraryFx columns store name elsewhere TXshZeraryFxColumn *zColumn = dynamic_cast(column); @@ -877,7 +890,7 @@ void ColumnArea::DrawHeader::drawColumnName() const { } void ColumnArea::DrawHeader::drawThumbnail(QPixmap &iconPixmap) const { - if (col < 0 || isEmpty) return; + if (isEmpty) return; QRect thumbnailRect = o->rect(PredefinedRect::THUMBNAIL_AREA).translated(orig); @@ -952,8 +965,7 @@ void ColumnArea::DrawHeader::drawThumbnail(QPixmap &iconPixmap) const { } void ColumnArea::DrawHeader::drawPegbarName() const { - if (col < 0 || isEmpty || !o->flag(PredefinedFlag::PEGBAR_NAME_VISIBLE)) - return; + if (isEmpty || !o->flag(PredefinedFlag::PEGBAR_NAME_VISIBLE)) return; TStageObjectId columnId = m_viewer->getObjectId(col); TStageObjectId parentId = xsh->getStageObjectParent(columnId); @@ -963,7 +975,7 @@ void ColumnArea::DrawHeader::drawPegbarName() const { p.setPen(m_viewer->getVerticalLineColor()); if (o->flag(PredefinedFlag::PEGBAR_NAME_BORDER)) p.drawRect(pegbarnamerect); - if (column->getSoundColumn() || column->getSoundTextColumn() || + if (col < 0 || column->getSoundColumn() || column->getSoundTextColumn() || column->getPaletteColumn()) return; @@ -1374,7 +1386,7 @@ void ColumnArea::drawPaletteColumnHead(QPainter &p, int col) { // AREA TColumnSelection *selection = m_viewer->getColumnSelection(); const Orientation *o = m_viewer->orientation(); - QPoint orig = m_viewer->positionToXY(CellPosition(0, max(col, 0))); + QPoint orig = m_viewer->positionToXY(CellPosition(0, max(col, -1))); QString fontName = Preferences::instance()->getInterfaceFont(); if (fontName == "") { @@ -1541,7 +1553,7 @@ void ColumnArea::paintEvent(QPaintEvent *event) { // AREA // draw column fan (collapsed columns) if (!columnFan->isActive(col)) { drawFoldedColumnHead(p, col); - } else if (col >= 0) { + } else { TXshColumn *column = m_viewer->getXsheet()->getColumn(col); int colType = (column && !column->isEmpty()) ? column->getColumnType() @@ -1889,18 +1901,12 @@ void ColumnArea::mousePressEvent(QMouseEvent *event) { TXsheet *xsh = m_viewer->getXsheet(); ColumnFan *fan = xsh->getColumnFan(o); m_col = m_viewer->xyToPosition(event->pos()).layer(); - // do nothing for the camera column - if (m_col < 0) // CAMERA - { - TApp::instance()->getCurrentSelection()->getSelection()->makeNotCurrent(); - m_viewer->getColumnSelection()->selectNone(); - } // when clicking the column fan - else if (m_col >= 0 && !fan->isActive(m_col)) // column Fan + if (!fan->isActive(m_col)) // column Fan { for (auto o : Orientations::all()) { fan = xsh->getColumnFan(o); - for (int i = m_col; i >= 0 && !fan->isActive(i); i--) fan->activate(i); + for (int i = m_col; !fan->isActive(i); i--) fan->activate(i); } TApp::instance()->getCurrentScene()->setDirtyFlag(true); @@ -1908,9 +1914,18 @@ void ColumnArea::mousePressEvent(QMouseEvent *event) { return; } // set the clicked column to current - else - m_viewer->setCurrentColumn(m_col); + else { + if (m_col < 0) // CAMERA + { + TApp::instance() + ->getCurrentSelection() + ->getSelection() + ->makeNotCurrent(); + m_viewer->getColumnSelection()->selectNone(); + } + m_viewer->setCurrentColumn(m_col); + } TXshColumn *column = xsh->getColumn(m_col); bool isEmpty = !column || column->isEmpty(); TApp::instance()->getCurrentObject()->setIsSpline(false); @@ -2026,7 +2041,7 @@ void ColumnArea::mousePressEvent(QMouseEvent *event) { } // synchronize the current column and the current fx TApp::instance()->getCurrentFx()->setFx(column->getFx()); - } else if (m_col >= 0) { + } else { if (m_viewer->getColumnSelection()->isColumnSelected(m_col) && event->button() == Qt::RightButton) return; @@ -2291,8 +2306,9 @@ void ColumnArea::contextMenuEvent(QContextMenuEvent *event) { const Orientation *o = m_viewer->orientation(); int col = m_viewer->xyToPosition(event->pos()).layer(); - if (col < 0) // CAMERA - return; + + bool isCamera = col < 0; + m_viewer->setCurrentColumn(col); TXsheet *xsh = m_viewer->getXsheet(); QPoint topLeft = m_viewer->positionToXY(CellPosition(0, col)); @@ -2302,7 +2318,7 @@ void ColumnArea::contextMenuEvent(QContextMenuEvent *event) { CommandManager *cmdManager = CommandManager::instance(); //---- Preview - if (!xsh->isColumnEmpty(col) && + if ((isCamera || !xsh->isColumnEmpty(col)) && o->rect(PredefinedRect::EYE_AREA).contains(mouseInCell)) { menu.setObjectName("xsheetColumnAreaMenu_Preview"); @@ -2314,7 +2330,7 @@ void ColumnArea::contextMenuEvent(QContextMenuEvent *event) { menu.addAction(cmdManager->getAction("MI_SwapEnabledColumns")); } //---- Lock - else if (!xsh->isColumnEmpty(col) && + else if ((isCamera || !xsh->isColumnEmpty(col)) && o->rect(PredefinedRect::LOCK_AREA).contains(mouseInCell)) { menu.setObjectName("xsheetColumnAreaMenu_Lock"); @@ -2326,7 +2342,7 @@ void ColumnArea::contextMenuEvent(QContextMenuEvent *event) { menu.addAction(cmdManager->getAction("MI_ToggleColumnLocks")); } //---- Camstand - else if (!xsh->isColumnEmpty(col) && + else if ((isCamera || !xsh->isColumnEmpty(col)) && o->rect(PredefinedRect::PREVIEW_LAYER_AREA).contains(mouseInCell)) { menu.setObjectName("xsheetColumnAreaMenu_Camstand"); @@ -2375,6 +2391,13 @@ void ColumnArea::contextMenuEvent(QContextMenuEvent *event) { } menu.addSeparator(); menu.addAction(cmdManager->getAction(MI_FoldColumns)); + QAction *cameraToggle = cmdManager->getAction(MI_ToggleXsheetCameraColumn); + bool cameraVisible = Preferences::instance()->isXsheetCameraColumnEnabled(); + if (cameraVisible) + cameraToggle->setText(tr("Hide Camera Column")); + else + cameraToggle->setText(tr("Show Camera Column")); + menu.addAction(cameraToggle); menu.addSeparator(); menu.addAction(cmdManager->getAction(MI_ToggleXSheetToolbar)); @@ -2458,6 +2481,7 @@ void ColumnArea::onSubSampling(QAction *action) { const set indexes = selection->getIndices(); set::const_iterator it; for (it = indexes.begin(); it != indexes.end(); it++) { + if (*it < 0) continue; // Ignore camera column TXshColumn *column = xsh->getColumn(*it); TXshColumn::ColumnType type = column->getColumnType(); if (type != TXshColumn::eLevelType) continue; diff --git a/toonz/sources/toonz/xsheetcmd.cpp b/toonz/sources/toonz/xsheetcmd.cpp index 1544141..e6a72c4 100644 --- a/toonz/sources/toonz/xsheetcmd.cpp +++ b/toonz/sources/toonz/xsheetcmd.cpp @@ -979,6 +979,8 @@ static void newNoteLevel() { TTool::Application *app = TTool::getApplication(); TXsheet *xsh = app->getCurrentScene()->getScene()->getXsheet(); int col = TTool::getApplication()->getCurrentColumn()->getColumnIndex(); + if (col < 0) + col = 0; // Normally insert before. In case of camera, insert after TXshSoundTextColumn *textSoundCol = new TXshSoundTextColumn(); textSoundCol->setXsheet(xsh); diff --git a/toonz/sources/toonz/xsheetdragtool.cpp b/toonz/sources/toonz/xsheetdragtool.cpp index f8e3ce6..747c87a 100644 --- a/toonz/sources/toonz/xsheetdragtool.cpp +++ b/toonz/sources/toonz/xsheetdragtool.cpp @@ -179,8 +179,10 @@ public: void onDrag(const CellPosition &pos) override { TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); int row = pos.frame(), col = pos.layer(); - if (col < 0 || (!getViewer()->orientation()->isVerticalTimeline() && - col >= xsh->getColumnCount())) + int firstCol = + Preferences::instance()->isXsheetCameraColumnEnabled() ? -1 : 0; + if (col < firstCol || (!getViewer()->orientation()->isVerticalTimeline() && + col >= xsh->getColumnCount())) return; if (row < 0) row = 0; if (m_modifier & Qt::ControlModifier) @@ -1487,8 +1489,10 @@ public: TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); int col = pos.layer(); if (!m_enabled) return; - if (col < 0 || (!getViewer()->orientation()->isVerticalTimeline() && - col >= xsh->getColumnCount())) + int firstCol = + Preferences::instance()->isXsheetCameraColumnEnabled() ? -1 : 0; + if (col < firstCol || (!getViewer()->orientation()->isVerticalTimeline() && + col >= xsh->getColumnCount())) return; TColumnSelection *selection = getViewer()->getColumnSelection(); selection->selectNone(); @@ -1620,6 +1624,7 @@ public: TXsheet *xsh = app->getCurrentXsheet()->getXsheet(); std::set indices = selection->getIndices(); + indices.erase(-1); // Ignore camera column if (indices.empty()) return; assert(m_lastCol == *indices.begin()); diff --git a/toonz/sources/toonz/xsheetviewer.cpp b/toonz/sources/toonz/xsheetviewer.cpp index 37f8fbd..95519b1 100644 --- a/toonz/sources/toonz/xsheetviewer.cpp +++ b/toonz/sources/toonz/xsheetviewer.cpp @@ -284,6 +284,8 @@ XsheetViewer::XsheetViewer(QWidget *parent, Qt::WFlags flags) SLOT(positionSections())); emit orientationChanged(orientation()); + + onPreferenceChanged("XsheetCamera"); } //----------------------------------------------------------------------------- @@ -659,12 +661,15 @@ bool XsheetViewer::refreshContentSize(int dx, int dy) { if (m_orientation->isVerticalTimeline()) contentSize = positionToXY(CellPosition(frameCount + 1, columnCount + 1)); else { - contentSize = positionToXY(CellPosition(frameCount + 1, 0)); + int firstCol = + Preferences::instance()->isXsheetCameraColumnEnabled() ? -1 : 0; + contentSize = positionToXY(CellPosition(frameCount + 1, firstCol)); ColumnFan *fan = xsh->getColumnFan(m_orientation); contentSize.setY(contentSize.y() + 1 + - (fan->isActive(0) ? m_orientation->cellHeight() - : m_orientation->foldedCellSize())); + (fan->isActive(firstCol) + ? m_orientation->cellHeight() + : m_orientation->foldedCellSize())); } QSize actualSize(contentSize.x(), contentSize.y()); @@ -710,10 +715,13 @@ void XsheetViewer::updateAreeSize() { areaFilled = positionToXY( CellPosition(xsh->getFrameCount() + 1, xsh->getColumnCount() + 1)); else { - areaFilled = positionToXY(CellPosition(xsh->getFrameCount() + 1, 0)); + int firstCol = + Preferences::instance()->isXsheetCameraColumnEnabled() ? -1 : 0; + areaFilled = + positionToXY(CellPosition(xsh->getFrameCount() + 1, firstCol)); ColumnFan *fan = xsh->getColumnFan(m_orientation); - areaFilled.setY(areaFilled.y() + 1 + (fan->isActive(0) + areaFilled.setY(areaFilled.y() + 1 + (fan->isActive(firstCol) ? o->cellHeight() : o->foldedCellSize())); } @@ -807,14 +815,14 @@ QPoint XsheetViewer::positionToXY(const CellPosition &pos) const { // area // since the layers are flipped - usePoint.setY(usePoint.y() + (fan->isActive(pos.layer()) - ? o->cellHeight() - : o->foldedCellSize())); + usePoint.setY(usePoint.y() - o->cellHeight() + (fan->isActive(pos.layer()) + ? o->cellHeight() + : o->foldedCellSize())); int columnCount = qMax(1, xsh->getColumnCount()); int colsHeight = o->colToLayerAxis(columnCount, fan); if (colsHeight) - usePoint.setY(colsHeight - usePoint.y()); + usePoint.setY(colsHeight - usePoint.y() - o->cellHeight()); else usePoint.setY(0); @@ -900,6 +908,7 @@ bool XsheetViewer::areCellsSelectedEmpty() { bool XsheetViewer::areSoundCellsSelected() { int r0, c0, r1, c1; getCellSelection()->getSelectedCells(r0, c0, r1, c1); + if (c0 < 0) return false; int i, j; for (i = r0; i <= r1; i++) for (j = c0; j <= c1; j++) { @@ -915,6 +924,7 @@ bool XsheetViewer::areSoundCellsSelected() { bool XsheetViewer::areSoundTextCellsSelected() { int r0, c0, r1, c1; getCellSelection()->getSelectedCells(r0, c0, r1, c1); + if (c0 < 0) return false; int i, j; for (i = r0; i <= r1; i++) for (j = c0; j <= c1; j++) { @@ -927,6 +937,14 @@ bool XsheetViewer::areSoundTextCellsSelected() { //----------------------------------------------------------------------------- +bool XsheetViewer::areCameraCellsSelected() { + int r0, c0, r1, c1; + getCellSelection()->getSelectedCells(r0, c0, r1, c1); + return c0 < 0; +} + +//----------------------------------------------------------------------------- + void XsheetViewer::setScrubHighlight(int row, int startRow, int col) { if (m_scrubCol == -1) m_scrubCol = col; m_scrubRow0 = std::min(row, startRow); @@ -1175,6 +1193,8 @@ void XsheetViewer::keyPressEvent(QKeyEvent *event) { TCellSelection *cellSel = dynamic_cast(TSelection::getCurrent()); + int firstCol = + Preferences::instance()->isXsheetCameraColumnEnabled() ? -1 : 0; // Use arrow keys to shift the cell selection. Ctrl + arrow keys to resize the // selection range. if (Preferences::instance()->isUseArrowKeyToShiftCellSelectionEnabled() && @@ -1185,7 +1205,7 @@ void XsheetViewer::keyPressEvent(QKeyEvent *event) { if (m_cellArea->isControlPressed()) { // resize if (r0 == r1 && shift.frame() < 0) return; - if (c0 == c1 && shift.layer() < 0) return; + if (c0 == c1 && shift.layer() < firstCol) return; cellSel->selectCells(r0, c0, r1 + shift.frame(), c1 + shift.layer()); updateCells(); TApp::instance()->getCurrentSelection()->notifySelectionChanged(); @@ -1193,7 +1213,7 @@ void XsheetViewer::keyPressEvent(QKeyEvent *event) { } else { // shift CellPosition offset(shift * stride); int movedR0 = std::max(0, r0 + offset.frame()); - int movedC0 = std::max(0, c0 + offset.layer()); + int movedC0 = std::max(firstCol, c0 + offset.layer()); int diffFrame = movedR0 - r0; int diffLayer = movedC0 - c0; cellSel->selectCells(r0 + diffFrame, c0 + diffLayer, r1 + diffFrame, @@ -1205,6 +1225,7 @@ void XsheetViewer::keyPressEvent(QKeyEvent *event) { if (shift) { now = now + shift * stride; now.ensureValid(); + if (now.layer() < firstCol) now.setLayer(firstCol); setCurrentRow(now.frame()); setCurrentColumn(now.layer()); return; @@ -1321,6 +1342,8 @@ void XsheetViewer::onPreferenceChanged(const QString &prefName) { if (prefName == "XSheetToolbar") { positionSections(); refreshContentSize(0, 0); + } else if (prefName == "XsheetCamera") { + refreshContentSize(0, 0); } } @@ -1361,7 +1384,7 @@ void XsheetViewer::onCurrentColumnSwitched() { void XsheetViewer::scrollToColumn(int col) { int colNext = col + (m_orientation->isVerticalTimeline() ? 1 : -1); - if (colNext < 0) colNext = 0; + if (colNext < 0) colNext = -1; int x0 = columnToLayerAxis(col); int x1 = columnToLayerAxis(colNext); @@ -1735,12 +1758,12 @@ int XsheetViewer::getFrameZoomAdjustment() { } void XsheetViewer::zoomOnFrame(int frame, int factor) { - QPoint xyOrig = positionToXY(CellPosition(frame, 0)); + QPoint xyOrig = positionToXY(CellPosition(frame, -1)); m_frameZoomFactor = factor; m_layerFooterPanel->setZoomSliderValue(m_frameZoomFactor); - QPoint xyNew = positionToXY(CellPosition(frame, 0)); + QPoint xyNew = positionToXY(CellPosition(frame, -1)); int viewShift = xyNew.x() - xyOrig.x(); diff --git a/toonz/sources/toonz/xsheetviewer.h b/toonz/sources/toonz/xsheetviewer.h index aa2a8fa..abd1e33 100644 --- a/toonz/sources/toonz/xsheetviewer.h +++ b/toonz/sources/toonz/xsheetviewer.h @@ -597,6 +597,7 @@ public: /*! Return true if selection contain only sound cell.*/ bool areSoundCellsSelected(); bool areSoundTextCellsSelected(); + bool areCameraCellsSelected(); XsheetGUI::DragTool *getDragTool() const { return m_dragTool; }; void setDragTool(XsheetGUI::DragTool *dragTool); diff --git a/toonz/sources/toonz/xshrowviewer.cpp b/toonz/sources/toonz/xshrowviewer.cpp index 30c1541..092fb57 100644 --- a/toonz/sources/toonz/xshrowviewer.cpp +++ b/toonz/sources/toonz/xshrowviewer.cpp @@ -150,8 +150,11 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { else p.setPen(m_viewer->getTextColor()); - QPoint basePoint = m_viewer->positionToXY(CellPosition(r, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) basePoint.setY(0); + QPoint basePoint = m_viewer->positionToXY(CellPosition(r, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + basePoint.setY(0); + else + basePoint.setX(0); QRect labelRect = m_viewer->orientation() ->rect(PredefinedRect::FRAME_LABEL) .translated(basePoint); @@ -278,8 +281,11 @@ void RowArea::drawPlayRangeBackground(QPainter &p, int r0, int r1) { for (int r = r0; r <= r1; r++) { if (!(playR0 <= r && r <= playR1) && ((r - m_r0) % step == 0)) continue; - QPoint basePoint = m_viewer->positionToXY(CellPosition(r, 0)); - if (!o->isVerticalTimeline()) basePoint.setY(0); + QPoint basePoint = m_viewer->positionToXY(CellPosition(r, -1)); + if (!o->isVerticalTimeline()) + basePoint.setY(0); + else + basePoint.setX(0); QRect previewBoxRect = o->rect(PredefinedRect::PREVIEW_FRAME_AREA) .adjusted(0, 0, -frameAdj, 0) @@ -324,16 +330,22 @@ void RowArea::drawPlayRange(QPainter &p, int r0, int r1) { p.setBrush(QBrush(ArrowColor)); if (m_r0 > r0 - 1 && r1 + 1 > m_r0) { - QPoint topLeft = m_viewer->positionToXY(CellPosition(m_r0, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(m_r0, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); m_viewer->drawPredefinedPath(p, PredefinedPath::BEGIN_PLAY_RANGE, topLeft, ArrowColor, QColor(Qt::black)); } if (m_r1 > r0 - 1 && r1 + 1 > m_r1) { - QPoint topLeft = m_viewer->positionToXY(CellPosition(m_r1, 0)); + QPoint topLeft = m_viewer->positionToXY(CellPosition(m_r1, -1)); topLeft.setX(topLeft.x() - frameAdj); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); m_viewer->drawPredefinedPath(p, PredefinedPath::END_PLAY_RANGE, topLeft, ArrowColor, QColor(Qt::black)); } @@ -345,8 +357,11 @@ void RowArea::drawCurrentRowGadget(QPainter &p, int r0, int r1) { int currentRow = m_viewer->getCurrentRow(); if (currentRow < r0 || r1 < currentRow) return; - QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QRect header = m_viewer->orientation() ->rect(PredefinedRect::FRAME_HEADER) .translated(topLeft); @@ -363,8 +378,11 @@ void RowArea::drawOnionSkinBackground(QPainter &p, int r0, int r1) { int frameAdj = m_viewer->getFrameZoomAdjustment(); for (int r = r0; r <= r1; r++) { - QPoint basePoint = m_viewer->positionToXY(CellPosition(r, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) basePoint.setY(0); + QPoint basePoint = m_viewer->positionToXY(CellPosition(r, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + basePoint.setY(0); + else + basePoint.setX(0); QRect oRect = m_viewer->orientation() ->rect(PredefinedRect::ONION_AREA) @@ -461,8 +479,11 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { verticalLine.x2() - 3, verticalLine.y2()); } // Draw onion skin main handle - QPoint handleTopLeft = m_viewer->positionToXY(CellPosition(currentRow, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) handleTopLeft.setY(0); + QPoint handleTopLeft = m_viewer->positionToXY(CellPosition(currentRow, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + handleTopLeft.setY(0); + else + handleTopLeft.setX(0); QRect handleRect = onionRect.translated(handleTopLeft); handleRect.adjust(-frameAdj / 2, 0, -frameAdj / 2, 0); int angle180 = 16 * 180; @@ -487,8 +508,11 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { p.setBrush(mos < 0 ? backDotColor : frontDotColor); else p.setBrush(Qt::NoBrush); - QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow + mos, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow + mos, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QRect dotRect = m_viewer->orientation() ->rect(PredefinedRect::ONION_DOT) .translated(topLeft); @@ -508,8 +532,11 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { p.setBrush(QBrush(QColor(0, 255, 255, 128))); else p.setBrush(Qt::NoBrush); - QPoint topLeft = m_viewer->positionToXY(CellPosition(fos, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(fos, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QRect dotRect = m_viewer->orientation() ->rect(PredefinedRect::ONION_DOT_FIXED) .translated(topLeft); @@ -521,8 +548,11 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { if (m_showOnionToSet != None) { p.setPen(QColor(255, 255, 0)); p.setBrush(QBrush(QColor(255, 255, 0))); - QPoint topLeft = m_viewer->positionToXY(CellPosition(m_row, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(m_row, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QRect dotRect = m_viewer->orientation() ->rect(m_showOnionToSet == Fos ? PredefinedRect::ONION_DOT_FIXED @@ -539,8 +569,11 @@ void RowArea::drawCurrentTimeIndicator(QPainter &p) { int frameAdj = m_viewer->getFrameZoomAdjustment(); int currentRow = m_viewer->getCurrentRow(); - QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QRect header = m_viewer->orientation() ->rect(PredefinedRect::FRAME_HEADER) .adjusted(-frameAdj / 2, 0, -frameAdj / 2, 0) @@ -563,8 +596,11 @@ void RowArea::drawCurrentTimeLine(QPainter &p) { int frameAdj = m_viewer->getFrameZoomAdjustment(); int currentRow = m_viewer->getCurrentRow(); - QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QRect header = m_viewer->orientation() ->rect(PredefinedRect::FRAME_HEADER) .adjusted(-frameAdj / 2, 0, -frameAdj / 2, 0) @@ -650,8 +686,11 @@ void RowArea::drawShiftTraceMarker(QPainter &p) { p.setPen(colorsVec[i]); p.setBrush(Qt::gray); QPoint topLeft = - m_viewer->positionToXY(CellPosition(currentRow + offsVec[i], 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + m_viewer->positionToXY(CellPosition(currentRow + offsVec[i], -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QRect dotRect = m_viewer->orientation() ->rect(PredefinedRect::SHIFTTRACE_DOT) .translated(topLeft); @@ -667,8 +706,11 @@ void RowArea::drawShiftTraceMarker(QPainter &p) { if (m_showOnionToSet == ShiftTraceGhost) { p.setPen(QColor(255, 255, 0)); p.setBrush(QColor(255, 255, 0, 180)); - QPoint topLeft = m_viewer->positionToXY(CellPosition(m_row, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(m_row, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QRect dotRect = m_viewer->orientation() ->rect(PredefinedRect::SHIFTTRACE_DOT) .translated(topLeft); @@ -735,8 +777,11 @@ void RowArea::drawPinnedCenterKeys(QPainter &p, int r0, int r1) { if (tmp_pinnedCol != prev_pinnedCol) { prev_pinnedCol = tmp_pinnedCol; if (r != r0 - 1) { - QPoint topLeft = m_viewer->positionToXY(CellPosition(r, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(r, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QPoint mouseInCell = m_pos - topLeft; if (keyRect.contains(mouseInCell)) p.setBrush(QColor(30, 210, 255)); @@ -829,8 +874,11 @@ void RowArea::mousePressEvent(QMouseEvent *event) { int currentFrame = TApp::instance()->getCurrentFrame()->getFrame(); int row = m_viewer->xyToPosition(pos).frame(); - QPoint topLeft = m_viewer->positionToXY(CellPosition(row, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(row, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QPoint mouseInCell = event->pos() - topLeft; int frameAdj = m_viewer->getFrameZoomAdjustment(); @@ -978,8 +1026,11 @@ void RowArea::mouseMoveEvent(QMouseEvent *event) { int currentRow = TApp::instance()->getCurrentFrame()->getFrame(); int row = m_viewer->xyToPosition(m_pos).frame(); int frameAdj = m_viewer->getFrameZoomAdjustment(); - QPoint topLeft = m_viewer->positionToXY(CellPosition(row, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(row, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QPoint mouseInCell = event->pos() - topLeft; if (row < 0) return; @@ -1054,10 +1105,16 @@ void RowArea::mouseMoveEvent(QMouseEvent *event) { update(); - QPoint base0 = m_viewer->positionToXY(CellPosition(m_r0, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) base0.setY(0); - QPoint base1 = m_viewer->positionToXY(CellPosition(m_r1, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) base1.setY(0); + QPoint base0 = m_viewer->positionToXY(CellPosition(m_r0, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + base0.setY(0); + else + base0.setX(0); + QPoint base1 = m_viewer->positionToXY(CellPosition(m_r1, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + base1.setY(0); + else + base1.setX(0); QPainterPath startArrow = o->path(PredefinedPath::BEGIN_PLAY_RANGE).translated(base0); QPainterPath endArrow = @@ -1186,8 +1243,11 @@ void RowArea::mouseDoubleClickEvent(QMouseEvent *event) { int currentFrame = TApp::instance()->getCurrentFrame()->getFrame(); int row = m_viewer->xyToPosition(event->pos()).frame(); int frameAdj = m_viewer->getFrameZoomAdjustment(); - QPoint topLeft = m_viewer->positionToXY(CellPosition(row, 0)); - if (!m_viewer->orientation()->isVerticalTimeline()) topLeft.setY(0); + QPoint topLeft = m_viewer->positionToXY(CellPosition(row, -1)); + if (!m_viewer->orientation()->isVerticalTimeline()) + topLeft.setY(0); + else + topLeft.setX(0); QPoint mouseInCell = event->pos() - topLeft; if (TApp::instance()->getCurrentFrame()->isEditingScene() && event->buttons() & Qt::LeftButton && diff --git a/toonz/sources/toonzlib/columnfan.cpp b/toonz/sources/toonzlib/columnfan.cpp index 4b24cf3..61e5a1a 100644 --- a/toonz/sources/toonzlib/columnfan.cpp +++ b/toonz/sources/toonzlib/columnfan.cpp @@ -1,6 +1,7 @@ #include "toonz/columnfan.h" +#include "toonz/preferences.h" // TnzCore includes #include "tstream.h" @@ -11,7 +12,8 @@ //============================================================================= // ColumnFan -ColumnFan::ColumnFan() : m_firstFreePos(0), m_unfolded(74), m_folded(9) {} +ColumnFan::ColumnFan() + : m_firstFreePos(0), m_unfolded(74), m_folded(9), m_cameraActive(true) {} //----------------------------------------------------------------------------- @@ -51,6 +53,14 @@ void ColumnFan::update() { //----------------------------------------------------------------------------- int ColumnFan::layerAxisToCol(int coord) const { + if (Preferences::instance()->isXsheetCameraColumnEnabled()) { + int firstCol = + m_cameraActive + ? m_unfolded + : ((m_columns.size() > 0 && !m_columns[0].m_active) ? 0 : m_folded); + if (coord < firstCol) return -1; + coord -= firstCol; + } if (coord < m_firstFreePos) { std::map::const_iterator it = m_table.lower_bound(coord); if (it == m_table.end()) return -3; @@ -63,17 +73,30 @@ int ColumnFan::layerAxisToCol(int coord) const { //----------------------------------------------------------------------------- int ColumnFan::colToLayerAxis(int col) const { - int m = m_columns.size(); + int m = m_columns.size(); + int firstCol = 0; + if (Preferences::instance()->isXsheetCameraColumnEnabled()) { + if (col < -1) return -m_unfolded; + if (col < 0) return 0; + firstCol = + m_cameraActive + ? m_unfolded + : ((m_columns.size() > 0 && !m_columns[0].m_active) ? 0 : m_folded); + } if (col >= 0 && col < m) - return m_columns[col].m_pos; + return firstCol + m_columns[col].m_pos; else - return m_firstFreePos + (col - m) * m_unfolded; + return firstCol + m_firstFreePos + (col - m) * m_unfolded; } //----------------------------------------------------------------------------- void ColumnFan::activate(int col) { int m = m_columns.size(); + if (col < 0) { + m_cameraActive = true; + return; + } if (col < m) { m_columns[col].m_active = true; int i; @@ -91,6 +114,10 @@ void ColumnFan::activate(int col) { //----------------------------------------------------------------------------- void ColumnFan::deactivate(int col) { + if (col < 0) { + m_cameraActive = false; + return; + } while ((int)m_columns.size() <= col) m_columns.push_back(Column()); m_columns[col].m_active = false; update(); @@ -99,8 +126,9 @@ void ColumnFan::deactivate(int col) { //----------------------------------------------------------------------------- bool ColumnFan::isActive(int col) const { - return 0 <= col && col < (int)m_columns.size() ? m_columns[col].m_active - : true; + return 0 <= col && col < (int)m_columns.size() + ? m_columns[col].m_active + : col < 0 ? m_cameraActive : true; } //----------------------------------------------------------------------------- @@ -110,6 +138,7 @@ bool ColumnFan::isEmpty() const { return m_columns.empty(); } //----------------------------------------------------------------------------- void ColumnFan::copyFoldedStateFrom(const ColumnFan &from) { + m_cameraActive = from.m_cameraActive; for (int i = 0, n = (int)from.m_columns.size(); i < n; i++) if (!from.isActive(i)) deactivate(i); } @@ -119,6 +148,8 @@ void ColumnFan::copyFoldedStateFrom(const ColumnFan &from) { void ColumnFan::saveData( TOStream &os) { // only saves indices of folded columns int index, n = (int)m_columns.size(); + if (Preferences::instance()->isXsheetCameraColumnEnabled() && !m_cameraActive) + os << -1 << 1; for (index = 0; index < n;) { while (index < n && m_columns[index].m_active) index++; if (index < n) { diff --git a/toonz/sources/toonzlib/fxcommand.cpp b/toonz/sources/toonzlib/fxcommand.cpp index 0ea8a78..6e70ec9 100644 --- a/toonz/sources/toonzlib/fxcommand.cpp +++ b/toonz/sources/toonzlib/fxcommand.cpp @@ -921,6 +921,9 @@ void TFxCommand::insertFx(TFx *newFx, const QList &fxs, int row) { if (!newFx) return; + if (col < 0) + col = 0; // Normally insert before. In case of camera, insert after + std::unique_ptr undo( new InsertFxUndo(newFx, row, col, fxs, links, app)); if (undo->isConsistent()) { diff --git a/toonz/sources/toonzlib/preferences.cpp b/toonz/sources/toonzlib/preferences.cpp index 79b498b..e7cdc47 100644 --- a/toonz/sources/toonzlib/preferences.cpp +++ b/toonz/sources/toonzlib/preferences.cpp @@ -347,7 +347,8 @@ Preferences::Preferences() , m_currentColumnColor(TPixel::Black) , m_enableWinInk(false) , m_useOnionColorsForShiftAndTraceGhosts(false) - , m_rasterBackgroundColor(TPixel::White) { + , m_rasterBackgroundColor(TPixel::White) + , m_showXsheetCameraColumn(true) { TCamera camera; m_defLevelType = PLI_XSHLEVEL; m_defLevelWidth = camera.getSize().lx; @@ -726,6 +727,8 @@ Preferences::Preferences() getValue(*m_settings, "rasterBackgroundColor", m_rasterBackgroundColor); TImageWriter::setBackgroundColor(m_rasterBackgroundColor); + + getValue(*m_settings, "showXsheetCameraColumn", m_showXsheetCameraColumn); } //----------------------------------------------------------------- @@ -1772,4 +1775,11 @@ void Preferences::setRasterBackgroundColor(const TPixel32 &color) { QString::number((int)color.b)); m_settings->setValue("rasterBackgroundColor_M", QString::number((int)color.m)); -} \ No newline at end of file +} + +//----------------------------------------------------------------- + +void Preferences::enableXsheetCameraColumn(bool on) { + m_showXsheetCameraColumn = on; + m_settings->setValue("showXsheetCameraColumn", on ? "1" : "0"); +} diff --git a/toonz/sources/toonzlib/txsheet.cpp b/toonz/sources/toonzlib/txsheet.cpp index 849cea3..3d22278 100644 --- a/toonz/sources/toonzlib/txsheet.cpp +++ b/toonz/sources/toonzlib/txsheet.cpp @@ -338,7 +338,8 @@ bool TXsheet::setCells(int row, int col, int rowCount, const TXshCell cells[]) { else if (levelType == MESH_XSHLEVEL) type = TXshColumn::eMeshType; } - bool wasColumnEmpty = isColumnEmpty(col); + bool wasColumnEmpty = isColumnEmpty(col); + if (col < 0) return false; TXshCellColumn *column = touchColumn(col, type)->getCellColumn(); if (!column) return false; @@ -1299,6 +1300,7 @@ void TXsheet::insertColumn(int col, TXshColumn::ColumnType type) { //----------------------------------------------------------------------------- void TXsheet::insertColumn(int col, TXshColumn *column) { + if (col < 0) col = 0; column->setXsheet(this); m_imp->m_columnSet.insertColumn(col, column); m_imp->m_pegTree->insertColumn(col); @@ -1387,7 +1389,7 @@ int TXsheet::getFirstFreeColumnIndex() const { TXshColumn *TXsheet::touchColumn(int index, TXshColumn::ColumnType type) { TXshColumn *column = m_imp->m_columnSet.touchColumn(index, type).getPointer(); - if (!column) return 0; + if (index < 0 || !column) return 0; // NOTE (Daniele): The following && should be a bug... but I fear I'd break // something changing it.