diff --git a/toonz/sources/tnztools/CMakeLists.txt b/toonz/sources/tnztools/CMakeLists.txt index e6bfa70..c375266 100644 --- a/toonz/sources/tnztools/CMakeLists.txt +++ b/toonz/sources/tnztools/CMakeLists.txt @@ -9,6 +9,7 @@ set(MOC_HEADERS tooloptionscontrols.h toonzrasterbrushtool.h viewtools.h + controlpointeditortool.h ../include/tools/imagegrouping.h ../include/tools/screenpicker.h ../include/tools/toolhandle.h diff --git a/toonz/sources/tnztools/controlpointeditortool.cpp b/toonz/sources/tnztools/controlpointeditortool.cpp index 45b1849..5bb2a95 100644 --- a/toonz/sources/tnztools/controlpointeditortool.cpp +++ b/toonz/sources/tnztools/controlpointeditortool.cpp @@ -1,11 +1,9 @@ - +#include "controlpointeditortool.h" #include "tundo.h" #include "tthreadmessage.h" #include "tvectorimage.h" #include "drawutil.h" -#include "controlpointselection.h" -#include "tproperty.h" #include "tenv.h" #include "tools/tool.h" @@ -22,8 +20,6 @@ #include "toonz/stage2.h" #include "toonz/tstageobject.h" -// For Qt translation support -#include #include using namespace ToolUtils; @@ -121,126 +117,6 @@ void getSegmentParameter(ControlPointEditorStroke *cpEditor, int beforeIndex, } } // namespace -//============================================================================= -// ControlPointEditorTool -//----------------------------------------------------------------------------- - -class ControlPointEditorTool final : public TTool { - Q_DECLARE_TR_FUNCTIONS(ControlPointEditorTool) - - bool m_draw; - bool m_isMenuViewed; - int m_lastPointSelected; - bool m_isImageChanged; - ControlPointSelection m_selection; - ControlPointEditorStroke m_controlPointEditorStroke; - std::pair m_moveSegmentLimitation; // Indici dei punti di controllo - // che limitano la curva da - // muovere - ControlPointEditorStroke m_moveControlPointEditorStroke; // Usate per muovere - // la curva durante - // il drag. - TRectD m_selectingRect; - TPointD m_pos; - - TPropertyGroup m_prop; - TEnumProperty m_selectType; - - TBoolProperty - m_autoSelectDrawing; // Consente di scegliere se swichare tra i livelli. - - TBoolProperty m_snap; - TEnumProperty m_snapSensitivity; - double m_snapMinDistance; - bool m_foundSnap; - TPointD m_snapPoint; - - TPointD m_firstPos; // The first point inserted in m_track - StrokeGenerator m_track; // Lazo selection generator. - TStroke *m_stroke; // Stores the stroke generated by m_track. - - enum Action { - NONE, - RECT_SELECTION, - FREEHAND_SELECTION, - CP_MOVEMENT, - SEGMENT_MOVEMENT, - IN_SPEED_MOVEMENT, - OUT_SPEED_MOVEMENT - }; - Action m_action; - - enum CursorType { NORMAL, ADD, EDIT_SPEED, EDIT_SEGMENT, NO_ACTIVE }; - CursorType m_cursorType; - - TUndo *m_undo; - - void selectRegion(TStroke *stroke); - void startFreehand(const TPointD &pos); - void freehandDrag(const TPointD &pos); - void closeFreehand(const TPointD &pos); - -public: - ControlPointEditorTool(); - - ToolType getToolType() const override { return TTool::LevelWriteTool; } - - void updateTranslation() override; - - TPropertyGroup *getProperties(int targetType) override { return &m_prop; } - - // da TSelectionOwner: chiamato quando la selezione corrente viene cambiata - void onSelectionChanged() { invalidate(); } - - // da TSelectionOwner: chiamato quando si vuole ripristinare una vecchia - // selezione - // attualmente non usato - bool select(const TSelection *) { return false; } - ControlPointEditorStroke getControlPointEditorStroke() { - return m_controlPointEditorStroke; - }; - - void initUndo(); - - void getNearestStrokeColumnIndexes(std::vector &indexes, TPointD pos); - - void drawMovingSegment(); - void drawControlPoint(); - void draw() override; - void mouseMove(const TPointD &pos, const TMouseEvent &e) override; - void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override; - void rightButtonDown(const TPointD &pos, const TMouseEvent &) override; - - void moveControlPoints(const TPointD &delta); - void moveSpeed(const TPointD &delta, bool isIn); - void moveSegment(const TPointD &delta, bool dragging, bool isShiftPressed); - - void leftButtonDrag(const TPointD &pos, const TMouseEvent &e) override; - void leftButtonUp(const TPointD &pos, const TMouseEvent &e) override; - void addContextMenuItems(QMenu *menu) override; - - void linkSpeedInOut(int index); - void unlinkSpeedInOut(int pointIndex); - - bool keyDown(QKeyEvent *event) override; - void onEnter() override; - void onLeave() override; - bool onPropertyChanged(std::string propertyName) override; - - void onActivate() override; - void onDeactivate() override; - void onImageChanged() override; - int getCursorId() const override; - - // returns true if the pressed key is recognized and processed. - bool isEventAcceptable(QEvent *e) override; - - TPointD calculateSnap(TPointD pos); - void drawSnap(); - TPointD getSnap(TPointD pos); - void resetSnap(); - -} controlPointEditorTool; //----------------------------------------------------------------------------- @@ -966,9 +842,6 @@ bool ControlPointEditorTool::keyDown(QKeyEvent *event) { TVectorImageP vi(getImage(true)); if (!vi || (vi && m_selection.isEmpty())) return false; - // Inizializzo l'UNDO - initUndo(); - TPointD delta; switch (event->key()) { case Qt::Key_Up: @@ -987,6 +860,9 @@ bool ControlPointEditorTool::keyDown(QKeyEvent *event) { return false; break; } + // Inizializzo l'UNDO + initUndo(); + moveControlPoints(delta); invalidate(); @@ -1084,8 +960,8 @@ void ControlPointEditorTool::onImageChanged() { m_controlPointEditorStroke.setStroke((TVectorImage *)0, -1); return; } else { - m_selection.selectNone(); - m_controlPointEditorStroke.setStroke(vi, currentStroke); + if (m_controlPointEditorStroke.setStroke(vi, currentStroke)) + m_selection.selectNone(); } } @@ -1158,3 +1034,5 @@ void ControlPointEditorTool::closeFreehand(const TPointD &pos) { m_stroke = m_track.makeStroke(error); m_stroke->setStyle(1); } + +ControlPointEditorTool controlPointEditorTool; \ No newline at end of file diff --git a/toonz/sources/tnztools/controlpointeditortool.h b/toonz/sources/tnztools/controlpointeditortool.h index fe64369..e394ccd 100644 --- a/toonz/sources/tnztools/controlpointeditortool.h +++ b/toonz/sources/tnztools/controlpointeditortool.h @@ -1,214 +1,141 @@ #pragma once -#ifndef CONTROLPOINT_SELECTION_INCLUDED -#define CONTROLPOINT_SELECTION_INCLUDED +#ifndef CONTROLPOINTEDITORTOOL_H +#define CONTROLPOINTEDITORTOOL_H #include "toonzqt/selection.h" #include "tool.h" #include "tstroke.h" #include "tcurves.h" +#include "tproperty.h" +#include "controlpointselection.h" +#include "toonz/strokegenerator.h" + +// For Qt translation support +#include + +class TUndo; //============================================================================= -// ControlPointEditorStroke +// ControlPointEditorTool //----------------------------------------------------------------------------- -/*!La classe ControlPointEditorStroke effettua tutte le operazioni matematiche - * sullo Stroke */ -class ControlPointEditorStroke { -private: - //! Punti di controllo comprensivi di SpeedIn e SpeenOut - class ControlPoint { - public: - int m_indexPoint; - TPointD m_speedIn; - TPointD m_speedOut; - bool m_isCusp; - - ControlPoint(int i, TPointD speedIn, TPointD speedOut, bool isCusp = true) - : m_indexPoint(i) - , m_speedIn(speedIn) - , m_speedOut(speedOut) - , m_isCusp(isCusp) {} - ControlPoint() {} +class ControlPointEditorTool final : public TTool { + Q_DECLARE_TR_FUNCTIONS(ControlPointEditorTool) + + bool m_draw; + bool m_isMenuViewed; + int m_lastPointSelected; + bool m_isImageChanged; + ControlPointSelection m_selection; + ControlPointEditorStroke m_controlPointEditorStroke; + std::pair m_moveSegmentLimitation; // Indici dei punti di controllo + // che limitano la curva da + // muovere + ControlPointEditorStroke m_moveControlPointEditorStroke; // Usate per muovere + // la curva durante + // il drag. + TRectD m_selectingRect; + TPointD m_pos; + + TPropertyGroup m_prop; + TEnumProperty m_selectType; + + TBoolProperty + m_autoSelectDrawing; // Consente di scegliere se swichare tra i livelli. + + TBoolProperty m_snap; + TEnumProperty m_snapSensitivity; + double m_snapMinDistance; + bool m_foundSnap; + TPointD m_snapPoint; + + TPointD m_firstPos; // The first point inserted in m_track + StrokeGenerator m_track; // Lazo selection generator. + TStroke* m_stroke; // Stores the stroke generated by m_track. + + enum Action { + NONE, + RECT_SELECTION, + FREEHAND_SELECTION, + CP_MOVEMENT, + SEGMENT_MOVEMENT, + IN_SPEED_MOVEMENT, + OUT_SPEED_MOVEMENT }; + Action m_action; + + enum CursorType { NORMAL, ADD, EDIT_SPEED, EDIT_SEGMENT, NO_ACTIVE }; + CursorType m_cursorType; + + TUndo* m_undo; - vector m_controlPoints; - TStroke *m_stroke; - int m_strokeIndex; - - /*! Viene riempito il vettore \b m_controlPoints scegliendo da \b m_stroke - soltanto - i punti di controllo nelle posizioni pari. - */ - void updateControlPoints(); - - //! Viene settato il valore \b p.m_isCusp osservando lo SpeedIn e SpeedOut del - //! punto. - void setCusp(ControlPoint &p); - - void setSpeedIn(ControlPoint &cp, const TPointD &p) { - cp.m_speedIn = m_stroke->getControlPoint(cp.m_indexPoint) - p; - } - void setSpeedOut(ControlPoint &cp, const TPointD &p) { - cp.m_speedOut = p - m_stroke->getControlPoint(cp.m_indexPoint); - } - - /*! Inserisce un punto nel chunk di lunghezza maggiore selezionato tra quelli - compresi - tra il chunk \b indexA e \b indexB. - */ - void insertPoint(int indexA, int indexB); - - /*! Verifica che in \b m_stroke tra due cuspidi sia sempre presente un numero - pari - di Chunk: in caso contrario richiama la \b insertPoint; - */ - void adjustChunkParity(); - - //! Sposta il punto di controllo \b index di un fattore delta - void moveSingleControlPoint(int indexPoint, const TPointD &delta); - - /*! Sposta i punti di controllo precedenti al punto \b index di un fattore -delta. -Se \b moveSpeed==true e' usato per movimento degli speed, altrimenti per - movimento dei punti di controllo. - */ - void movePrecControlPoints(int indexPoint, const TPointD &delta, - bool moveSpeed); - - /*! Sposta i punti di controllo successivi al punto \b index di un fattore -delta. -Se \b moveSpeed==true e' usato per movimento degli speed, altrimenti per - movimento dei punti di controllo. - */ - void moveNextControlPoints(int indexPoint, const TPointD &delta, - bool moveSpeed); + void selectRegion(TStroke* stroke); + void startFreehand(const TPointD& pos); + void freehandDrag(const TPointD& pos); + void closeFreehand(const TPointD& pos); public: - ControlPointEditorStroke() : m_stroke(0), m_strokeIndex(-1) {} - - /*!Viene modificato lo stroke in modo tale che tra due cuspidi esista sempre - un - numero pari di chunk. - ATTENZIONE: poiche' puo' aggiungere punti di controllo allo stroke, e' bene - richiamare - tale funzione solo quando e' necessario. - */ - void setStroke(TStroke *stroke, int strokeIndex); - - void setStrokeIndex(int strokeIndex) { m_strokeIndex = strokeIndex; } - int getStrokeIndex() { return m_strokeIndex; } - - TThickPoint getControlPoint(int index) const { - assert(m_stroke && 0 <= index && index < (int)m_controlPoints.size()); - return m_stroke->getControlPoint(m_controlPoints[index].m_indexPoint); - } - TThickPoint getSpeedIn(int index) const { - assert(m_stroke && 0 <= index && index < (int)m_controlPoints.size()); - return m_controlPoints[index].m_speedIn; - } - TThickPoint getSpeedOut(int index) const { - assert(m_stroke && 0 <= index && index < (int)m_controlPoints.size()); - return m_controlPoints[index].m_speedOut; - } - - int getControlPointCount() const { return m_controlPoints.size(); } - - //! Ritorna \b true se il punto index e' una cuspide. - bool getIsCusp(int index) const { - assert(m_stroke && 0 <= index && index < (int)getControlPointCount()); - return m_controlPoints[index].m_isCusp; - } - - //! Viene settato il valore \b m_isCusp del punto index-esimo a \b isCusp. - void linkUnlinkSpeeds(int index, bool isCusp) { - m_controlPoints[index].m_isCusp = isCusp; - } - - /*! Sposta il ControlPoint \b index di un fattore delta con continuita', - cioe' spostando anche i punti di controllo adiacenti se - necessario.*/ - void moveControlPoint(int index, const TPointD &delta); - - //! Cancella il punto di controllo \b point. - void deleteControlPoint(int index); - - /*! Aggiunge il punto di controllo \b point. - Ritorna l'indice del punto di controllo appena inserito.*/ - int addControlPoint(const TPointD &pos); - - /*! Ritorna l'indice del cp piu' vicino al punto pos. - distance2 riceve il valore del quadrato della distanza - se la ControlPointEditorStroke e' vuota ritorna -1.*/ - int getClosestControlPoint(const TPointD &pos, double &distance2) const; - - //! Ritorna true sse e' definita una curva e se pos e' abbastanza vicino alla - //! curva - bool isCloseTo(const TPointD &pos, double pixelSize) const; - - /*! Ritorna l'indice del cp il cui bilancino e' piu' vicino al punto pos. - \b minDistance2 riceve il valore del quadrato della distanza - se la ControlPointEditorStroke e' vuota ritorna -1. \b isIn e' true - se il bilancino cliccato - corrisponde allo SpeedIn.*/ - int getClosestSpeed(const TPointD &pos, double &minDistance2, - bool &isIn) const; - - /*! Sposta il bilancino del punto \b index di un fattore delta. \b isIn deve - essere - true se si vuole spostare lo SpeedIn.*/ - void moveSpeed(int index, const TPointD &delta, bool isIn, double pixelSize); - - /*! Se isLinear e' true setta a "0" il valore dello speedIn e il valore dello - speedOut; - altrimenti li setta ad un valore di default. Ritorna vero se - almeno un punto e' ststo modificato.*/ - bool setLinear(int index, bool isLinear); - - void setLinearSpeedIn(int index); - void setLinearSpeedOut(int index); - - bool isSpeedInLinear(int index); - bool isSpeedOutLinear(int index); - - bool isSelfLoop() { return m_stroke->isSelfLoop(); } -}; + ControlPointEditorTool(); -//============================================================================= -// ControlPointSelection -//----------------------------------------------------------------------------- + ToolType getToolType() const override { return TTool::LevelWriteTool; } -class ControlPointSelection : public QObject, public TSelection { - Q_OBJECT + void updateTranslation() override; -private: - std::set m_selectedPoints; - ControlPointEditorStroke *m_controlPointEditorStroke; + TPropertyGroup* getProperties(int targetType) override { return &m_prop; } -public: - ControlPointSelection() : m_controlPointEditorStroke(0) {} + // da TSelectionOwner: chiamato quando la selezione corrente viene cambiata + void onSelectionChanged() { invalidate(); } + + // da TSelectionOwner: chiamato quando si vuole ripristinare una vecchia + // selezione + // attualmente non usato + bool select(const TSelection*) { return false; } + ControlPointEditorStroke getControlPointEditorStroke() { + return m_controlPointEditorStroke; + }; + + void initUndo(); + + void getNearestStrokeColumnIndexes(std::vector& indexes, TPointD pos); + + void drawMovingSegment(); + void drawControlPoint(); + void draw() override; + void mouseMove(const TPointD& pos, const TMouseEvent& e) override; + void leftButtonDown(const TPointD& pos, const TMouseEvent& e) override; + void rightButtonDown(const TPointD& pos, const TMouseEvent&) override; + + void moveControlPoints(const TPointD& delta); + void moveSpeed(const TPointD& delta, bool isIn); + void moveSegment(const TPointD& delta, bool dragging, bool isShiftPressed); - void setControlPointEditorStroke( - ControlPointEditorStroke *controlPointEditorStroke) { - m_controlPointEditorStroke = controlPointEditorStroke; - } + void leftButtonDrag(const TPointD& pos, const TMouseEvent& e) override; + void leftButtonUp(const TPointD& pos, const TMouseEvent& e) override; + void addContextMenuItems(QMenu* menu) override; - bool isEmpty() const { return m_selectedPoints.empty(); } + void linkSpeedInOut(int index); + void unlinkSpeedInOut(int pointIndex); - void selectNone() { m_selectedPoints.clear(); } - bool isSelected(int index) const; - void select(int index); - void unselect(int index); + bool keyDown(QKeyEvent* event) override; + void onEnter() override; + void onLeave() override; + bool onPropertyChanged(std::string propertyName) override; - void deleteControlPoints(); + void onActivate() override; + void onDeactivate() override; + void onImageChanged() override; + int getCursorId() const override; - void addMenuItems(QMenu *menu); + // returns true if the pressed key is recognized and processed. + bool isEventAcceptable(QEvent* e) override; - void enableCommands(); + TPointD calculateSnap(TPointD pos); + void drawSnap(); + TPointD getSnap(TPointD pos); + void resetSnap(); -protected slots: - void setLinear(); - void setUnlinear(); + bool isBusy() { return m_undo != nullptr; } }; -#endif // CONTROLPOINT_SELECTION_INCLUDED +#endif // CONTROLPOINTEDITORTOOL_H diff --git a/toonz/sources/tnztools/controlpointselection.cpp b/toonz/sources/tnztools/controlpointselection.cpp index cb67c7f..2019561 100644 --- a/toonz/sources/tnztools/controlpointselection.cpp +++ b/toonz/sources/tnztools/controlpointselection.cpp @@ -3,6 +3,7 @@ #include "controlpointselection.h" #include "tvectorimage.h" #include "tmathutil.h" +#include "controlpointeditortool.h" #include "tools/toolhandle.h" #include "tools/toolutils.h" @@ -71,7 +72,7 @@ void insertPoint(TStroke *stroke, int indexA, int indexB) { if (j == stroke->getChunkCount() - 1) w1 = 1; else - w1 = stroke->getW(stroke->getChunk(j)->getP2()); + w1 = stroke->getW(stroke->getChunk(j)->getP2()); double length0 = stroke->getLength(w0); double length1 = stroke->getLength(w1); if (length < length1 - length0) { @@ -179,8 +180,11 @@ void ControlPointEditorStroke::resetControlPoints() { } if (i == 0) // calcola solo lo speedOut { - speedOut = nextP - p; - if (isSelfLoop()) speedIn = p - stroke->getControlPoint(cpCount - 2); + speedOut = nextP - p; + if (isSelfLoop()) { + precP = stroke->getControlPoint(cpCount - 2); + speedIn = p - precP; + } } if (i == cpCount - 1) // calcola solo lo speedIn speedIn = p - precP; @@ -452,23 +456,26 @@ void ControlPointEditorStroke::moveSingleControlPoint(int index, //----------------------------------------------------------------------------- -void ControlPointEditorStroke::setStroke(const TVectorImageP &vi, +bool ControlPointEditorStroke::setStroke(const TVectorImageP &vi, int strokeIndex) { + bool ret = true; + if (m_strokeIndex == strokeIndex && m_vi == vi) ret = false; m_strokeIndex = strokeIndex; m_vi = vi; if (!vi || strokeIndex == -1) { m_controlPoints.clear(); - return; + return true; } TStroke *stroke = getStroke(); const TThickQuadratic *chunk = stroke->getChunk(0); if (stroke->getControlPointCount() == 3 && chunk->getP0() == chunk->getP1() && chunk->getP0() == chunk->getP2()) { resetControlPoints(); - return; + return ret; } adjustChunkParity(); resetControlPoints(); + return ret; } //----------------------------------------------------------------------------- @@ -622,8 +629,8 @@ bool ControlPointEditorStroke::setLinear(int index, bool isLinear, if (isLinear != isSpeedOutLinear(index)) setLinearSpeedOut(index, isLinear, updatePoints); else - moveNext = false; - bool ret = moveNext || movePrec; + moveNext = false; + bool ret = moveNext || movePrec; if (ret) m_controlPoints[index].m_isCusp = true; return ret; } @@ -813,7 +820,7 @@ void ControlPointEditorStroke::deleteControlPoint(int index) { // Aggiorno gli indici dei punti nella stroke assert((int)newPointsIndex.size() == (int)getControlPointCount()); - for (i = 0; i < (int)getControlPointCount(); i++) + for (i = 0; i < (int)getControlPointCount(); i++) m_controlPoints[i].m_pointIndex = newPointsIndex.at(i); int prev = prevIndex(index); @@ -1077,6 +1084,11 @@ void ControlPointSelection::setUnlinear() { void ControlPointSelection::deleteControlPoints() { TTool *tool = TTool::getApplication()->getCurrentTool()->getTool(); + + // cancel deleting while dragging points + ControlPointEditorTool *cpTool = dynamic_cast(tool); + if (cpTool && cpTool->isBusy()) return; + TVectorImageP vi(tool->getImage(false)); int currentStrokeIndex = m_controlPointEditorStroke->getStrokeIndex(); if (!vi || isEmpty() || currentStrokeIndex == -1) return; diff --git a/toonz/sources/tnztools/controlpointselection.h b/toonz/sources/tnztools/controlpointselection.h index 44fa20f..b4682be 100644 --- a/toonz/sources/tnztools/controlpointselection.h +++ b/toonz/sources/tnztools/controlpointselection.h @@ -66,7 +66,7 @@ public: /*! Modify stroke: between two linear or cusp point must be a pair chunk number. PAY ATTENTION: Can add control point in the stroke. */ - void setStroke(const TVectorImageP &vi, int strokeIndex); + bool setStroke(const TVectorImageP &vi, int strokeIndex); TStroke *getStroke() const { return m_vi ? m_vi->getStroke(m_strokeIndex) : 0; } @@ -161,7 +161,6 @@ public: void addMenuItems(QMenu *menu); void enableCommands() override; - protected slots: void setLinear(); void setUnlinear();