diff --git a/toonz/sources/tnztools/pumptool.cpp b/toonz/sources/tnztools/pumptool.cpp index 2bf17283..725bfd38 100644 --- a/toonz/sources/tnztools/pumptool.cpp +++ b/toonz/sources/tnztools/pumptool.cpp @@ -58,6 +58,9 @@ class PumpTool final : public TTool { bool m_cursorEnabled; //!< Whether the 'pump preview cursor' can be seen bool m_draw; //!< Should be removed...? + bool m_isCtrlPressed; //!< Whether control key is held down or not + int m_lockedStrokeIndex; + TPointD m_oldPoint, m_downPoint; //!< Mouse positions upon editing TThickPoint m_cursor; //!< Pump preview cursor data int m_cursorId; @@ -129,6 +132,10 @@ private: void splitStroke(TStroke *s); TStroke *mergeStrokes(const std::vector &strokes); + bool getNearestStrokeWithLock(const TPointD &p, double &outW, + UINT &strokeIndex, double &dist2, + bool onlyInCurrentGroup = false); + } PumpToolInstance; //***************************************************************************** @@ -181,7 +188,7 @@ void PumpTool::draw() { tglDrawCircle(m_cursor, m_cursor.thick + 4 * getPixelSize()); } - if (vi->getNearestStroke(m_cursor, w, index, dist, true)) { + if (getNearestStrokeWithLock(m_cursor, w, index, dist, true)) { TStroke *stroke = vi->getStroke(index); double totalLen = stroke->getLength(); double actionLen = actionRadius(totalLen); @@ -203,8 +210,8 @@ void PumpTool::draw() { len1 += totalLen; } else { len1 = 0; - } - } + } + } double len2 = len + actionLen; if (len2 > totalLen) { @@ -212,8 +219,8 @@ void PumpTool::draw() { len2 -= totalLen; } else { len2 = totalLen; - } - } + } + } w1 = stroke->getParameterAtLength(len1); w2 = stroke->getParameterAtLength(len2); @@ -265,7 +272,7 @@ void PumpTool::draw() { //---------------------------------------------------------------------- -void PumpTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) { +void PumpTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) { if (getViewer() && getViewer()->getGuidedStrokePickerMode()) { getViewer()->doPickGuideStroke(pos); return; @@ -273,6 +280,8 @@ void PumpTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) { if (m_active || !m_enabled) return; + m_isCtrlPressed = e.isCtrlPressed(); + assert(m_undo == 0); m_active = false; @@ -297,7 +306,7 @@ void PumpTool::leftButtonDown(const TPointD &pos, const TMouseEvent &) { int i; UINT index; - if (vi->getNearestStroke(pos, m_actionW, index, dist2)) { + if (getNearestStrokeWithLock(pos, m_actionW, index, dist2)) { // A stroke near the pressed point was found - modify it m_active = true; m_strokeIndex = index; @@ -348,6 +357,8 @@ void PumpTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) { TVectorImageP vi(getImage(true)); if (!vi || !m_outStroke) return; + m_isCtrlPressed = e.isCtrlPressed(); + QMutexLocker lock(vi->getMutex()); // Revert current deformation, recovering the one from button press @@ -385,7 +396,7 @@ void PumpTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) { // Apply deformation std::vector splitStrokesCopy(m_splitStrokes); - splitStrokesCopy[m_stroke1Idx] = stroke1; + splitStrokesCopy[m_stroke1Idx] = stroke1; if (stroke2) splitStrokesCopy[m_stroke2Idx] = stroke2; m_outStroke = mergeStrokes(splitStrokesCopy); @@ -398,7 +409,7 @@ void PumpTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e) { //---------------------------------------------------------------------- -void PumpTool::leftButtonUp(const TPointD &pos, const TMouseEvent &) { +void PumpTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e) { TVectorImageP vi; if (!m_active || !m_enabled) goto cleanup; @@ -406,6 +417,8 @@ void PumpTool::leftButtonUp(const TPointD &pos, const TMouseEvent &) { vi = TVectorImageP(getImage(true)); if (!vi) goto cleanup; + m_isCtrlPressed = e.isCtrlPressed(); + { m_active = false; @@ -415,8 +428,8 @@ void PumpTool::leftButtonUp(const TPointD &pos, const TMouseEvent &) { double t; UINT index; double dist2; - if (vi->getNearestStroke(pos, t, index, dist2)) { - TStroke *nearestStroke = vi->getStroke(index); + if (getNearestStrokeWithLock(pos, t, index, dist2)) { + TStroke *nearestStroke = vi->getStroke(index); if (nearestStroke) m_cursor = nearestStroke->getThickPoint(t); } @@ -478,6 +491,8 @@ void PumpTool::invalidateCursorArea() { void PumpTool::mouseMove(const TPointD &pos, const TMouseEvent &e) { if (m_active || !m_enabled) return; + m_isCtrlPressed = e.isCtrlPressed(); + // Cursor preview updates on 3-pixel steps if (tdistance2(pos, m_oldPoint) < 9.0 * sq(getPixelSize())) return; @@ -502,7 +517,7 @@ bool PumpTool::moveCursor(const TPointD &pos) { double t; UINT index; double dist2; - if (vi->getNearestStroke(pos, t, index, dist2)) { + if (getNearestStrokeWithLock(pos, t, index, dist2)) { TStroke *stroke = vi->getStroke(index); if (stroke) { m_cursor = stroke->getThickPoint(t); @@ -690,7 +705,7 @@ void PumpTool::splitStroke(TStroke *s) { cpCount = stroke2->getControlPointCount(); m_cpLenDiff2.resize(cpCount); - for (i = 0; i < cpCount; ++i) + for (i = 0; i < cpCount; ++i) m_cpLenDiff2[i] = stroke2->getLengthAtControlPoint(i) - m_actionS2; } } @@ -753,3 +768,29 @@ TStroke *PumpTool::mergeStrokes(const std::vector &strokes) { return mergedStroke; } + +bool PumpTool::getNearestStrokeWithLock(const TPointD &p, double &outW, + UINT &strokeIndex, double &dist2, + bool onlyInCurrentGroup) { + TVectorImageP vi = TImageP(getImage(false)); + if (!vi) return false; + + if (m_lockedStrokeIndex >= vi->getStrokeCount()) { + m_lockedStrokeIndex = -1; + } + + if (m_isCtrlPressed && m_lockedStrokeIndex >= 0) { + TStroke *stroke = vi->getStroke(m_lockedStrokeIndex); + strokeIndex = m_lockedStrokeIndex; + return stroke->getNearestW(p, outW, dist2); + } + + UINT index; + if (vi->getNearestStroke(p, outW, index, dist2, onlyInCurrentGroup)) { + m_lockedStrokeIndex = index; + strokeIndex = index; + return true; + } + + return false; +}