From 3639da6d5ab4f99a4743405177a1a9ec88869c9e Mon Sep 17 00:00:00 2001 From: shun_iwasawa Date: Wed, 18 Jan 2017 16:31:22 +0900 Subject: [PATCH] arrowkey to shift cell selection, input w/o dblclk --- toonz/sources/include/toonz/preferences.h | 17 ++ toonz/sources/toonz/cellselection.cpp | 55 +++++- toonz/sources/toonz/cellselection.h | 4 + toonz/sources/toonz/preferencespopup.cpp | 30 +++- toonz/sources/toonz/preferencespopup.h | 2 + toonz/sources/toonz/tapp.cpp | 3 +- toonz/sources/toonz/xshcellviewer.cpp | 210 ++++++++++++++++------ toonz/sources/toonz/xshcellviewer.h | 10 +- toonz/sources/toonz/xsheetviewer.cpp | 57 +++++- toonz/sources/toonzlib/preferences.cpp | 23 ++- 10 files changed, 347 insertions(+), 64 deletions(-) diff --git a/toonz/sources/include/toonz/preferences.h b/toonz/sources/include/toonz/preferences.h index 4e3e30dd..d3917fff 100644 --- a/toonz/sources/include/toonz/preferences.h +++ b/toonz/sources/include/toonz/preferences.h @@ -340,6 +340,16 @@ public: return m_showKeyframesOnXsheetCellArea; } + void enableUseArrowKeyToShiftCellSelection(bool on); + bool isUseArrowKeyToShiftCellSelectionEnabled() const { + return m_useArrowKeyToShiftCellSelection; + } + + void enableInputCellsWithoutDoubleClicking(bool on); + bool isInputCellsWithoutDoubleClickingEnabled() const { + return m_inputCellsWithoutDoubleClickingEnabled; + } + // Animation tab void setKeyframeType(int s); @@ -526,6 +536,13 @@ private: // whether to use numpad and tab key shortcut for selecting styles bool m_useNumpadForSwitchingStyles; + // use arrow key to shift cel selection, ctrl + arrow key to resize the + // selection range. + bool m_useArrowKeyToShiftCellSelection; + + // enable to input drawing numbers into cells without double-clicking + bool m_inputCellsWithoutDoubleClickingEnabled; + private: Preferences(); ~Preferences(); diff --git a/toonz/sources/toonz/cellselection.cpp b/toonz/sources/toonz/cellselection.cpp index b73a4d47..6408a957 100644 --- a/toonz/sources/toonz/cellselection.cpp +++ b/toonz/sources/toonz/cellselection.cpp @@ -1033,8 +1033,8 @@ public: //----------------------------------------------------------------------------- // if at least one of the cell in the range, return false -bool checkIfCellsHaveTheSameContent(int &r0, int &c0, int &r1, int &c1, - TXshCell &cell) { +bool checkIfCellsHaveTheSameContent(const int &r0, const int &c0, const int &r1, + const int &c1, const TXshCell &cell) { TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); for (int c = c0; c <= c1; c++) { for (int r = r0; r <= r1; r++) { @@ -1076,6 +1076,13 @@ public: m_selection->selectCells(r0, c0, r1, c1); } + RenameCellsUndo(int r0, int c0, int r1, int c1, QMimeData *data, + TXshCell &cell) + : m_data(data), m_cell(cell) { + m_selection = new TCellSelection(); + m_selection->selectCells(r0, c0, r1, c1); + } + ~RenameCellsUndo() { delete m_selection; delete m_data; @@ -1196,6 +1203,22 @@ void TCellSelection::enableCommands() { enableCommand(this, MI_Reframe3, &TCellSelection::reframe3Cells); enableCommand(this, MI_Reframe4, &TCellSelection::reframe4Cells); } +//----------------------------------------------------------------------------- +// Used in RenameCellField::eventFilter() + +bool TCellSelection::isEnabledCommand( + std::string commandId) { // static function + static QList commands = { + MI_Autorenumber, MI_Reverse, MI_Swing, MI_Random, + MI_Increment, MI_ResetStep, MI_IncreaseStep, MI_DecreaseStep, + MI_Step2, MI_Step3, MI_Step4, MI_Each2, + MI_Each3, MI_Each4, MI_Rollup, MI_Rolldown, + MI_TimeStretch, MI_CloneLevel, MI_SetKeyframes, MI_Copy, + MI_Paste, MI_PasteInto, MI_Cut, MI_Clear, + MI_Insert, MI_PasteInto, MI_Reframe1, MI_Reframe2, + MI_Reframe3, MI_Reframe4}; + return commands.contains(commandId); +} //----------------------------------------------------------------------------- @@ -2052,3 +2075,31 @@ void TCellSelection::renameCells(TXshCell &cell) { } //----------------------------------------------------------------------------- +// rename cells for each columns with correspondent item in the list + +void TCellSelection::renameMultiCells(QList &cells) { + if (isEmpty()) return; + int r0, c0, r1, c1; + getSelectedCells(r0, c0, r1, c1); + assert(cells.size() == c1 - c0 + 1); + // register undo only if the cell is modified + bool somethingChanged = false; + for (int c = c0; c <= c1; c++) { + somethingChanged = + !checkIfCellsHaveTheSameContent(r0, c, r1, c, cells[c - c0]); + if (somethingChanged) break; + } + if (!somethingChanged) return; + + TXsheet *xsh = TApp::instance()->getCurrentXsheet()->getXsheet(); + TUndoManager::manager()->beginBlock(); + for (int c = c0; c <= c1; c++) { + TCellData *data = new TCellData(); + data->setCells(xsh, r0, c, r1, c); + RenameCellsUndo *undo = + new RenameCellsUndo(r0, c, r1, c, data, cells[c - c0]); + undo->redo(); + TUndoManager::manager()->add(undo); + } + TUndoManager::manager()->endBlock(); +} diff --git a/toonz/sources/toonz/cellselection.h b/toonz/sources/toonz/cellselection.h index 9b9091d0..a2df65f4 100644 --- a/toonz/sources/toonz/cellselection.h +++ b/toonz/sources/toonz/cellselection.h @@ -100,6 +100,10 @@ public: void reframe4Cells() { reframeCells(4); } void renameCells(TXshCell &cell); + // rename cells for each columns with correspondent item in the list + void renameMultiCells(QList &cells); + + static bool isEnabledCommand(std::string commandId); }; #endif // TCELLSELECTION_H diff --git a/toonz/sources/toonz/preferencespopup.cpp b/toonz/sources/toonz/preferencespopup.cpp index 2b518ae5..ff4d4291 100644 --- a/toonz/sources/toonz/preferencespopup.cpp +++ b/toonz/sources/toonz/preferencespopup.cpp @@ -975,6 +975,18 @@ void PreferencesPopup::onUseNumpadForSwitchingStylesClicked(bool checked) { "NumpadForSwitchingStyles"); } +//----------------------------------------------------------------------------- + +void PreferencesPopup::onUseArrowKeyToShiftCellSelectionClicked(int on) { + m_pref->enableUseArrowKeyToShiftCellSelection(on); +} + +//----------------------------------------------------------------------------- + +void PreferencesPopup::onInputCellsWithoutDoubleClickingClicked(int on) { + m_pref->enableInputCellsWithoutDoubleClicking(on); +} + //********************************************************************************** // PrefencesPopup's constructor //********************************************************************************** @@ -1162,6 +1174,10 @@ PreferencesPopup::PreferencesPopup() new CheckBox(tr("Ignore Alpha Channel on Levels in Column 1"), this); CheckBox *showKeyframesOnCellAreaCB = new CheckBox(tr("Show Keyframes on Cell Area"), this); + CheckBox *useArrowKeyToShiftCellSelectionCB = + new CheckBox(tr("Use Arrow Key to Shift Cell Selection"), this); + CheckBox *inputCellsWithoutDoubleClickingCB = + new CheckBox(tr("Enable to Input Cells without Double Clicking"), this); //--- Animation ------------------------------ categoryList->addItem(tr("Animation")); @@ -1416,6 +1432,10 @@ PreferencesPopup::PreferencesPopup() ignoreAlphaonColumn1CB->setChecked(m_pref->isIgnoreAlphaonColumn1Enabled()); showKeyframesOnCellAreaCB->setChecked( m_pref->isShowKeyframesOnXsheetCellAreaEnabled()); + useArrowKeyToShiftCellSelectionCB->setChecked( + m_pref->isUseArrowKeyToShiftCellSelectionEnabled()); + inputCellsWithoutDoubleClickingCB->setChecked( + m_pref->isInputCellsWithoutDoubleClickingEnabled()); //--- Animation ------------------------------ QStringList list; @@ -1856,11 +1876,13 @@ PreferencesPopup::PreferencesPopup() xsheetFrameLay->addWidget(ignoreAlphaonColumn1CB, 3, 0, 1, 2); xsheetFrameLay->addWidget(showKeyframesOnCellAreaCB, 4, 0, 1, 2); + xsheetFrameLay->addWidget(useArrowKeyToShiftCellSelectionCB, 5, 0, 1, 2); + xsheetFrameLay->addWidget(inputCellsWithoutDoubleClickingCB, 6, 0, 1, 2); } xsheetFrameLay->setColumnStretch(0, 0); xsheetFrameLay->setColumnStretch(1, 0); xsheetFrameLay->setColumnStretch(2, 1); - xsheetFrameLay->setRowStretch(5, 1); + xsheetFrameLay->setRowStretch(7, 1); xsheetBox->setLayout(xsheetFrameLay); stackedWidget->addWidget(xsheetBox); @@ -2188,6 +2210,12 @@ PreferencesPopup::PreferencesPopup() SLOT(onDragCellsBehaviourChanged(int))); ret = ret && connect(showKeyframesOnCellAreaCB, SIGNAL(stateChanged(int)), this, SLOT(onShowKeyframesOnCellAreaChanged(int))); + ret = ret && + connect(useArrowKeyToShiftCellSelectionCB, SIGNAL(stateChanged(int)), + SLOT(onUseArrowKeyToShiftCellSelectionClicked(int))); + ret = ret && + connect(inputCellsWithoutDoubleClickingCB, SIGNAL(stateChanged(int)), + SLOT(onInputCellsWithoutDoubleClickingClicked(int))); //--- Animation ---------------------- ret = ret && connect(m_keyframeType, SIGNAL(currentIndexChanged(int)), diff --git a/toonz/sources/toonz/preferencespopup.h b/toonz/sources/toonz/preferencespopup.h index ddc1be1b..0f11f337 100644 --- a/toonz/sources/toonz/preferencespopup.h +++ b/toonz/sources/toonz/preferencespopup.h @@ -170,6 +170,8 @@ private slots: void onFfmpegTimeoutChanged(); void onFastRenderPathChanged(); void onUseNumpadForSwitchingStylesClicked(bool); + void onUseArrowKeyToShiftCellSelectionClicked(int); + void onInputCellsWithoutDoubleClickingClicked(int); }; //********************************************************************************** diff --git a/toonz/sources/toonz/tapp.cpp b/toonz/sources/toonz/tapp.cpp index 698fe265..5b29adb8 100644 --- a/toonz/sources/toonz/tapp.cpp +++ b/toonz/sources/toonz/tapp.cpp @@ -483,7 +483,8 @@ void TApp::onFrameSwitched() { TCellSelection *sel = dynamic_cast(TSelection::getCurrent()); - if (sel && !sel->isRowSelected(row)) { + if (sel && !sel->isRowSelected(row) && + !Preferences::instance()->isUseArrowKeyToShiftCellSelectionEnabled()) { sel->selectNone(); } } diff --git a/toonz/sources/toonz/xshcellviewer.cpp b/toonz/sources/toonz/xshcellviewer.cpp index a63fd371..e7db7d55 100644 --- a/toonz/sources/toonz/xshcellviewer.cpp +++ b/toonz/sources/toonz/xshcellviewer.cpp @@ -25,6 +25,7 @@ #include "toonzqt/gutil.h" #include "toonzqt/tselectionhandle.h" #include "historytypes.h" +#include "toonzqt/menubarcommand.h" // TnzLib includes #include "toonz/tscenehandle.h" @@ -498,22 +499,51 @@ RenameCellField::RenameCellField(QWidget *parent, XsheetViewer *viewer) setFixedSize(XsheetGUI::ColumnWidth + 3, XsheetGUI::RowHeight + 4); connect(this, SIGNAL(returnPressed()), SLOT(onReturnPressed())); setContextMenuPolicy(Qt::PreventContextMenu); + setObjectName("RenameCellField"); + setAttribute(Qt::WA_TranslucentBackground, true); + installEventFilter(this); } //----------------------------------------------------------------------------- -void RenameCellField::showInRowCol(int row, int col) { +void RenameCellField::showInRowCol(int row, int col, bool multiColumnSelected) { m_viewer->scrollTo(row, col); m_row = row; m_col = col; move(QPoint(m_viewer->columnToX(col) - 1, m_viewer->rowToY(row) - 2)); +#ifdef _WIN32 + static QFont font("Arial", XSHEET_FONT_SIZE, QFont::Normal); +#else static QFont font("Helvetica", XSHEET_FONT_SIZE, QFont::Normal); +#endif setFont(font); + setAlignment(Qt::AlignRight | Qt::AlignBottom); // Se la cella non e' vuota setto il testo - TXsheet *xsh = m_viewer->getXsheet(); + TXsheet *xsh = m_viewer->getXsheet(); + + // adjust text position + int padding = 3; + if (Preferences::instance()->isShowKeyframesOnXsheetCellAreaEnabled()) { + TStageObject *pegbar = xsh->getStageObject(m_viewer->getObjectId(col)); + int r0, r1; + if (pegbar && pegbar->getKeyframeRange(r0, r1)) padding += 9; + } + + // make the field semi-transparent + QColor bgColor = m_viewer->getColumnHeadPastelizer(); + QString styleSheetStr = QString( + "#RenameCellField { padding-right:%1px; " + "background-color:rgba(%2,%3,%4,75); color:%5;}") + .arg(padding) + .arg(bgColor.red()) + .arg(bgColor.green()) + .arg(bgColor.blue()) + .arg(m_viewer->getTextColor().name()); + setStyleSheet(styleSheetStr); + TXshCell cell = xsh->getCell(row, col); if (!cell.isEmpty()) { TFrameId fid = cell.getFrameId(); @@ -522,18 +552,23 @@ void RenameCellField::showInRowCol(int row, int col) { // convert the last one digit of the frame number to alphabet // Ex. 12 -> 1B 21 -> 2A 30 -> 3 if (Preferences::instance()->isShowFrameNumberWithLettersEnabled()) - setText((fid.isEmptyFrame() || fid.isNoFrame()) - ? QString::fromStdWString(levelName) - : QString::fromStdWString(levelName) + QString(" ") + - m_viewer->getFrameNumberWithLetters(fid.getNumber())); + setText( + (fid.isEmptyFrame() || fid.isNoFrame()) + ? QString::fromStdWString(levelName) + : (multiColumnSelected) + ? m_viewer->getFrameNumberWithLetters(fid.getNumber()) + : QString::fromStdWString(levelName) + QString(" ") + + m_viewer->getFrameNumberWithLetters(fid.getNumber())); else { 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) - : QString::fromStdWString(levelName) + QString(" ") + - QString::fromStdString(frameNumber)); + : (multiColumnSelected) + ? QString::fromStdString(frameNumber) + : QString::fromStdWString(levelName) + QString(" ") + + QString::fromStdString(frameNumber)); } selectAll(); } @@ -563,7 +598,6 @@ void RenameCellField::renameCell() { parse_with_letter(QString::fromStdWString(newName), levelName, fid); else parse(QString::fromStdWString(newName), levelName, fid); - TXshLevel *xl = 0; TXsheet *xsheet = m_viewer->getXsheet(); bool animationSheetEnabled = @@ -591,32 +625,46 @@ void RenameCellField::renameCell() { return; } + TCellSelection *cellSelection = dynamic_cast( + TApp::instance()->getCurrentSelection()->getSelection()); + if (!cellSelection) return; + + QList cells; + if (levelName == L"") { - // prendo il livello dalla cella precedente. Se non c'e' dalla corrente - // (forse sto modificando una cella non vuota) + int r0, c0, r1, c1; + cellSelection->getSelectedCells(r0, c0, r1, c1); + bool changed = false; + // rename cells for each column in the selection + for (int c = c0; c <= c1; c++) { + // if there is no level at the current cell, take the level from the + // previous frames + // (when editing not empty column) - // no: faccio il contrario. cfr #6152. celle A-1,B-1. Edito B-1 e la - // rinomino in 2. Quindi devo prima verificare - // che la cella corrente non sia vuota - - TXshCell cell; - int tmpRow = m_row; - while (1) { - cell = xsheet->getCell(tmpRow, m_col); - if (!cell.isEmpty() || tmpRow == 0) break; - tmpRow--; + TXshCell cell; + int tmpRow = m_row; + while (1) { + cell = xsheet->getCell(tmpRow, c); + if (!cell.isEmpty() || tmpRow == 0) break; + tmpRow--; + } + TXshLevel *xl = cell.m_level.getPointer(); + if (!xl || (xl->getType() == OVL_XSHLEVEL && + xl->getPath().getFrame() == TFrameId::NO_FRAME)) { + cells.append(TXshCell()); + continue; + } + // if the next upper cell is empty, then make this cell empty too + if (fid == TFrameId::NO_FRAME) + fid = (m_row - tmpRow <= 1) ? cell.m_frameId : TFrameId(0); + cells.append(TXshCell(xl, fid)); + changed = true; } - xl = cell.m_level.getPointer(); - if (!xl || (xl->getType() == OVL_XSHLEVEL && - xl->getPath().getFrame() == TFrameId::NO_FRAME)) - return; - // if the next upper cell is empty, then make this cell empty too - if (fid == TFrameId::NO_FRAME) - fid = (m_row - tmpRow <= 1) ? cell.m_frameId : TFrameId(0); + if (!changed) return; } else { ToonzScene *scene = m_viewer->getXsheet()->getScene(); TLevelSet *levelSet = scene->getLevelSet(); - xl = levelSet->getLevel(levelName); + TXshLevel *xl = levelSet->getLevel(levelName); if (!xl && fid != TFrameId::NO_FRAME) { if (animationSheetEnabled) { Preferences *pref = Preferences::instance(); @@ -628,22 +676,19 @@ void RenameCellField::renameCell() { } else xl = scene->createNewLevel(TZI_XSHLEVEL, levelName); } + if (!xl) return; + cells.append(TXshCell(xl, fid)); } - if (!xl) return; - - TCellSelection *cellSelection = dynamic_cast( - TApp::instance()->getCurrentSelection()->getSelection()); - if (!cellSelection) return; - - TXshCell cell(xl, fid); if (fid.getNumber() == 0) { TCellSelection::Range range = cellSelection->getSelectedCells(); cellSelection->deleteCells(); // revert cell selection cellSelection->selectCells(range.m_r0, range.m_c0, range.m_r1, range.m_c1); - } else - cellSelection->renameCells(cell); + } else if (cells.size() == 1) + cellSelection->renameCells(cells[0]); + else + cellSelection->renameMultiCells(cells); } //----------------------------------------------------------------------------- @@ -659,8 +704,9 @@ void RenameCellField::onReturnPressed() { int offset = range.m_r1 - range.m_r0 + 1; cellSelection->selectCells(range.m_r0 + offset, range.m_c0, range.m_r1 + offset, range.m_c1); + showInRowCol(m_row + offset, m_col, range.getColCount() > 1); + m_viewer->updateCells(); TApp::instance()->getCurrentSelection()->notifySelectionChanged(); - showInRowCol(m_row + offset, m_col); } //----------------------------------------------------------------------------- @@ -671,6 +717,26 @@ void RenameCellField::focusOutEvent(QFocusEvent *e) { QLineEdit::focusOutEvent(e); } +//----------------------------------------------------------------------------- +// Override shortcut keys for cell selection commands + +bool RenameCellField::eventFilter(QObject *obj, QEvent *e) { + if (e->type() != QEvent::ShortcutOverride) return false; + + TCellSelection *cellSelection = dynamic_cast( + TApp::instance()->getCurrentSelection()->getSelection()); + if (!cellSelection) return false; + + QKeyEvent *ke = (QKeyEvent *)e; + std::string keyStr = + QKeySequence(ke->key() + ke->modifiers()).toString().toStdString(); + QAction *action = CommandManager::instance()->getActionFromShortcut(keyStr); + if (!action) return false; + + return TCellSelection::isEnabledCommand( + CommandManager::instance()->getIdFromAction(action)); +} + //----------------------------------------------------------------------------- void RenameCellField::keyPressEvent(QKeyEvent *event) { @@ -681,23 +747,48 @@ void RenameCellField::keyPressEvent(QKeyEvent *event) { QLineEdit::keyPressEvent(event); return; } - TCellSelection::Range range = cellSelection->getSelectedCells(); - int offset = range.m_r1 - range.m_r0 + 1; - if (event->key() == Qt::Key_Up && m_row > 0) { - renameCell(); - cellSelection->selectCells(range.m_r0 - offset, range.m_c0, - range.m_r1 - offset, range.m_c1); - showInRowCol(m_row - offset, m_col); - TApp::instance()->getCurrentSelection()->notifySelectionChanged(); - } else if (event->key() == Qt::Key_Down) { - renameCell(); - cellSelection->selectCells(range.m_r0 + offset, range.m_c0, - range.m_r1 + offset, range.m_c1); - showInRowCol(m_row + offset, m_col); - TApp::instance()->getCurrentSelection()->notifySelectionChanged(); - } else + int r0, c0, r1, c1; + cellSelection->getSelectedCells(r0, c0, r1, c1); + int rowStride = r1 - r0 + 1; + + QPoint offset(0, 0); + switch (int key = event->key()) { + case Qt::Key_Up: + offset.setY(-1); + break; + case Qt::Key_Down: + offset.setY(1); + break; + case Qt::Key_Left: + offset.setX(-1); + break; + case Qt::Key_Right: + offset.setX(1); + break; + default: QLineEdit::keyPressEvent(event); + return; + break; + } + if (isCtrlPressed && + Preferences::instance()->isUseArrowKeyToShiftCellSelectionEnabled()) { + if (r0 == r1 && offset.y() == -1) return; + if (c0 == c1 && offset.x() == -1) return; + cellSelection->selectCells(r0, c0, r1 + offset.y(), c1 + offset.x()); + } else { + offset.setY(offset.y() * rowStride); + if (r0 + offset.y() < 0) offset.setY(-r0); + if (c0 + offset.x() < 0) return; + // It needs to be discussed - I made not to rename cell with arrow key. + // 19/Jan/2017 shun-iwasawa + // renameCell(); + cellSelection->selectCells(r0 + offset.y(), c0 + offset.x(), + r1 + offset.y(), c1 + offset.x()); + showInRowCol(m_row + offset.y(), m_col + offset.x(), c1 - c0 > 0); + } + m_viewer->updateCells(); + TApp::instance()->getCurrentSelection()->notifySelectionChanged(); } //============================================================================= @@ -1150,6 +1241,9 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference) { #endif p.setFont(font); + // do not draw frame number under RenameCellField + if (m_renameCell->isVisible() && m_renameCell->isLocatedAt(row, col)) return; + // if the same level & same fId with the previous cell, then draw vertical // line if (sameLevel && prevCell.m_frameId == cell.m_frameId) { // cella uguale a @@ -1956,7 +2050,9 @@ void CellArea::mouseDoubleClickEvent(QMouseEvent *event) { m_viewer->getXsheet()->getCell(row, col).isEmpty())) return; - m_renameCell->showInRowCol(row, col); + int colCount = m_viewer->getCellSelection()->getSelectedCells().getColCount(); + + m_renameCell->showInRowCol(row, col, colCount > 1); } //----------------------------------------------------------------------------- @@ -2111,6 +2207,10 @@ void CellArea::onControlPressed(bool pressed) { update(); } +//----------------------------------------------------------------------------- + +const bool CellArea::isControlPressed() { return isCtrlPressed; } + //----------------------------------------------------------------------------- void CellArea::createCellMenu(QMenu &menu, bool isCellSelected) { CommandManager *cmdManager = CommandManager::instance(); diff --git a/toonz/sources/toonz/xshcellviewer.h b/toonz/sources/toonz/xshcellviewer.h index 31d24b4b..c033fc81 100644 --- a/toonz/sources/toonz/xshcellviewer.h +++ b/toonz/sources/toonz/xshcellviewer.h @@ -27,11 +27,14 @@ public: RenameCellField(QWidget *parent, XsheetViewer *viewer); ~RenameCellField() {} - void showInRowCol(int row, int col); + void showInRowCol(int row, int col, bool multiColumnSelected = false); + + bool isLocatedAt(int row, int col) { return row == m_row && col == m_col; } protected: void focusOutEvent(QFocusEvent *) override; void keyPressEvent(QKeyEvent *event) override; + bool eventFilter(QObject *, QEvent *) override; void renameCell(); @@ -88,9 +91,14 @@ public: // display upper-directional smart tab only when pressing ctrl key void onControlPressed(bool pressed); + const bool isControlPressed(); // void keyUpDownPressed(int newRow); + void showRenameField(int row, int col, bool multiColumnSelected = false) { + m_renameCell->showInRowCol(row, col, multiColumnSelected); + } + protected: void paintEvent(QPaintEvent *) override; diff --git a/toonz/sources/toonz/xsheetviewer.cpp b/toonz/sources/toonz/xsheetviewer.cpp index 34d6a6b5..7ca63c89 100644 --- a/toonz/sources/toonz/xsheetviewer.cpp +++ b/toonz/sources/toonz/xsheetviewer.cpp @@ -777,12 +777,54 @@ void XsheetViewer::keyPressEvent(QKeyEvent *event) { int frameCount = getXsheet()->getFrameCount(); int row = getCurrentRow(), col = getCurrentColumn(); + int rowStride = 1; + TCellSelection *cellSel = + dynamic_cast(TSelection::getCurrent()); + // Use arrow keys to shift the cell selection. Ctrl + arrow keys to resize the + // selection range. + if (Preferences::instance()->isUseArrowKeyToShiftCellSelectionEnabled() && + cellSel && !cellSel->isEmpty()) { + int r0, c0, r1, c1; + cellSel->getSelectedCells(r0, c0, r1, c1); + rowStride = cellSel->getSelectedCells().getRowCount(); + QPoint offset(0, 0); + switch (int key = event->key()) { + case Qt::Key_Up: + offset.setY(-1); + break; + case Qt::Key_Down: + offset.setY(1); + break; + case Qt::Key_Left: + offset.setX(-1); + break; + case Qt::Key_Right: + offset.setX(1); + break; + } + if (m_cellArea->isControlPressed()) { + if (r0 == r1 && offset.y() == -1) return; + if (c0 == c1 && offset.x() == -1) return; + cellSel->selectCells(r0, c0, r1 + offset.y(), c1 + offset.x()); + updateCells(); + TApp::instance()->getCurrentSelection()->notifySelectionChanged(); + return; + } else { + offset.setY(offset.y() * rowStride); + if (r0 + offset.y() < 0) offset.setY(-r0); + if (c0 + offset.x() < 0) return; + cellSel->selectCells(r0 + offset.y(), c0 + offset.x(), r1 + offset.y(), + c1 + offset.x()); + TApp::instance()->getCurrentSelection()->notifySelectionChanged(); + } + } + switch (int key = event->key()) { case Qt::Key_Up: - setCurrentRow(std::max(row - 1, 0)); + setCurrentRow(std::max(row - rowStride, 0)); break; case Qt::Key_Down: - setCurrentRow(row + 1); + setCurrentRow(row + rowStride); break; case Qt::Key_Left: setCurrentColumn(std::max(col - 1, 0)); @@ -988,7 +1030,16 @@ void XsheetViewer::onSelectionSwitched(TSelection *oldSelection, /*! update display of the cell selection range in title bar */ void XsheetViewer::onSelectionChanged(TSelection *selection) { - if ((TSelection *)getCellSelection() == selection) changeWindowTitle(); + if ((TSelection *)getCellSelection() == selection) { + changeWindowTitle(); + if (Preferences::instance()->isInputCellsWithoutDoubleClickingEnabled()) { + TCellSelection *cellSel = getCellSelection(); + if (!cellSel->isEmpty()) + m_cellArea->showRenameField( + cellSel->getSelectedCells().m_r0, cellSel->getSelectedCells().m_c0, + cellSel->getSelectedCells().getColCount() > 1); + } + } } //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonzlib/preferences.cpp b/toonz/sources/toonzlib/preferences.cpp index 3d636181..1abc82de 100644 --- a/toonz/sources/toonzlib/preferences.cpp +++ b/toonz/sources/toonzlib/preferences.cpp @@ -297,7 +297,9 @@ Preferences::Preferences() , m_fastRenderPath("desktop") , m_ffmpegTimeout(30) , m_shortcutPreset("defopentoonz") - , m_useNumpadForSwitchingStyles(true) { + , m_useNumpadForSwitchingStyles(true) + , m_useArrowKeyToShiftCellSelection(false) + , m_inputCellsWithoutDoubleClickingEnabled(false) { TCamera camera; m_defLevelType = PLI_XSHLEVEL; m_defLevelWidth = camera.getSize().lx; @@ -571,6 +573,10 @@ Preferences::Preferences() setShortcutPreset(m_shortcutPreset.toStdString()); getValue(*m_settings, "useNumpadForSwitchingStyles", m_useNumpadForSwitchingStyles); + getValue(*m_settings, "useArrowKeyToShiftCellSelection", + m_useArrowKeyToShiftCellSelection); + getValue(*m_settings, "inputCellsWithoutDoubleClickingEnabled", + m_inputCellsWithoutDoubleClickingEnabled); } //----------------------------------------------------------------- @@ -1342,4 +1348,19 @@ int Preferences::matchLevelFormat(const TFilePath &fp) const { void Preferences::enableUseNumpadForSwitchingStyles(bool on) { m_useNumpadForSwitchingStyles = on; m_settings->setValue("useNumpadForSwitchingStyles", on ? "1" : "0"); +} + +//----------------------------------------------------------------- + +void Preferences::enableUseArrowKeyToShiftCellSelection(bool on) { + m_useArrowKeyToShiftCellSelection = on; + m_settings->setValue("useArrowKeyToShiftCellSelection", on ? "1" : "0"); +} + +//----------------------------------------------------------------- + +void Preferences::enableInputCellsWithoutDoubleClicking(bool on) { + m_inputCellsWithoutDoubleClickingEnabled = on; + m_settings->setValue("inputCellsWithoutDoubleClickingEnabled", + on ? "1" : "0"); } \ No newline at end of file