diff --git a/toonz/sources/include/orientation.h b/toonz/sources/include/orientation.h index 2b51735..ef37228 100644 --- a/toonz/sources/include/orientation.h +++ b/toonz/sources/include/orientation.h @@ -107,8 +107,10 @@ enum class PredefinedRect { PEGBAR_NAME, //! where to display pegbar name PARENT_HANDLE_NAME, //! where to display parent handle number FILTER_COLOR, //! where to show layer's filter color - CONFIG_AREA, //! clickable area larger than the config icon, containing it - CONFIG //! the config icon itself + CONFIG_AREA, //! clickable area larger than the config icon, containing it + CONFIG, //! the config icon itself + FRAME_DOT, //! Cell's frame indicator + FRAME_INDICATOR //! Row # indicator }; enum class PredefinedLine { LOCKED, //! dotted vertical line when cell is locked diff --git a/toonz/sources/include/toonzqt/spreadsheetviewer.h b/toonz/sources/include/toonzqt/spreadsheetviewer.h index e49170b..4581e40 100644 --- a/toonz/sources/include/toonzqt/spreadsheetviewer.h +++ b/toonz/sources/include/toonzqt/spreadsheetviewer.h @@ -69,7 +69,7 @@ private: void connectScrollbars(); void disconnectScrollbars(); - void handleScroll(const QPoint &offset) const; + void handleScroll(QPoint &offset); void onScroll(const CellPositionRatio &offset); void prepareToScrollRatio(const CellPositionRatio &offset); @@ -79,6 +79,7 @@ private slots: void onHScroll(int value); signals: void prepareToScrollOffset(const QPoint &offset); + void zoomScrollAdjust(QPoint &offset, bool toZoom); }; //------------------------------------------------------------------- diff --git a/toonz/sources/toonz/Resources/zoom_in.svg b/toonz/sources/toonz/Resources/zoom_in.svg new file mode 100644 index 0000000..a4b7cf6 --- /dev/null +++ b/toonz/sources/toonz/Resources/zoom_in.svg @@ -0,0 +1,10 @@ + + + + + + + diff --git a/toonz/sources/toonz/Resources/zoom_out.svg b/toonz/sources/toonz/Resources/zoom_out.svg new file mode 100644 index 0000000..bf9edb8 --- /dev/null +++ b/toonz/sources/toonz/Resources/zoom_out.svg @@ -0,0 +1,9 @@ + + + + + + diff --git a/toonz/sources/toonz/toonz.qrc b/toonz/sources/toonz/toonz.qrc index b76e317..be7026c 100644 --- a/toonz/sources/toonz/toonz.qrc +++ b/toonz/sources/toonz/toonz.qrc @@ -452,5 +452,7 @@ Resources/locator_over.svg Resources/refresh.svg Resources/refresh_over.svg + Resources/zoom_in.svg + Resources/zoom_out.svg diff --git a/toonz/sources/toonz/xshcellviewer.cpp b/toonz/sources/toonz/xshcellviewer.cpp index 6af036e..6eec2eb 100644 --- a/toonz/sources/toonz/xshcellviewer.cpp +++ b/toonz/sources/toonz/xshcellviewer.cpp @@ -1307,7 +1307,11 @@ void CellArea::drawSoundCell(QPainter &p, int row, int col, bool isReference) { else xy.setX(xy.x() + 1); } - QRect cellRect = o->rect(PredefinedRect::CELL).translated(QPoint(x, y)); + + int frameAdj = m_viewer->getFrameZoomAdjustment(); + int frameZoomF = m_viewer->getFrameZoomFactor(); + QRect cellRect = o->rect(PredefinedRect::CELL).translated(QPoint(x, y)); + cellRect.adjust(0, 0, -frameAdj, 0); QRect rect = cellRect.adjusted(1, 1, 0, 0); int maxNumFrame = soundColumn->getMaxFrame() + 1; int startFrame = soundColumn->getFirstRow(); @@ -1358,8 +1362,12 @@ void CellArea::drawSoundCell(QPainter &p, int row, int col, bool isReference) { drawEndOfDragHandle(p, isLastRow, xy, cellColor); drawLockedDottedLine(p, soundColumn->isLocked(), xy, cellColor); - QRect trackRect = o->rect(PredefinedRect::SOUND_TRACK).translated(xy); - QRect previewRect = o->rect(PredefinedRect::PREVIEW_TRACK).translated(xy); + QRect trackRect = o->rect(PredefinedRect::SOUND_TRACK) + .adjusted(0, 0, -frameAdj, 0) + .translated(xy); + QRect previewRect = o->rect(PredefinedRect::PREVIEW_TRACK) + .adjusted(0, 0, -frameAdj, 0) + .translated(xy); NumberRange trackBounds = o->layerSide(trackRect); NumberRange previewBounds = o->layerSide(previewRect); NumberRange trackAndPreview(trackBounds.from(), previewBounds.to()); @@ -1367,10 +1375,10 @@ void CellArea::drawSoundCell(QPainter &p, int row, int col, bool isReference) { NumberRange timeBounds = o->frameSide(trackRect); int offset = row - cell.getFrameId().getNumber(); // rows since start of the clip - int begin = timeBounds.from(); // time axis - int end = timeBounds.to(); - int soundPixel = - begin - m_viewer->rowToFrameAxis(offset); // pixels since start of clip + int begin = timeBounds.from(); // time axis + int end = timeBounds.to(); + int soundPixel = o->rowToFrameAxis(row) - + o->rowToFrameAxis(offset); // pixels since start of clip int trackWidth = trackBounds.length(); int lastMin, lastMax; @@ -1387,9 +1395,10 @@ void CellArea::drawSoundCell(QPainter &p, int row, int col, bool isReference) { bool scrub = m_viewer->isScrubHighlighted(row, col); int i; + int z = 100 / frameZoomF; for (i = begin; i <= end; i++) { soundLevel->getValueAtPixel(o, soundPixel, minmax); - soundPixel++; + soundPixel += z; // ++; int min, max; pmin = minmax.first; pmax = minmax.second; @@ -1411,7 +1420,6 @@ void CellArea::drawSoundCell(QPainter &p, int row, int col, bool isReference) { QLine stroke = o->horizontalLine(i, previewBounds.adjusted(-1, -1)); p.drawLine(stroke); } - if (i != begin) { // "audio track" in the middle of the column p.setPen(m_viewer->getSoundColumnTrackColor()); @@ -1435,6 +1443,7 @@ void CellArea::drawSoundCell(QPainter &p, int row, int col, bool isReference) { if (isFirstRow) { QRect modifierRect = m_viewer->orientation() ->rect(PredefinedRect::BEGIN_SOUND_EDIT) + .adjusted(-frameAdj, 0, -frameAdj, 0) .translated(xy); if (r0 != r0WithoutOff) p.fillRect(modifierRect, SoundColumnExtenderColor); m_soundLevelModifyRects.append(modifierRect); // list of clipping rects @@ -1442,6 +1451,7 @@ void CellArea::drawSoundCell(QPainter &p, int row, int col, bool isReference) { if (isLastRow) { QRect modifierRect = m_viewer->orientation() ->rect(PredefinedRect::END_SOUND_EDIT) + .adjusted(-frameAdj, 0, -frameAdj, 0) .translated(xy); if (r1 != r1WithoutOff) p.fillRect(modifierRect, SoundColumnExtenderColor); m_soundLevelModifyRects.append(modifierRect); @@ -1453,8 +1463,10 @@ void CellArea::drawSoundCell(QPainter &p, int row, int col, bool isReference) { // paint side bar void CellArea::drawDragHandle(QPainter &p, const QPoint &xy, const QColor &sideColor) const { + int frameAdj = m_viewer->getFrameZoomAdjustment(); QRect dragHandleRect = m_viewer->orientation() ->rect(PredefinedRect::DRAG_HANDLE_CORNER) + .adjusted(0, 0, -frameAdj, 0) .translated(xy); p.fillRect(dragHandleRect, QBrush(sideColor)); } @@ -1463,9 +1475,10 @@ void CellArea::drawDragHandle(QPainter &p, const QPoint &xy, void CellArea::drawEndOfDragHandle(QPainter &p, bool isEnd, const QPoint &xy, const QColor &cellColor) const { if (!isEnd) return; + int frameAdj = m_viewer->getFrameZoomAdjustment(); QPainterPath corner = m_viewer->orientation() ->path(PredefinedPath::DRAG_HANDLE_CORNER) - .translated(xy); + .translated(xy - QPoint(frameAdj, 0)); p.fillPath(corner, QBrush(cellColor)); } @@ -1475,16 +1488,20 @@ void CellArea::drawLockedDottedLine(QPainter &p, bool isLocked, const QColor &cellColor) const { if (!isLocked) return; p.setPen(QPen(cellColor, 2, Qt::DotLine)); + int frameAdj = m_viewer->getFrameZoomAdjustment(); QLine dottedLine = m_viewer->orientation()->line(PredefinedLine::LOCKED).translated(xy); + dottedLine.setP2(QPoint(dottedLine.x2() - frameAdj, dottedLine.y2())); p.drawLine(dottedLine); } void CellArea::drawCurrentTimeIndicator(QPainter &p, const QPoint &xy) { + int frameAdj = m_viewer->getFrameZoomAdjustment(); QRect cell = m_viewer->orientation()->rect(PredefinedRect::CELL).translated(xy); + cell.adjust(-frameAdj / 2, 0, -frameAdj / 2, 0); - int cellMid = cell.left() + (cell.width() / 2); + int cellMid = cell.left() + (cell.width() / 2) - 1; int cellTop = cell.top(); int cellBottom = cell.bottom(); @@ -1530,8 +1547,10 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference) { TXshCell nextCell; nextCell = xsh->getCell(row + 1, col); // cell in next frame + int frameAdj = m_viewer->getFrameZoomAdjustment(); QRect cellRect = o->rect(PredefinedRect::CELL).translated(QPoint(x, y)); - QRect rect = cellRect.adjusted(1, 1, 0, 0); + cellRect.adjust(0, 0, -frameAdj, 0); + QRect rect = cellRect.adjusted(1, 1, 0, 0); if (cell.isEmpty()) { // it means previous is not empty // diagonal cross meaning end of level QColor levelEndColor = m_viewer->getTextColor(); @@ -1623,6 +1642,8 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference) { .translated(QPoint(x, y)); } + nameRect.adjust(0, 0, -frameAdj, 0); + // draw text in red if the file does not exist bool isRed = false; TXshSimpleLevel *sl = cell.getSimpleLevel(); @@ -1660,10 +1681,23 @@ void CellArea::drawLevelCell(QPainter &p, int row, int col, bool isReference) { : PredefinedLine::CONTINUE_LEVEL; QLine continueLine = o->line(which).translated(xy); + continueLine.setP2(QPoint(continueLine.x2() - frameAdj, continueLine.y2())); p.drawLine(continueLine); } // draw frame number else { + if (m_viewer->getFrameZoomFactor() <= 50) { + p.setPen(Qt::black); + p.setBrush(isRed ? QColor(230, 100, 100) : m_viewer->getTextColor()); + QRect dotRect = m_viewer->orientation() + ->rect(PredefinedRect::FRAME_DOT) + .translated(QPoint(x, y)); + dotRect.adjust(-frameAdj / 2, 0, -frameAdj / 2, 0); + p.drawEllipse(dotRect); + p.setBrush(Qt::NoBrush); + return; + } + TFrameId fid = cell.m_frameId; // convert the last one digit of the frame number to alphabet @@ -1738,8 +1772,10 @@ void CellArea::drawSoundTextCell(QPainter &p, int row, int col) { TXshCell nextCell; nextCell = xsh->getCell(row + 1, col); + int frameAdj = m_viewer->getFrameZoomAdjustment(); QRect cellRect = o->rect(PredefinedRect::CELL).translated(QPoint(x, y)); - QRect rect = cellRect.adjusted(1, 1, 0, 0); + cellRect.adjust(0, 0, -frameAdj, 0); + QRect rect = cellRect.adjusted(1, 1, 0, 0); if (cell.isEmpty()) { // diagonal cross meaning end of level QColor levelEndColor = m_viewer->getTextColor(); levelEndColor.setAlphaF(0.3); @@ -1795,6 +1831,7 @@ void CellArea::drawSoundTextCell(QPainter &p, int row, int col) { p.setPen(Qt::black); QRect nameRect = o->rect(PredefinedRect::CELL_NAME).translated(QPoint(x, y)); + nameRect.adjust(0, 0, -frameAdj, 0); // il nome va scritto se e' diverso dalla cella precedente oppure se // siamo su una marker line @@ -1819,6 +1856,7 @@ void CellArea::drawSoundTextCell(QPainter &p, int row, int col) { ? PredefinedLine::CONTINUE_LEVEL_WITH_NAME : PredefinedLine::CONTINUE_LEVEL; QLine continueLine = o->line(which).translated(xy); + continueLine.setP2(QPoint(continueLine.x2() - frameAdj, continueLine.y2())); p.drawLine(continueLine); } @@ -1870,8 +1908,11 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col, return; } + + int frameAdj = m_viewer->getFrameZoomAdjustment(); QRect cellRect = o->rect(PredefinedRect::CELL).translated(QPoint(x, y)); - QRect rect = cellRect.adjusted(1, 1, 0, 0); + cellRect.adjust(0, 0, -frameAdj, 0); + QRect rect = cellRect.adjusted(1, 1, 0, 0); if (cell.isEmpty()) { // this means the former is not empty QColor levelEndColor = m_viewer->getTextColor(); levelEndColor.setAlphaF(0.3); @@ -1932,6 +1973,7 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col, QPen oldPen = p.pen(); p.setPen(QPen(m_viewer->getTextColor(), 1)); QLine continueLine = o->line(PredefinedLine::CONTINUE_LEVEL).translated(xy); + continueLine.setP2(QPoint(continueLine.x2() - frameAdj, continueLine.y2())); p.drawLine(continueLine); p.setPen(oldPen); } else { @@ -1953,6 +1995,7 @@ void CellArea::drawPaletteCell(QPainter &p, int row, int col, .translated(QPoint(x, y)); } + nameRect.adjust(0, 0, -frameAdj, 0); bool isRed = false; TXshPaletteLevel *pl = cell.getPaletteLevel(); if (pl && !pl->getPalette()) isRed = true; @@ -2021,7 +2064,9 @@ void CellArea::drawKeyframe(QPainter &p, const QRect toBeUpdated) { static QPixmap selectedKey = svgToPixmap(":Resources/selected_key.svg"); static QPixmap key = svgToPixmap(":Resources/key.svg"); - const QRect &keyRect = o->rect(PredefinedRect::KEY_ICON); + int frameAdj = m_viewer->getFrameZoomAdjustment(); + const QRect &keyRect = o->rect(PredefinedRect::KEY_ICON) + .adjusted(-frameAdj / 2, 0, -frameAdj / 2, 0); TXsheet *xsh = m_viewer->getXsheet(); ColumnFan *columnFan = xsh->getColumnFan(o); @@ -2057,13 +2102,16 @@ void CellArea::drawKeyframe(QPainter &p, const QRect toBeUpdated) { int handleRow0, handleRow1; if (getEaseHandles(segmentRow0, segmentRow1, ease0, ease1, handleRow0, handleRow1)) { + QPoint topLeft = + m_viewer->positionToXY(CellPosition(handleRow0, col)); m_viewer->drawPredefinedPath(p, PredefinedPath::BEGIN_EASE_TRIANGLE, - CellPosition(handleRow0, col), + topLeft + QPoint(-frameAdj / 2, 0), m_viewer->getLightLineColor(), m_viewer->getTextColor()); + topLeft = m_viewer->positionToXY(CellPosition(handleRow1, col)); m_viewer->drawPredefinedPath(p, PredefinedPath::END_EASE_TRIANGLE, - CellPosition(handleRow1, col), + topLeft + QPoint(-frameAdj / 2, 0), m_viewer->getLightLineColor(), m_viewer->getTextColor()); } @@ -2138,8 +2186,10 @@ void CellArea::drawKeyframe(QPainter &p, const QRect toBeUpdated) { void CellArea::drawKeyframeLine(QPainter &p, int col, const NumberRange &rows) const { - const QRect &keyRect = - m_viewer->orientation()->rect(PredefinedRect::KEY_ICON); + int frameAdj = m_viewer->getFrameZoomAdjustment(); + const QRect &keyRect = m_viewer->orientation() + ->rect(PredefinedRect::KEY_ICON) + .adjusted(-frameAdj / 2, 0, -frameAdj / 2, 0); QPoint begin = keyRect.center() + m_viewer->positionToXY(CellPosition(rows.from(), col)); QPoint end = @@ -2247,13 +2297,14 @@ void CellArea::paintEvent(QPaintEvent *event) { if (getDragTool()) getDragTool()->drawCellsArea(p); // focus cell border - int row = m_viewer->getCurrentRow(); - int col = m_viewer->getCurrentColumn(); - QPoint xy = m_viewer->positionToXY(CellPosition(row, col)); - QRect rect = m_viewer->orientation() + int frameAdj = m_viewer->getFrameZoomAdjustment(); + int row = m_viewer->getCurrentRow(); + int col = m_viewer->getCurrentColumn(); + QPoint xy = m_viewer->positionToXY(CellPosition(row, col)); + QRect rect = m_viewer->orientation() ->rect(PredefinedRect::CELL) .translated(xy) - .adjusted(1, 1, -1, -1); + .adjusted(1, 1, -1 - frameAdj, -1); p.setPen(Qt::black); p.setBrush(Qt::NoBrush); p.drawRect(rect); @@ -2290,6 +2341,7 @@ void CellArea::mousePressEvent(QMouseEvent *event) { m_viewer->setQtModifiers(event->modifiers()); assert(!m_isPanning); m_isMousePressed = true; + int frameAdj = m_viewer->getFrameZoomAdjustment(); if (event->button() == Qt::LeftButton) { assert(getDragTool() == 0); @@ -2353,10 +2405,12 @@ void CellArea::mousePressEvent(QMouseEvent *event) { bool isKeyframeFrame = pegbar && pegbar->getKeyframeRange(k0, k1) && (k1 > k0 || k0 == row) && k0 <= row && row <= k1 + 1; - bool isKeyFrameArea = - isKeyframeFrame && - o->rect(PredefinedRect::KEYFRAME_AREA).contains(mouseInCell) && - row < k1 + 1; + + bool isKeyFrameArea = isKeyframeFrame && + o->rect(PredefinedRect::KEYFRAME_AREA) + .adjusted(-frameAdj / 2, 0, -frameAdj / 2, 0) + .contains(mouseInCell) && + row < k1 + 1; bool accept = false; if (isKeyFrameArea) { // They are in the keyframe selection @@ -2455,6 +2509,7 @@ void CellArea::mousePressEvent(QMouseEvent *event) { void CellArea::mouseMoveEvent(QMouseEvent *event) { const Orientation *o = m_viewer->orientation(); + int frameAdj = m_viewer->getFrameZoomAdjustment(); m_viewer->setQtModifiers(event->modifiers()); setCursor(Qt::ArrowCursor); @@ -2538,8 +2593,8 @@ void CellArea::mouseMoveEvent(QMouseEvent *event) { ->getZeraryColumnFx() ->getZeraryFx() ->getName()); - else if ((!xsh->getCell(row, col).isEmpty() && !isSoundColumn) && x > 6 && - x < o->cellWidth()) { + else if ((!xsh->getCell(row, col).isEmpty() && !isSoundColumn) && // x > 6 && + x < (o->cellWidth() - frameAdj)) { TXshCell cell = xsh->getCell(row, col); TFrameId fid = cell.getFrameId(); std::wstring levelName = cell.m_level->getName(); diff --git a/toonz/sources/toonz/xsheetviewer.cpp b/toonz/sources/toonz/xsheetviewer.cpp index df49b3f..ba18fb7 100644 --- a/toonz/sources/toonz/xsheetviewer.cpp +++ b/toonz/sources/toonz/xsheetviewer.cpp @@ -48,11 +48,11 @@ TEnv::IntVar FrameDisplayStyleInXsheetRowArea( namespace XsheetGUI { //----------------------------------------------------------------------------- -const int ColumnWidth = 74; -const int RowHeight = 20; -const int SCROLLBAR_WIDTH = 16; -const int TOOLBAR_HEIGHT = 30; - +const int ColumnWidth = 74; +const int RowHeight = 20; +const int SCROLLBAR_WIDTH = 16; +const int TOOLBAR_HEIGHT = 30; +const int ZOOM_SLIDER_WIDTH = 80; } // namespace XsheetGUI //============================================================================= @@ -217,7 +217,8 @@ XsheetViewer::XsheetViewer(QWidget *parent, Qt::WFlags flags) , m_qtModifiers(0) , m_frameDisplayStyle(to_enum(FrameDisplayStyleInXsheetRowArea)) , m_orientation(nullptr) - , m_xsheetLayout("Classic") { + , m_xsheetLayout("Classic") + , m_frameZoomFactor(100) { m_xsheetLayout = Preferences::instance()->getLoadedXsheetLayout(); @@ -269,6 +270,14 @@ XsheetViewer::XsheetViewer(QWidget *parent, Qt::WFlags flags) m_frameScroller.setFrameScrollArea(m_cellScrollArea); connect(&m_frameScroller, &Spreadsheet::FrameScroller::prepareToScrollOffset, this, &XsheetViewer::onPrepareToScrollOffset); + connect(&m_frameScroller, &Spreadsheet::FrameScroller::zoomScrollAdjust, this, + &XsheetViewer::onZoomScrollAdjust); + + m_frameZoomSlider = new QSlider(Qt::Horizontal, this); + m_frameZoomSlider->setMinimum(20); + m_frameZoomSlider->setMaximum(100); + m_frameZoomSlider->setValue(m_frameZoomFactor); + m_frameZoomSlider->setToolTip(tr("Zoom in/out of timeline")); connectScrollBars(); @@ -277,6 +286,11 @@ XsheetViewer::XsheetViewer(QWidget *parent, Qt::WFlags flags) connect(m_toolbar, SIGNAL(updateVisibility()), this, SLOT(positionSections())); + connect(m_frameZoomSlider, SIGNAL(sliderReleased()), this, + SLOT(onFrameZoomSliderReleased())); + connect(m_frameZoomSlider, SIGNAL(valueChanged(int)), this, + SLOT(onFrameZoomSliderValueChanged(int))); + emit orientationChanged(orientation()); } @@ -397,6 +411,18 @@ void XsheetViewer::positionSections() { bodyLayer.adjusted(0, -XsheetGUI::SCROLLBAR_WIDTH))); m_rowScrollArea->setGeometry(o->frameLayerRect( bodyFrame.adjusted(0, -XsheetGUI::SCROLLBAR_WIDTH), headerLayer)); + if (o->isVerticalTimeline()) + m_frameZoomSlider->hide(); + else { + if (m_frameZoomSlider->isHidden()) m_frameZoomSlider->show(); + QRect sliderRect = + QRect(0, 0, XsheetGUI::ZOOM_SLIDER_WIDTH, + XsheetGUI::SCROLLBAR_WIDTH - 2) + .translated(m_columnScrollArea->rect().right() - + XsheetGUI::ZOOM_SLIDER_WIDTH - 17, + height() - XsheetGUI::SCROLLBAR_WIDTH + 1); + m_frameZoomSlider->setGeometry(sliderRect); + } } void XsheetViewer::disconnectScrollBars() { @@ -540,6 +566,12 @@ void XsheetViewer::scroll(QPoint delta) { else if (!notUpdateSizeH && notUpdateSizeV) // Resize orizzontale refreshContentSize(x, 0); + // Recheck in case refreshContentSize changed the max + if (!notUpdateSizeH) + maxValueH = m_cellScrollArea->horizontalScrollBar()->maximum(); + if (!notUpdateSizeV) + maxValueV = m_cellScrollArea->verticalScrollBar()->maximum(); + if (valueH > maxValueH && x > 0) // Se il valore e' maggiore del max e x>0 // scrollo al massimo valore orizzontale valueH = m_cellScrollArea->horizontalScrollBar()->maximum(); @@ -560,6 +592,22 @@ void XsheetViewer::onPrepareToScrollOffset(const QPoint &offset) { //----------------------------------------------------------------------------- +void XsheetViewer::onZoomScrollAdjust(QPoint &offset, bool toZoom) { + int frameZoomFactor = getFrameZoomFactor(); + + // toZoom = true: Adjust standardized offset down to zoom factor + // toZoom = false: Adjust zoomed offset up to standardized offset + int newX; + if (toZoom) + newX = (offset.x() * frameZoomFactor) / 100; + else + newX = (offset.x() * 100) / frameZoomFactor; + + offset.setX(newX); +} + +//----------------------------------------------------------------------------- + void XsheetViewer::setAutoPanSpeed(const QPoint &speed) { bool wasAutoPanning = isAutoPanning(); m_autoPanSpeed = speed; @@ -679,7 +727,10 @@ void XsheetViewer::updateAreeSize() { CellPosition XsheetViewer::xyToPosition(const QPoint &point) const { const Orientation *o = orientation(); - return o->xyToPosition(point, getXsheet()->getColumnFan(o)); + QPoint usePoint = point; + if (!o->isVerticalTimeline()) + usePoint.setX((usePoint.x() * 100) / getFrameZoomFactor()); + return o->xyToPosition(usePoint, getXsheet()->getColumnFan(o)); } CellPosition XsheetViewer::xyToPosition(const TPoint &point) const { return xyToPosition(QPoint(point.x, point.y)); @@ -692,7 +743,10 @@ CellPosition XsheetViewer::xyToPosition(const TPointD &point) const { QPoint XsheetViewer::positionToXY(const CellPosition &pos) const { const Orientation *o = orientation(); - return o->positionToXY(pos, getXsheet()->getColumnFan(o)); + QPoint result = o->positionToXY(pos, getXsheet()->getColumnFan(o)); + if (!o->isVerticalTimeline()) + result.setX((result.x() * getFrameZoomFactor()) / 100); + return result; } int XsheetViewer::columnToLayerAxis(int layer) const { @@ -700,7 +754,10 @@ int XsheetViewer::columnToLayerAxis(int layer) const { return o->colToLayerAxis(layer, getXsheet()->getColumnFan(o)); } int XsheetViewer::rowToFrameAxis(int frame) const { - return orientation()->rowToFrameAxis(frame); + int result = orientation()->rowToFrameAxis(frame); + if (!orientation()->isVerticalTimeline()) + result = (result * getFrameZoomFactor()) / 100; + return result; } //----------------------------------------------------------------------------- @@ -738,6 +795,19 @@ void XsheetViewer::drawPredefinedPath(QPainter &p, PredefinedPath which, //----------------------------------------------------------------------------- +void XsheetViewer::drawPredefinedPath(QPainter &p, PredefinedPath which, + QPoint xy, optional fill, + optional outline) const { + QPainterPath path = orientation()->path(which).translated(xy); + if (fill) p.fillPath(path, QBrush(*fill)); + if (outline) { + p.setPen(*outline); + p.drawPath(path); + } +} + +//----------------------------------------------------------------------------- + bool XsheetViewer::areCellsSelectedEmpty() { int r0, c0, r1, c1; getCellSelection()->getSelectedCells(r0, c0, r1, c1); @@ -918,12 +988,20 @@ void XsheetViewer::hideEvent(QHideEvent *) { //----------------------------------------------------------------------------- -/* -void XsheetViewer::paintEvent(QPaintEvent*) -{ +void XsheetViewer::paintEvent(QPaintEvent *) { QPainter p(this); - //p.fillRect(visibleRegion().boundingRect().adjusted(1,1,-1,-1),QBrush(grey150)); -}*/ + + static QPixmap zoomIn = svgToPixmap(":Resources/zoom_in.svg"); + const QRect zoomInRect = QRect(m_frameZoomSlider->geometry().right() + 2, + m_frameZoomSlider->geometry().top(), 14, 14); + static QPixmap zoomOut = svgToPixmap(":Resources/zoom_out.svg"); + const QRect zoomOutRect = QRect(m_frameZoomSlider->geometry().left() - 16, + m_frameZoomSlider->geometry().top(), 14, 14); + + p.setRenderHint(QPainter::SmoothPixmapTransform, true); + p.drawPixmap(zoomInRect, zoomIn); + p.drawPixmap(zoomOutRect, zoomOut); +} //----------------------------------------------------------------------------- @@ -942,6 +1020,25 @@ void XsheetViewer::resizeEvent(QResizeEvent *event) { void XsheetViewer::wheelEvent(QWheelEvent *event) { switch (event->source()) { case Qt::MouseEventNotSynthesized: { + if (0 != (event->modifiers() & Qt::ControlModifier) && + event->angleDelta().y() != 0) { + QPoint pos(event->pos().x() - m_columnArea->geometry().width() + + m_cellArea->visibleRegion().boundingRect().left(), + event->pos().y()); + int targetFrame = xyToPosition(pos).frame(); + + int newFactor = + getFrameZoomFactor() + ((event->angleDelta().y() > 0 ? 1 : -1) * 10); + if (newFactor > m_frameZoomSlider->maximum()) + newFactor = m_frameZoomSlider->maximum(); + else if (newFactor < m_frameZoomSlider->minimum()) + newFactor = m_frameZoomSlider->minimum(); + + zoomOnFrame(targetFrame, newFactor); + event->accept(); + return; + } + int markerDistance = 6, markerOffset = 0; TApp::instance() ->getCurrentScene() @@ -1512,13 +1609,20 @@ void XsheetViewer::setFrameDisplayStyle(FrameDisplayStyle style) { void XsheetViewer::save(QSettings &settings) const { settings.setValue("orientation", orientation()->name()); + settings.setValue("frameZoomFactor", m_frameZoomFactor); } void XsheetViewer::load(QSettings &settings) { - QVariant name = settings.value("orientation"); - if (!name.canConvert(QVariant::String)) return; + QVariant zoomFactor = settings.value("frameZoomFactor"); + QVariant name = settings.value("orientation"); - m_orientation = Orientations::byName(name.toString()); - emit orientationChanged(orientation()); + if (zoomFactor.canConvert(QVariant::Int)) { + m_frameZoomSlider->setValue(zoomFactor.toInt()); + } + + if (name.canConvert(QVariant::String)) { + m_orientation = Orientations::byName(name.toString()); + emit orientationChanged(orientation()); + } } //----------------------------------------------------------------------------- @@ -1532,6 +1636,49 @@ TPanel *createXsheetViewer(QWidget *parent) } */ +//---------------------------------------------------------------- +int XsheetViewer::getFrameZoomFactor() const { + if (orientation()->isVerticalTimeline()) return 100; + + return m_frameZoomFactor; +} + +int XsheetViewer::getFrameZoomAdjustment() { + if (orientation()->isVerticalTimeline()) return 0; + + QRect frameRect = orientation()->rect(PredefinedRect::FRAME_HEADER); + int adj = frameRect.width() - + ((frameRect.width() * getFrameZoomFactor()) / 100) - 1; + + return qMax(0, adj); +} + +void XsheetViewer::zoomOnFrame(int frame, int factor) { + QPoint xyOrig = positionToXY(CellPosition(frame, 0)); + + m_frameZoomFactor = factor; + m_frameZoomSlider->blockSignals(true); + m_frameZoomSlider->setValue(factor); + m_frameZoomSlider->blockSignals(false); + + QPoint xyNew = positionToXY(CellPosition(frame, 0)); + + int viewShift = xyNew.x() - xyOrig.x(); + + scroll(QPoint(viewShift, 0)); + + onFrameZoomSliderReleased(); +} + +void XsheetViewer::onFrameZoomSliderValueChanged(int val) { + zoomOnFrame(getCurrentRow(), val); +} + +void XsheetViewer::onFrameZoomSliderReleased() { + TApp::instance()->getCurrentXsheet()->notifyXsheetChanged(); + m_rowArea->update(); +} + //============================================================================= // XSheetViewerCommand //----------------------------------------------------------------------------- diff --git a/toonz/sources/toonz/xsheetviewer.h b/toonz/sources/toonz/xsheetviewer.h index 4cd2852..65cff19 100644 --- a/toonz/sources/toonz/xsheetviewer.h +++ b/toonz/sources/toonz/xsheetviewer.h @@ -525,6 +525,9 @@ class XsheetViewer final : public QFrame, public SaveLoadQSettings { QString m_xsheetLayout; + int m_frameZoomFactor; + QSlider *m_frameZoomSlider; + public: enum FrameDisplayStyle { Frame = 0, SecAndFrame, SixSecSheet, ThreeSecSheet }; @@ -624,6 +627,11 @@ public: void drawPredefinedPath(QPainter &p, PredefinedPath which, const CellPosition &pos, optional fill, optional outline) const; + + void drawPredefinedPath(QPainter &p, PredefinedPath which, QPoint xy, + optional fill, + optional outline) const; + //--------- void updateCells() { m_cellArea->update(m_cellArea->visibleRegion()); } @@ -1085,6 +1093,8 @@ protected: void scrollToRow(int row); void scrollToVerticalRange(int y0, int y1); + void paintEvent(QPaintEvent *) override; + void showEvent(QShowEvent *) override; void hideEvent(QHideEvent *) override; void resizeEvent(QResizeEvent *event) override; @@ -1128,6 +1138,16 @@ public slots: void onOrientationChanged(const Orientation *newOrientation); void onPrepareToScrollOffset(const QPoint &offset); + void onZoomScrollAdjust(QPoint &offset, bool toZoom); + + void setFrameZoomFactor(int f) { m_frameZoomFactor = f; } + int getFrameZoomFactor() const; + int getFrameZoomAdjustment(); + + void zoomOnFrame(int frame, int factor); + + void onFrameZoomSliderValueChanged(int val); + void onFrameZoomSliderReleased(); }; #endif // XSHEETVIEWER_H diff --git a/toonz/sources/toonz/xshrowviewer.cpp b/toonz/sources/toonz/xshrowviewer.cpp index 14ac76e..73c9e95 100644 --- a/toonz/sources/toonz/xshrowviewer.cpp +++ b/toonz/sources/toonz/xshrowviewer.cpp @@ -78,6 +78,7 @@ void RowArea::setDragTool(DragTool *dragTool) { //----------------------------------------------------------------------------- void RowArea::drawRows(QPainter &p, int r0, int r1) { + const Orientation *o = m_viewer->orientation(); int playR0, playR1, step; XsheetGUI::getPlayRange(playR0, playR1, step); @@ -115,7 +116,9 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { int x1 = visibleRect.right(); int y0 = visibleRect.top(); int y1 = visibleRect.bottom(); - NumberRange layerSide = m_viewer->orientation()->layerSide(visibleRect); + NumberRange layerSide = o->layerSide(visibleRect); + + int frameAdj = m_viewer->getFrameZoomAdjustment(); for (int r = r0; r <= r1; r++) { int frameAxis = m_viewer->rowToFrameAxis(r); @@ -125,10 +128,29 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { ? m_viewer->getMarkerLineColor() : m_viewer->getLightLineColor(); p.setPen(color); - QLine horizontalLine = - m_viewer->orientation()->horizontalLine(frameAxis, layerSide); + QLine horizontalLine = o->horizontalLine(frameAxis, layerSide); p.drawLine(horizontalLine); + if (!o->isVerticalTimeline() && m_viewer->getFrameZoomFactor() <= 50) { + QPoint basePoint = m_viewer->positionToXY(CellPosition(r, 0)); + QRect indRect = + o->rect(PredefinedRect::FRAME_INDICATOR).translated(basePoint); + indRect.adjust(-frameAdj / 2, 0, -frameAdj / 2, 0); + QColor useColor; + if (playR0 <= r && r <= playR1) { + useColor = ((r - m_r0) % step == 0) + ? m_viewer->getPreviewFrameTextColor() + : m_viewer->getTextColor(); + } + // not in preview range + else + useColor = m_viewer->getTextColor(); + p.fillRect(indRect, useColor); + } + } + + int z = 0; + for (int r = r0; r <= r1; r++) { // draw frame text if (playR0 <= r && r <= playR1) { p.setPen(((r - m_r0) % step == 0) ? m_viewer->getPreviewFrameTextColor() @@ -139,12 +161,13 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { p.setPen(m_viewer->getTextColor()); QPoint basePoint = m_viewer->positionToXY(CellPosition(r, 0)); - QRect labelRect = m_viewer->orientation() - ->rect(PredefinedRect::FRAME_LABEL) - .translated(basePoint); - int align = m_viewer->orientation()->dimension( - PredefinedDimension::FRAME_LABEL_ALIGN); + QRect labelRect = + o->rect(PredefinedRect::FRAME_LABEL).translated(basePoint); + labelRect.adjust(-frameAdj / 2, 0, -frameAdj / 2, 0); + + int align = o->dimension(PredefinedDimension::FRAME_LABEL_ALIGN); // display time and/or frame number + z++; switch (m_viewer->getFrameDisplayStyle()) { case XsheetViewer::SecAndFrame: { int frameRate = TApp::instance() @@ -153,6 +176,8 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { ->getProperties() ->getOutputProperties() ->getFrameRate(); + int zz = frameRate / 5; + zz = frameRate / zz; QString str; int koma = (r + 1) % frameRate; if (koma == 1) { @@ -160,7 +185,12 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { str = QString("%1' %2\"") .arg(QString::number(sec).rightJustified(2, '0')) .arg(QString::number(koma).rightJustified(2, '0')); + z = 0; } else { + if (!o->isVerticalTimeline() && m_viewer->getFrameZoomFactor() <= 50) { + if ((z + 1) % zz) break; + if (r % frameRate == 1 || (r + 2) % frameRate == 1) break; + } if (koma == 0) koma = frameRate; str = QString("%1\"").arg(QString::number(koma).rightJustified(2, '0')); } @@ -171,6 +201,9 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { } case XsheetViewer::Frame: { + if (!o->isVerticalTimeline() && m_viewer->getFrameZoomFactor() <= 50 && + r > 0 && (r + 1) % 5) + break; QString number = QString::number(r + 1); p.drawText(labelRect, align, number); break; @@ -184,6 +217,8 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { ->getProperties() ->getOutputProperties() ->getFrameRate(); + int zz = frameRate / 5; + zz = frameRate / zz; QString str; int koma = (r + 1) % (frameRate * 6); if ((r + 1) % frameRate == 1) { @@ -191,7 +226,12 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { str = QString("p%1 %2") .arg(QString::number(page)) .arg(QString::number(koma).rightJustified(3, '0')); + z = 0; } else { + if (!o->isVerticalTimeline() && m_viewer->getFrameZoomFactor() <= 50) { + if ((z + 1) % zz) break; + if (r % frameRate == 1 || (r + 2) % frameRate == 1) break; + } if (koma == 0) koma = frameRate * 6; str = QString("%1").arg(QString::number(koma).rightJustified(3, '0')); } @@ -206,6 +246,8 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { ->getProperties() ->getOutputProperties() ->getFrameRate(); + int zz = frameRate / 5; + zz = frameRate / zz; QString str; int koma = (r + 1) % (frameRate * 3); if ((r + 1) % frameRate == 1) { @@ -213,7 +255,12 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { str = QString("p%1 %2") .arg(QString::number(page)) .arg(QString::number(koma).rightJustified(2, '0')); + z = 0; } else { + if (!o->isVerticalTimeline() && m_viewer->getFrameZoomFactor() <= 50) { + if ((z + 1) % zz) break; + if (r % frameRate == 1 || (r + 2) % frameRate == 1) break; + } if (koma == 0) koma = frameRate * 3; str = QString("%1").arg(QString::number(koma).rightJustified(2, '0')); } @@ -228,6 +275,7 @@ void RowArea::drawRows(QPainter &p, int r0, int r1) { void RowArea::drawPlayRange(QPainter &p, int r0, int r1) { bool playRangeEnabled = XsheetGUI::isPlayRangeEnabled(); + int frameAdj = m_viewer->getFrameZoomAdjustment(); // Update the play range internal fields if (playRangeEnabled) { @@ -246,15 +294,18 @@ void RowArea::drawPlayRange(QPainter &p, int r0, int r1) { QColor ArrowColor = (playRangeEnabled) ? QColor(255, 255, 255) : grey150; p.setBrush(QBrush(ArrowColor)); - if (m_r0 > r0 - 1 && r1 + 1 > m_r0) - m_viewer->drawPredefinedPath(p, PredefinedPath::BEGIN_PLAY_RANGE, - CellPosition(m_r0, 0), ArrowColor, - QColor(Qt::black)); + if (m_r0 > r0 - 1 && r1 + 1 > m_r0) { + QPoint topLeft = m_viewer->positionToXY(CellPosition(m_r0, 0)); + m_viewer->drawPredefinedPath(p, PredefinedPath::BEGIN_PLAY_RANGE, topLeft, + ArrowColor, QColor(Qt::black)); + } - if (m_r1 > r0 - 1 && r1 + 1 > m_r1) - m_viewer->drawPredefinedPath(p, PredefinedPath::END_PLAY_RANGE, - CellPosition(m_r1, 0), ArrowColor, - QColor(Qt::black)); + if (m_r1 > r0 - 1 && r1 + 1 > m_r1) { + QPoint topLeft = m_viewer->positionToXY(CellPosition(m_r1, 0)); + topLeft.setX(topLeft.x() - frameAdj); + m_viewer->drawPredefinedPath(p, PredefinedPath::END_PLAY_RANGE, topLeft, + ArrowColor, QColor(Qt::black)); + } } //----------------------------------------------------------------------------- @@ -266,8 +317,9 @@ void RowArea::drawCurrentRowGadget(QPainter &p, int r0, int r1) { QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow, 0)); QRect header = m_viewer->orientation() ->rect(PredefinedRect::FRAME_HEADER) - .translated(topLeft) - .adjusted(1, 1, 0, 0); + .translated(topLeft); + int frameAdj = m_viewer->getFrameZoomAdjustment(); + header.adjust(1, 1, -frameAdj, 0); p.fillRect(header, m_viewer->getCurrentRowBgColor()); } @@ -281,6 +333,8 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { assert(xsh); int currentRow = m_viewer->getCurrentRow(); + int frameAdj = m_viewer->getFrameZoomAdjustment(); + // get onion colors TPixel frontPixel, backPixel; bool inksOnly; @@ -319,10 +373,11 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { p.setBrush(Qt::NoBrush); if (minMos < 0) // previous frames { - int layerAxis = onionCenter_layer; - int fromFrameAxis = - m_viewer->rowToFrameAxis(currentRow + minMos) + onionCenter_frame; - int toFrameAxis = m_viewer->rowToFrameAxis(currentRow) + onionCenter_frame; + int layerAxis = onionCenter_layer; + int fromFrameAxis = m_viewer->rowToFrameAxis(currentRow + minMos) + + onionCenter_frame - (frameAdj / 2); + int toFrameAxis = m_viewer->rowToFrameAxis(currentRow) + onionCenter_frame - + (frameAdj / 2); QLine verticalLine = m_viewer->orientation()->verticalLine( layerAxis, NumberRange(fromFrameAxis, toFrameAxis)); if (m_viewer->orientation()->isVerticalTimeline()) @@ -334,11 +389,11 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { } if (maxMos > 0) // forward frames { - int layerAxis = onionCenter_layer; - int fromFrameAxis = - m_viewer->rowToFrameAxis(currentRow) + onionCenter_frame; - int toFrameAxis = - m_viewer->rowToFrameAxis(currentRow + maxMos) + onionCenter_frame; + int layerAxis = onionCenter_layer; + int fromFrameAxis = m_viewer->rowToFrameAxis(currentRow) + + onionCenter_frame - (frameAdj / 2); + int toFrameAxis = m_viewer->rowToFrameAxis(currentRow + maxMos) + + onionCenter_frame - (frameAdj / 2); QLine verticalLine = m_viewer->orientation()->verticalLine( layerAxis, NumberRange(fromFrameAxis, toFrameAxis)); if (m_viewer->orientation()->isVerticalTimeline()) @@ -351,7 +406,8 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { // Draw onion skin main handle QPoint handleTopLeft = m_viewer->positionToXY(CellPosition(currentRow, 0)); QRect handleRect = onionRect.translated(handleTopLeft); - int angle180 = 16 * 180; + handleRect.adjust(-frameAdj / 2, 0, -frameAdj / 2, 0); + int angle180 = 16 * 180; int turn = m_viewer->orientation()->dimension(PredefinedDimension::ONION_TURN) * 16; p.setBrush(QBrush(backColor)); @@ -375,6 +431,7 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { QRect dotRect = m_viewer->orientation() ->rect(PredefinedRect::ONION_DOT) .translated(topLeft); + dotRect.adjust(-frameAdj / 2, 0, -frameAdj / 2, 0); p.drawEllipse(dotRect); } @@ -393,6 +450,7 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { QRect dotRect = m_viewer->orientation() ->rect(PredefinedRect::ONION_DOT_FIXED) .translated(topLeft); + dotRect.adjust(-frameAdj / 2, 0, -frameAdj / 2, 0); p.drawEllipse(dotRect); } @@ -406,6 +464,7 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { ->rect(m_showOnionToSet == Fos ? PredefinedRect::ONION_DOT_FIXED : PredefinedRect::ONION_DOT) .translated(topLeft); + dotRect.adjust(-frameAdj / 2, 0, -frameAdj / 2, 0); p.drawEllipse(dotRect); } } @@ -413,14 +472,16 @@ void RowArea::drawOnionSkinSelection(QPainter &p) { //----------------------------------------------------------------------------- void RowArea::drawCurrentTimeIndicator(QPainter &p) { + int frameAdj = m_viewer->getFrameZoomAdjustment(); int currentRow = m_viewer->getCurrentRow(); QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow, 0)); QRect header = m_viewer->orientation() ->rect(PredefinedRect::FRAME_HEADER) + .adjusted(-frameAdj / 2, 0, -frameAdj / 2, 0) .translated(topLeft); - int frameMid = header.left() + (header.width() / 2); + int frameMid = header.left() + (header.width() / 2) - 1; int frameTop = header.top() + 22; QPainterPath markerHead = m_viewer->orientation() @@ -434,14 +495,16 @@ void RowArea::drawCurrentTimeIndicator(QPainter &p) { } void RowArea::drawCurrentTimeLine(QPainter &p) { + int frameAdj = m_viewer->getFrameZoomAdjustment(); int currentRow = m_viewer->getCurrentRow(); QPoint topLeft = m_viewer->positionToXY(CellPosition(currentRow, 0)); QRect header = m_viewer->orientation() ->rect(PredefinedRect::FRAME_HEADER) + .adjusted(-frameAdj / 2, 0, -frameAdj / 2, 0) .translated(topLeft); - int frameMid = header.left() + (header.width() / 2); + int frameMid = header.left() + (header.width() / 2) - 1; int frameTop = header.top(); int frameBottom = header.bottom(); @@ -489,9 +552,11 @@ void RowArea::drawPinnedCenterKeys(QPainter &p, int r0, int r1) { int columnCount = xsh->getColumnCount(); int prev_pinnedCol = -2; + int frameAdj = m_viewer->getFrameZoomAdjustment(); - QRect keyRect = - m_viewer->orientation()->rect(PredefinedRect::PINNED_CENTER_KEY); + QRect keyRect = m_viewer->orientation() + ->rect(PredefinedRect::PINNED_CENTER_KEY) + .adjusted(-frameAdj / 2, 0, -frameAdj / 2, 0); p.setPen(Qt::black); r1 = (r1 < xsh->getFrameCount() - 1) ? xsh->getFrameCount() - 1 : r1; @@ -549,6 +614,8 @@ void RowArea::paintEvent(QPaintEvent *event) { // current frame drawCurrentRowGadget(p, r0, r1); + drawRows(p, r0, r1); + if (TApp::instance()->getCurrentFrame()->isEditingScene()) { if (Preferences::instance()->isOnionSkinEnabled()) drawOnionSkinSelection(p); @@ -561,7 +628,7 @@ void RowArea::paintEvent(QPaintEvent *event) { drawCurrentTimeLine(p); } - drawRows(p, r0, r1); + // drawRows(p, r0, r1); if (TApp::instance()->getCurrentTool()->getTool()->getName() == T_Skeleton) drawPinnedCenterKeys(p, r0, r1); @@ -592,18 +659,24 @@ void RowArea::mousePressEvent(QMouseEvent *event) { int row = m_viewer->xyToPosition(pos).frame(); QPoint topLeft = m_viewer->positionToXY(CellPosition(row, 0)); QPoint mouseInCell = event->pos() - topLeft; + int frameAdj = m_viewer->getFrameZoomAdjustment(); if (Preferences::instance()->isOnionSkinEnabled() && - o->rect(PredefinedRect::ONION_AREA).contains(mouseInCell)) { + o->rect(PredefinedRect::ONION_AREA) + .adjusted(0, 0, -frameAdj, 0) + .contains(mouseInCell)) { if (row == currentFrame) { setDragTool( XsheetGUI::DragTool::makeCurrentFrameModifierTool(m_viewer)); frameAreaIsClicked = true; } else if (o->rect(PredefinedRect::ONION_FIXED_DOT_AREA) + .adjusted(0, 0, -frameAdj, 0) .contains(mouseInCell)) setDragTool(XsheetGUI::DragTool::makeKeyOnionSkinMaskModifierTool( m_viewer, true)); - else if (o->rect(PredefinedRect::ONION_DOT_AREA).contains(mouseInCell)) + else if (o->rect(PredefinedRect::ONION_DOT_AREA) + .adjusted(0, 0, -frameAdj, 0) + .contains(mouseInCell)) setDragTool(XsheetGUI::DragTool::makeKeyOnionSkinMaskModifierTool( m_viewer, false)); else { @@ -626,7 +699,9 @@ void RowArea::mousePressEvent(QMouseEvent *event) { setDragTool( XsheetGUI::DragTool::makeCurrentFrameModifierTool(m_viewer)); frameAreaIsClicked = true; - } else if (o->rect(PredefinedRect::PLAY_RANGE).contains(mouseInCell) && + } else if (o->rect(PredefinedRect::PLAY_RANGE) + .adjusted(0, 0, -frameAdj, 0) + .contains(mouseInCell) && (row == playR0 || row == playR1)) { if (!playRangeEnabled) XsheetGUI::setPlayRange(playR0, playR1, step); setDragTool(XsheetGUI::DragTool::makePlayRangeModifierTool(m_viewer)); @@ -655,7 +730,7 @@ void RowArea::mousePressEvent(QMouseEvent *event) { m_viewer->dragToolClick(event); event->accept(); } // left-click - // pan by middle-drag + // pan by middle-drag else if (event->button() == Qt::MidButton) { m_pos = event->pos(); m_isPanning = true; @@ -703,14 +778,19 @@ 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 mouseInCell = event->pos() - m_viewer->positionToXY(CellPosition(row, 0)); if (row < 0) return; // whether to show ability to set onion marks if (Preferences::instance()->isOnionSkinEnabled() && row != currentRow) { - if (o->rect(PredefinedRect::ONION_FIXED_DOT_AREA).contains(mouseInCell)) + if (o->rect(PredefinedRect::ONION_FIXED_DOT_AREA) + .adjusted(0, 0, -frameAdj, 0) + .contains(mouseInCell)) m_showOnionToSet = Fos; - else if (o->rect(PredefinedRect::ONION_DOT_AREA).contains(mouseInCell)) + else if (o->rect(PredefinedRect::ONION_DOT_AREA) + .adjusted(0, 0, -frameAdj, 0) + .contains(mouseInCell)) m_showOnionToSet = Mos; } @@ -719,7 +799,9 @@ void RowArea::mouseMoveEvent(QMouseEvent *event) { bool isRootBonePinned; int pinnedCenterColumnId = -1; if (TApp::instance()->getCurrentTool()->getTool()->getName() == T_Skeleton && - o->rect(PredefinedRect::PINNED_CENTER_KEY).contains(mouseInCell)) { + o->rect(PredefinedRect::PINNED_CENTER_KEY) + .adjusted(-frameAdj, 0, -frameAdj, 0) + .contains(mouseInCell)) { int col = m_viewer->getCurrentColumn(); TXsheet *xsh = m_viewer->getXsheet(); if (col >= 0 && xsh && !xsh->isColumnEmpty(col)) { diff --git a/toonz/sources/toonzlib/orientation.cpp b/toonz/sources/toonzlib/orientation.cpp index 4db5531..0e9b386 100644 --- a/toonz/sources/toonzlib/orientation.cpp +++ b/toonz/sources/toonzlib/orientation.cpp @@ -17,6 +17,8 @@ const int PLAY_MARKER_SIZE = 10; const int ONION_SIZE = 19; const int ONION_DOT_SIZE = 8; const int PINNED_SIZE = 10; +const int FRAME_DOT_SIZE = 8; +const int FRAME_IND_SIZE = 3; } class TopToBottomOrientation : public Orientation { @@ -81,7 +83,7 @@ class LeftToRightOrientation : public Orientation { const int EXTENDER_HEIGHT = 12; const int SOUND_PREVIEW_HEIGHT = 6; const int FRAME_HEADER_HEIGHT = 50; - const int ONION_X = (CELL_WIDTH - ONION_SIZE) / 2, ONION_Y = 0; + const int ONION_X = 0, ONION_Y = 0; const int PLAY_RANGE_Y = ONION_SIZE; const int ICON_WIDTH = 20; const int ICON_HEIGHT = 20; @@ -300,6 +302,7 @@ TopToBottomOrientation::TopToBottomOrientation() { PredefinedRect::END_SOUND_EDIT, QRect(CELL_DRAG_WIDTH, CELL_HEIGHT - 2, CELL_WIDTH - CELL_DRAG_WIDTH, 2)); addRect(PredefinedRect::LOOP_ICON, QRect(keyRect.left(), 0, 10, 11)); + addRect(PredefinedRect::FRAME_DOT, QRect(0, 0, -1, -1)); // hide // Note viewer addRect( @@ -338,6 +341,7 @@ TopToBottomOrientation::TopToBottomOrientation() { addRect(PredefinedRect::PINNED_CENTER_KEY, QRect((FRAME_HEADER_WIDTH - PINNED_SIZE) / 2, (CELL_HEIGHT - PINNED_SIZE) / 2, PINNED_SIZE, PINNED_SIZE)); + addRect(PredefinedRect::FRAME_INDICATOR, QRect(0, 0, -1, -1)); // hide // Column viewer addRect(PredefinedRect::LAYER_HEADER, @@ -889,6 +893,10 @@ LeftToRightOrientation::LeftToRightOrientation() { QRect(CELL_WIDTH - 2, CELL_DRAG_HEIGHT, 2, CELL_HEIGHT - CELL_DRAG_HEIGHT)); addRect(PredefinedRect::LOOP_ICON, QRect(0, keyRect.top(), 10, 11)); + addRect( + PredefinedRect::FRAME_DOT, + QRect((CELL_WIDTH - FRAME_DOT_SIZE) / 2 - 1, + CELL_HEIGHT - FRAME_DOT_SIZE - 6, FRAME_DOT_SIZE, FRAME_DOT_SIZE)); // Notes viewer addRect( @@ -908,16 +916,18 @@ LeftToRightOrientation::LeftToRightOrientation() { addRect(PredefinedRect::PLAY_RANGE, QRect(0, PLAY_RANGE_Y, CELL_WIDTH, PLAY_MARKER_SIZE)); addRect(PredefinedRect::ONION, - QRect(ONION_X, ONION_Y + (3 * ONION_DOT_SIZE - ONION_SIZE) / 2, - ONION_SIZE, ONION_SIZE) + QRect(ONION_X + (CELL_WIDTH - ONION_SIZE) / 2 - 1, + ONION_Y + (3 * ONION_DOT_SIZE - ONION_SIZE) / 2, ONION_SIZE, + ONION_SIZE) .adjusted(1, 2, 1, 2)); int adjustOnion = (ONION_SIZE - ONION_DOT_SIZE) / 2; addRect(PredefinedRect::ONION_DOT, - QRect(ONION_X + adjustOnion, ONION_Y + ONION_DOT_SIZE, ONION_DOT_SIZE, - ONION_DOT_SIZE) + QRect(ONION_X + adjustOnion + (CELL_WIDTH - ONION_SIZE) / 2, + ONION_Y + ONION_DOT_SIZE, ONION_DOT_SIZE, ONION_DOT_SIZE) .adjusted(1, 1, 1, 1)); addRect(PredefinedRect::ONION_DOT_FIXED, - QRect(ONION_X + adjustOnion, ONION_Y, ONION_DOT_SIZE, ONION_DOT_SIZE) + QRect(ONION_X + adjustOnion + (CELL_WIDTH - ONION_SIZE) / 2, ONION_Y, + ONION_DOT_SIZE, ONION_DOT_SIZE) .adjusted(1, 1, 1, 1)); addRect(PredefinedRect::ONION_AREA, QRect(ONION_X, ONION_Y, CELL_WIDTH, ONION_SIZE)); @@ -929,6 +939,10 @@ LeftToRightOrientation::LeftToRightOrientation() { PredefinedRect::PINNED_CENTER_KEY, QRect((CELL_WIDTH - PINNED_SIZE) / 2, (FRAME_HEADER_HEIGHT - PINNED_SIZE) / 2, PINNED_SIZE, PINNED_SIZE)); + addRect(PredefinedRect::FRAME_INDICATOR, + QRect((CELL_WIDTH - FRAME_IND_SIZE) / 2, + FRAME_HEADER_HEIGHT - FRAME_IND_SIZE, FRAME_IND_SIZE, + FRAME_IND_SIZE)); // Column viewer addRect(PredefinedRect::LAYER_HEADER, diff --git a/toonz/sources/toonzqt/spreadsheetviewer.cpp b/toonz/sources/toonzqt/spreadsheetviewer.cpp index 9a7e7a8..37a233c 100644 --- a/toonz/sources/toonzqt/spreadsheetviewer.cpp +++ b/toonz/sources/toonzqt/spreadsheetviewer.cpp @@ -75,13 +75,18 @@ void FrameScroller::onHScroll(int x) { static QList frameScrollers; -void FrameScroller::handleScroll(const QPoint &offset) const { - CellPositionRatio ratio = orientation()->xyToPositionRatio(offset); +void FrameScroller::handleScroll(QPoint &offset) { if ((m_orientation->isVerticalTimeline() && offset.x()) || (!m_orientation->isVerticalTimeline() && offset.y())) // only synchronize changes by frames axis return; + // In case of a zoomed viewer is sending this out, adjust the + // zoomed offset back to a standardized offset + emit zoomScrollAdjust(offset, false); + + CellPositionRatio ratio = orientation()->xyToPositionRatio(offset); + for (int i = 0; i < frameScrollers.size(); i++) if (frameScrollers[i] != this) { if (!frameScrollers[i]->isSyncing()) { @@ -95,6 +100,11 @@ void adjustScrollbar(QScrollBar *scrollBar, int add); void FrameScroller::onScroll(const CellPositionRatio &ratio) { QPoint offset = orientation()->positionRatioToXY(ratio); + + // In case of a zoomed viewer is receiving this, adjust the + // standardized offset to zoomed offset + emit zoomScrollAdjust(offset, true); + // scroll area should be resized before moving down the scroll bar. // SpreadsheetViewer::onPrepareToScrollOffset() will be invoked immediately // since the receiver is in the same thread.